PDF-RAG — Retrieval-Augmented Generation
An end-to-end Retrieval-Augmented Generation system that combines local BGE embeddings, vector search, BM25 keyword retrieval, and Gemini generation/evaluation to turn PDF documents into a searchable knowledge base and generate grounded, evaluated, source-cited answers.
2026 · AI/RAG project · Full-stack ownership
At a Glance
Chunk strategy
800 / 100
token-aware chunks with overlap
Embeddings
768D
Local BGE embeddings for document and query retrieval
Retrieval
Hybrid
Vector Search + BM25
Evaluation
Structured
faithfulness + relevance + completeness + context sufficiency
Architecture-focused project demonstrating asynchronous ingestion, local embeddings, hybrid retrieval, rank fusion, grounded generation, evaluation, and bounded self-correction.
The Problem
Large PDF documents contain valuable information but are difficult to query efficiently through traditional search. Sending entire documents directly to an LLM is constrained by context size, increases token usage, and makes it difficult to reliably ground answers in the source material.
A vector-only retrieval approach can identify semantically similar content, but semantic similarity is not always enough. Exact terminology, names, identifiers, technical phrases, and domain-specific keywords can be better captured through lexical search. The system therefore combines semantic and keyword retrieval while keeping document processing asynchronous.
Generation quality also needs to be measured independently from retrieval. A retrieved context can be relevant while the generated answer is incomplete or unsupported, so the system evaluates answers against the supplied query and context and can optionally revise weak answers.
Constraints
Architecture Overview
Ingestion
Express API + S3-compatible object storage
Processing
RabbitMQ + asynchronous document consumer
Chunking
BPE tokenization + token-aware chunks
Semantic
Local BGE embeddings + MongoDB Atlas Vector Search
Keyword
BM25 lexical retrieval
Generation
RRF → Context Builder → Gemini Generator + Evaluator
Key Engineering Decisions
Using token-aware chunking instead of character-based splitting
Embedding and generation models operate within token-based context constraints. I implemented BPE tokenization and used an 800-token chunk size with 100-token overlap so chunks could be controlled according to actual model tokenization rather than arbitrary character counts.
Created predictable chunks that respect model context constraints while preserving contextual overlap between adjacent sectionsRunning embeddings locally
Embedding generation is part of the retrieval pipeline, so I moved it from a hosted embedding API to a local BGE model through FastEmbed. This removes the embedding API dependency while keeping Gemini for answer generation and evaluation.
Semantic retrieval runs locally with 768-dimensional BGE embeddings while the retrieval architecture remains unchangedCombining semantic and lexical retrieval
Vector search is effective at understanding conceptual similarity, but it can underperform when a query depends on exact terminology, names, identifiers, or technical phrases. I introduced BM25 keyword retrieval alongside vector search so the system could retrieve both semantically relevant and exact-term matches.
Retrieval can capture both conceptual relevance and exact database-style terminologyUsing Reciprocal Rank Fusion instead of merging raw scores
Vector similarity and BM25 produce scores with different meanings and scales, making direct score comparison unreliable. Rather than attempting arbitrary score normalization, I used Reciprocal Rank Fusion to combine the ranked results from both retrieval strategies based on their positions in each result set.
Produced a unified ranking without requiring incompatible vector and keyword scores to be directly comparedMoving document processing to an asynchronous pipeline
PDF extraction, tokenization, embedding generation, and indexing can be expensive operations. Performing them inside the upload request would unnecessarily block the API. RabbitMQ was introduced so the API could persist the document and publish an event while a background consumer handled the ingestion pipeline.
Upload requests remain responsive while document processing runs independently in the backgroundAdding structured LLM evaluation and bounded self-correction
A generated answer can be well-formed while still being unsupported, incomplete, or poorly grounded. The system evaluates answers against the retrieved query context using structured criteria and, when enabled, gives the generator bounded feedback to revise the answer before evaluating it again.
Answer quality is measured explicitly and the optional feedback loop can revise weak answers without changing the retrieved contextGrounding generation through hybrid retrieval
The LLM should answer questions using the uploaded documents rather than relying on unrelated model knowledge. At query time, semantic and lexical retrieval rankings are fused through RRF, the resulting context is passed to the generation step, and source references remain attached to the retrieved chunks.
Gemini-generated answers are grounded in retrieved document context and returned alongside source chunk referencesOutcomes
- Built a complete PDF-to-RAG pipeline from document upload through grounded answer generation
- Implemented token-aware chunking using BPE tokenization
- Integrated local BGE embeddings through FastEmbed for offline document and query retrieval
- Implemented semantic retrieval using MongoDB Atlas Vector Search
- Added BM25 keyword retrieval for exact-term matching
- Combined semantic and keyword rankings using Reciprocal Rank Fusion (RRF)
- Introduced RabbitMQ-based asynchronous document processing
- Built context construction and grounded answer generation with source citations
- Added structured LLM evaluation for faithfulness, relevance, completeness, and context sufficiency
- Added an optional bounded feedback loop for answer revision and re-evaluation
- Designed document lifecycle tracking with uploaded, processing, completed, and failed states
- Containerized the development environment using Docker Compose
Takeaway
“Building a useful RAG system requires more than connecting an LLM to a vector database. Retrieval quality depends on document processing, token-aware chunking, embedding strategy, lexical retrieval, semantic retrieval, rank fusion, and context construction. Generation quality then needs separate evaluation for grounding and completeness, with bounded self-correction available when revision is needed.”