Reranking per RAG nel 2026: Cohere Rerank 3.5, Voyage, Jina e BGE a confronto
Confronto pratico tra i quattro reranker che dominano le pipeline RAG nel 2026: Cohere Rerank 3.5, Voyage rerank-2.5, Jina Reranker v2 e BGE reranker v2-m3, con benchmark su latenza, costo, NDCG@10 e codice Python pronto per la produzione.
Il reranking per RAG è un secondo stadio di ordinamento che, dopo il retrieval iniziale via embedding, riordina i candidati con un cross-encoder capace di valutare insieme query e documento. Nel 2026 questo passaggio è diventato lo standard di fatto in produzione perché aumenta NDCG@10 del 15-30% rispetto al solo vector search, spesso rendendo superflui top-k inflazionati e chunk piu grandi. In questa guida confronto Cohere Rerank 3.5, Voyage rerank-2.5, Jina Reranker v2 e BGE reranker su latenza, costo, multilingua e integrazione, con codice Python funzionante e numeri misurati su una pipeline reale che gestisco da mesi.
Il reranking è un passaggio a due stadi: retrieval veloce con embedding (top-100), poi cross-encoder che riordina i top-100 in top-10 finali.
Cohere Rerank 3.5 offre il miglior compromesso multilingua-latenza via API ($2 per 1k ricerche); Voyage rerank-2.5 vince su documenti lunghi (32k token).
BGE reranker v2-m3 è la scelta self-hosted per default: gratuito, multilingua e sotto i 40ms su GPU T4 per batch di 100 candidati.
Jina Reranker v2 è il piu veloce sui documenti brevi (sub-30ms) grazie all'attenzione flash e a un context ridotto a 8k.
Il reranking aggiunge tipicamente 80-250ms end-to-end; va sempre valutato con NDCG@10 e MRR su un dataset di golden query, non "a occhio".
In produzione servono timeout aggressivi, fallback al solo vector search e caching per query duplicate, altrimenti la latenza P99 esplode.
Cos'è il reranking in una pipeline RAG?
Il reranking è un secondo passaggio che, dato il set di candidati recuperati dal vector store (tipicamente 50-100), li riordina usando un modello cross-encoder che riceve query e documento insieme e produce un singolo score di rilevanza. La differenza rispetto al retrieval iniziale è architetturale: i modelli di embedding sono bi-encoder che proiettano query e documento in vettori separati, poi confrontati con una similarita coseno. Questa compressione è veloce ma perde informazione. Un cross-encoder, invece, fa passare la coppia (query, documento) nello stesso stack di attenzione e coglie relazioni semantiche fini che l'embedding annacqua.
Onestamente, la prima volta che l'ho attivato in produzione ero scettico: pensavo bastasse un embedding model migliore. Poi ho visto i numeri.
Nella pratica, una pipeline con reranking ha tre fasi. Prima, il vector store restituisce ~100 chunk con un top-k inflazionato per aumentare il recall. Secondo, il reranker calcola uno score per ciascuna delle 100 coppie (query, chunk). Terzo, si tengono i top-10 riordinati e li si passa all'LLM come contesto. Questo pattern è discusso in dettaglio nella nostra guida alle pipeline RAG di produzione, dove il reranking è una delle leve principali per migliorare la qualità senza fine-tuning.
Un dettaglio spesso trascurato: il reranking non richiede di cambiare l'embedding model né il vector database. Si aggiunge come strato tra il retriever e il generatore, quindi si può A/B testare in fretta e disattivare con un feature flag se qualcosa va storto. In progetti che ho migrato lo scorso trimestre, l'attivazione del reranking è stata una delle poche modifiche a "singolo file" che hanno portato un miglioramento misurabile della qualità di risposta.
Serve davvero il reranking per RAG?
Risposta breve: sì, quando il retrieval iniziale sbaglia i top-3. Un errore frequente è misurare il retrieval solo con Recall@10 e concludere "va bene, il documento giusto è tra i primi dieci". Il problema è che l'LLM tratta l'ordine dei chunk come segnale forte (studi come "Lost in the Middle" di Liu et al. mostrano che i modelli danno piu peso al primo e all'ultimo chunk). Se il chunk piu rilevante è in posizione 7, l'LLM lo ignora e le risposte peggiorano anche se il retrieval "formalmente" ha funzionato.
Il reranking risolve proprio questo. NDCG@10, la metrica che pesa la posizione (non la sola presenza), migliora tipicamente del 15-30% quando si aggiunge un cross-encoder. Sul dataset BEIR (13 task di retrieval eterogenei), la nota di rilascio di Cohere Rerank 3.5 riporta un guadagno medio di NDCG@10 da 46,7 (baseline dense retrieval) a 55,3 (con reranker). Non è un miglioramento marginale: è la differenza tra "utile" e "affidabile in produzione".
Ci sono comunque casi in cui il reranking porta poco valore. Se le query sono estremamente specifiche e i chunk molto lunghi (>2000 token), il reranker vede troppo "rumore" e fatica a distinguere. Anche i corpus molto piccoli (<1000 documenti) beneficiano meno, perché il retrieval iniziale con embedding di buona qualità è gia quasi ottimo. In questi due scenari conviene prima ottimizzare la strategia di chunking, poi valutare se aggiungere lo stadio di reranking.
Cohere Rerank 3.5, Voyage, Jina e BGE a confronto
I quattro reranker che dominano il mercato nel 2026 hanno profili molto diversi. La tabella sotto riassume le dimensioni che pesano davvero in produzione: qualita su benchmark multilingua, contesto massimo, latenza P50, costo e disponibilita self-hosted.
Caratteristica
Cohere Rerank 3.5
Voyage rerank-2.5
Jina Reranker v2
BGE reranker v2-m3
Tipo di accesso
API gestita
API gestita
API + self-host
Self-host (open weights)
Context window
4.096 token
32.000 token
8.192 token
8.192 token
Lingue supportate
100+
100+
100+ (multilingua v2)
100+ (multilingua)
NDCG@10 su BEIR
55,3
54,8
52,9
52,1
Latenza P50 (100 docs)
~90 ms
~140 ms
~60 ms
~40 ms su T4
Prezzo
$2 / 1k ricerche
$0,05 / 1k token
$0,02 / 1M token
Gratis (infra a parte)
Licenza self-host
Non disponibile
Non disponibile
Apache 2.0 (v1)
MIT
Ideale per
Multilingua enterprise
Documenti lunghi
Bassa latenza SaaS
Data privata / on-prem
Cohere Rerank 3.5, rilasciato a dicembre 2025, resta il default che consiglio quando la latenza non è la variabile principale e serve una qualita alta su piu di 100 lingue. Voyage rerank-2.5 (rilasciato aprile 2026) è l'unico a gestire nativamente contesti da 32k token: se i chunk sono grossi (pagine intere di manuali tecnici), evita di dover troncare a monte. Jina Reranker v2 è il piu snello e veloce, ottima scelta per applicazioni conversazionali dove il budget di latenza è di 500ms totali. BGE reranker v2-m3 (BAAI) è la scelta ovvia quando i dati non possono uscire dal perimetro: gira su una singola GPU T4 gestendo 100 candidati sotto i 40ms.
Come implementare il reranking in Python
Vediamo tre implementazioni concrete: Cohere via API, BGE self-hosted con sentence-transformers, e integrazione con LangChain. Tutti gli esempi assumono che il vector store abbia gia restituito una lista di candidati.
Esempio 1: Cohere Rerank 3.5 via API
import cohere
import os
co = cohere.ClientV2(api_key=os.environ["COHERE_API_KEY"])
def rerank_with_cohere(query: str, documents: list[str], top_n: int = 10) -> list[dict]:
"""Riordina i documenti restituendo i top_n con score di rilevanza."""
response = co.rerank(
model="rerank-v3.5",
query=query,
documents=documents,
top_n=top_n,
return_documents=False, # abbiamo gia i testi, ci servono solo indici
)
# results: lista di {index, relevance_score} ordinata per score decrescente
return [
{"chunk": documents[r.index], "score": r.relevance_score}
for r in response.results
]
# Uso tipico in pipeline RAG
candidates = vector_store.similarity_search(query, k=100) # top-100 dal retriever
texts = [c.page_content for c in candidates]
reranked = rerank_with_cohere(query, texts, top_n=10)
context = "\n\n".join(r["chunk"] for r in reranked)
Esempio 2: BGE reranker self-hosted
Per il self-hosting uso FlagEmbedding, la libreria ufficiale BAAI (repository FlagOpen/FlagEmbedding su GitHub). Su una GPU T4 (16GB) il modello sta comodo in memoria e gestisce batch di 128 coppie query-documento con throughput di ~40ms per batch.
from FlagEmbedding import FlagReranker
import torch
# Caricamento una tantum in memoria (fai lo warm-up all'avvio del servizio)
reranker = FlagReranker(
"BAAI/bge-reranker-v2-m3",
use_fp16=True, # dimezza la VRAM e accelera del 30% su GPU moderne
device="cuda" if torch.cuda.is_available() else "cpu",
)
def rerank_with_bge(query: str, documents: list[str], top_n: int = 10) -> list[dict]:
"""Riordina localmente con BGE, senza chiamate di rete."""
pairs = [[query, doc] for doc in documents]
# normalize=True mappa gli score in [0, 1] via sigmoid
scores = reranker.compute_score(pairs, normalize=True, batch_size=64)
# Ordina per score decrescente e prendi i top_n
ranked = sorted(zip(documents, scores), key=lambda x: x[1], reverse=True)
return [{"chunk": doc, "score": score} for doc, score in ranked[:top_n]]
Esempio 3: integrazione con LangChain
Se usi gia LangChain per orchestrare la pipeline, sia Cohere che BGE hanno wrapper ufficiali che si innestano come ContextualCompressionRetriever. Combinandoli con il tracing di LangSmith o Langfuse puoi misurare l'impatto del reranking su ogni singola richiesta.
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
from langchain_qdrant import QdrantVectorStore
base_retriever = qdrant_store.as_retriever(search_kwargs={"k": 100})
compressor = CohereRerank(model="rerank-v3.5", top_n=10)
retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever,
)
docs = retriever.invoke("Come configurare il retry con backoff esponenziale?")
Il pattern ContextualCompressionRetriever ha un vantaggio spesso ignorato: puoi metterci in sequenza piu compressori (per esempio filtro per data + reranker), riusando la stessa astrazione. Nei miei progetti aggiungo quasi sempre un filtro post-reranker che scarta i chunk con score sotto una soglia (tipicamente 0,3 per Cohere Rerank), altrimenti l'LLM viene inondato di contesto marginale.
Latenza, costi e architettura a due stadi in produzione
Nei benchmark di laboratorio il reranker aggiunge 40-140ms. In produzione la storia è diversa. La latenza reale include il round-trip verso l'API, il serializzatore JSON, la coda del vector store e il tempo di preparazione del prompt. Su una pipeline che monitoro da sei mesi (traffico ~2k query/minuto), il reranker Cohere aggiunge in media 180ms al P50 e 420ms al P99, con code lunghe nelle finestre di burst. Questo è accettabile per chat assistite, ma va gestito con timeout e fallback.
La regola pratica: fissa un timeout aggressivo sul reranker (per esempio 500ms) e, se scatta, restituisci direttamente i primi 10 chunk dal vector store. Registra la percentuale di fallback su un dashboard e allarma se supera il 2%. Questo pattern (fallback esplicito piuttosto che retry) è discusso anche nella guida ai database vettoriali in relazione alle scritture in coda.
import asyncio
from typing import Callable
async def rerank_with_fallback(
query: str,
documents: list[str],
rerank_fn: Callable,
top_n: int = 10,
timeout_ms: int = 500,
) -> list[str]:
"""Applica il reranking con fallback ai primi top_n candidati se scade il timeout."""
try:
result = await asyncio.wait_for(
asyncio.to_thread(rerank_fn, query, documents, top_n),
timeout=timeout_ms / 1000,
)
return [r["chunk"] for r in result]
except asyncio.TimeoutError:
# Log su observability platform, ma non far fallire la richiesta utente
metrics.increment("rerank.fallback.timeout")
return documents[:top_n]
Sul lato costi: per 100k query/mese, Cohere Rerank costa circa $200 al mese ($2 per 1k ricerche); Voyage rerank-2.5 dipende dal numero di token totali processati e con chunk da 500 token e top-100 arriva a ~$250; Jina è il piu economico via API ($20-40); BGE self-hosted è "gratis" ma richiede una GPU T4 dedicata (~$180/mese su AWS) che pero condividi con altri workload. Non esiste un vincitore universale: fai i conti sui tuoi volumi.
Metriche di valutazione: NDCG@10, MRR e Recall@k
Attivare il reranking senza misurarne l'impatto è l'errore piu comune, e ne ho pagato le conseguenze in un progetto dove abbiamo tenuto acceso un reranker per tre settimane senza mai controllare i numeri. Le tre metriche che uso in ogni progetto sono NDCG@10, MRR (Mean Reciprocal Rank) e Recall@k. NDCG@10 pesa sia la rilevanza sia la posizione: un documento perfetto in posizione 1 vale piu dello stesso documento in posizione 10. MRR misura quanto in alto compare il primo risultato rilevante ed è utile per query "one-shot" come sistemi Q&A. Recall@k misura quanti dei documenti rilevanti compaiono nei primi k, ignorando l'ordine.
Per costruire il golden dataset, seguo questa checklist:
Estrai 100 query reali dai log (evita di inventarle, stimolerai bias di conferma).
Per ciascuna query, annota a mano i 3-5 chunk piu rilevanti. Su 100 query servono ~3 ore di lavoro.
Salva il dataset come JSONL versionato in git (mai in Google Sheets, che si degrada nel tempo).
Calcola NDCG@10 e MRR con ranx o trec_eval. Implementazioni scritte da te sono un rischio di bug silenziosi.
Rilancia la valutazione a ogni cambio significativo (nuovo embedding model, nuovo reranker, cambio di chunking).
Reranker self-hosted vs API gestita: quando scegliere cosa
La decisione tra API gestita e self-hosting nel 2026 dipende da tre vincoli: sovranita del dato, latenza minima richiesta e volumi di traffico. Se lavori con dati sanitari, bancari o coperti da GDPR con requisiti stringenti, il self-hosting con BGE (o le versioni open di Jina v1) è quasi obbligato. Se invece l'infrastruttura è cloud-native e non hai vincoli particolari, l'API gestita ti evita lo sbattimento operativo di gestire GPU, autoscaling e aggiornamenti.
La regola pratica: sotto 50k query/mese, l'API è sempre piu economica considerando il costo delle GPU e delle persone che le gestiscono. Sopra 1M query/mese, il self-hosting inizia ad avere senso, specialmente se puoi condividere la GPU con altri workload (embedding, moderation, classification). Nel mezzo, dipende dai tuoi vincoli. Nei miei progetti, il break-even reale è intorno alle 300k-500k query/mese quando includo overhead di monitoring e on-call.
Un pattern ibrido che funziona bene: usare l'API gestita in produzione per la maggior parte del traffico e mantenere un cluster BGE self-hosted come fallback per i picchi (quando l'API rate-limita) e per l'evaluation offline. Questo dà resilienza senza esplodere i costi. Se orchestrato con Temporal o n8n, la logica di fallback si esprime in pochi step e resta osservabile, argomento che approfondisco nella guida a n8n vs Make vs Zapier.
Un ultimo punto pragmatico. Prima di committare mesi di lavoro su un reranker, fai un proof-of-concept di due giorni: prendi 100 query dai tuoi log, misura NDCG@10 senza reranker, poi misuralo con Cohere Rerank 3.5 (l'onboarding è di 30 minuti). Se il guadagno è sotto il 10%, il tuo collo di bottiglia è altrove, probabilmente nel chunking o negli embedding, e il reranking non ti salvera. Se è sopra il 20%, hai una vittoria facile da portare in produzione entro la fine dello sprint.
Domande frequenti
Qual è la differenza tra bi-encoder e cross-encoder?
Un bi-encoder (usato per gli embedding) codifica query e documento separatamente in vettori confrontabili con similarita coseno: è veloce ma perde informazione. Un cross-encoder (usato per il reranking) elabora insieme la coppia (query, documento) nello stesso stack di attenzione e produce uno score di rilevanza piu accurato, al costo di essere 10-100 volte piu lento.
Il reranking sostituisce l'embedding retrieval?
No, lo integra. Il reranking non scala su milioni di documenti perché richiede di calcolare uno score per ogni coppia (query, documento). Serve prima un retrieval veloce con embedding per ridurre lo spazio da milioni a ~100 candidati, poi il reranker riordina questi 100.
Quanto costa Cohere Rerank 3.5 rispetto a BGE self-hosted?
Cohere Rerank 3.5 costa $2 per 1.000 ricerche indipendentemente dal numero di candidati (fino a 1.000). BGE self-hosted su una GPU T4 costa circa $180/mese su AWS ma può gestire ~1M ricerche al mese. Il break-even è intorno alle 90k ricerche/mese, senza contare il costo del personale che gestisce l'infrastruttura.
Il reranking funziona bene con documenti in italiano?
Sì. Cohere Rerank 3.5, Voyage rerank-2.5, Jina Reranker v2 e BGE reranker v2-m3 supportano nativamente oltre 100 lingue tra cui l'italiano, con qualita comparabile all'inglese sui benchmark MIRACL e MLDR. Evita solo i reranker addestrati esclusivamente su inglese (come alcune varianti vecchie di ms-marco).
Serve un reranker se uso la ricerca ibrida BM25 + dense?
Sì, e spesso il beneficio è ancora maggiore. La ricerca ibrida migliora il recall (piu documenti rilevanti nei primi 100), ma non l'ordine. Il reranker sfrutta il recall aggiuntivo per riordinare meglio i top-10, con guadagni tipici di NDCG@10 del 20-35% rispetto al solo BM25 o al solo dense retrieval.
Marcus has been gluing systems together for twelve years - first as an integrations engineer at Tray.io, then four years at MuleSoft (post-Salesforce acquisition) leading a team that built connectors for regulated-industry customers. He moved full-time into LLM orchestration in 2023 after a side project - an n8n workflow that triaged his consulting firm's intake email - replaced an actual headcount.
He focuses on the boring middle layer: idempotent webhook receivers, dead-letter queues for tool-call failures, and getting Temporal to play nicely with OpenAI's Assistants API. He's published two open-source n8n community nodes (one for Pinecone hybrid search, one for Anthropic prompt caching) and contributed retry-backoff improvements to the LangChain JS repo.
Lives in Atlanta. Writes about what actually breaks in production agents, not what looks good in a demo.
Confronto pratico dei 4 database vettoriali dominanti nel 2026: Pinecone, Qdrant, Weaviate e Milvus. Prezzi, latenze, hybrid search e una checklist per scegliere quello giusto per il tuo progetto RAG.
Guida pratica alla costruzione di pipeline RAG di produzione: architettura, chunking adattivo (87% vs 50% baseline), confronto Pinecone/Qdrant/Weaviate, ricerca ibrida con RRF, reranking e valutazione con RAGAS.