视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
reranking【文档与办公】Reranking retrieved documents with cross-encoders and LLM rerankers. Cohere Rerank v3, Voyage rerank-2, BGE reranker, ColBERT late interaction, Jina reranker. Cost and latency tradeoffs, top-K in / top-N out strategy. USE WHEN: user mentions "rerank", "reranker", "cross-encoder", "Cohere Rerank", "Voyage rerank", "BGE reranker", "ColBERT", "Jina rer…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: reranking description: | Reranking retrieved documents with cross-encoders and LLM rerankers. Cohere Rerank v3, Voyage rerank-2, BGE reranker, ColBERT late interaction, Jina reranker. Cost and latency tradeoffs, top-K in / top-N out strategy.
USE WHEN: user mentions "rerank", "reranker", "cross-encoder", "Cohere Rerank", "Voyage rerank", "BGE reranker", "ColBERT", "Jina reranker", "bi-encoder"
advanced-retrieval or hybrid-search;
query rewriting - use query-transformations; agent decisions - use agentic-rag
allowed-tools: Read, Grep, Glob, Write, Edit| Aspect | Bi-encoder (retrieval) | Cross-encoder (reranking) |
|---|---|---|
| Encoding | Query and doc encoded separately | Query + doc encoded jointly |
| Index time | Precompute doc vectors | No precompute possible |
| Query time | ANN search in ms | One forward pass per (query, doc) pair |
| Scaling | Millions of docs | Tens to hundreds of docs per query |
| Quality | Good recall | Great precision |
The standard production pattern: bi-encoder retrieves 50-200 candidates, cross-encoder scores each candidate against the query, keep top 3-10.
Rerank when:
Skip when:
Retrieve top 50 -> Rerank -> Keep top 5 -> LLM
Rerank inputs should be 5-10x your final N. Too few inputs and reranker cannot find the best; too many and latency spikes.
import cohere
co = cohere.ClientV2()
def cohere_rerank(query: str, docs: list[str], top_n: int = 5):
resp = co.rerank(
model="rerank-v3.5", # multilingual; use rerank-english-v3.0 for EN-only
query=query,
documents=docs,
top_n=top_n,
)
return [(r.index, r.relevance_score) for r in resp.results]
LangChain wrapper:
from langchain_cohere import CohereRerank
from langchain.retrievers import ContextualCompressionRetriever
reranker = CohereRerank(model="rerank-v3.5", top_n=5)
retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=hybrid_retriever,
)
Cost: ~$2 per 1k search units (1 search unit = 1 query + up to 100 docs, chunked). Latency: 100-300ms at top-n=5, top-k=50.
import voyageai
vo = voyageai.Client()
def voyage_rerank(query: str, docs: list[str], top_k: int = 5):
resp = vo.rerank(query=query, documents=docs, model="rerank-2", top_k=top_k)
return [(r.index, r.relevance_score) for r in resp.results]
Voyage's rerank-2 is competitive with Cohere on English and strong on code. rerank-2-lite is cheaper and faster for low-stakes.
import requests, os
def jina_rerank(query: str, docs: list[str], top_n: int = 5):
r = requests.post(
"https://api.jina.ai/v1/rerank",
headers={"Authorization": f"Bearer {os.environ['JINA_API_KEY']}"},
json={
"model": "jina-reranker-v2-base-multilingual",
"query": query,
"documents": docs,
"top_n": top_n,
},
timeout=10,
)
r.raise_for_status()
return [(x["index"], x["relevance_score"]) for x in r.json()["results"]]
from FlagEmbedding import FlagReranker
# bge-reranker-v2-m3: multilingual, 568M params; bge-reranker-base: EN-only, 278M
reranker = FlagReranker("BAAI/bge-reranker-v2-m3", use_fp16=True)
def bge_rerank(query: str, docs: list[str], top_n: int = 5):
pairs = [[query, d] for d in docs]
scores = reranker.compute_score(pairs, normalize=True)
ranked = sorted(enumerate(scores), key=lambda x: x[1], reverse=True)[:top_n]
return ranked # list of (index, score)
Run on a T4 GPU: ~20ms for 50 pairs. Zero per-query cost after infra. Best choice when data cannot leave your network.
ColBERT encodes each token of query and doc separately, scores via MaxSim between token vectors. Higher quality than single-vector bi-encoders, cheaper than full cross-encoders.
from ragatouille import RAGPretrainedModel
rag = RAGPretrainedModel.from_pretrained("colbert-ir/colbertv2.0")
rag.index(collection=documents, index_name="kb")
# Used as retriever, not just reranker
results = rag.search(query="token refresh flow", k=10)
# Or as reranker over a candidate list
reranked = rag.rerank(query="token refresh flow", documents=candidates, k=5)
Storage cost ~4x single-vector indexes, but no separate reranker needed.
Useful when the reranker needs reasoning or instructions. Slower and pricier.
from anthropic import Anthropic
import json
client = Anthropic()
PROMPT = """You are ranking passages for relevance to a query.
Score each passage from 0 to 10 for how directly it answers the query.
Return a JSON array of objects: {{"index": int, "score": float}}.
Query: {q}
Passages:
{passages}"""
def llm_rerank(query: str, docs: list[str], top_n: int = 5):
numbered = "\n\n".join(f"[{i}] {d}" for i, d in enumerate(docs))
msg = client.messages.create(
model="claude-haiku-4-5-20250929", max_tokens=2048,
messages=[{"role": "user", "content": PROMPT.format(q=query, passages=numbered)}],
)
scored = json.loads(msg.content[0].text)
ranked = sorted(scored, key=lambda x: x["score"], reverse=True)[:top_n]
return [(s["index"], s["score"]) for s in ranked]
Use Haiku — Sonnet/Opus for reranking is almost always overkill.
| Reranker | Latency (50 docs) | Cost / 1k queries | Quality (MTEB rerank) |
|---|---|---|---|
| Cohere rerank-v3.5 | 100-300ms | ~$2.00 | High |
| Voyage rerank-2 | 100-250ms | ~$1.50 | High |
| Jina v2 base | 150-300ms | ~$1.00 | Mid-High |
| BGE v2-m3 (self-host T4) | 20-80ms | Infra only | Mid-High |
| ColBERT v2 (self-host) | 10-40ms | Infra only | Mid-High (retrieval-grade) |
| LLM (Claude Haiku) | 300-800ms | ~$3-8 | High (instructable) |
All numbers are order-of-magnitude; measure in your environment.
async def retrieve_and_rerank(query: str, top_n: int = 5):
candidates = await hybrid_retriever.ainvoke(query) # 50 docs
docs_text = [d.page_content for d in candidates]
pairs = cohere_rerank(query, docs_text, top_n=top_n)
return [candidates[i] for i, score in pairs if score > 0.2] # drop low-conf
The score threshold (0.2 here) is corpus-specific; calibrate with a gold set.
Two-stage rerank for very large candidate pools:
Retrieve 500 -> BGE (self-host) rerank to 50 -> Cohere rerank to 5 -> LLM
Only worth it when retrieval recall@50 is too low; usually better to fix retrieval.
| Anti-Pattern | Fix |
|---|---|
| Reranking only top 5 | Send 5-10x your final N (at least 25-50) |
| Reranking the full corpus | Reranking is quadratic in #docs; retrieve first |
| LLM reranking with Opus | Use Haiku — quality barely changes, cost 10x lower |
| No score threshold | Drop candidates below a calibrated score |
| Single model for all domains | Cohere/Voyage for English; BGE-m3 for multilingual self-host |
| Synchronous reranker call in user path | Set a hard timeout; fall back to raw retrieval |
| Re-encoding docs on every query | Cross-encoder does this by design; that is the cost |
| Ignoring reranker evaluation | Log score distributions; alert on drift |