Production RAG Architecture: Hybrid Retrieval and Reranking
Production RAG quality is retrieval, not model; most failures come from wrong documents. Dense vectors miss exact terms like CVE-2024-1235, so production…

Production RAG architecture is not about the model — it is about retrieval. Most teams fail not because the LLM is weak, but because the retrieval pipeline returns the wrong documents. This essay examines the three levers that separate demo RAG from production RAG: hybrid retrieval, reranking, and index freshness. We cover concrete patterns, tradeoffs, and failure modes.
How This Was Researched
This analysis is based on official documentation and published engineering blogs; we did not run these workloads hands-on. Sources include vendor documentation from Pinecone, Qdrant, Weaviate, Cohere, Voyage AI, Elastic, and Anthropic, plus peer-reviewed papers on retrieval evaluation. Last researched: August 2026.
Why Retrieval Quality Is the Production Bottleneck
Vector-only pipelines fail on exact terms, IDs, and rare entities: embeddings capture semantic similarity but lose lexical precision, so a pure dense retriever can rank a textually wrong document above the exact match. Pinecone’s hybrid search documentation notes that dense vectors alone miss exact-match queries that sparse methods handle trivially.
In production, users query with product codes, version numbers, and API names, not natural language paragraphs. A pure dense retriever will rank CVE-2024-1235 above the exact match because it is closer in embedding space. The result is hallucinated answers built on plausible but incorrect context. This is the fundamental reason hybrid retrieval exists.
Hybrid Search: Combining Dense and Sparse Retrieval
Hybrid retrieval runs a dense vector search and a sparse keyword search in parallel, then fuses the results. The dense path captures semantic similarity; the sparse path (typically BM25) handles exact terms, IDs, and rare entities. Reciprocal Rank Fusion (RRF) is the most robust default because dense and sparse scores are not directly comparable, as Qdrant’s hybrid query documentation shows.
Weighted fusion requires careful score calibration and breaks when one retriever’s score distribution shifts. Weaviate’s hybrid search explanation demonstrates that RRF handles the scale mismatch between cosine similarity and BM25 scores gracefully. When hybrid wins: any corpus with product IDs, code identifiers, legal clauses, or medical codes. When it does not add value: pure conversational corpora with no structured identifiers.
def reciprocal_rank_fusion(dense_results, sparse_results, k=60):
fused_scores = {}
for rank, doc_id in enumerate(dense_results):
fused_scores[doc_id] = fused_scores.get(doc_id, 0) + 1 / (k + rank + 1)
for rank, doc_id in enumerate(sparse_results):
fused_scores[doc_id] = fused_scores.get(doc_id, 0) + 1 / (k + rank + 1)
return sorted(fused_scores, key=fused_scores.get, reverse=True)
Reranking: Where It Belongs in the Pipeline
Reranking is the second stage: retrieve top-K (e.g., 100) with hybrid search, then rerank to top-N (e.g., 10) before sending to the LLM. The reranker is a cross-encoder that scores the query-document pair jointly, capturing interactions that bi-encoders miss. Cohere’s rerank documentation positions this as a precision layer on top of any retriever.
The latency budget is tight: cross-encoders are expensive, so the reranker must only see a small candidate set. The standard pattern is retrieve wide, rerank narrow. Voyage AI’s documentation describes their reranker as a distinct model from their embeddings, reinforcing that these are separate components with separate scaling requirements. Skipping the reranker means accepting the retriever’s first-pass ranking, which is optimized for recall, not precision. The tradeoff: a reranker adds 50-200ms latency but can double answer accuracy on ambiguous queries. In production, this is the cheapest accuracy improvement per millisecond you will find.
Index Freshness: Keeping the Corpus Current
A stale index produces confident answers about outdated information — worse than no answer. Production RAG requires a streaming update pipeline, not nightly batch jobs: change data capture (CDC) from the source database feeds the index, and each document chunk needs a version ID so updates delete or supersede the old chunk and re-embed the new one.
Elastic’s kNN query documentation shows that vector fields are immutable once indexed — you cannot update an embedding in place, you must reindex the document. This has a direct implication: chunk versioning is not optional. If you delete a document, you must propagate the delete to every chunk derived from it. Anthropic’s contextual retrieval post addresses a related freshness problem: augmenting chunks with context before embedding, which improves retrieval but increases the re-embedding cost on every update. The staleness tradeoff is real: more frequent updates mean higher indexing cost and potential index churn. The production pattern is tiered freshness — hot documents update in minutes, archival documents update daily.
# Pseudo-code for chunk versioning on source change
def on_source_change(document):
old_chunks = get_chunks_by_document_id(document.id)
delete_chunks(old_chunks)
new_chunks = chunk_and_embed(document.content)
insert_chunks(new_chunks, version=document.version)
Evaluating Retrieval Quality in Production
Offline metrics tell you if the retriever is broken; online signals tell you if the system is working. The standard offline metrics are recall@k, nDCG, and hit rate, measured against a golden dataset of query-document pairs, per the RAG evaluation review.
The RAGAS paper introduces LLM-based evaluation metrics that correlate with human judgment. In production, you need both: golden datasets catch regressions before deploy; online signals — user feedback, answer acceptance rate, and retrieval-groundedness scores — catch issues golden datasets miss. The critical insight: your golden dataset must include the hard cases that motivated hybrid retrieval in the first place — exact IDs, rare entities, and multi-lingual queries. If your golden set only has natural language questions, you will not detect sparse-retriever failures. LangChain’s RAG tutorial and LlamaIndex’s documentation both provide reference implementations for building these evaluation harnesses.
What makes a production RAG architecture reliable?
Reliability comes from explicit handling of failure modes. The architecture must degrade gracefully when the retriever returns nothing, when the reranker times out, or when the index is stale. Google Cloud’s RAG guide emphasizes that production RAG is a data pipeline problem, not a model problem.
This means: hybrid retrieval with RRF fusion to cover both semantic and lexical queries, a reranker with a hard latency budget and a fallback to first-pass results on timeout, and a versioned index with CDC-driven updates. The Databricks glossary on RAG and IBM’s RAG overview both confirm that retrieval quality dominates end-to-end answer quality. When you design a production RAG architecture, you are designing a retrieval system with an LLM on top — not the reverse. This connects directly to the AI stack reference for infrastructure patterns and our analysis of LLM caching at scale for serving considerations. For the full tooling picture, see our tools index. The pattern also pairs with our context engineering techniques post and our streaming inference architecture breakdown.
FAQ
What is hybrid search in RAG?
Hybrid search runs a dense vector retriever and a sparse keyword retriever in parallel, then fuses the ranked lists. The dense path captures semantic similarity; the sparse path handles exact terms, IDs, and rare entities. Fusion via Reciprocal Rank Fusion avoids score normalization issues between incompatible scoring scales.
When do you need a reranker in RAG?
You need a reranker when first-pass retrieval returns relevant-but-noisy results that reduce answer quality. If your retriever’s top-10 contains more than a couple of irrelevant documents, a cross-encoder reranker will improve precision. The cost is latency, so rerank a small candidate set (top-50 to top-100) down to the final top-10.
How do you keep a RAG index fresh?
Use change data capture from the source database to trigger incremental updates. Each chunk carries a version ID; on source change, delete old chunks and re-embed new ones. Vector fields are immutable in most engines, so updates require reindexing. Tier freshness: hot data updates in minutes, archival data less frequently.
📖 Related Reads
- ToolBrain — tool reviews, LLM comparisons, and AI workflow guides
Cross-links automatically generated from CodeIntel Log.