Re-ranking en RAG: la pieza que sube la calidad de verdad
Actualizado: 2026-07-07
Los embeddings recuperan rápido pero ordenan mal, porque codifican consulta y documento en vectores independientes sin cruzar tokens. Un reranker cross-encoder sobre el top-100 corrige esa señal y sube Precisión@10 entre un 15 y un 30 por ciento en corpus de más de 100k documentos. Cuándo compensa añadir uno y cuándo el límite de latencia hace que no sea viable.
El reranking en RAG existe porque un pipeline básico hace recuperación top-k con embeddings y pasa los documentos directamente al LLM. Funciona, pero esconde una carencia estructural. Los embeddings son bi-encoders: codifican la consulta y el documento por separado y comparan con un producto escalar. Eso los hace rapidísimos sobre millones de vectores, pero mediocres a la hora de discriminar entre los diez o veinte candidatos más parecidos. Ahí entra un reranker, y ahí es donde la mayoría de proyectos RAG pasan de «decente» a «realmente útil».
Puntos clave
-
El flujo canónico es: embedding retrieval top-100, reranker selecciona top-10, LLM genera con ese contexto.
-
Un reranker bien elegido sube Precisión@10 entre un 15 y un 30 % en corpus de más de 100k documentos.
-
Cohere Rerank es la opción hosted más sólida; BGE-reranker-large es el estándar open-source.
-
El reranker no arregla un retrieval inicial malo: si el bi-encoder ya descartó el documento correcto, el reranker no lo puede recuperar.
-
Por debajo de los 200 ms de límite de latencia, el reranker probablemente no cabe; en chat asíncrono, sí.
Bi-encoder frente a cross-encoder
Un bi-encoder genera dos vectores independientes (uno para la query, otro para el documento) y los compara con coseno o producto escalar. Todo el contexto tiene que comprimirse en esos vectores sin saber qué se va a preguntar. Es una aproximación eficiente, no una medida fina de relevancia.
Un cross-encoder hace lo contrario. Concatena query y documento y los pasa juntos por el transformer, dejando que las cabezas de atención miren token a token qué palabras de la consulta activan qué fragmentos del documento. El coste es alto: una llamada al modelo por cada par, pero la señal es mucho más rica. Un bi-encoder dice «este documento se parece al tipo de cosas que suele preguntar alguien»; un cross-encoder dice «este documento responde a esta pregunta concreta».
En la práctica, no se puede usar un cross-encoder sobre millones de documentos, pero sí sobre cien. Por eso el patrón estándar combina ambos. El bi-encoder hace recall barato sobre el corpus entero y el cross-encoder hace precisión cara sobre la lista corta.
El flujo canónico en producción
Tres etapas bien delimitadas:
-
Recuperación vectorial: top-100 del índice en menos de 100 ms.
-
Reranker: reordena los 100, selecciona el top-10, en 300-500 ms dependiendo del modelo.
-
LLM: genera la respuesta con esos 10 documentos en contexto.
Se añaden unos cientos de milisegundos, pero la calidad del top-10 mejora tanto que el LLM alucina menos y responde con más concreción. El usuario nota la diferencia: el sistema parece entender, no solo devolver «algo parecido». El reranking tiene especial valor en pipelines que también se benefician de pgvector para el almacenamiento vectorial o Cohere Embed v3 para embeddings de calidad.
Rerankers que importan hoy
Cohere Rerank[1] es la opción hospedada de referencia. Los modelos rerank-english-v3.0 y rerank-multilingual-v3.0 marcan el techo en la mayoría de benchmarks públicos. La API es una sola llamada, cobran por cada mil documentos procesados, y el coste ronda los dos dólares por mil queries con cien candidatos. La desventaja es la clásica: dependencia externa, latencia de red y datos que salen de tu infraestructura.
BGE-reranker[2], de BAAI, es el estándar de facto en open-source. La versión bge-reranker-large con 568 millones de parámetros se acerca mucho a Cohere en calidad, y la generación v2 (bge-reranker-v2-m3) ofrece opciones multilingüe competitivas. Requiere GPU para latencias razonables, pero una T4 o L4 modesta basta para cargas medias.
Como baseline ligero están los cross-encoders clásicos de sentence-transformers, como cross-encoder/ms-marco-MiniLM-L-12-v2. No baten a BGE large, pero corren en CPU y son suficientes para prototipos.
from sentence_transformers import CrossEncoder
model = CrossEncoder("BAAI/bge-reranker-large", max_length=512)
pairs = [(query, doc) for doc in candidates]
scores = model.predict(pairs, batch_size=32)
ranked = sorted(zip(candidates, scores), key=lambda x: -x[1])[:10]
Cuándo compensa de verdad
El reranker ayuda claramente en:
-
Corpus grandes (más de 100k documentos) donde el recall del embedding es bueno pero la ordenación del top-20 es ruidosa.
-
Consultas ambiguas donde varios documentos son plausibles y la diferencia no cabe en la geometría vectorial.
-
Long tail temático donde los embeddings generales pierden matiz de dominio.
No compensa en:
-
Corpus pequeños bien curados (<10k documentos) donde el embedding suele clavar el top-1.
-
Consultas exactas como búsqueda de código o identificadores.
-
Límite de latencia <200 ms end-to-end: no hay sitio para medio segundo extra.
En benchmarks sobre QA con 200k documentos, consistentes con los resultados del BEIR benchmark[3] y del MTEB Leaderboard[4], pasar de solo embeddings a embeddings + Cohere Rerank sube Precisión@10 del 45 al 68 %, con Recall@10 subiendo del 68 al 72. Con cross-encoder open-source, del 45 al 62. Los saltos se traducen directamente en menos alucinación del LLM.
Límite de latencia realista
El margen real queda así:
-
Recuperación vectorial (índice HNSW bien dimensionado): 20-80 ms.
-
Reranker BGE large en GPU: 300-500 ms. Cohere hospedado: 200-400 ms.
-
Generación LLM: el tramo dominante, casi siempre >1 segundo.
En total, 1,5-3 segundos, aceptable para chat asíncrono o búsqueda enriquecida. Para sub-segundo, hay margen: reducir el top-k inicial a 50, usar el reranker base en lugar del large, y cachear queries frecuentes. El cache sobre queries normalizadas tiene tasas de acierto superiores al 30 % en dominios estrechos.
Errores habituales
-
Recuperar solo el top-10 antes de rerankear: si el bi-encoder ya descartó el documento correcto, el reranker no lo resucita. Hay que llegar al top-50 o top-100.
-
No medir antes y después: sin Precisión@5, Recall@10 y MRR sobre queries reales, la intuición de «mejora» no se sostiene.
-
Rerankear un retrieval inicial malo: chunks demasiado grandes, embeddings sin ajuste al dominio. El reranker puede elegir lo mejor de lo que recibe, no inventar lo que falta.
Conclusión
El reranking es una de las intervenciones con mejor ratio coste-beneficio en todo el stack RAG. Integrar Cohere Rerank son unas horas y un endpoint; desplegar BGE-reranker en GPU propia son un par de días y un servicio más. La decisión hosted vs. self-hosted depende casi siempre del volumen: por debajo de 10k queries diarias Cohere sale a cuenta, por encima de 100k la GPU amortiza. Si rerankear o no ya no es una pregunta real: cualquier pipeline RAG que busque calidad medible lo hace. La discusión útil está ahora en cómo trocear, cómo evaluar y cómo cachear.