Late-interaction reranking (ColBERT & beyond)

Architecture · ~9 min read ·

Not every retrieval stack needs a cross-encoder reranker. Late-interaction models such as ColBERT score query–document pairs with token-level interactions while keeping embeddings cacheable — often a better fit than bi-encoders and cheaper than full cross-encoders at scale.

What late-interaction means

A bi-encoder embeds the query and each document independently — fast, but no token-level matching. A cross-encoder feeds query + document through one transformer and outputs a single relevance score — accurate, but you pay full inference per pair.

Late-interaction sits between them: you still pre-compute document token embeddings offline, but at query time you run a cheap interaction (typically MaxSim — max cosine per query token) between query tokens and document tokens. You get finer matching than a single vector dot product without scoring every pair with a full cross-encoder.

Cross-encoder vs late-interaction vs bi-encoder

ArchitecturePrecompute docs?Query-time costTypical use
Bi-encoderYes (1 vector/doc)Very lowStage-1 recall over millions
Late-interaction (ColBERT)Yes (token vectors/doc)Low–mediumStage-1 or stage-1.5; lexical-ish precision
Cross-encoder rerankerNoHigh per pairStage-2 on 50–100 candidates

Many 2026 stacks chain them: bi-encoder or hybrid recall → optional ColBERT rescore on hundreds → cross-encoder rerank on dozens. See hybrid retrieval + rerank for the merge step.

When to skip cross-encoder rerank

Cross-encoder reranking pays off when your shortlist is small (≤100) and order quality matters for downstream LLM prompts. Consider not adding one when:

Rule of thumb: if Recall@50 is low, fix retrieval — no reranker architecture invents missing chunks.

ColBERTv2 in practice

# pip install -U "sentence-transformers>=6"
# Rescore first-stage candidates with ColBERTv2's token-level MaxSim,
# keep the top 50 for an optional cross-encoder pass
from sentence_transformers import MultiVectorEncoder

colbert = MultiVectorEncoder("colbert-ir/colbertv2.0")

query = "reset API key"
candidates = [...]  # e.g. the top 200 from BM25 or a bi-encoder

q = colbert.encode_query([query])        # queries and documents are encoded
d = colbert.encode_document(candidates)  # differently: use both methods
scores = colbert.similarity(q, d)[0]     # one MaxSim score per candidate
top50 = [candidates[i] for i in scores.argsort(descending=True)[:50].tolist()]
# Pass top50 to bge-reranker or Cohere for final ordering

Since version 6.0 (August 2026), sentence-transformers loads ColBERT-style models directly — Stanford ColBERT checkpoints like colbert-ir/colbertv2.0, PyLate models and ColPali-style visual retrievers — through MultiVectorEncoder (release notes). We ran the snippet above on sentence-transformers 6.1.0 in October 2026. Used this way, rescoring what your first stage returns, it needs no index at all; to search a whole corpus with ColBERT itself you would build a compressed index such as PLAID (LightOn’s fast-plaid), as the release notes explain.

ColBERT shines on keyword-heavy corpora (support KBs, legal clauses, SKUs) where bi-encoders blur exact tokens. It does not run in our browser demo — different inference path — but belongs on your architecture comparison checklist.

How to pick an architecture

Millions of docs, tight latency?
  → bi-encoder (+ BM25 hybrid if lexical matters)

Recall OK but order noisy, 100–1000 candidates?
  → late-interaction (ColBERT) OR widen cross-encoder input

Top 50–100 need LLM-grade precision?
  → cross-encoder rerank (bge, Cohere, Jina, mxbai…)

Task-specific instructions in the query?
  → instruction-following hosted rerank (Contextual AI, etc.)

Unsure?
  → 30 labelled queries + NDCG@5 before/after each stage

Emerging open cross-encoders such as Qwen3-Reranker compete with bge on multilingual stacks; pair them with late-interaction when you need both scale and precision.

See cross-encoder rerank in the browser

Our demo shows stage-2 cross-encoder scoring — compare it with the bi-encoder proxy column to see what late-interaction or hybrid retrieval would need to fix.

Open the demo →

Keep reading