AI agents

Hybrid Search and Reranking: When and How to Combine Them

Antonio Evans9 min read

A three stage funnel drawn as boxes connected by arrows.
Key points

Key points

  1. 1Run keyword (BM25) and vector retrieval in parallel, because they fail on different query types and each covers the other's blind spot.
  2. 2Fuse ranked lists with reciprocal rank fusion rather than adding raw scores, since BM25 and cosine scores live on incompatible scales.
  3. 3Treat the reranker as a second stage over a shortlist, not a replacement for retrieval, because cross encoders score pairs and cannot scan a whole corpus.
  4. 4Decide by latency budget and measured recall, not by habit: skip reranking when the budget is tight or the candidate set is already precise.

Why one retriever is never enough

Retrieval-augmented generation works by fetching passages a model did not memorize and appending them to the prompt, so the answer is grounded in a source you control rather than in training data the AWS explainer the IBM overview. Google's documentation puts the operational point bluntly: if the retrieved information is irrelevant, the generation can be grounded and still be off topic or wrong the Google Cloud RAG page. Retrieval, not prompting, is where most answer-quality problems actually live.

The two families of retriever fail in complementary ways. BM25 is a lexical ranking function that scores documents by how often query terms appear, adjusted for term rarity and document length, which makes it excellent for unique identifiers and technical terms and blind to meaning Anthropic's contextual retrieval writeup. Dense embeddings do the reverse: they match paraphrase and concept ("how do I get back into my account" finds "Account Recovery") but routinely underweight a rare string that appears verbatim in exactly one document the pgEdge hybrid search post.

A worked example makes the split concrete. Set a query of Error code TS-999. Anthropic's writeup uses exactly this case: an embedding model may surface generic error-code documentation while missing the one page containing the literal string, whereas BM25 finds that string reliably Anthropic. Now ask "why did our data center revenue drop" and the failure flips: BM25 latches onto "revenue" and "data center" as separate tokens, while embeddings tie the whole intent to the right discussion the advanced retrieval pipeline walkthrough. If your query mix contains both shapes, and most production mixes do, a single retriever has a built-in error rate you cannot prompt your way out of.

The measured lift is real but not magical. On the WANDS e-commerce dataset, BM25 alone and pure vector search scored nearly identically (NDCG 0.6983 versus 0.6953), while a tuned hybrid reached 0.7497, about a 7.4 percent lift over either the hybrid search reference. That number is the honest expectation for adding a second retriever: single digit percentage points on ranking quality, larger on the specific query classes that were failing.

One more lever sits before retrieval and is often cheaper than either addition. Anthropic prepends a short generated context to each chunk before embedding and before BM25 indexing, and reports that this contextual retrieval cut failed retrievals by 49 percent, or 67 percent when combined with reranking Anthropic. Their cookbook reports contextual embeddings alone reduced the top-20 retrieval failure rate by 35 percent across data sources tested, with Pass@10 rising from roughly 87 to roughly 95 percent on a codebase dataset the Claude cookbook. If your chunks are small and context-poor, fix chunking and context before you add a reranker.

Deciding whether you need hybrid at all

Chunking and retrieval are separate decisions, and conflating them wastes money. Chunking determines what can be found at all: embedding models have context windows and truncate beyond them, and a chunk that makes no sense to a human will not make sense to the model Pinecone's chunking guide. NVIDIA's experiments across multiple datasets found page-level chunking gave the highest average end-to-end RAG accuracy at 0.648 with the lowest variance, while very small (128 token) and very large (2,048 token) chunks generally underperformed NVIDIA's chunking study. Notably, the best chunk size varied by document type even within financial filings, so it is an empirical setting, not a default.

Assuming your chunks are sane, use a short decision rule:

  • Queries are mostly natural language, corpus is small, latency budget is loose, and recall is already acceptable. Stay with dense-only retrieval and spend your effort on chunking and evaluation.
  • Queries contain product codes, error codes, names, part numbers, parameter names, or regulatory references. Add BM25. This is the strongest single signal you need hybrid.
  • Users complain that a document they know exists does not come back. That is a recall problem. Add the second retriever before adding a reranker.
  • The right passage is in the top 50 but not the top 5. That is an ordering problem. A reranker is the correct fix, and hybrid may be unnecessary.
  • P99 latency budget is under 100 milliseconds end to end. Skip the reranker. Run the two retrievers in parallel and fuse, which costs roughly the slower of the two, not the sum.

Diagnosing which problem you have matters more than any single technique. If relevant chunks never appear in the candidate set, no reranker can recover them, because rerankers reorder what they are given. Rerankers improve ordering, not recall the reranker comparison.

Building the hybrid candidate set

The mechanics are straightforward. Offline, chunk the corpus, generate a dense embedding per chunk, and build a BM25 (or sparse) index over the same chunks. Qdrant's tutorial describes this as storing three representations per document: dense for semantics, sparse for keyword matching, and optionally a late-interaction representation for reranking the Qdrant hybrid tutorial. You can also keep BM25 inside the database you already run: the pgEdge vectorizer computes both a dense embedding and a BM25 sparse vector per chunk inside PostgreSQL and fuses results with RRF pgEdge.

At query time, issue both searches concurrently:

  1. Embed the query and run an approximate nearest-neighbor search for the top N candidates (N around 50 to 200).
  2. Run the BM25 query for the top N candidates.
  3. Deduplicate by chunk ID and fuse the two ranked lists.
  4. Optionally rerank the fused shortlist and keep the top 5 to 20 for the prompt.

Two implementation details save trouble. First, retrieve more per retriever than you intend to keep, because fusion discards items that only one method ranks low. Second, when chunks carry metadata such as ticker, fiscal quarter or report type, apply those filters inside both queries rather than after fusion, otherwise you needlessly shrink the candidate pool the advanced retrieval pipeline.

A minimal fusion step in Python looks like this:

def rrf(ranked_lists, k=60):
    scores = {}
    for results in ranked_lists:          # each list: chunk ids, best first
        for rank, doc_id in enumerate(results, start=1):
            scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
    return sorted(scores.items(), key=lambda x: -x[1])

That is the whole algorithm. The next section explains why it beats a weighted average.

Fusing scores: RRF versus weighted linear combination

The temptation is to add 0.5 * bm25_score + 0.5 * cosine_score. Do not. BM25 produces unbounded positive scores while cosine similarity is bounded roughly between -1 and 1, so an unnormalized weighted sum lets BM25 dominate regardless of the weight you set the hybrid search reference. Any alpha you pick is then tuning the normalization artifact, not the retrieval behavior.

Reciprocal rank fusion sidesteps this by scoring each document only by its rank in each list: 1 / (k + rank), summed across lists. A document ranked highly by both retrievers wins; a document found by only one still has a chance, just a smaller one pgEdge. OpenSearch adopted RRF as its default fusion path precisely because rank-based aggregation is stable across mismatched score distributions, resistant to outliers, and requires no normalization tuning the OpenSearch RRF announcement. A larger k flattens the score curve, giving more weight to lower-ranked documents the hybrid search reference.

Fusion methodInputs neededTuning requiredBest when
Reciprocal rank fusionRanked lists onlyk (default 60)Scores are incomparable; mixed query types; fast start
Weighted linear combinationCalibrated scoresweight per retriever plus normalizationYou can calibrate on a labeled set and scores are stable
Rank-based normalization plus weightsBothTwo knobsA single method reliably dominates on your traffic

The decision rule: start with RRF at k=60. Only switch to weighted combination if you have a labeled evaluation set large enough to tune the weight and you have verified the scores are calibrated between retrievers. RRF at defaults beats weighted averages often enough that tuning is not worth the engineering time until everything else is measured the hybrid search reference.

One caveat worth knowing: fusion defaults differ by engine, and some products changed their default fusion algorithm between releases. Check what your vector store actually does before you benchmark.

Choosing and sizing the reranker

Two reranker families matter. Cross encoders feed the query and a document jointly into one model and emit a relevance score, which makes them accurate and too slow to run over a large corpus. Late interaction models (ColBERT-style) precompute per-token document vectors and score query tokens against them at query time, giving accuracy close to a cross encoder at lower latency and with more involved indexing the Qdrant tutorial.

Reranker typeLatency (vendor and author reports)InfrastructureChoose when
Mini cross encoderabout 5 to 15 ms on GPU per author reportsSimple, easy to self-hostYou need a modest lift and about 10 ms headroom
Base cross encoderroughly 2 to 3 times a miniSimpleMixed domains, about 20 to 50 ms headroom
Large cross encoder50 to 150 ms per 200 candidates unless heavily batchedGPU, batchingQuality dominates, as in legal or medical retrieval
Late interactionBetween cross encoder and single-vectorSpecialized indexesYou need cross-encoder-like accuracy under a tight cap

Latency and throughput figures above are the ranges reported in a survey of twelve reranker patterns the reranker comparison; treat them as planning numbers and measure on your own hardware.

Sizing the candidate set is the main lever you control, and it trades cost for quality linearly. Reranking 50 candidates costs a tenth of reranking 500. Practical ranges:

  • Latency-critical search UI: rerank 25 to 50, keep 5.
  • Question answering where one miss is expensive: rerank 100 to 200, keep 10.
  • Rerank 500 or more only if your retrieval is noisy and you have measured that the extra depth pays.

Anthropic's numbers suggest reranking on top of hybrid is worth the second stage when quality matters: contextual retrieval plus reranking cut failed retrievals by 67 percent versus 49 percent without reranking Anthropic. Their pipeline is the canonical shape: BM25 top chunks plus embedding top chunks, combined and deduplicated by rank fusion, then rated by a reranker before the prompt Anthropic. A segment of the practitioner community treats hybrid plus rerank as the minimum for production, having found pure vector retrieval insufficient outside demos one practitioner's account.

Provider choice is a secondary decision. If you already call several model types, mixing embedding and reranking providers behind one credential removes integration work; Quanta Inference exposes text, image, video, audio and embedding models through a single OpenAI-compatible key at Quanta Inference. Whatever you pick, run the reranker only on the fused shortlist, cache scores for repeated query-document pairs if your traffic repeats, and cap candidate count at the smallest number that preserves your measured recall.

Measuring the addition, not the vibe

Every one of these techniques is an experiment, and the only defensible way to add them is one at a time against a labeled set. The metrics are standard: recall@k or Pass@k (was the golden chunk in the top k), and NDCG for ordering quality. Anthropic's cookbook uses Pass@k against 248 queries each with a golden chunk, which is a small but workable template the Claude cookbook.

A procedure that works:

  1. Build 100 to 300 queries with known correct chunks, sampled from real traffic and including the query types that currently fail (codes, names, and paraphrases).
  2. Measure your baseline: recall@50, recall@5, and NDCG@10.
  3. Add BM25 and RRF. Measure again. If recall@50 does not move, hybrid is not your problem.
  4. Add the reranker over the fused top 50. Measure NDCG@10 and end-to-end P99 latency.
  5. Keep only the changes that move the metric beyond run-to-run noise, and check the cost per 1,000 queries before shipping.

Instrument the pipeline with per-stage timings, because the parallel retrieval step and the rerank step fail differently under load. Google's documentation recommends a metrics-driven "RAG Ops" loop, adjusting search configuration, source curation, parsing or chunking, and query rewriting based on measured quality rather than intuition Google Cloud. That is also the right frame for costing: a reranker that adds 40 ms and a few tenths of a cent per query is cheap if it lifts answer accuracy on the queries that generate support tickets, and wasteful if it reorders a list that was already correct.

If the evaluation work itself is the bottleneck, or you need a retrieval pipeline built and instrumented for a specific line of business, that is a scoped engagement: describe what you need at Quanta and a specialist picks it up with you.

FAQ

FAQ

Do I need hybrid search if I already use a strong embedding model?

Not necessarily. Dense retrieval handles paraphrase and concept queries well, and hybrid mainly buys you exact-term matching plus a single digit percentage ranking lift on mixed workloads the hybrid search reference. Add BM25 when your logs show queries with codes, names, or parameter strings failing, and fix chunking first if chunks are context-poor.

Why does adding BM25 and vector scores with weights perform badly?

Because the scores are not on the same scale: BM25 is unbounded while cosine similarity is bounded, so BM25 dominates any unnormalized sum the hybrid search reference. Reciprocal rank fusion avoids the problem by using rank positions only, which is why OpenSearch adopted it for merging heterogeneous result lists OpenSearch.

How many candidates should I pass to the reranker?

Start at 50, keep 5 to 10, and expand only if measurements justify it. A cross encoder scores each query-document pair, so cost and latency scale with candidate count, and reranking 50 costs a tenth of reranking 500 the reranker comparison. Because rerankers reorder rather than retrieve, check recall at the candidate depth before you tune anything else.

Can a reranker fix missing documents?

No. Reranking changes ordering within the candidate set, not recall of that set the reranker comparison. If the right chunk never appears in the top 50 from either retriever, fix chunking, add context to chunks before indexing, or add the second retriever Anthropic NVIDIA.

Does hybrid retrieval change what I should store in the vector database?

Yes. You store a dense vector per chunk and a sparse or BM25 representation per chunk, and optionally a late-interaction representation, then run both searches at query time the Qdrant tutorial. Some systems compute the sparse representation inside the database itself to keep the two indexes in sync pgEdge.

Sources

Sources

  1. What is RAG? - Retrieval-Augmented Generation AI Explained - AWS
  2. What is RAG (Retrieval Augmented Generation)? - IBM
  3. What is Retrieval-Augmented Generation (RAG)? - Google Cloud
  4. Contextual Retrieval in AI Systems - Anthropic
  5. BM25, Sparse Vectors, and Reciprocal Rank Fusion
  6. Advanced Retrieval Pipeline for RAG (HyDE, Hybrid Search, Reranking)
  7. Hybrid Search: BM25, Vector & Reranking Reference 2026
  8. Enhancing RAG with contextual retrieval | Claude Cookbook
  9. Chunking Strategies for LLM Applications - Pinecone
  10. Finding the Best Chunking Strategy for Accurate AI Responses
  11. 12 Vector Rerankers Compared: Cost vs Quality
  12. Qdrant Hybrid Search with Reranking
  13. Introducing reciprocal rank fusion for hybrid search
  14. Introducing Hybrid Search and Rerank to Improve the Retrieval Accuracy ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles