Why single-stage retrieval fails in production
Most RAG tutorials show a single vector search step: embed the query, find the top-k nearest chunks, stuff them into the prompt. In practice this breaks in predictable ways.
Dense-only retrieval fails on exact-match needs โ product codes, version numbers, rare proper nouns. The embedding model smears meaning across 768+ dimensions; a query for CVE-2024-3094 returns vaguely similar security content, not the exact chunk that mentions that string.
Sparse-only retrieval (BM25) fails on semantic gaps โ a document about "cardiac arrest" won't surface for the query "heart stopped beating" unless those exact tokens appear. It also can't handle multilingual or paraphrase-heavy queries.
The solution is a three-stage pipeline: (1) sparse retrieval via BM25, (2) dense retrieval via bi-encoder embeddings, (3) fusion + cross-encoder reranking. Each stage has a different cost-recall tradeoff, and stacking them gets you both recall breadth and precision at the top.
