Module 4: Re-ranking — the second stage that turns mediocre retrieval into excellent retrieval

Module 4: Re-ranking — the second stage that turns mediocre retrieval into excellent retrieval

Module overview

Up to this point, every technique we covered manipulates the query (M03: optimization), the documents (M02: chunking), or the search metric. Re-ranking is structurally different: it adds a second scoring stage after the initial retrieval. The idea is simple but powerful: retrieval with cosine similarity is fast but noisy. Instead of fighting that limitation, we accept its nature and add a second step that refines the candidates with a more precise model.

                    Query
                      │
                      ▼
    ┌──────────────────────────────────┐
    │ Stage 1: retrieval with cosine   │
    │ Top-30 candidates (fast but      │
    │ noisy — some are irrelevant)     │
    └─────────────┬────────────────────┘
                  │
                  ▼
    ┌──────────────────────────────────┐
    │ Stage 2: re-ranking              │
    │ Re-score each (query, doc) pair  │
    │ with a more sophisticated model  │
    └─────────────┬────────────────────┘
                  │
                  ▼
              Final top-5
              (high precision)

This two-stage architecture — a fast bi-encoder + a precise cross-encoder — is the "state of the art" pattern in production RAG. Typical gain: precision goes up 15-25 points. This capsule introduces the module, the three types of re-ranker you'll compare (local cross-encoder, LLM-based, Cohere managed), and how to decide which one to use.

By the end of this module you'll be able to:

  • ✅ Explain why cosine similarity has an intrinsic ceiling that justifies re-ranking
  • ✅ Implement the three main techniques: local cross-encoder, LLM-based, Cohere Rerank
  • ✅ Optimize the operational trade-offs (n_results, batching, caching)
  • ✅ Apply a decision framework to pick the right technique for your context
  • ✅ Build a production-ready re-ranking system with A/B testing and metrics

Estimated module time: 3-4 hours (8 capsules).


Why re-ranking is the improvement with the best ROI

If your RAG system is in production and quality needs to improve, re-ranking is usually the first intervention with the best gain/effort ratio. Compared with other options:

TechniqueTypical precision gainEngineering effortRecurring cost
Switching the embedding model (small → large)+3-5%1 day + re-ingestMore expensive embeddings
Improving chunking+5-10%2-3 days + re-ingest$0
Query optimization+5-15% (varies)1-2 weeks$20-200/month
Re-ranking (cross-encoder)+15-25%1 day$0
Hybrid search+5-15%1-2 weeks + re-index$0

Re-ranking typically gives more gain for less effort. That's why it's the second most common intervention after reasonable chunking. The reason is structural: cosine similarity has an inherent ceiling, and adding a second scoring stage breaks through it.


The concrete problem: cosine similarity has a ceiling

Picture this query and the top-5 cosine similarity returns:

Query: "how do I implement OAuth2 authentication in FastAPI?"

Top-5 with cosine:

#1  cosine: 0.85  "FastAPI OAuth2 implementation guide"
                  ✅ Relevant: specific to the query

#2  cosine: 0.83  "OAuth2 authentication overview"
                  ❌ Irrelevant: generic, never mentions FastAPI

#3  cosine: 0.82  "FastAPI security dependencies"
                  ✅ Relevant: covers OAuth2 within security

#4  cosine: 0.80  "OAuth2 specification (RFC 6749)"
                  ❌ Irrelevant: a theoretical spec, not implementation

#5  cosine: 0.79  "FastAPI authentication tutorial"
                  ✅ Relevant: implementation-focused

Precision@5: 3/5 = 60%

The cosine scores are all similar (0.79-0.85). The metric doesn't distinguish "FastAPI-specific" from "generic OAuth2" — both talk about the topic, both rank high.

Re-ranking with a cross-encoder:

Top-5 after the rerank (over the top-30 candidates):

#1  score: 9.2   "FastAPI OAuth2 implementation guide"        ✅
#2  score: 8.8   "FastAPI security dependencies"               ✅
#3  score: 8.5   "FastAPI authentication tutorial"             ✅
#4  score: 8.1   "OAuth2 with FastAPI code examples"           ✅
#5  score: 7.4   "Securing FastAPI endpoints with OAuth2"      ✅

Precision@5: 5/5 = 100%

The cross-encoder analyzes the (query, doc) pair as a single unit. It detects that "FastAPI-specific" answers the query and "generic OAuth2" doesn't. The absolute score reflects real relevance.

Result: the false positives (docs about generic OAuth2, the RFC) get filtered out. The downstream LLM receives focused context.


The three techniques you'll learn

Technique 1: local cross-encoder (a reasonable default)

from sentence_transformers import CrossEncoder
model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-12-v2')
scores = model.predict([(query, doc) for doc in candidates])
  • ✅ Free (runs locally)
  • ✅ Latency ~150ms for 20 candidates
  • ✅ Quality: typically +20% precision
  • ❌ Suboptimal multilingual (the model was trained in English)

When: typical production with an English monolingual corpus. It's the default option covering 80% of cases.

Capsule 03 covers it in detail.

Technique 2: LLM-based (maximum quality, expensive)

score = llm_rerank_pair(query, document)  # GPT-4o-mini scores 0-10
  • ✅ Quality: typically +24% precision
  • ❌ Latency +1500ms for 20 candidates
  • ❌ Cost +$0.002/query
  • ✅ Excellent multilingual

When: critical domains (legal, medical, financial) where an extra 3-5% precision justifies the cost.

Capsule 04 covers it.

Technique 3: Cohere Rerank (managed, in between)

import cohere
co = cohere.Client(api_key)
results = co.rerank(query=query, documents=docs, top_n=5)
  • ✅ Quality: typically +21% precision
  • ✅ Latency ~250ms
  • ⚠️ Cost ~$0.002 per 1K docs
  • ✅ Excellent multilingual

When: teams with no MLE to maintain a local cross-encoder, or a multilingual corpus.

Capsule 05 covers it.


Module map

CapsuleTopicTime
01 (you are here)Module introduction10-15 min
02Why cosine similarity has a ceiling30 min
03Cross-encoder re-ranking (the default)30 min
04LLM-based re-ranking (premium)30 min
05Cohere Rerank API (managed)25 min
06Trade-offs and operational optimizations25 min
07Decision framework — which technique to pick30 min
08Capstone project — a re-ranking system45 min

Estimated total: 3-4 hours. It's one of the best-ROI modules in the path.


Connection with previous and following modules

Previous modules:
  ├─ M01: RAG Pipeline → re-ranking slots in after the initial retrieval
  ├─ M02: Chunking → better chunking + re-ranking complement each other
  └─ M03: Query Optimization → query optimization improves retrieval; re-ranking refines the output

This module prepares you for:
  ├─ M05: Hybrid Search → hybrid search + re-ranking is the "state of the art" pattern
  ├─ M06: Metadata Filtering → re-ranking is applied after the filtering
  ├─ M07: Production with Pinecone → Pinecone has a native rerank
  └─ M08: Evaluation → how to measure whether rerank improves things vs just adds complexity

The "state of the art" pattern in production RAG (May 2026):

Query
  ↓
Query optimization (M03)
  ↓
Hybrid search (M05) — BM25 + cosine
  ↓
Metadata filter (M06)
  ↓
Re-ranking (this module)
  ↓
LLM generation

This module is one of the three pillars (along with chunking and hybrid search) that separate an "MVP" RAG from a "production-ready" RAG.


Expected cumulative gain

If you go through every module in the path, the system's quality improves cumulatively:

Starting point (an "MVP" system):
  Cosine + recursive chunk + no optimization = ~68% precision@5

After M02 (optimized chunking):                 +5-10 pts → 73-78%
After M03 (query optimization):                 +5-10 pts → 78-88%
After M04 (re-ranking) ← YOU ARE HERE:          +15-25 pts → 88-95%
After M05 (hybrid search):                      +3-8 pts → 91-95%
After M06 (metadata filter):                    +2-5 pts → 93-97%

Re-ranking alone accounts for most of the gain. That's why many teams add it first, before investing in more complex optimizations.


Concrete cases: when each technique wins

To anchor the decisions you'll make at the end of the module, three examples:

Case A: internal support chatbot, 200K docs, a team of 3

  • Constraints: English corpus, no dedicated MLE, latency <500ms.
  • Expected recommendation: Cohere Rerank ($5-15/month, 0 maintenance, quality close to an LLM).
  • Why not a cross-encoder: with no MLE, maintaining models locally adds operational overhead.
  • Why not an LLM: $200/month for an internal chatbot isn't justified vs Cohere at $15.

Case B: LATAM legal SaaS assistant, 500K multilingual cases

  • Constraints: Spanish + Portuguese + English, precision is critical, generous budget.
  • Expected recommendation: a cross-encoder + LLM cascade for queries flagged "high stakes".
  • Why a cascade: the cross-encoder filters fast (a multilingual model), the LLM refines the top-15 at maximum quality.
  • Why not Cohere alone: a critical domain justifies the LLM's extra cost.

Case C: an internal Stack Overflow search for a startup

  • Constraints: 10M docs (large scale), high volume, limited budget.
  • Expected recommendation: a local cross-encoder (free at scale).
  • Why not Cohere: $30/month is manageable, but it grows with volume. A cross-encoder is fixed at the cost of infra.
  • Why not an LLM: prohibitive at 10M docs / 50K daily queries.

These three cases cover the typical patterns. The module teaches you to derive the right decision for your specific case.


Prerequisites before starting the module

Make sure you have:

  • ✅ A working RAG pipeline with cosine retrieval (covered in M01)
  • ✅ Reasonable chunking (recursive with chunk_size=500, overlap=50 at minimum) — M02
  • ✅ Your own eval set with at least 30 queries and ground truth — to validate the gain
  • ✅ Access to the OpenAI API (for capsule 04 on LLM rerank)
  • ✅ A Cohere account (a free trial is available) — for capsule 05

If you're missing the eval set, build it before starting the module. Without it, the benchmarks you'll run in each capsule are blind.


Technical setup for the module

# Capsule 03 (local cross-encoder)
pip install sentence-transformers

# Capsule 04 (LLM-based)
pip install openai pydantic

# Capsule 05 (Cohere)
pip install cohere

Environment variables:

# .env
OPENAI_API_KEY=sk-...
COHERE_API_KEY=...

Self-check before moving on

Before starting capsule 02, make sure you can answer:

  1. Why does re-ranking typically give more gain for less effort than other techniques?
  2. What's the structural difference between a bi-encoder (cosine) and a cross-encoder (rerank)?
  3. When would you NOT need re-ranking in your RAG system?
Answers
  1. Because cosine similarity has an inherent ceiling (it measures semantic overlap, not real relevance). Adding a second scoring stage breaks through that ceiling. The gain comes from the architecture (two stages), not from marginally optimizing one component. Low effort: add a library + 30 lines of code. High benefit: 15-25 points of precision.

  2. A bi-encoder (cosine) processes the query and the document independently, producing two vectors that are then compared with cosine similarity. Fast but shallow. A cross-encoder (rerank) processes the (query, doc) pair together, attending to token-by-token interactions. Slower, but it captures the relationship the bi-encoder can't see.

  3. An MVP with a small dataset (<10K docs): cosine is enough, the false positives don't pile up. A system with a strict SLA (<200ms total): the rerank's extra latency breaks the SLA. When your current precision is already >92% on the eval set: the marginal gain doesn't justify the extra cost. When false positives don't affect the user (e.g. the downstream LLM is robust enough to ignore them).


Next step: Capsule 02

The next capsule gets into the detailed "why" of cosine similarity's failure modes. Without understanding those modes concretely, re-ranking techniques sound like unnecessary optimization. Once you understand them, the rest of the module becomes obviously useful.


Resources

  1. Sentence Transformers — Cross-Encoders — Official documentation
  2. Pinecone — Re-ranking Guide — Visual tutorial
  3. Cohere Rerank Documentation — For capsule 05
  4. BEIR Benchmark — Empirical comparisons
  5. Anthropic — Contextual Retrieval — Complementary technique
  6. Khattab & Zaharia — ColBERT Paper — Late interaction as the cross-encoder's evolution

Estimated time: 10-15 minutes Next: 02-problems-with-cosine-similarity.md