Re-ranking en RAG: la pieza que sube la calidad de verdad

Gráfica con columnas coloridas ordenadas representando reordenación de resultados

Un pipeline RAG básico hace retrieval top-k con embeddings y pasa resultados directamente al LLM. Funciona, pero tiene problema: embeddings son bi-encoder — eficientes pero no óptimos para ordenar exactly los top resultados. Un re-ranker aplicado sobre top-50 o top-100 de retrieval initial mejora precision 15-30% en la mayoría de benchmarks. Es la pieza que convierte RAG “decent” en “realmente útil”.

El problema con embeddings solo

Embeddings (bi-encoders):

  • Rápidos: una query vs millones de docs en ms.
  • Aproximan similitud, no compute finamente.
  • Contextuales unidireccionales: query embedding y doc embedding calculated separately.

Re-rankers (cross-encoders):

  • Más lentos: query + doc juntos por el modelo.
  • Mucho más precisos.
  • Escalar cuadráticamente con candidates.

Trade-off: usar embeddings para recall rápido sobre millones, re-ranker para precision sobre top candidates.

Flujo típico

  1. Embedding retrieval: query → top-100 docs (<100ms).
  2. Re-ranker: top-100 → top-10 reordenados (~500ms).
  3. LLM: top-10 + query → respuesta.

Añade latencia pero la ganancia en precisión de los top-10 finales compensa.

Re-rankers populares

Cohere Rerank

Cohere Rerank (comercial):

  • API hosted: paga por call.
  • Cross-encoder entrenado para relevance.
  • Multilingüe: EN, ES, FR, DE, IT, JA, KO, ZH, AR.
  • Best-in-class en muchos benchmarks.
import cohere
co = cohere.Client("YOUR_API_KEY")

results = co.rerank(
    query="¿Qué es RAG?",
    documents=docs,  # lista de strings o dicts
    top_n=10,
    model="rerank-multilingual-v3.0"
)

BGE-reranker

BGE-reranker (open-source):

  • BAAI: mismos creadores de BGE embeddings.
  • Self-hosteable GPU.
  • Tiers: base (278M), large (568M), v2 mejorado.
  • Calidad cercana a Cohere en benchmarks.
from sentence_transformers import CrossEncoder

model = CrossEncoder("BAAI/bge-reranker-large")
scores = model.predict([(query, doc) for doc in docs])
ranked = sorted(zip(docs, scores), key=lambda x: -x[1])

Jina-reranker

Jina Reranker: comercial alternative, multilingüe strong.

Cross-encoders sentence-transformers

Modelos como cross-encoder/ms-marco-MiniLM-L-12-v2: open-source, rápidos, baseline decent.

Métricas de mejora

Benchmark en dataset de RAG QA:

Pipeline Precision@10 Recall@10
Embeddings only 45% 68%
Embeddings + cross-encoder 62% 71%
Embeddings + Cohere Rerank 68% 72%
Embeddings + Cohere Rerank + LLM filter 73% 73%

Saltos incrementales significativos.

Cuándo re-rank ayuda

Buenas condiciones:

  • Dataset > 100k docs (donde embedding recall no es perfect).
  • Queries ambiguas: donde multiple candidates son “plausible”.
  • Long tail topics: embeddings pierden en nichos.
  • Multilingüe cross-lingual: especialmente importante.

Cuándo no necesario:

  • Dataset < 10k: embedding-only suele bastar.
  • Queries específicas exactas: embeddings hit top-1.
  • Latencia ultra-crítica: re-rank añade 200-500ms.

Patrón coste/calidad

Optimizar:

  • Top-k inicial para re-rank: más grande = mejor recall, más coste. 50-100 es sweet spot.
  • Tier de re-ranker: pequeño para prototype, grande para producción.
  • Cache: queries repetidas reusan resultados.
  • Batch: procesar múltiples queries in batch.

Integración con frameworks

LangChain:

from langchain_cohere import CohereRerank
from langchain.retrievers import ContextualCompressionRetriever

compressor = CohereRerank(top_n=10)
reranked_retriever = ContextualCompressionRetriever(
    base_retriever=vector_retriever,
    base_compressor=compressor,
)

LlamaIndex:

from llama_index.postprocessor.cohere_rerank import CohereRerank

rerank_postprocessor = CohereRerank(top_n=10)
query_engine = index.as_query_engine(
    node_postprocessors=[rerank_postprocessor]
)

Integrations first-class en ambos.

Self-hosted vs hosted

Cohere Rerank hosted:

  • Setup trivial.
  • Calidad top.
  • Coste: $2/1000 queries.
  • Dependencia externa.

BGE-reranker self-hosted:

  • Infra propia (GPU).
  • Control total.
  • Coste: GPU amortizado.
  • Calidad cercana pero levemente menor.

Para <10k queries/día, Cohere hosted gana. Para >100k/día, BGE self-hosted puede ser más barato.

Re-ranking con LLM

Pattern más reciente: usar LLM directamente como re-ranker. GPT-4o o Claude 3.5 Sonnet scoring docs vs query.

prompt = f"Ordena estos docs por relevancia a la query.\n\nQuery: {query}\n\nDocs:\n{enumerated_docs}"

Ventajas:

  • Calidad excepcional.
  • Explainability: puede dar razones.

Desventajas:

  • Más caro.
  • Lento (>2s para 50 docs).

Para cases premium, vale. Para volumen, cross-encoder dedicado gana.

Errores comunes

  • No cachear: re-rank queries idénticas redo-ing.
  • Top-k inicial pequeño: si retrieval inicial trae top-10, re-rank no ayuda mucho.
  • Re-rank sobre docs ya retrieved malos: mejora limitada si retrieval falla.
  • No evaluar: “assumption” de mejora sin medir.

Evaluación

Antes y después:

  • Golden set con query → relevant doc pairs.
  • Medir Precision@5, Recall@10, MRR antes/después.
  • A/B test en producción con sample real.

Si mejora no es clara en métricas, probablemente no vale overhead.

Dónde se aplica además de RAG

  • Search ranking: search engines mejorando results.
  • Recommendation systems: ordenar candidates finales.
  • Legal discovery: reordenar docs relevantes.
  • Academic search: finding cited papers.

Pattern transferible a cualquier retrieval + ranking problem.

Conclusión

Re-ranking es una de las mejoras más efectivas para pipelines RAG serios. El salto de precision es real y notable. Integrar Cohere Rerank o BGE-reranker es trabajo de horas, no semanas. Para proyectos RAG que buscan calidad tangible, no añadirlo es dejar performance en la mesa. La decisión entre hosted (Cohere) o self-hosted (BGE) depende de volumen y compliance. En cualquier caso, medir antes y después — el valor solo existe si se puede demostrar.

Síguenos en jacar.es para más sobre RAG, retrieval quality y evaluación de LLMs.

Entradas relacionadas