Problem
Medicine is unforgiving of errors. An LLM that hallucinates could recommend a contra-indicated drug, miss a critical drug interaction, or misstate a dosing protocol. Yet LLMs will hallucinate if trained only on general web text; medical knowledge requires both breadth (rare conditions) and precision (exact dosing).
The approach: Retrieval-Augmented Generation (RAG). Instead of asking the LLM to generate from memory, we:
- Retrieve relevant clinical evidence first
- Show the LLM the evidence (+ prompt it to cite sources)
- Have it generate grounded responses
- Fact-check the response against retrieved evidence
This dramatically reduces hallucinations and forces source attribution (critical for liability).
Data Preparation
We ingested diverse clinical sources:
- PubMed abstracts (8M total; selected 12,000 relevant to common queries)
- UpToDate articles (3,000 clinical summaries)
- ICD-10 disease codes (15,000 conditions + descriptions)
- Drug databases (20,000 medications + interactions from FDA, WHO)
- Clinical guidelines (AHA, ACC, ADA, ACS recommendations)
Chunking strategy:
- Semantic boundaries: split at sentence/paragraph level, not mid-concept
- Max 512 tokens per chunk (leaves room in LLM context window for prompt + response)
- Overlap: 50-token overlap between chunks (context continuity)
- Result: 125,000 chunks, avg. 380 tokens each
Embeddings:
- Model: Sentence Transformers (all-MiniLM-L6-v2), 384-dim vectors
- Storage: Chroma (in-memory + persistent), with FAISS indexing for fast retrieval
- Retrieval time: <100ms for top-5 similar documents
Evaluation set:
- 500 medical queries covering common conditions, drug interactions, procedural questions
- Ground-truth answers: written by medical experts (2 reviewers per query)
- Source citations: each answer tagged with relevant PubMed/guideline references
- Validation: automatic BLEU score vs expert answers; manual review for edge cases
Models Evaluated
| Component |
Model |
Result |
Rationale |
| Embeddings |
Sentence Transformers (MiniLM) |
Kept |
Fast (10ms/query), medical domain-aware, small model (22M params) |
| Retrieval |
Chroma + FAISS |
Kept |
Sub-100ms retrieval, easy deployment, no external deps |
| Generation (fast path) |
Llama 3.1 8B |
Kept |
80ms inference, 95% accuracy, open-weight |
| Generation (hard cases) |
GPT-4 Turbo |
Kept |
98% accuracy, reserved for low-confidence queries |
| Fact-checking |
GPT-4 (separate) |
Kept |
Validates if response matches retrieved evidence; catches hallucinations |
| Vector DB |
Pinecone (alt) |
Cut |
Operational overhead; Chroma sufficient + cheaper |
| Keyword search |
BM25 |
Cut |
Poor for medical queries (synonyms, abbreviations); semantic search necessary |
| Quantization |
int8 (Llama) |
Kept |
40% smaller model, minimal accuracy loss |
Architecture
Request flow:
User: "Drug interactions with warfarin + ibuprofen?"
v
1. Embed query (Sentence Transformers, <10ms)
2. Vector search (Chroma, top-5 documents, <100ms)
Retrieved: PubMed abstract on warfarin-NSAID interactions,
FDA warning on GI bleed risk, drug interaction database
v
3. Build LLM prompt:
"Evidence: [retrieved docs...] \n Question: [user query]\n Answer:"
v
4. Generate response (Llama 3.1 8B, <80ms)
Response: "Warfarin + ibuprofen has significant interaction risk (GI bleed, INR elevation).
Recommend acetaminophen instead. Source: [PubMed:123456]"
v
5. Fact-check (async, GPT-4):
"Does response match retrieved evidence?" -> Yes / No / Partial
v
6. If confidence < 70% or fact-check flags issue:
-> Escalate to physician review
-> User sees: "High-confidence AI response" vs "Requires physician review"
Caching:
- Query cache (Redis): common questions cached with TTL 5h
- Embedding cache: pre-computed for 5,000 frequent queries
- Response versioning: track when clinical guidelines change; invalidate stale cached answers
Safety layers:
- Confidence scoring: LLM outputs confidence; low-confidence answers routed to physician
- Fact-check failure: if GPT-4 fact-check says “hallucinated,” response flagged for review
- Source attribution: user can click sources to read full documents
- Audit log: every query + response stored (PostgreSQL) for regulatory review
Production & Scale
Timeline:
- Nov 2024: System deployed to beta (100 users, medical staff)
- Dec 2024: Scaled to 1,000 users; integrated iOS app
- Jan 2026: 12,000+ queries/month; 99.2% uptime
Metrics:
- Factual accuracy: 95% (Llama) / 98% (GPT-4)
- Hallucination rate: 2.1% detected by fact-check model
- Average latency: <2s (retrieval + generation + fact-check)
- Physician review rate: 3.2% (only edge cases + low confidence)
- User satisfaction: 4.7/5 (cite: “responses are evidence-based and helpful”)
Monitoring:
- CloudWatch: latency percentiles, error rates, embedding cache hit ratio
- Custom: hallucination detection (automatic flag if response lacks citations or contradicts evidence)
- Weekly review: domain experts audit 5% sample of responses
Regulatory:
- FDA classification: decision support tool (not diagnostic)
- HIPAA compliance: no patient data stored; encrypted transit; audit trail
- Liability: clear disclaimers (“consult physician; not a substitute for medical advice”)
Cost structure:
- Infrastructure: $800/month (Lambda + RDS + cache)
- LLM inference: $0.02 per Llama query; $0.20 per GPT-4 fact-check
- Data: PubMed/UpToDate subscriptions amortized across users
- Per-user cost: ~$2/month (at 12k queries/month)
Challenges & lessons:
- Retrieval relevance: Initial vector DB had low recall (missing relevant docs)
- Solution: Multi-step retrieval (BM25 + semantic) improved recall from 65% -> 92%
- Fact-check cost: GPT-4 for every query was expensive
- Solution: Only fact-check low-confidence answers (confidence < 80%); saves 70% cost
- Citation accuracy: LLM sometimes cited documents that weren’t actually used
- Solution: Constrain LLM to cite only from retrieved evidence; enforce in prompt
Result: A medical Q&A system with 95% factual accuracy, sub-2s latency, and transparent sourcing. Physicians can trust the system for decision support because every answer is grounded in clinical evidence.