Reranking in RAG: Why Retrieval Order Matters

Published: August 8, 2026 — Your RAG system retrieves the right chunk 80% of the time, but the answers still feel wrong. Here's the part most people miss: the LLM doesn't see your whole corpus — it sees only the top-k chunks you hand it. If a wrong chunk sneaks into that tiny window, it crowds out a right one, and the model confidently answers from the wrong material. Reranking is the second pass that fixes the order before the LLM ever sees it. This post explains how cross-encoders do that, and adds reranking to the 30-minute RAG pipeline.

⚡ Quick Takeaways

Why Retrieval Order Determines Answer Quality

RAG works like this: retrieve the most relevant passages, stuff them into the prompt, let the model answer from them. That design has a hidden vulnerability — the context window is tiny. With 3–5 chunks in front of the LLM, retrieval precision isn't a nice-to-have; it's the whole game.

First-stage retrievers (BM25 or bi-encoder embeddings) are deliberately fast and approximate. They're great at getting a relevant chunk into the top-50, but the exact ordering of that shortlist is often wrong — especially with dense, near-duplicate, or ambiguous documents. That's the gap reranking closes: retrieve generously, then reorder precisely.

Bi-Encoders vs Cross-Encoders: The Core Concept

Dimension Bi-encoder (first stage) Cross-encoder (reranker)
How it scores Embeds query and document separately, then compares vectors Takes query + document as one input pair, scores relevance jointly
Speed Very fast; document embeddings are precomputed once Slow per pair — must run the model for every (query, document) combination
Accuracy Good — captures meaning, misses fine-grained detail Excellent — sees token-level interaction between query and document
Role First-stage retrieval over the whole corpus Second-stage reranking of a shortlist

💡 Why cross-encoders win at reranking: a bi-encoder must compress the entire document into one vector before it knows the query, so it discards query-specific detail. A cross-encoder reads the query and document together, letting every token of the document interact with the query — the same reason it's too expensive to run on a whole corpus, and the exact reason it's perfect for a 50-item shortlist.

The Two-Stage Pipeline

1. Retrieve (fast, broad)

Bi-encoder or hybrid BM25 + semantic search returns the top 50–100 candidates. This stage is about recall: make sure the right chunk is in the list.

2. Rerank (slow, precise)

A cross-encoder scores every (query, candidate) pair and reorders the shortlist by true relevance. This stage is about precision: the top 3–5 that actually matter.

3. Generate

Feed the reranked top-k to the LLM as context. Now every slot in the context window earns its place.

This is why the community shorthand exists: cross-encoders are rerankers, not retrievers. Use them where they're strongest — on the shortlist — and let fast retrieval handle the full corpus. It's the same architecture used in production systems like Lawyer Assistant, which reranks hybrid retrieval results so legal citations resolve to the exact right clause.

Cross-Encoder Models in 2026

Model Size Notes
BGE-Reranker-v2-M3 ~570M params The open-source default — multilingual, strong on mixed-language corpora
ms-marco-MiniLM-L-6-v2 ~22M params The classic small reranker; runs anywhere, ~1s for 50 pairs on CPU
Qwen3-Reranker 0.6B / 4B / 8B Newer family; 100+ languages, strong quality at the larger sizes
Jina Reranker v3.5 ~0.6B+ Strong long-context reranking; cloud and open versions
Cohere Rerank API The managed cloud option; fast but sends queries off-device

📦 Running locally: reranker models run via sentence-transformers (the CrossEncoder class) or llama.cpp (which supports rerank natively). GGUF versions are available on Ollama and Hugging Face — though Ollama's dedicated rerank endpoint has been inconsistent, so sentence-transformers and llama.cpp are the reliable local paths. For a curated comparison of reranker models, see Local AI Zone's reranker guide.

Adding Reranking to the 30-Minute Pipeline

In the 30-minute RAG tutorial, Step 4 retrieves the top-3 and Step 5 feeds them straight to the model. Here's the upgrade: retrieve top-15 instead of top-3, rerank with a cross-encoder, then keep the top 3.

# Step 4 (modified): retrieve generously
results = collection.query(
    query_embeddings=[query_embedding],
    n_results=15,          # was 3
)
candidates = results["documents"][0]

# New step: rerank with a cross-encoder
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")  # or ms-marco-MiniLM-L-6-v2

pairs = [(query, doc) for doc in candidates]
scores = reranker.predict(pairs)  # one relevance score per (query, doc) pair

ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
top_k = [doc for doc, _ in ranked[:3]]   # the best 3, in true relevance order

# Step 5 (unchanged): generate from the reranked context
context = "\n\n".join(top_k)

Install the extra dependency with pip install sentence-transformers and the model downloads on first use. That's the entire change — retrieval stays fast and approximate, and the cross-encoder makes the final cut precise.

✅ When the symptom matches: your RAG answers are wrong even though the right chunk exists in the collection. That's the classic retrieval-order problem, and a reranker is the highest-leverage fix — the same reasoning that makes it a standard stage in production legal RAG.

When Reranking Is (and Isn't) Worth It

Add a reranker when…

Skip it when…

The honest default: build the simple pipeline first, measure where answers fail, and add reranking only when you can point at a retrieval-order failure. For choosing where the shortlist lives, our ChromaDB vs FAISS guide covers the vector store underneath.

Frequently Asked Questions (FAQ)

What is the difference between a bi-encoder and a cross-encoder?

A bi-encoder embeds the query and each document separately into vectors, so it is fast and can precompute document embeddings — but it cannot see the query and document together. A cross-encoder takes the query and one document as a single input pair and scores their relevance jointly, which is far more accurate but too slow for scanning a whole corpus. That's why the two work as a team: bi-encoder retrieves a shortlist, cross-encoder reranks it.

Why does retrieval order matter if the LLM sees all the context?

The LLM only sees the top-k chunks you feed it — usually 3 to 5. If a wrong chunk ranks in that top-k, it crowds out a right one, and the model can confidently answer from the wrong material. Reranking maximizes the chance that every slot in the context window is actually relevant, which directly improves answer accuracy.

How much does reranking improve RAG quality?

Measurably. On the WANDS benchmark, hybrid retrieval plus reranking reached 0.7497 NDCG versus 0.7068 for hybrid retrieval alone. On financial documents, a two-stage hybrid + reranking pipeline reached Recall@5 of 0.816. The gain is largest when documents are dense, ambiguous, or full of near-duplicates.

How slow is reranking?

A small cross-encoder like ms-marco-MiniLM-L-6-v2 reranks 50 query-document pairs in about a second on CPU. Because you only rerank the shortlist (50–100 candidates), the cost is small compared to the accuracy gain. GPU makes it near-instant.

Can I run a reranker locally?

Yes. BGE-Reranker-v2-M3 and Qwen3-Reranker run locally via sentence-transformers or llama.cpp, and small classic models like ms-marco-MiniLM-L-6-v2 run on modest hardware. Reranker GGUFs are available on Ollama and Hugging Face, though Ollama's dedicated rerank endpoint has been inconsistent — sentence-transformers and llama.cpp are the reliable local paths.

Do I always need a reranker?

No. If your queries are simple, your corpus is small and clean, and retrieval already returns obvious matches, a reranker adds latency for little gain. Add one when answers are wrong but the right chunk exists in the collection — the classic symptom of a retrieval-order problem.

Sources