Originally published on the CorLab Tech blog.
A doctor wants to know whether two medicines on a patient's list interact, and which source says so. A general chatbot answers fluently, but it cannot show where the answer came from. In medicine, the source is the part that matters.
This post walks through a medical AI agent that Mihai Dascal, CorLab's co-founder and CTO, built in three days, with input from the CorLab engineering team.
The agent answers from two sources only: official medicine leaflets and a drug interaction graph. Every answer traces back to one of them. The sections below show how this RAG knowledge graph setup keeps answers grounded, where it broke, and what a three-day build does not prove.
AI agent vs chatbot: why the difference matters here
The idea came from Mihai's wife, a practicing doctor. Her complaint was simple: AI chat tools sounded confident, but their answers were not evidence-based. She wanted an assistant that answers only from verified data and says so when the data is silent.
A healthcare chatbot usually follows a script or answers from what its model learned in training. An agent works differently. It has tools it can call, such as a document search or a database query, and a loop that picks the right tool for each question. It answers only from what the tool returns.
That difference makes an agent mostly a data project. The work goes into preparing sources, deciding which questions each source may answer, and testing that every question reaches the right source.
Mihai kept this agent deliberately narrow. It answers medication questions and interaction questions, and it takes no actions in other systems. The World Health Organization's guidance on large multi-modal models asks developers for exactly this kind of well-defined task. A narrow scope does not remove the risk of wrong answers, but it makes wrong answers easier to find.
Two kinds of medical knowledge, two stores
Mihai spent day 1 on the data model. The stack came together quickly: LangChain and LangGraph for the agent logic, Qdrant as the vector store, and Neo4j as the knowledge graph. Both databases ran on an Azure virtual machine.
The two stores hold different kinds of knowledge on purpose.
Leaflets go into vector search. Mihai scraped the official medicine leaflets (summaries of product characteristics) from the national medicines agency's website, parsed them, and stored them as embeddings in Qdrant. Leaflet answers sit in paragraphs, and a clinician's wording rarely matches the leaflet's wording. Vector search finds text by meaning, so it bridges that gap.
Interactions go into the graph. The interaction data came from an Excel file from Mihai's earlier medical research. His scripts parsed the file and loaded each interaction into Neo4j as a relationship between two drugs. An interaction is a link, not a passage. A question about two medicines becomes a lookup of that link, which returns a record or returns nothing.
Keeping the stores apart has a second benefit: the source of each answer is always obvious.
Routing is part of grounding
The agent runs on two LangChain tools. process_medication_query searches the leaflets, and process_interaction_query queries the graph. Both tools accept full questions, so a clinician can ask the way they would ask a colleague. This is how the build registers them, as published on the CorLab blog (long strings wrapped for reading):
The descriptions do the routing. The agent reads them to decide which tool fits a question, so "two or more drugs" sends interaction questions to the graph. The capitalized instruction matters just as much: if the agent passed only a drug name, the workflow would lose the context it needs to find the right answer.
Before adding any medical data, Mihai tested tool switching on something harmless: financial questions such as the price of Bitcoin. A Swagger API let him test the logic before any interface existed. If the agent could route a price question to the right tool, it could route a medication question too.
Routing deserves that early attention. A side-effect question belongs to the leaflets, and a question that names two drugs belongs to the graph. When routing fails, a correct source answers the wrong question. That failure is as risky as a hallucination, and it looks just as convincing.
Neo4j RAG: when the model writes the query
On day 2, vector search over the leaflets worked smoothly. The graph did not.
In the first version, the model wrote Cypher queries freely. Any small schema change or naming inconsistency broke the logic, and the schema was still changing. After two frustrating hours of debugging, Mihai dropped that approach and switched to LangChain's GraphCypherQAChain, which turns a question into a Cypher query against the graph's actual schema.
Two details matter in 2026. The chain now lives in the langchain-neo4j package, and it will not run until the developer sets allow_dangerous_requests. The LangChain reference also recommends credentials scoped to only the permissions the chain needs. For a medical graph, that means a read-only user. A model that can write queries can also write harmful ones.
How the medical AI agent stays grounded
In this build, grounding is mostly a data design decision, not a prompt trick.
The graph can say no. An interaction lookup returns a record or nothing, and an empty result lets the agent report that the data holds no record. The leaflets work the same way: the agent answers from retrieved passages, and when retrieval finds nothing relevant, it says so. Prompts and guardrails help, but only on top of sources that can come back empty.
The evidence supports this approach, with limits. A 2025 meta-analysis of 20 studies in the Journal of the American Medical Informatics Association found that retrieval-augmented generation improved model performance on biomedical tasks, with a pooled odds ratio of 1.35.
The same review cites a preliminary study in which GPT-4 Turbo extracted table data with only 16 percent accuracy. That is a real concern for leaflets full of dosing tables.
The model is the easiest part to swap. Because the agent reaches its data only through tools, a newer model can replace the original without any change to the graph or the leaflets. Model names date quickly. Tool boundaries and database permissions do not.
Day 3: the interface and going live
Day 3 gave the agent a face. Mihai started from an open-source Next.js and React project under the MIT license that already used WebSockets. He generated a Python backend to connect the WebSocket to the agent, then debugged authentication and message broadcasting by hand until they synced.
Supabase handled authentication, chat history, feedback collection, and admin tools. The code went to GitHub and then onto the Azure VM behind NGINX, with SSL from Certbot.
As a final test, Mihai added two new document types: clinical guidelines and operational protocols. The agent parsed them and answered questions about them right away. By the end of day 3, the agent was running on the Azure VM as a live demo, answering medication questions from the leaflets and interaction questions from the graph.
A single VM is fine for a prototype and little else. Production needs redundancy, separate hosting for the databases and the app, a staging environment, and monitoring that alerts someone when a database or model API stops responding. Running agents on a client's own data, and supporting them once they are live, is the core of CorLab's AI software development work.
What three days prove, and what they do not
Three days proved that the architecture works end to end: vector search, graph queries, tool routing, and a live interface. They did not prove clinical accuracy, security, or regulatory readiness.
An evaluation set comes first. So far, only Mihai has checked the prototype. Clinicians have not yet tested it against questions with agreed answers. Validation starts with clinicians writing realistic questions, including some the sources cannot answer, and agreeing on the correct response to each.
Clinicians then score the agent on accuracy, on citing the right source, and on declining when it should. That last score is easy to skip, and a confident wrong answer is where harm starts. The evaluation set must run again whenever the data or the model changes.
Data needs licensing and versioning. The interaction records came from a research spreadsheet, and Mihai scraped the leaflets only once. Production needs licensed, versioned sources and a process that reloads a leaflet whenever the agency updates it.
Security needs more than prototype auth. Patient data calls for role-based access, an audit log of every question and answer, and read-only database accounts. If the agent handles protected health information for a covered entity, HIPAA applies.
Regulation shapes the interface. The FDA reissued its Clinical Decision Support Software guidance on January 29, 2026. One of its criteria is that clinicians can independently review the basis for a recommendation.
The WHO also warns about automation bias: people miss errors they would otherwise catch because software produced them. Showing the source beside every answer, and flagging any answer without one, is what makes citations work in practice.
The takeaway
The hard parts of this build were never the language model. They sat where the model met a system with strict rules: a graph schema, a WebSocket protocol, and a clinician's need for a traceable answer. AI-generated code handled most of the plumbing, and it still needed debugging.
For teams building a medical AI agent, the order of effort is clear. Sources that can say no come first. Tested routing comes next, then an evaluation set that clinicians trust. The prompt comes last.
Irina writes about healthcare, logistics and AI software at CorLab Tech.



