A production-ready medical RAG (Retrieval-Augmented Generation) assistant that answers clinical questions with evidence-based citations, confidence scoring, and real-time source attribution — grounded in PubMed research.
You type a clinical question. The system retrieves the most relevant PubMed abstracts from a vector database, ranks them by evidence quality and recency, then uses GPT-4o-mini to write a cited answer grounded entirely in that retrieved evidence — not in the model's memory.
Every fact in the answer links to a numbered source card. Every source card shows evidence type, year, and a confidence score. The system refuses to fabricate information not present in the retrieved context.
git clone https://github.com/your-username/Healthcare_RAG.git
cd Healthcare_RAG
bash setup.shThat single command:
- Checks Python and Node.js versions
- Validates your
.envAPI keys - Installs all Python and Node packages
- Creates the Pinecone vector index
- Ingests 220 real PubMed articles across 3 medical topics
- Starts the FastAPI backend on
localhost:8000 - Starts the React frontend on
localhost:5173
Open http://localhost:5173 and start asking clinical questions.
┌─────────────────────────────────────────────────────────────────────────┐
│ USER INTERFACE (React) │
│ │
│ ┌──────────────┐ ┌─────────────────────────────┐ ┌───────────────┐ │
│ │ Sidebar │ │ Chat Panel │ │ Sources │ │
│ │ │ │ │ │ Panel │ │
│ │ • Chat hist │ │ • Message bubbles │ │ │ │
│ │ • Search │ │ • Inline citation badges ¹²³ │ │ • Numbered │ │
│ │ • Doc upload │ │ • Confidence ring % │ │ source │ │
│ │ • New chat │ │ • Copy button │ │ cards │ │
│ │ │ │ • Suggested chips │ │ • Evidence │ │
│ └──────────────┘ └──────────────┬──────────────┘ │ type tags │ │
│ │ │ • Copy APA │ │
│ │ POST /query │ • EV legend │ │
└───────────────────────────────────┼──────────────────┴───────────────┘ │
│
════════════════╪════════════════
HTTP · localhost:8000
════════════════╪════════════════
│
┌───────────────────────────────────▼────────────────────────────────────┐
│ FASTAPI BACKEND (backend_app.py) │
│ │
│ POST /query → validates request → calls Retriever │
│ GET /stats → returns Pinecone vector count │
│ CORS enabled for localhost:5173 │
└───────────────────────────────────┬────────────────────────────────────┘
│
┌───────────────────────────────────▼────────────────────────────────────┐
│ RAG PIPELINE (retrieval/retriever.py) │
│ │
│ 1. EMBED QUERY │
│ User question ──► OpenAI text-embedding-3-small │
│ (1536-dimension vector) │
│ │ │
│ 2. VECTOR SEARCH ▼ │
│ Query vector ──► Pinecone cosine similarity search │
│ top-20 candidate chunks returned │
│ │ │
│ 3. RERANK BY CONFIDENCE ▼ │
│ Each chunk scored: │
│ score = (similarity × 0.5) │
│ + (evidence_weight × 0.3) │
│ + (recency_weight × 0.2) │
│ │
│ Evidence weights: │
│ systematic_review → 1.00 rct → 0.85 │
│ clinical_trial → 0.80 guideline → 0.80 │
│ fda_label → 0.75 cohort_study → 0.65 │
│ abstract → 0.55 case_report → 0.40 │
│ │ │
│ 4. BUILD CONTEXT ▼ │
│ Top 5 chunks formatted as numbered [1][2][3] context │
│ │ │
│ 5. GENERATE ANSWER ▼ │
│ Context + question ──► GPT-4o-mini │
│ System prompt forces: cite [1][2], stay in context, │
│ never fabricate, flag conflicting sources │
│ │ │
│ 6. RETURN STRUCTURED RESPONSE ▼ │
│ { answer, citations[], confidence_score, │
│ confidence_label, sources_used, disclaimer } │
└───────────────────────────────────┬────────────────────────────────────┘
│
┌───────────────────────────┴──────────────────────────┐
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────────────┐
│ PINECONE CLOUD │ │ OPENAI API │
│ (Vector Database) │ │ │
│ │ │ Embeddings: │
│ Index: healthcare- │ │ text-embedding- │
│ rag │ │ 3-small │
│ Dimension: 1536 │ │ (1536 dims) │
│ Metric: cosine │ │ │
│ Cloud: AWS │ │ Chat: │
│ Region: us-east-1 │ │ gpt-4o-mini │
│ │ │ (answer gen) │
│ Each vector stores: │ │ │
│ • 1536 floats │ └─────────────────────┘
│ • source │
│ • pmid │
│ • title │
│ • year │
│ • evidence_type │
│ • url │
│ • text (800 chars) │
└──────────────────────┘
INGESTION PIPELINE (run once, then on-demand)
═════════════════════════════════════════════
PubMed E-utilities API (free, no key)
│
│ esearch: query → PMIDs
│ efetch: PMIDs → XML
▼
PubMedIngestor
• Parses XML → PubMedArticle objects
• Extracts: title, abstract, authors,
journal, year, pub_types, MeSH terms
• Classifies evidence type from pub_types
│
▼
Chunker
• Strategy 1: Short abstract → 1 chunk
• Strategy 2: Structured abstract (BACKGROUND/
METHODS/RESULTS) → split at section headers
• Strategy 3: Long text → sliding window
with 50-word overlap between chunks
│
▼
Embedder
• Batch embeds chunk text via OpenAI API
• 100 chunks per API call
• Returns list of 1536-dim vectors
│
▼
PineconeStore.upsert()
• Batches 100 vectors per upsert call
• ID = source_pmid_chunkN (idempotent)
• Metadata stored alongside vector
• Re-runs are safe — upsert overwrites
Healthcare_RAG/
│
├── setup.sh ← One-command setup and launch
├── backend_app.py ← FastAPI server (wraps Retriever)
├── .env ← Your API keys (never committed)
├── .gitignore
├── requirements.txt
│
├── config/
│ └── settings.py ← All settings loaded from .env
│
├── ingestion/
│ ├── pubmed_ingestor.py ← PubMed E-utilities API client
│ └── chunker.py ← 3-strategy medical text chunker
│
├── embeddings/
│ ├── embedder.py ← OpenAI embedding wrapper
│ └── pinecone_store.py ← Pinecone index manager
│
├── retrieval/
│ ├── confidence.py ← Evidence scoring formula
│ └── retriever.py ← Full RAG pipeline
│
├── scripts/
│ ├── setup.py ← Creates Pinecone index
│ └── ingest.py ← CLI ingestion runner
│
├── files/ ← React frontend (Vite)
│ ├── src/
│ │ ├── App.jsx
│ │ ├── index.css
│ │ ├── api/
│ │ │ └── client.js
│ │ └── components/
│ │ ├── Sidebar.jsx
│ │ ├── ChatPanel.jsx
│ │ ├── MessageBubble.jsx
│ │ └── SourcesPanel.jsx
│ ├── package.json
│ └── vite.config.js
│
└── tests/
├── test_component1.py ← PubMed ingestor tests
├── test_component2.py ← Chunker tests
├── test_component3.py ← Embedder tests
├── test_component4.py ← Pinecone store tests
├── test_component5.py ← Retriever + confidence tests
└── test_component6.py ← Full system integration test
| Source | What it provides | API | Cost |
|---|---|---|---|
| PubMed E-utilities | 36M+ biomedical abstracts, RCTs, systematic reviews | Free, no key | Free |
| ClinicalTrials.gov | 500K+ trial protocols and results | Free, no key | Free |
| FDA OpenFDA | Drug labels, adverse events, prescribing info | Free, no key | Free |
All three sources are freely available and require no registration. PubMed is the primary source used in the default setup.
| Service | Purpose | Free tier | Get it |
|---|---|---|---|
| Pinecone | Vector database | 1 index, 2GB (enough for ~1M vectors) | app.pinecone.io |
| OpenAI | Embeddings + answer generation | Pay-as-you-go (~$0.04 per 10K abstracts) | platform.openai.com |
git clone https://github.com/your-username/Healthcare_RAG.git
cd Healthcare_RAG
cp .env.example .env
# Edit .env with your real keyspip3 install pinecone==3.2.2 openai==1.30.0 requests==2.32.3 \
python-dotenv==1.0.1 fastapi==0.111.0 uvicorn==0.30.0 \
pydantic==2.7.1 tenacity==8.3.0 tqdm==4.66.4python3 scripts/setup.py# Start small to verify everything works
python3 scripts/ingest.py --query "type 2 diabetes treatment" --max 50
# Add more topics
python3 scripts/ingest.py --query "hypertension management" --max 100
python3 scripts/ingest.py --query "sepsis antibiotics protocol" --max 80
python3 scripts/ingest.py --query "heart failure pharmacotherapy" --max 80
python3 scripts/ingest.py --query "atrial fibrillation anticoagulation" --max 60python3 tests/test_component1.py
python3 tests/test_component2.py
python3 tests/test_component3.py
python3 tests/test_component4.py
python3 tests/test_component5.py
python3 tests/test_component6.pyuvicorn backend_app:app --reload --port 8000cd files
npm install
npm run devOpen http://localhost:5173
Every retrieved chunk is scored by three factors:
confidence = (similarity × 0.50)
+ (evidence_weight × 0.30)
+ (recency_weight × 0.20)
Similarity (50%) — cosine similarity from Pinecone vector search. How closely the chunk's meaning matches the query.
Evidence weight (30%) — based on study design. A systematic review of 50 RCTs is more trustworthy than a single case report.
Recency weight (20%) — papers from the last 2 years score 1.0, papers older than 20 years score 0.45. Clinical guidelines change over time.
The final answer confidence is a weighted average of the top 3 chunk scores, where the highest-ranked chunk contributes most.
Confidence levels shown in UI:
| Score | Label | Ring colour |
|---|---|---|
| ≥ 85% | High | Green |
| ≥ 70% | Moderate | Blue |
| ≥ 55% | Low | Amber |
| < 55% | Very low | Red |
| Plain ChatGPT | This system | |
|---|---|---|
| Information source | Model's training data (cutoff 2024) | Live PubMed abstracts you control |
| Citations | Hallucinated or absent | Real PMIDs with working URLs |
| Up-to-date | No | Yes — ingest new papers anytime |
| Domain control | None | You choose which topics to ingest |
| Confidence scoring | None | Transparent formula per answer |
| Hallucination risk | High for specifics | Minimised — constrained to retrieved context |
Run the ingestion script any time to expand the knowledge base:
python3 scripts/ingest.py --query "oncology immunotherapy checkpoint" --max 100
python3 scripts/ingest.py --query "chronic kidney disease management" --max 80
python3 scripts/ingest.py --query "asthma COPD inhaler therapy" --max 80
python3 scripts/ingest.py --query "depression anxiety SSRI treatment" --max 80Re-ingesting the same topic is safe — Pinecone upserts overwrite existing vectors with the same ID rather than creating duplicates.
This system is for educational and research purposes only. It is not a substitute for professional medical advice, diagnosis, or treatment. Always consult a qualified healthcare professional for medical decisions.