| title | Medical RAG Chatbot |
|---|---|
| emoji | ⚕️ |
| colorFrom | blue |
| colorTo | green |
| sdk | docker |
| app_port | 8501 |
An enterprise-grade Retrieval-Augmented Generation (RAG) chatbot designed to ingest, process, and query complex medical research papers (e.g., PubMed, ArXiv). It uses local embedding models to ensure data privacy and Google Gemini 1.5 Flash for high-quality, hallucination-free generation.
Medical Research RAG Chatbot | Python, LangChain, FAISS, Docker Live: huggingface.co/spaces/arinShr/medical-rag-assistant
- Built a Retrieval-Augmented Generation pipeline with LangChain, Gemini 1.5 Flash, and a local FAISS vector store, including multi-hop query decomposition for comparative queries across documents.
- Document Ingestion: PyMuPDF, LangChain (
RecursiveCharacterTextSplitter- 512 tokens / 50 overlap) - Embeddings & Vector Store:
sentence-transformers/all-MiniLM-L6-v2, FAISS (Local) - LLM & Chain: Google Gemini 1.5 Flash, LangChain
RetrievalQA - Frontend: Streamlit (with confidence scores & source citations)
- Evaluation: RAGAS (Faithfulness, Answer Relevancy, Context Precision)
- Deployment: Docker, GitHub Actions
Standard single-hop RAG often fails on comparative queries across multiple documents because the embedded query vector heavily skews toward the vocabulary of a single document. To solve this, the pipeline implements Query Decomposition:
- Uses a heuristic (RegEx) to detect comparative queries (
compare,differences, etc.) - Utilizes the LLM to split the query into independent sub-queries.
- Retrieves chunks independently for each sub-query to guarantee both source documents are represented.
- Synthesizes a comprehensive answer from the deduplicated, merged context.
Because query decomposition initiates multiple parallel LLM calls, it can easily exhaust API quotas (429 RESOURCE_EXHAUSTED). The system uses tenacity-style exponential backoff decorators to silently catch limit exceptions, sleep, and auto-retry, ensuring stable performance under load.
- Chunk Boundary Sensitivity: Dense clinical prose with separated entities (e.g., a drug name and its numeric efficacy separated by ~100 characters of explanatory text) can easily fall victim to "semantic splitting" if chunk overlap is too small. Initial configurations with a 50-character overlap cleanly severed key clinical statistics from their contextual entities, causing false-negative retrievals. Bumping
CHUNK_OVERLAPto 150 mathematically guaranteed these long-range numeric relationships remained co-located in the vector space, successfully restoring retrieval accuracy without requiring complex layout parsers.
resume 2/
├── data/
│ ├── raw/ # Put your medical PDFs here
│ └── vector_store/ # FAISS index is saved here
├── src/
│ ├── config.py # Global settings
│ ├── ingest.py # PDF parsing & chunking
│ ├── vector_store.py # Embeddings & DB building
│ ├── rag_chain.py # LLM logic
│ └── evaluate.py # RAGAS metrics
├── app.py # Streamlit frontend
├── .env.example # Template for GEMINI_API_KEY
└── requirements.txt # Dependencies
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtCopy the example environment file and add your Google Gemini API key:
cp .env.example .env
# Edit .env and replace with your GEMINI_API_KEY- Download 10-20 medical PDFs (e.g., Cardiology, Oncology) and place them in the
data/raw/directory. - Run the ingestion and vector store script:
python -m src.vector_store(This will chunk the PDFs and create a FAISS index in data/vector_store/)
Launch the Streamlit frontend:
streamlit run app.pyTo generate the RAGAS evaluation report to validate hallucination prevention (shows engineering rigor):
python -m src.evaluateTo build and run via Docker (e.g., for Hugging Face Spaces):
docker build -t medical-rag .
docker run -p 8501:8501 --env-file .env medical-rag