Reranking
What is reranking?
Vector search uses a bi-encoder: the query and each document are embedded separately into a fixed vector, then ranked by cosine similarity. It scales to billions of documents but loses fine-grained relevance because the encoders never see the query and document together. A reranker uses a cross-encoder: it scores each (query, document) pair jointly. This is far more accurate but ~100x more expensive, so you run it only on the top candidates from the bi-encoder. The standard two-stage retrieval pipeline:The Reranker interface
All four built-in providers implement the same interface so you can swap them freely.
RerankDocument
Accepts either a plain string OR an object with optional id + metadata:
RerankOptions
RerankResult
index field is the most important detail — it lets you trace each result back to the original input array without comparing strings.
Built-in providers
CohereReranker
npm install cohere-ai (optional peer dep).
Model options:
Retry behavior: automatic on HTTP 429 / 500 / 502 / 503 with exponential backoff (1s → 2s → fail), up to 2 retries.
VoyageReranker
fetch API directly. Throws Error("VoyageReranker: missing API key") if neither apiKey nor VOYAGE_API_KEY env is set.
Model options:
JinaReranker
ColbertReranker (local, no API key)
npm install @xenova/transformers (optional peer dep).
Runs a HuggingFace cross-encoder model entirely in process via WASM/ONNX. The first call after construction lazy-loads the model (~50MB download for MiniLM-L-6-v2); subsequent calls are local-only.
Important: the default MiniLM-L-6-v2 is a classic cross-encoder, not true ColBERT v2 late interaction. For production-grade ColBERT (~3x better quality, similar latency), point this at a dedicated endpoint such as JinaAI ColBERT or self-host ColBERTv2/PLAID. The class name “ColbertReranker” refers to the role (late-interaction reranker), not the model itself.
Wiring into a vector store
EveryVectorStore in @agentium/core accepts a rerank option:
How rerankMultiplier works
When a reranker is set:
- The vector backend fetches
topK * rerankMultipliercandidates from the underlying ANN index. - The reranker scores each one against the original query.
- The reranker returns the top
topKby its own score.
rerankMultiplier defaults to 3. Larger values give the reranker more candidates to choose from (better recall) at the cost of latency + reranker tokens. topK=5, rerankMultiplier=10 is a sensible “high quality” setting.
Query types the reranker sees
The reranker requires a text query. The vector backend hands it whatever it can extract:
This matters for multimodal indexes: if you want reranking on an image query, supply a text caption alongside the image part.
Backend-by-backend behavior
All four built-in backends call the sameBaseVectorStore.applyRerank() chokepoint, so behavior is identical:
InMemoryVectorStore— fetchestopK * multiplierfrom the local cosine ranking.PgVectorStore— adjusts the SQLLIMITto the larger fetch size; doesn’t applyminScoreuntil after rerank.QdrantVectorStore— setslimit: fetchKand omitsscore_thresholdwhen reranker is set (rerank handles thresholding).MongoDBVectorStore— applies to both the Atlas$vectorSearchpath and the in-process brute-force fallback.
minScore interaction
When you pass minScore with rerank:
Standalone usage
A reranker also works without a vector store, e.g. to reorder a BM25 candidate list or to score a set of LLM-generated options:Composing rerankers
You can stack rerankers cheaply by calling them in sequence:Performance characteristics
(Numbers are rough; benchmark your own workload.)
Errors and edge cases
See also
- Semantic Tool Selection reuses
Rerankerto pick the best tools when an agent has many. - GraphRAG / HybridRetriever composes vector + graph + rerank.
- Embeddings — the first stage of two-stage retrieval.