A production-grade retrieval-augmented generation (RAG) system that answers questions from enterprise documents with grounded citations, low hallucination risk, and measurable evaluation.
Live Demo: Under deployment
GitHub: Ahamed-h/DocMind
Organizations store critical knowledge inside PDFs such as HR policies, legal documents, compliance manuals, and SOPs. Manually searching these files is slow, and generic LLMs can hallucinate answers from pretraining instead of using the actual document set.
DocMind addresses this by retrieving relevant passages from uploaded documents, generating an answer grounded in those passages, attaching source citations, and returning an abstaining response when the required information is not present.
Evaluated on a 6-question test set using Gemini as the judge model and RAGAS metrics.
| Metric | Score | Interpretation |
|---|---|---|
| Faithfulness | 1.000 | Every evaluated claim was supported by retrieved context. |
| Context Precision | 0.750 | Most retrieved chunks were relevant, though some retrieval noise remains. |
| Context Recall | 0.833 | Most of the information needed to answer the query was retrieved. |
| Answer Relevancy | 0.797 | Answers generally addressed the user question well. |
| Overall Score | 0.845 | Strong end-to-end baseline across grounding, retrieval, and answer quality. |
A faithfulness score of 1.0 is especially important because it indicates the system did not add unsupported claims in the evaluated outputs.
User Query
β
βΌ
Query Rewriting (Gemini)
β Rewrites vague queries for better retrieval
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β Hybrid Retrieval β
β β
β FAISS (semantic) βββ β
β βββ RRF βββΊ Top merged β
β BM25 (keyword) βββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
Cross-Encoder Reranking
β Selects the most relevant chunks
βΌ
Gemini Generation
β
βΌ
LLM-as-Judge Hallucination Check
β Confidence score from 0 to 1
β Below threshold β "Insufficient information"
βΌ
Answer + Confidence + Source Citations
FAISS runs locally with no API cost or network dependency. For hundreds to low thousands of chunks, a local FAISS index is fast and simple to manage, while Pinecone is more useful at much larger operational scale.
Local sentence-transformer embeddings avoid API quotas, timeout issues, and repeated inference costs. This also makes indexing more reliable and reproducible.
Hybrid retrieval improves robustness. BM25 captures exact keyword and section-number matches, while FAISS captures semantic similarity.
Initial retrieval surfaces candidates; reranking improves the final context set by scoring query-chunk relevance more accurately than raw vector similarity alone.
- Upload and query PDF document collections.
- Hybrid retrieval with FAISS semantic search and BM25 keyword search.
- Reciprocal Rank Fusion (RRF) for ranked-list merging.
- Cross-encoder reranking for better context precision.
- Query rewriting before retrieval.
- LLM-as-judge hallucination detection.
- Confidence score with every answer.
- Source passage citations in responses.
- Graceful fallback when information is missing.
- Session chat history.
- RAGAS-based evaluation pipeline.
| Layer | Tool |
|---|---|
| Embeddings | sentence-transformers/all-MiniLM-L6-v2 |
| Vector Store | FAISS (IndexFlatL2) |
| Keyword Search | BM25 (rank-bm25) |
| Reranker | cross-encoder/ms-marco-MiniLM-L-6-v2 |
| Retrieval Merge | Reciprocal Rank Fusion |
| LLM | Gemini Flash |
| Evaluation | RAGAS |
| PDF Parsing | PyMuPDF |
| Frontend | Streamlit |
| Language | Python 3.12 |
docmind/
βββ core/
β βββ config.py # Centralized settings
β βββ ingestion.py # PDF loading, chunking, embeddings, FAISS build
β βββ retrieval.py # Hybrid retrieval, RRF merge, reranking
β βββ generation.py # Generation, query rewriting, confidence checks
β βββ evaluation.py # RAGAS evaluation logic
βββ data/
β βββ sample_docs/ # Input PDFs
βββ vector_store/ # Local FAISS index (gitignored)
βββ streamlit_app.py # Streamlit app entry point
βββ build_index.py # Build index from documents
βββ evaluate.py # Run evaluation metrics
βββ requirements.txt
βββ .env.example
βββ DECISIONS.md
βββ README.md
git clone https://github.com/Ahamed-h/DocMind.git
cd DocMind
python -m venv .venvWindows
.venv\Scripts\activatemacOS / Linux
source .venv/bin/activatepip install -r requirements.txtcp .env.example .envThen edit .env and add the required API keys.
Place PDF files inside data/sample_docs/.
python build_index.pystreamlit run streamlit_app.pypython evaluate.pyUpdate the test questions in evaluate.py so they match the content of your documents. The evaluation scores are printed in the terminal.
Questions suited to the included HR policy documents:
- How long is maternity leave?
- What happens if an employee violates the code of conduct?
- Can employees accept gifts from suppliers?
- What is the probationary period for new employees?
- What is the company policy on tobacco use?
Out-of-scope examples that should trigger an abstaining response:
- What is the company's stock price?
- Who is the CEO of Apple?
Large embedding batches caused timeout failures during development. This was resolved by switching to local sentence-transformer embeddings, which removed API dependence from the indexing path.
An earlier Gemini model name did not match the installed SDK behavior. The model configuration was corrected after checking available model naming in the active client setup.
answer_relevancy failed because the Google embedding object exposed embed_text() while RAGAS expected an interface compatible with embed_query(). This was fixed by using Hugging Face embeddings through a compatible wrapper.
RAGAS returned per-row metric lists rather than a single scalar. The reporting logic was updated to average the metric values safely before printing.
After temporarily removing some metrics during debugging, the report code still tried to print absent keys. This was fixed by printing metrics conditionally only when present.
context_recall required a reference field in each evaluation sample. The evaluation dataset was updated to include ground-truth answers for every test case.
Using OpenAI embeddings was dropped because of API limits. The final setup used Hugging Face embeddings locally for answer_relevancy instead.
- Persistent storage for query and evaluation logs.
- Token streaming in the Streamlit interface.
- Better source attribution across multiple PDFs.
- Automatic index rebuilds when documents change.
- A larger evaluation set for more robust benchmarking.
- Metadata-based filtering by document name or category.
See DECISIONS.md for a full decision log covering FAISS vs. managed vector databases, local vs. API embeddings, hybrid retrieval, reranking, model choices, and evaluation design.