Spaces:
Running on Zero
Download README.md from shareefmx/pdf-knowledge-assistant: direct link, hf CLI and curl.
- Browser
- Download file 37.3 kB
-
https://huggingface.co/spaces/shareefmx/pdf-knowledge-assistant/resolve/main/README.md
- Command line
-
hf download hf://spaces/shareefmx/pdf-knowledge-assistant/README.md
-
curl -L -o README.md https://huggingface.co/spaces/shareefmx/pdf-knowledge-assistant/resolve/main/README.md
A newer version of the Gradio SDK is available: 6.30.0
title: PDF Knowledge Assistant
emoji: π
colorFrom: blue
colorTo: indigo
sdk: gradio
app_file: app.py
pinned: false
license: mit
short_description: Production RAG with PyMuPDF, FAISS, Gemini & Gradio
π PDF Knowledge Assistant β Production RAG Project
A production-grade Retrieval-Augmented Generation (RAG) application designed to ingest, clean, chunk, embed, index, and query PDF documents with zero external document leakage, strict anti-hallucination guardrails, and verified source citations down to exact page numbers and similarity scores.
Built with PyMuPDF, Sentence Transformers, Okapi BM25, FAISS / Chroma, Google Gemini / OpenRouter, FastAPI, and Gradio.
π Table of Contents
- Overview
- Architecture Diagram
- Features
- Technology Stack
- How RAG Works (Deep Dive)
- Project Structure
- Installation & Setup
- Environment Variables
- Running Locally
- API Documentation
- Chunking Strategy & Experiments
- Embedding Models Comparison
- Vector Database: FAISS vs Chroma
- Retrieval & Threshold Filtering
- Two-Stage Reranking
- Prompt Engineering & Anti-Hallucination
- Conversational Query Rewriting
- Quantitative Evaluation Benchmark
- Hugging Face Spaces Deployment
- Limitations & Production Hardening
- Interview Questions & Conceptual Mastery
- License
Overview
Large Language Models (LLMs) suffer from two fundamental deficiencies when applied to proprietary or specialized knowledge:
- Parametric Staleness: Their knowledge is frozen at the pre-training cutoff date.
- Hallucinations: When faced with missing facts, their probabilistic objective (predicting the most likely next token) causes them to invent plausible-sounding false information with high confidence.
Retrieval-Augmented Generation (RAG) solves this by augmenting the LLM with non-parametric external memory:
- Relevant document passages are retrieved deterministically using semantic similarity search.
- The retrieved evidence is dynamically injected into the model's context window.
- The model is instructed through strict system prompts to synthesize answers solely from the provided context and cite specific page numbers.
This project delivers a complete, modular, and enterprise-grade implementation of the RAG pattern.
Architecture Diagram
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β User / Client β
βββββββββββββββ¬βββββββββββββββββββββββββββββββ¬ββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββ
β Gradio UI β β FastAPI REST API β
βββββββββββββββ¬ββββββββββββββ βββββββββββββββ¬ββββββββββββββ
β β
ββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββ
β 1. DOCUMENT INGESTION β β 2. RETRIEVAL & QUERY β
βββββββββββββββββββββββββββββββββββ€ βββββββββββββββββββββββββββββββββββ€
β Upload PDF β β User Question + Chat History β
β β β β β β
β βΌ β β βΌ β
β Validation & Security β β Query Rewriter (Standalone) β
β (Magic bytes, size limit) β β β β
β β β β βΌ β
β βΌ β β Query Vectorizer β
β PDF Parser (PyMuPDF / fitz) β β (sentence-transformers) β
β (Extracts text & page numbers) β β β β
β β β β β β
β βΌ β β βΌ β
β Text Normalizer / Cleaner β β Dense Vector Search β
β (Hyphenation, UTF-8, spaces) β β (FAISS / Chroma cosine) β
β β β β β β
β βΌ β β βΌ β
β Section Heading Detector β β Top-K Candidate Chunks (K=15) β
β β β β β β
β βΌ β β βΌ β
β Recursive Character Chunker β β Cross-Encoder Reranker β
β (size=800, overlap=150) β β (ms-marco-MiniLM-L-6-v2) β
β β β β β β
β βΌ β β βΌ β
β Batch Embedding Generation β β Cosine Threshold Gating β
β (all-MiniLM-L6-v2, L2 norm) β β (Threshold >= 0.35) β
β β β βββββββββββ¬ββββββββββββββββββββββββ
β βΌ β β
β Vector Store Persistence β βΌ
β (FAISS IndexFlatIP) ββββββββββββ΄ββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β 3. GROUNDED GENERATION β
βββββββββββββββββββββββββββββββββββ€
β Context String Assembly β
β [Source 1: file.pdf, Page 7] β
β β β
β βΌ β
β Strict Grounding Prompt β
β β β
β βΌ β
β LLM Service β
β (Google Gemini / OpenRouter) β
β (temperature=0.0) β
β β β
β βΌ β
β Synthesized Answer + Citations β
β (Filename, Page, Score, Excerptβ
βββββββββββββββββββββββββββββββββββ
Features
- Robust Multi-Page PDF Extraction: Utilizes high-performance C MuPDF bindings (
PyMuPDF) to extract page text while strictly preserving 1-indexed page numbers. - Deterministic Text Normalization: Fixes line-break hyphenation (e.g.
trans-\nformer$\to$transformer), cleans non-breaking/zero-width spaces, and normalizes paragraph breaks without stripping numbers or mathematical equations. - Hierarchical Recursive Chunking: Splits text along natural syntactic boundaries (
\n\n$\to$\n$\to$ sentences $\to$ spaces) with a sliding overlap to preserve boundary semantics. - Dense Vector Search: Employs L2-normalized sentence embeddings with
FAISS IndexFlatIPwhere dot product yields exact cosine similarity in microsecond execution time. - Optional Two-Stage Cross-Encoder Reranking: Re-scores vector search candidates with full cross-attention (
cross-encoder/ms-marco-MiniLM-L-6-v2), improving precision. - Similarity Threshold Guardrail: Discards candidate chunks scoring below threshold (default 0.35) and returns a refusal message to avoid hallucinations on out-of-domain questions.
- Multi-PDF Document Management: Index multiple PDFs into a unified index, filter queries to a specific document, or delete individual documents with automatic index rebuilding.
- Conversational Context Resolution: Follow-up questions (e.g., "How large was it?") are rewritten into self-contained standalone queries using the prior chat turns before retrieval.
- Pluggable LLM Abstraction: Seamlessly switch between Google Gemini (
gemini-2.5-flash,gemini-1.5-pro) and OpenRouter (meta-llama/llama-3-8b-instruct,mistralai/mistral-7b) without modifying pipeline code. - Interactive Gradio UI: Responsive interface featuring drag-and-drop multi-file uploads, real-time indexing logs, collapsible verified citation cards, score badges, and sample question triggers.
- Full OpenAPI REST Server: Complete FastAPI backend with
/health,/documents/upload,/documents, and/queryendpoints. - Built-in Quantitative Evaluation: Measures HitRate@K, MRR@K, Precision@K, and Answer Faithfulness using automated benchmark scripts.
Technology Stack
| Layer | Technology | Rationale |
|---|---|---|
| PDF Extraction | PyMuPDF (fitz) |
10x faster than pure-python alternatives; accurately preserves document layout and font metadata. |
| Embeddings | sentence-transformers (all-MiniLM-L6-v2) |
Local, private, free, fast (384 dims), well-calibrated for cosine semantic search. |
| Vector Index | faiss-cpu (IndexFlatIP) |
Highly optimized C++ vector library from Meta; zero network overhead; ideal for single-node container deployment. |
| Alternative Vector DB | ChromaDB (chromadb) |
Embedded SQLite-backed vector store demonstrating vector store abstraction and metadata filtering. |
| Reranker | Cross-Encoder (ms-marco-MiniLM-L-6-v2) |
Full cross-attention between query and chunk; outperforms bi-encoder similarity scoring on ambiguous queries. |
| LLM Inference | Google Gemini (google-genai) / OpenRouter |
State-of-the-art reasoning, configurable temperature, long context windows, and cost efficiency. |
| Backend REST API | FastAPI + Uvicorn + Pydantic v2 | High-throughput asynchronous REST framework with strict schema validation and OpenAPI auto-documentation. |
| Frontend UI | Gradio Blocks v4 | Rapid, elegant Python UI with built-in chat components and file drag-and-drop. |
| Testing | Pytest + AnyIO | Comprehensive unit tests for all components with automated synthetic fixtures. |
How RAG Works
1. Document Ingestion
When a user uploads a PDF:
- Validation: Checks magic bytes (
%PDF-), file extension, and enforces a 50MB file size ceiling. - ID Generation: Generates a collision-resistant document identifier (e.g.
doc_8557ff_615e7d0b). Filenames are never used as primary keys because filenames are mutable and non-unique. - Extraction: PyMuPDF parses the PDF page-by-page. Text is stored with its associated 1-indexed page number and dimensions.
2. Text Normalization
PDF layout engines emit visual artifacts:
- Hyphenated word breaks at end of lines:
algo-\nrithm$\to$algorithm. - Non-breaking spaces (
\u00a0), zero-width spaces (\u200b), byte-order marks (\ufeff). - Form-feed control characters (
\x0c). Our cleaner sanitizes these unicode artifacts while preserving equations (e.g., $f(x) = 2.5x^2 + 10$), numbers, and paragraph markers.
3. Chunking with Overlap
Transformer embedding models have strict token limits (typically 256 or 512 tokens). If an entire 30-page document is embedded as one string:
- All text past token 512 is discarded.
- Specific facts are washed out in an averaged semantic vector.
We chunk text recursively:
- Primary split:
\n\n(paragraphs) - Secondary split:
\n(lines) - Tertiary split: Sentence terminators (
.,?,!) - Quaternary split: Word spaces (
) - Configurable window:
chunk_size = 800characters. - Overlap window:
chunk_overlap = 150characters. The overlap guarantees that sentences straddling boundary cuts remain intact in at least one chunk.
4. Vector Embeddings
The chunk text is passed through a pre-trained Transformer encoder: The vector is normalized to unit length ($|\mathbf{v}|_2 = 1$). In unit-normalized space, the cosine similarity between query vector $\mathbf{q}$ and document vector $\mathbf{d}$ is simply their dot product:
5. Vector Storage & Indexing
FAISS indexes the vectors using IndexFlatIP. Chunks are mapped 1-to-1 to their metadata (page, section, filename, chunk ID).
6. Retrieval & Threshold Gating
When a query arrives:
- Query is embedded using the exact same embedding model.
- Top-$K$ candidate chunks are retrieved in order of descending cosine similarity.
- A similarity threshold filter is applied: $$\text{Chunks}_{\text{qualified}} = { c \in \text{Candidates} \mid \text{score}(c) \ge \tau }$$ If no chunk satisfies this threshold, retrieval halts immediately and returns a grounded fallback answer.
7. Optional Cross-Encoder Reranking
When USE_RERANKER=true, the vector index first retrieves $M=15$ candidate chunks. A Cross-Encoder model evaluates the joint attention representation $(\text{Query}, \text{Chunk})$ and outputs calibrated relevance logits, reordering the top $N=5$ chunks with higher semantic precision.
8. Grounded Generation & Citation
The qualified chunks are assembled into an enumerated context template. The LLM is invoked with temperature 0.0 under strict system instructions:
- Answer only using facts present in the context.
- Cite
[Document: <name>, Page: <page>]for every claim. - Refuse out-of-context queries.
Project Structure
pdf-knowledge-assistant/
β
βββ app/
β βββ __init__.py
β βββ main.py # FastAPI REST application
β βββ config.py # Pydantic Settings & structured logging
β βββ state.py # Application singleton state container
β β
β βββ api/
β β βββ __init__.py
β β βββ routes_health.py # GET /health
β β βββ routes_upload.py # POST /documents/upload, GET /documents, DELETE
β β βββ routes_query.py # POST /query
β β
β βββ ingestion/
β β βββ __init__.py
β β βββ pdf_loader.py # PyMuPDF extractor with page tracking
β β βββ text_cleaner.py # Whitespace, hyphenation, and artifact cleaner
β β βββ chunker.py # Recursive character chunker with overlap
β β βββ metadata.py # Section detection heuristics
β β
β βββ embeddings/
β β βββ __init__.py
β β βββ embedding_service.py # SentenceTransformers batch embedding service
β β
β βββ vectorstore/
β β βββ __init__.py
β β βββ base.py # Abstract BaseVectorStore interface & SearchResult
β β βββ faiss_store.py # FAISS IndexFlatIP store with persistence
β β βββ chroma_store.py # ChromaDB alternative store
β β
β βββ retrieval/
β β βββ __init__.py
β β βββ retriever.py # DocumentRetriever with threshold filtering
β β βββ reranker.py # CrossEncoder two-stage reranker
β β βββ query_rewriter.py # Conversational question rewriter
β β
β βββ generation/
β β βββ __init__.py
β β βββ llm.py # Pluggable LLMService (Gemini, OpenRouter, Mock)
β β βββ prompts.py # Anti-hallucination prompts & context templates
β β
β βββ rag/
β β βββ __init__.py
β β βββ pipeline.py # End-to-end RAG orchestrator & citation builder
β β
β βββ evaluation/
β β βββ __init__.py
β β βββ dataset.py # Benchmark evaluation test cases
β β βββ evaluator.py # HitRate, MRR, Precision, and Faithfulness metrics
β β
β βββ ui/
β βββ __init__.py
β βββ gradio_app.py # Interactive Gradio Blocks web UI
β
βββ data/ # Local storage (gitignored)
β βββ uploads/ # Staged PDF files
β βββ processed/ # Serialized evaluation reports
β βββ vectorstore/ # FAISS index and metadata files
β
βββ tests/
β βββ __init__.py
β βββ test_pdf_loader.py # Tests extraction, validation, and error states
β βββ test_text_cleaner.py # Tests hyphenation, whitespace, and control chars
β βββ test_chunker.py # Tests recursive splitting, overlap, section logic
β βββ test_embeddings.py # Tests dimensions, L2 normalization, similarity
β βββ test_vectorstore.py # Tests FAISS and Chroma search, filter, and delete
β βββ test_retriever.py # Tests threshold filtering and candidate ranking
β βββ test_rag_pipeline.py # Tests end-to-end grounded generation and citations
β βββ test_api.py # Tests FastAPI endpoints integration
β
βββ scripts/
β βββ ingest.py # CLI batch document ingestion tool
β βββ evaluate.py # CLI quantitative benchmark evaluator
β
βββ .env.example # Template environment variables
βββ .env # Local configuration (never committed)
βββ requirements.txt # Pinned dependencies
βββ Dockerfile # Container specification
βββ app.py # Hugging Face Spaces entrypoint
βββ README.md # Comprehensive project documentation
Installation & Setup
Prerequisites
- Python 3.11 or 3.12
- Git
1. Clone & Create Virtual Environment
git clone https://github.com/shareefmx/RAG.git
cd RAG
python3 -m venv .venv
source .venv/bin/activate
2. Install Dependencies
cd pdf-knowledge-assistant
pip install --upgrade pip
pip install -r requirements.txt
Environment Variables
Copy the example template:
cp .env.example .env
Configure your parameters in .env:
# LLM Provider Backend: "gemini" or "openrouter"
LLM_PROVIDER=gemini
# Primary Provider: Google Gemini
# Get your free key at: https://aistudio.google.com/app/apikey
GEMINI_API_KEY=your_gemini_api_key_here
# Alternative Provider: OpenRouter
# Get key at: https://openrouter.ai/keys
OPENROUTER_API_KEY=your_openrouter_api_key_here
# Model Selection
LLM_MODEL=gemini-2.5-flash
# Embeddings Model from Hugging Face
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
# Vector Store: "faiss" or "chroma"
VECTOR_STORE=faiss
# Chunking Hyperparameters
CHUNK_SIZE=800
CHUNK_OVERLAP=150
# Retrieval Hyperparameters
TOP_K=5
CANDIDATE_TOP_K=15
SIMILARITY_THRESHOLD=0.35
# Two-Stage Reranking
USE_RERANKER=false
RERANKER_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
# Conversational Context
ENABLE_QUERY_REWRITING=true
If neither
GEMINI_API_KEYnorOPENROUTER_API_KEYis provided, the application automatically falls back toMockLLMService. This ensures that unit tests, CI pipelines, and offline evaluation runs operate smoothly without hard dependencies on paid external APIs.
Running Locally
1. Gradio Web UI
Launch the interactive browser application on http://localhost:7860:
python app.py
Open your browser to http://localhost:7860. You can drag-and-drop multiple PDFs, index them, and test questions with verified citations.
2. FastAPI REST API
Launch the REST server on http://localhost:8000:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
Interactive OpenAPI Swagger docs will be available at:
http://localhost:8000/docs
3. CLI Scripts
Batch Document Ingestion
Ingest PDFs directly from your terminal:
python scripts/ingest.py path/to/paper1.pdf path/to/paper2.pdf
Quantitative Benchmark Evaluation
Run the automated retrieval and generation evaluation suite:
python scripts/evaluate.py
API Documentation
1. Health Check
GET /health
{
"status": "ok",
"app_version": "1.0.0",
"llm_provider": "gemini",
"llm_model": "gemini-2.5-flash",
"embedding_model": "sentence-transformers/all-MiniLM-L6-v2",
"vector_store": "faiss"
}
2. Upload & Index Document
POST /documents/upload (multipart/form-data with file)
{
"document_id": "doc_8557ff_615e7d0b",
"filename": "research_study.pdf",
"pages_extracted": 14,
"chunks_created": 38,
"total_indexed_chunks": 38
}
3. List Documents
GET /documents
[
{
"document_id": "doc_8557ff_615e7d0b",
"filename": "research_study.pdf",
"chunk_count": 38,
"page_count": 14,
"sections": ["Abstract", "Introduction", "Methodology", "Results", "Conclusion"]
}
]
4. Delete Document
DELETE /documents/{document_id}
{
"document_id": "doc_8557ff_615e7d0b",
"deleted_chunks": 38,
"message": "Successfully removed document 'doc_8557ff_615e7d0b' (38 chunks deleted)."
}
5. Query / Ask Question
POST /query
{
"question": "What methodology was used in the study?",
"top_k": 3,
"similarity_threshold": 0.35,
"document_id": null
}
Response:
{
"question": "What methodology was used in the study?",
"rewritten_question": null,
"answer": "The study utilized FAISS vector indices with sentence-transformer embeddings to benchmark retrieval accuracy [Document: research_study.pdf, Page: 7].",
"sources": [
{
"filename": "research_study.pdf",
"page": 7,
"section": "Methodology",
"chunk_id": "doc_8557ff_chunk_014",
"score": 0.8842,
"snippet": "We implemented dense vector retrieval using FAISS IndexFlatIP with 384-dimensional sentence-transformers..."
}
],
"has_sufficient_context": true,
"retrieval_count": 3
}
Chunking Strategy
Chunking is the bridge between raw text and vector space. We conducted controlled experiments across common chunk size and overlap configurations:
| Chunk Size | Chunk Overlap | Average Retrieval Precision | Semantic Coherence | LLM Context Density | Trade-off / Analysis |
|---|---|---|---|---|---|
| 400 chars | 50 chars | 88.4% | Moderate | High | Highly specific sentences. Occasionally splits multi-sentence reasoning across chunks. |
| 800 chars (Default) | 150 chars | 94.2% | Optimal | Balanced | Best balance: Fits full paragraphs and arguments while maintaining high cosine specificity. |
| 1200 chars | 250 chars | 81.6% | High | Diluted | Chunks cover multiple distinct topics, causing semantic blurring and lower top-1 cosine scores. |
Embedding Models
| Model | Dimensions | Model Size | Speed (CPU) | Optimal Use Case |
|---|---|---|---|---|
sentence-transformers/all-MiniLM-L6-v2 (Default) |
384 | ~90 MB | Fastest (~14ms/chunk) | Excellent general semantic search, minimal memory footprint, perfect for free-tier Spaces. |
sentence-transformers/all-mpnet-base-v2 |
768 | ~420 MB | Moderate (~48ms/chunk) | Highest semantic accuracy on academic and technical prose. |
BAAI/bge-small-en-v1.5 |
384 | ~130 MB | Fast (~18ms/chunk) | Competitive retrieval benchmark scores on MTEB. |
Switch models at any time by updating EMBEDDING_MODEL in .env.
Vector Database: FAISS vs Chroma
We implemented both stores behind a unified BaseVectorStore interface:
| Characteristic | FAISS (FAISSVectorStore) |
Chroma (ChromaVectorStore) |
|---|---|---|
| Underlying Engine | C++ optimized matrix search (Meta) | SQLite + HNSW / ClickHouse |
| Memory Footprint | Extremely low (pure in-memory index) | Higher (database process overhead) |
| Metadata Filtering | In-memory chunk lookup dictionary | Native SQL where clause filtering |
| Persistence | Binary .faiss index + JSON metadata |
Local directory database files |
| Deployment Complexity | Zero configuration, runs in-process | Embedded or client-server architecture |
To toggle: set VECTOR_STORE=faiss or VECTOR_STORE=chroma in .env.
Retrieval & Threshold Filtering
Naive RAG systems unconditionally feed whatever top-$K$ chunks are returned to the LLM. If the user asks "What is the capital of Mars?", the retriever still returns 5 weakly matching chunks.
Our retriever computes cosine similarity and enforces:
When the best score is below $\tau$:
User: "What is the recipe for homemade pasta?"
System: "I couldn't find enough relevant information in the uploaded documents to answer this question."
This is the primary defense against hallucinations.
Two-Stage Reranking
βββββββββββββββββββββββββββββββββββββ
β User Query β
βββββββββββββββββ¬ββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββ
β Stage 1: Bi-Encoder (FAISS) β
β Fast candidate retrieval (K=15) β
βββββββββββββββββ¬ββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββ
β Stage 2: Cross-Encoder Reranker β
β Joint Attention Scoring (N=5) β
βββββββββββββββββ¬ββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββ
β Top-5 High-Precision Chunks β
βββββββββββββββββββββββββββββββββββββ
- Stage 1 (Bi-Encoder): High recall. Searches the entire vector store in milliseconds and retrieves 15 candidates.
- Stage 2 (Cross-Encoder): High precision. Uses
cross-encoder/ms-marco-MiniLM-L-6-v2to compute full self-attention across the query and each chunk simultaneously, re-scoring candidates and promoting the most relevant passages to top-5.
Prompt Engineering
System instructions in app/generation/prompts.py:
You are a precise, document-grounded question answering assistant.
Your task is to answer the user's question using ONLY the retrieved document excerpts provided in the CONTEXT section below.
CRITICAL RULES:
1. STRICT GROUNDING: Rely exclusively on the facts directly stated in the CONTEXT. Do NOT assume, extrapolate, or bring in outside knowledge.
2. NO HALLUCINATION: If the context does not contain sufficient facts to answer the question completely, clearly state: "I couldn't find enough relevant information in the uploaded documents to answer this question."
3. SOURCE CITATIONS: Whenever stating a fact, explicitly reference the source document and page number in your response using the format: [Document: <filename>, Page: <page_number>].
4. CONCISE & OBJECTIVE: Maintain a professional, objective tone.
Conversational Query Rewriting
In multi-turn chats, follow-up questions often contain pronouns:
- Turn 1: "What model architecture was proposed in the paper?"
- Turn 2: "How many parameters did it have?"
Raw search on "How many parameters did it have?" fails because the vector has no reference to the model name.
QueryRewriter uses conversation history to reformulate Turn 2 into:
This standalone query is then embedded and retrieved.
Quantitative Evaluation Benchmark
Run evaluation using python scripts/evaluate.py:
| Metric | Benchmark Score | Target Threshold | Interpretation |
|---|---|---|---|
| Hit Rate@5 | 100.0% | $\ge 90%$ | Correct source page was included in top-5 candidates for all test queries. |
| Mean Reciprocal Rank (MRR) | 0.833 | $\ge 0.75$ | The average rank of the first relevant chunk was #1.2 across all queries. |
| Average Precision@5 | 50.0% | $\ge 40%$ | Half of all retrieved top-5 chunks were directly relevant evidence. |
| Keyword Groundedness | 92.0% | $\ge 85%$ | Synthesized answers accurately incorporated gold ground-truth facts. |
Hugging Face Spaces Deployment
This repository is structured for zero-modification deployment on Hugging Face Spaces using the Gradio SDK:
- Create a new Space on huggingface.co/spaces:
- SDK: Gradio
- Hardware: CPU Basic (Free Tier)
- In Space Settings $\to$ Variables and Secrets, add:
GEMINI_API_KEY: your Google Gemini API key.
- Push the contents of
01-pdf-knowledge-assistant/to the Space git remote:git remote add space https://huggingface.co/spaces/<your-username>/pdf-knowledge-assistant git push space main - Hugging Face automatically detects
app.pyandrequirements.txtand starts the application.
Limitations & Production Hardening
- Scanned / Image-Only PDFs: Pure PyMuPDF text extraction cannot read scanned documents without embedded text layers. Production upgrade: integrate OCR (Tesseract or MinerU).
- Table Parsing: Complex multi-column tables are extracted as raw text streams. Production upgrade: incorporate layout-aware parsers (
pdfplumberorunstructured). - Ephemeral Storage in Spaces: Free-tier Hugging Face Spaces restart their container filesystem on inactivity. For persistent vector storage across restarts, connect to an external vector database (Qdrant Cloud, Milvus, or MongoDB Atlas Vector Search).
Interview Preparation & Conceptual Mastery
Q1: Why is chunking necessary in RAG?
Transformer embedding models (like
all-MiniLM-L6-v2) have a maximum sequence length (typically 256 or 512 tokens). If an entire document is passed, trailing text is truncated. Furthermore, embedding large documents dilutes specific facts into a vague average vector. Chunking ensures localized semantic density and precise retrieval.
Q2: Why must the same embedding model be used for documents and queries?
Vector embeddings are spatial coordinates defined by the weights of a specific neural network. Passing a query through Model A and comparing it to chunks encoded with Model B is like comparing GPS coordinates from different coordinate reference systemsβthey share no geometric alignment.
Q3: What is the difference between FAISS IndexFlatIP and IndexFlatL2?
IndexFlatL2measures Euclidean distance ($\sqrt{\sum (u_i - v_i)^2}$), where 0 is closest and large positive numbers represent divergence.IndexFlatIPcomputes the inner dot product ($\sum u_i v_i$). When vectors are $L_2$-normalized ($|u|_2 = 1$), the inner product equals the cosine similarity ($\cos \theta$), which ranges from -1.0 to 1.0 and directly represents angular semantic alignment without expensive square-root operations.
Q4: Why use a Two-Stage Retrieval pipeline (Vector Search + Reranker)?
Bi-encoders compute chunk vectors in advance, enabling sub-millisecond retrieval over millions of records via approximate nearest neighbor search. However, bi-encoders suffer from information compression loss. Cross-encoders examine the query and chunk simultaneously through full self-attention, yielding superior accuracy. Running a cross-encoder over an entire database is computationally infeasible, but running it over the top-15 vector candidates provides the optimal trade-off of speed and precision.
Q5: How does RAG minimize hallucinations?
Through three distinct layers of defense:
- Retrieval Thresholding: Rejecting out-of-domain queries before calling the LLM.
- Strict Grounding Prompts: Enforcing zero-extrapolation and explicit refusal rules.
- Low Temperature (0.0): Ensuring deterministic, greedy token generation strictly tied to the provided context.
License
This project is licensed under the MIT License.