AI Engineer World's Fair 2025
Case Study + Deep Dive: Telemedicine Support Agents with LangGraph/MCP
Read the talk
Case Study + Deep Dive: Telemedicine Support Agents with LangGraph/MCP
Ava turns patient texts into proposed treatment-state updates, scheduled messages and human review, while keeping medical instructions in documents clinicians can maintain.
From a talk by Dan Mason
Before you start: Familiarity with Python, LLM tool calling and basic application state will help; the article introduces the LangGraph and MCP mechanisms as they appear.
Keeping treatment on track at home
How do you help someone follow a medication schedule after they leave a clinic, when they are administering the treatment themselves during an emotionally difficult event? Avila Science addresses that problem for early pregnancy loss. Its text-message service answers questions, sends reminders and checks in on patients while they retain their relationship with a doctor. The difficulty extends beyond this treatment: chemotherapy is another setting where remembering what to do, and when, can be hard.
Dan Mason’s walkthrough exposes a hybrid system built by Stride, using selectively redacted client code. Custom requirements justified custom software, but the implementation draws heavily on LangChain, LangGraph and LangSmith. Patient information, privacy obligations and regional hosting requirements shape the architecture. Human judgment remains part of the workflow, rather than something the model is expected to replace.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Two systems with a defined contract
LangGraph’s visual representation made the workflow explainable to the client: follow a transition, inspect a loop, find the evaluation step and identify where a human enters. The examples use Claude, but Mason says the core tool-calling code also works with Gemini and OpenAI models. Portability comes from keeping most behavior in tool calls and MCP interactions rather than provider-specific features.
| Layer | Technologies | Responsibility |
|---|---|---|
| Agent runtime | Python, LangGraph | Interpret the conversation and propose changes |
| Application | Node, React, MongoDB, Twilio | Dashboard, persistence and text messaging |
| Hosting | AWS | Deploy the components in required regions |
Some deployments needed to remain entirely in Europe, which influenced the cloud choice. The agent runtime is only one part of the service; the gateway and durable application remain conventional software.
LangSmith supplies traces and datasets, while an external harness pulls and preprocesses that data for promptfoo’s LLM rubric. That separation accommodates the preprocessing this workflow needs and avoids making LangSmith’s evaluation system the only option. The rubric lets another model judge results against written criteria.
The team consisted of two software engineers, a designer and Mason. The engineers maintained the gateway, dashboard and database; Mason built the LangGraph side behind their shared contract. After an earlier engineering career and a long period in product work, he returned to implementation with coding assistants. Cline generated much of the Python, while he wrote most of the prompt material by hand. He favored access to capable models and their context over minimizing coding-assistant token spend. A public LangGraph/MCP sample was available for experimentation, separate from the proprietary application shown in the workshop.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
From button pushing to supervised operations
Here, an agent means an LLM controls application flow. That requires three things together: capability, transparency and control. A capable system whose actions are invisible is dangerous; a transparent system that operators cannot steer leaves them watching mistakes they cannot correct. Ava’s architecture tries to make the work both visible and steerable.
The existing product already had a detailed treatment workflow. An operator would read a text saying the patient had taken medicine at 3 PM, or asking whether bleeding was expected, and click the corresponding console button. The button selected approved language from a complicated flowchart. Growing that service required more people clicking more buttons, while adding treatments required changing the software.
The replacement expresses each treatment as a blueprint and a knowledge base. These preserve medically approved wording—the reason operators originally selected messages instead of composing advice freely. An agent proposes the next action, and a self-evaluation step surfaces complicated situations. Operations associates become supervisors. A physician’s assistant leads the operations team and receives out-of-blueprint escalations through Slack, preserving a clinical escalation path.
Mason estimates roughly 10× patient-serving capacity, with measurement still underway. Development and token costs remain, but another major benefit is the ability to introduce treatments through maintained documents, largely Google Docs, without implementing another treatment-specific code path. Clinical-quality measurement was still early despite use with real people; operator review and patient satisfaction were the proposed signals. The capacity estimate assumes operators review about one in ten exchanges, with each approval taking roughly the effort of the old button click.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A proposal, an evaluator and a state boundary
The virtual operations associate, or virtual OA, examines a patient interaction and proposes what should happen next. Its job includes choosing messages, asking questions and maintaining facts such as which medicines the patient has, when they plan to take them, when they actually took them and their local time. The proposal then goes to an evaluator agent.
This evaluator is a live LLM judge, separate from offline regression evaluation. It assesses the proposed response and the complexity of the interaction. Mason finds complexity easier to elicit reliably than admissions of error: a model may insist its answer is right while still recognizing that it changed patient data, set anchors and scheduled several messages. That combination can justify human review.
Two kinds of tools support the run. MCP tools read local documents or communicate with the larger application across the network. Local Python tools manipulate state inside the current graph run. Those local mutations do not immediately write to a database. Incoming JSON initializes the graph state; the application also supplies that state as model-visible context. Tool calls evolve it, and Python serializes the resulting state at the end. Graph state and model context are related, but they are not automatically the same thing.
Most work stays in one agent to keep the graph independent of any particular treatment. Smaller specialized agents were possible, but Mason also wanted to preserve cache reuse across a mostly stable message stream; changing the system prompt when switching agent identities could disrupt that reuse. Patient conversations can span days, with later follow-ups, but the system preserves patient messages rather than carrying forward all the computation that generated each reply.
The architecture diagram places Python, LangGraph and the blueprint knowledge base above the application’s API layer, MCP server, database, SMS queue and dashboard. At this point, the documents live close to Python. Mason intends to move more of that context into the durable application side, where the dashboard and messaging gateway already live.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Onboarding, local time and movable treatment anchors
The dashboard makes the change in operating model visible. Previously, every incoming patient text activated Needs Attention. The new system reserves that queue for selected interventions. In Mason’s test conversations, the patient-facing personality is Ava. A patient scans a QR code on a medicine package, enters a phone number and receives the initial text. Free-form replies replace the old console’s separate buttons for different meanings of yes. Operators can reveal a rationale explaining the selected response.
After confirming that the patient has medicine, Ava needs their local time. SMS alone does not provide the information necessary to schedule treatment messages, and the service deliberately avoids collecting unnecessary patient information. In the example, Mason supplies the time while on the East Coast; Ava derives a UTC offset and saves it. If a patient later reports a different local time while traveling, the system can revise that state and continue.
Ava next asks whether treatment has started. When the patient plans to start soon, the model requests a regimen image and supplies its date and time parameters. Conventional software stamps those values onto an SVG and sends it as MMS. The model selects the content and timing; it does not draw the image. In this example, the instructions go out immediately because the planned start falls within the blueprint’s 35-minute window.
The planned dose was at 5:45, but Mason did not confirm it until the next day. A reminder had already been scheduled with the original message. When he returned to say he had taken the medicine, Ava recorded an anchor: a treatment event that happened, or is expected to happen, at a particular time. If the patient instead corrects the plan and says the medicine has not been taken, the anchor and downstream messages can change together. The old workflow required an operator to reschedule those items manually.
Patient silence does not keep an agent running. Each incoming patient message starts a response computation; the result may update anchors, advance the treatment phase and schedule future messages. The application preserves those changes and delivers scheduled reminders. There is no agent polling to ask whether the patient has replied. If the patient returns days later, a new run picks up from the saved state.
Anchors also let the conversation move out of order. A patient can arrive already having taken the first pill and started the second. Ava should recognize the completed steps, establish the relevant anchors and move forward. The governing instruction is simple: do not ask the patient a question they have already answered.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Fresh runs and explicit document navigation
Within one response computation, the model sees the serialized starting state, calls tools to change it and can request the current state again. Between patient messages, the system starts fresh. Experiments with longer-lived threads produced malformed tool calls and JSON errors, particularly with older Claude models. Fresh runs also avoid retaining obsolete blueprint instructions when documents change between exchanges. Human feedback still steers the workflow in English rather than through treatment-specific console controls.
Document access follows explicit references rather than a vector-search RAG pipeline. A small treatment entry document identifies the files for each phase, and a CSV contains additional questions and answers. The selected documents are small enough to load whole. Mason prefers that completeness to the risk that retrieval returns a relevant fragment while omitting another part of the treatment needed for a sound decision.
If Ava asks when the patient will take their medicine and receives a complaint about stomach pain, it should first address the patient’s concern using the approved material, then gently repeat the question it still needs answered. Triage and knowledge-base documents provide that escape from the main blueprint. There is no separate off-track flag: the system retains the treatment phase while answering questions.
The same emphasis on explainability shapes the framework choice. Mason had used AutoGen and experimented with CrewAI, but favored LangGraph’s visual workflow, observability and support options for eventual client handoff. Native provider APIs could also orchestrate tools; he preferred a framework dependency to tighter model-provider coupling. Software overhead was not the dominant constraint for this workload.
overview.md supplies the treatment’s document map, while a triage overview remains available when needed. Blueprints mostly define the treatment’s anchor types. The durable patient record is called a schedule document: a versioned snapshot containing exchanged messages, unsent scheduled messages and treatment state. That versioning permits inspection of what the system believed at an earlier point.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The security boundary and model choice
Mason describes the application and its MCP connections as isolated inside an AWS VPC. The agent’s available tool targets are its own documents and the application backend. Patient text remains an adversarial input surface. Operations associates spent substantial time trying to trick the workflow, although Mason distinguishes that testing from a dedicated personal-data exfiltration exercise. Phone numbers are withheld from the agent payload; the patient’s identified first name remains, as does the treatment information needed for decisions.
When a blueprint does not perfectly fit, the OA is instructed to choose the best available response and disclose uncertainty in its rationale. In practice, Mason says the model is not particularly good at admitting that uncertainty. The evaluator adds another check: did the OA use the approved wording exactly, adapt it appropriately, or encounter a situation complex enough to require a person?
The existing service operates at a scale Mason characterizes as thousands rather than millions of patients. He reports no model-call scaling problem at that stage and considers the text-message gateway a possible future bottleneck. Growth would come from additional treatments, hospitals and clinics. Claude’s steerability and visible explanatory output helped determine its selection. o4-mini also performed well in his experiments, but exposed less of the explanatory trace he wanted for debugging. These are observations from this workflow, not a model leaderboard.
Patient responses do not fine-tune the model. Humans inspect failures and revise prompts or guidelines instead. Mason describes an intention to avoid keeping a durable patient relationship beyond treatment, while providers maintain their own records; he does not specify the deletion mechanics. He also acknowledges the sensitivity of carrier-delivered medical messages. The implementation limits what reaches the model to information needed for decision-making, rather than treating the model as the patient-record system.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Following a check-in through LangSmith
After the medication steps, Ava checks in on the patient’s progress. A patient may stop responding and later resume; the service does not require continuous engagement. In the sandbox, Mason submits a reply saying pregnancy symptoms have decreased, then opens LangSmith while that run processes asynchronously. He inspects a prior Sonnet 4 trace to show the underlying structure.
The input identifies the patient source, the thread that can be resumed for feedback, the current three-day check-in phase and the treatment anchors. The anchors include a mixture of UTC and Eastern timestamps, illustrating why time handling is a recurring source of difficulty. The message queue carries the patient-facing exchange, rationales and confidence fields, but excludes the internal model and tool conversation from earlier runs. A configurable history limit can supply only recent messages and allow the model to request more.
In the inspected trace, the last patient reply answers yes to a question about blood clots. The agent then assembles the context it needs:
- List the directories it may access.
- Read the general guidelines, confidence framework and treatment overview.
- Follow the overview to the current phase’s blueprint.
- Inspect recent messages and any already scheduled messages.
The blueprint is a structured, bulleted document that evolved from earlier charts. It supplies conditions and approved responses without turning each branch into executable if statements.
The OA determines that the next blueprint question concerns pregnancy symptoms and schedules it for immediate delivery. The evaluator then reviews the new message. It asks whether the system understood the patient, had the necessary knowledge and selected an appropriate response. Separately, it looks for complexity: anchor changes, patient-data updates, multiple messages, duplicates or reminders for events that already happened.
The inspected check-in receives a model-generated confidence score of 100%, and its new message is sent automatically. The output state contains the anchors, message history and unsent message for the gateway to deliver. This is an intentional automatic-send path: Mason acknowledges residual risk and the operational trade-off involved in not reviewing every response. The displayed percentage is the system’s scoring result, not a demonstrated probability of medical correctness.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Investigating failures and challenging the evaluator
Scoring rules are hand-tuned with the operations team. Spot checks and patient corrections—such as reporting that a recorded medication time is wrong—help identify cases requiring review. Low-confidence traces provide a starting point for investigation. The Slack channel used for clinical escalation also becomes a queue of behavior reports that lead to prompt changes or new evaluation cases. Mason describes many observed mistakes as recoverable misunderstandings and says concerning symptoms prompt human involvement; he does not present a measured failure funnel.
The comparison baseline is the existing human-operated service. Mason says historical human-error data exists, but supplies no human-versus-agent error rates. He distinguishes correcting a misunderstanding from the more consequential risk of giving advice outside approved medical language. The goal is to use human attention on difficult cases instead of assuming that manual button selection is error-free.
Rapid model improvement weakened the case for fine-tuning. In an experiment with Haiku, more precise blueprints improved instruction following, but time calculations remained poor. Mason estimated Haiku at about one-third of Sonnet’s cost in that comparison; he also regarded o4-mini as slightly cheaper than Haiku and similarly capable to Sonnet for this workflow, while preferring Claude’s transparency. These were historical, informal comparisons. He retained explanatory model output because it helped diagnose why a tool was called, despite its additional tokens.
Repeat treatment introduces another state question. A new QR-code activation can start a fresh treatment, an old conversation can be reactivated, and different treatments can use different phone numbers. Mason also describes letting a patient explain that they are starting the regimen again, so the agent can reset the relevant state.
An audience member then challenges the evaluator directly: does another agent deliver enough benefit to justify its cost, how often does it change an outcome, and why use the same model family? Both demonstrated agents use Claude. Mason reports occasional benefit from a different system prompt and task, but provides no measured evaluator uplift. Keeping a separate node preserves the option to try another model family or a specialized evaluator later.
The evaluator has access to the OA’s guidelines, so it can check the proposal against the actual instructions. The OA can also read the confidence framework. That makes the two tasks distinct, but does not eliminate shared blind spots: Mason acknowledges that apparently simple cases can still fail. Complexity could potentially be assessed by the OA itself, whereas correctness self-assessment remains particularly unreliable.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resuming a proposal for human feedback
The live check-in completes while the discussion continues: decreased symptoms lead to the next completion question, followed by an invitation to ask further questions. Each exchange has a starting state, an internal computation and an ending state. LangSmith retains the internal agent dialogue and tool calls for debugging; the application snapshots the input and output without replaying that internal trace on every new patient message.
A second conversation demonstrates review before execution. During onboarding, Ava proposes setting the patient’s UTC offset to −420 minutes, advancing the treatment phase and sending multiple messages. The onboarding proposal scores 70%, below the configured 75% human-review threshold. The individual changes appear reasonable, but their combination produces enough deductions to pause the proposal.
Instead of approving immediately, Mason asks Ava to mention the patient’s name in its message. Feedback resumes the existing thread—the exception to starting a fresh run for each patient message—so the agent can see how it reached the proposal. The revised result adds the name while preserving the time-zone offset, treatment phase and reminder.
Natural-language feedback replaces a direct message-edit box. That choice lets operators request changes across different treatment structures without requiring a custom editor for every kind of state. Only after Mason approves do the messages go out and the proposed state changes take effect. Revising a proposal and committing it are separate operations.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Keeping medical instructions maintainable
Emotional or medically sensitive exchanges remain bounded by approved responses and escalation. Mason notes that even the legacy button-driven service could feel like a human conversation to patients. The agent does not gain permission to improvise unrestricted counseling. Humans can intervene, and some branches direct patients to call a clinician or emergency services instead of extending the text conversation indefinitely.
Why not encode the treatment blueprint as another LangGraph graph? The client needs to maintain it without an engineer. The displayed Google Doc, titled Avila Blueprint - Onboarding, contains triggers, an overview, a medication question, sample wording and branching next steps. It includes explanations of why a question matters, not just the text to send.
A patient can combine several facts in one reply: they have the medication, already took the pills, have stomach pain and feel confused. A rigid flowchart would need to account for those combinations explicitly. The document instead gives the agent an outline, conditions and approved language, allowing it to skip answered questions and address multiple concerns. Mason does not establish a safe nesting depth for conditional instructions. The format came from combining existing human flowcharts and operating instructions; he did not run a controlled comparison isolating the benefit of the explanatory text.
The physician’s assistant co-owns the blueprint with Mason. They propose and accept changes in Google Docs, then export the document to Markdown and check it into source control. Database-backed editing is planned, but the maintenance requirement stays the same: the people responsible for the treatment language must be able to inspect and change it. Human readability is an intentional trade-off.
Human approval does not automatically train the model or modify those documents. Resumed review interactions can be found in LangSmith, and humans may use them to improve the blueprints. In the name-edit example, the agent updates the unsent message in place and keeps the proposal’s original confidence score, ensuring that it returns to human review rather than escaping the review gate after revision.
That inspectability has a latency and token cost. When the audience points to long traces and large cumulative token totals, Mason says the displayed LangSmith costs appear not to reflect caching correctly in his integration. Current LangSmith cost tracking supports cache-aware usage and pricing; that does not establish whether these historical traces supplied the necessary usage details. Reusing an in-progress thread could reduce context loading, but the team accepts fresh-run overhead to avoid the errors encountered with accumulated context.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Separating roles, knowledge and operating rules
The context documents define the framework’s vocabulary: blueprints, anchors, schedules and scheduled messages. Those definitions are loaded as context rather than permanently embedded in the system prompt, allowing treatment terminology to evolve. Knowledge access is tiered:
- Use approved language from the current blueprint when it answers the question.
- Follow the triage overview to a relevant symptom document, such as stomach pain or bleeding.
- Consult the larger CSV question-and-answer collection if necessary.
The model does not load the entire medical corpus at once. Mason acknowledges that the backup CSV could suit RAG, but it is used infrequently enough that the team has not implemented retrieval for it.
The OA and evaluator have comparatively small role prompts. Each knows the other exists, what it is responsible for and how to take turns. Turn-taking needs explicit instructions because an empty model response can stop execution even when the graph expects more work. The scoring framework lives outside those role prompts so both agents can read it.
The confidence framework supplies examples of intent understanding and knowledge sufficiency. It also permits limited use of general model knowledge—for example, recognizing that a named antibiotic belongs to a class discussed in approved material. Mason explicitly treats that generalization as an accepted risk. Complexity deductions apply to the overall interaction: an individual message can match its blueprint perfectly while the combined state changes still warrant review.
The longer guidelines cover reusable operating behavior:
- Tool discipline: Call a tool and wait for its result; do not fabricate either side of the interaction.
- Time handling: Ask for local time without requiring physical location, and use ISO timestamps for system-facing values.
- State updates: Set anchors and schedule messages through the common framework rather than treatment-specific code.
These rules address recurring failures while keeping the same runtime usable for another drug or regimen.
The runtime explicitly caches system-prompt content and the growing message stream within a run. Mason estimates baseline turns at 10,000–15,000 cached tokens and the cost of generating a patient message at $0.15–$0.20. Those are separate estimates: a patient response can require multiple model turns. Unpredictable patient reply intervals complicate reuse across conversations. Mason was unsure whether the newer one-hour cache would help enough; current Claude prompt-caching documentation specifies identical-prefix requirements, a default five-minute lifetime and an optional one-hour lifetime.
Mason and the physician’s assistant evolve the guidelines as they encounter edge cases. The rules need to handle both short regimens and longer schedules such as weekly or monthly treatment support. Context length itself had not become the limiting factor for a single response computation; combining multiple patient exchanges into one continuing internal thread caused more trouble.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Tools define what the model can change
The tool layer combines filesystem MCP access with local Python operations. MCP supplies documents, with database-backed access as another arrangement. The local tools manipulate anchors, messages, confidence, treatment and patient data inside the graph run. Much of the application’s Python lives in those tool implementations.
LangGraph’s Command combines an update with a routing destination. A tool can return a result and send control back to the evaluator or OA that requested it. The following Python pattern illustrates that result-and-route mechanism for a local tool response:
python
from typing import Literal
from langchain_core.messages import ToolMessage
from langgraph.types import Command
AgentName = Literal["virtual_oa", "evaluator"]
def return_tool_result(
caller: AgentName,
tool_call_id: str,
result: str,
) -> Command[Literal["virtual_oa", "evaluator"]]:
return Command(
update={
"messages": [
ToolMessage(
content=result,
tool_call_id=tool_call_id,
)
]
},
goto=caller,
)
Here messages is the graph’s message channel, configured to accumulate messages. The tool result becomes part of the conversation, while goto determines which agent receives control next.
Testing scenarios first came from the physician’s assistant role-playing difficult patients, then the wider operations team, and eventually real use. The team could also replay conversations from the previous service. That existing operational history supplied edge cases a greenfield implementation would have had to discover from scratch.
Not every field in the incoming state is editable. The agent cannot change the patient’s source or rewrite previously sent messages. It can modify patient data, anchors and unsent messages because tools exist for those operations. An absent mutation tool is a stronger boundary than asking the model to refrain from using one. The demonstrated permissions are encoded in the operations available to the agent.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Retry execution failures, evaluate state transitions
The retry node handles failures of execution rather than disagreements with the proposed outcome. If an agent emits malformed tool-call JSON, the system detects it, removes the offending internal message and sends a corrective instruction back to the originating agent through Command. If the model ends its turn without saying anything, it is prompted to provide an explicit response, even a completion message. Low confidence is different: it is a valid result that should reach a human, not a reason to keep retrying until the score rises.
Offline regression testing starts with historical examples in a LangSmith Happy Path dataset. Each example contains an input state and an expected output state. The test is therefore broader than matching an answer to a question: it must assess messages, anchors, schedules and other state changes together.
Historical time is the awkward part. Replaying a state from weeks earlier against today’s clock can produce different schedules even if the workflow is behaving sensibly. Mason’s harness combines timestamp replacement with explicit temporal guidance. Its execution path is:
- Load dataset examples from LangSmith.
- Preprocess dates, times and relevant circumstances.
- Run the medical agent against the adjusted input state.
- Compare the output with the reference through an LLM rubric.
The harness is Python coordinated by a Bash script. In the demonstration, it calls LangGraph running on Mason’s laptop; the same approach could target a cloud instance.
Promptfoo’s YAML config connects the custom harness to a judge, identified here as GPT-4o. The rubric distinguishes equivalent results, minor discrepancies and serious breakage. It includes specific guidance about anchor wording and time differences so the judge does not confuse superficial differences with a failed workflow. Conversely, the judge’s written explanation can reveal that the rubric is too permissive—for example, if a missing reminder should have caused failure. Mason describes the small displayed set as broadly passing, but emphasizes that the rubric can be strengthened.
A separate dataset covers recurring known-bad situations, some omitted from the demonstration. Mason guesses the LangGraph application contains approximately 4,000 lines of Python, mostly tool calls and routing. The treatment behavior largely resides in prompts and guidelines; the separate Node, React and MongoDB application has its own implementation and ownership.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A second treatment without a new application
The portability test is an Ozempic prototype. Mason gives Cline the existing Avila document structure and a Novo Nordisk dosing reference, asks it to create another treatment and then makes follow-up adjustments. The resulting test conversation, Oliver with Ozempic, retains Ava’s persona while asking about injection pens, establishing local time and discussing a weekly schedule. Mason reports no application-code changes for the Ozempic demonstration. It demonstrates reuse of the document structure, without establishing medical validation or production deployment of the generated treatment.
Returning to retries reveals why deleting a malformed internal message matters. Mason found Sonnet 3.5 more prone to malformed tool calls than Sonnet 4. The code recognizes attempted calls through clues such as tool_call_id and malformed bracket patterns, removes the failed message and asks the agent to try again. Leaving that message in context could let the model fabricate a tool result and then behave as though it had read a blueprint it had actually invented. The retry is intended to regenerate a real call, not preserve a fictional success.
The displayed graph does not draw the retry node’s return loops, even though Command can route execution back to either agent. This is a limitation of the visualization shown, not a restriction on execution. Current LangGraph documentation supports rendering dynamic destinations through return-type annotations, as illustrated in the earlier Python pattern; it does not establish which annotations the demonstrated code used.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
What the review score actually means
A lower score can mean the interaction is complicated even when no particular message appears wrong. Mason gives a hypothetical score of 0.9 for sending multiple messages without another identified concern. The client chooses a review threshold that permits some such cases to proceed automatically, reserving human attention for more substantial uncertainty or complexity. Otherwise, operators would spend their days approving routine output—the George Jetson version of the old button-clicking job.
An audience member identifies the conceptual problem: the system combines confidence and complexity in one number. Mason agrees. Ambiguity sometimes lowers the score, but less frequently than he would like, so complexity deductions help move appropriate cases into review. The score is an operational escalation signal, not a calibrated estimate that a medical response is correct. It measures a blend of uncertainty about the answer and complexity of the proposed interaction.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Deploying and extending the workflow
Deployment uses LangGraph’s prebuilt containerization with modifications. Terraform deploys both the agent and application halves, and GitHub Actions automates the workflow. At recording time, Mason says their required deployment arrangement was not supported by LangGraph Platform and that discussions with LangChain were ongoing. The exact platform requirement and commercial arrangement are not specified.
The project did not begin from an empty repository. Mason forked an existing open-source LangGraph project into private client code, reusing a workflow-with-tools structure from earlier work outside healthcare. Repeated engagements reduced the scaffolding effort. He estimates that a few months of work produced functionality that might have required a year or more with conventional software development. That estimate concerns the project’s implementation effort, not a measured productivity experiment.
Coding assistants still needed documentation and active debugging when framework APIs were newer than their knowledge. Mason supplied API docs and worked through novel LangGraph failures iteratively; he personally preferred o3 to Claude for debugging. His prior engineering experience remained useful for recognizing bad behavior and directing corrections. A final MCP clarification reinforces the boundary: document access and connections back to the application use MCP, while the graph’s local state tools remain ordinary Python operations.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Handling new input and leaving an operable system
Patients often split one thought across several texts. The gateway has a configurable preprocessing delay that can gather a burst before starting work, although Mason is unsure whether it is enabled in the demonstrated environment. More importantly, a new message invalidates an already running response thread. The replacement run receives the accumulated conversation so it can answer the complete input instead of publishing a reply based on a stale fragment.
Irrelevant input is handled through treatment-only instructions. Ava should decline unrelated topics such as weather. If an exchange becomes unresolvable, it lowers confidence and asks for human help. Mason reports little observed misuse among patients who engage because they want treatment support, but the escalation path remains necessary.
Framework independence is possible. In a personal college-counseling project, Mason deliberately avoided LangGraph and similar frameworks, asking Cline to build a direct model-interaction layer. It worked, but inspecting behavior through ordinary Google Cloud logs was less convenient. For a client system, the eventual handoff matters: somebody else must be able to understand, debug and operate it after the original builders leave.
His preference for Cline follows a related trade-off. Mason favored direct tool access for a capable model, paying for the tokens used, over the optimization constraints he associated with subscription-priced IDE assistants at the time. He describes Claude Code and Codex as belonging to the same general style of tool-using coding agent. This is his rationale for the development workflow, rather than a current pricing comparison.
The final question asks how predeployment tests fit alongside evaluations and production feedback. Mason’s answer exposes a material difference between the two halves of the system: his Python agent code lacks a robust conventional test framework and relies primarily on evals and overall behavior. Stride’s engineers use test-driven development for the application side, which he describes as well tested. He acknowledges that the Python answer is not ideal. The system’s visible traces, review gates and regression datasets make its behavior inspectable, but the closing admission leaves implementation-level verification as unfinished work.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
Avila's overview of its early pregnancy loss treatment and digital patient-support work.
Configure an LLM judge to evaluate outputs against custom criteria.
Further reading
Stride's account of Ava's agent architecture, evaluation harness and claimed operational capacity gains.
A public coding-agent example combining LangGraph orchestration with an MCP gateway and multiple model providers.
- NICHD pregnancy loss FAQsArticle
Patient-oriented information about pregnancy loss and recurrent pregnancy loss.
Updates since the talk
Current guidance for graph state, dynamic routing, interruption and resumption.
Current cache-prefix rules, lifetime options, pricing mechanics and usage reporting.
Record token usage and calculate costs with separate prices for cached tokens.
Read the transcript and explore slides
Loading transcript and slides…