Módulo 4: Re-ranking — la segunda etapa que transforma retrieval mediocre en excelente
Cápsula 05: Cohere Rerank API — la opción managed cuando no quieres mantener modelos
Descripción de la cápsula
Cross-encoder local es gratis pero requiere mantener un modelo en tu infraestructura: descarga del modelo (~80-200 MB), inferencia en CPU/GPU, ocasionalmente actualizar a nuevas versiones. LLM re-ranking es más caro y más lento, y depende de OpenAI/Anthropic. Cohere Rerank es la tercera opción: API managed especializada en re-ranking, sin infrastructure local, sin LLM general — un modelo entrenado específicamente para esta tarea.
Para muchos equipos, Cohere Rerank es el sweet spot práctico: calidad cercana a LLM rerank, latencia cercana a cross-encoder, costo razonable, y zero infrastructure overhead. Especialmente brilla en dos casos: equipos pequeños sin recursos para mantener modelos, y aplicaciones multilingües donde los cross-encoders entrenados en inglés (MS MARCO) no rinden bien.
Esta cápsula te enseña cuándo elegirlo sobre las otras opciones, cómo integrarlo correctamente, y cómo calcular el costo total de propiedad para decidir si vale el cambio.
Al finalizar esta cápsula serás capaz de:
- ✅ Identificar los dos escenarios donde Cohere Rerank gana sobre cross-encoder local
- ✅ Implementar Cohere Rerank con manejo correcto de API keys y errores
- ✅ Diferenciar los modelos disponibles (rerank-v3.5, rerank-multilingual-v3) y cuándo elegir cada uno
- ✅ Calcular el costo mensual y el TCO comparado con cross-encoder local + LLM rerank
- ✅ Anticipar el riesgo crítico: vendor lock-in y plan de fallback
- ✅ Diseñar un patrón de fallback automático API → cross-encoder local cuando Cohere falla
Tiempo estimado: 25-30 minutos
Las tres opciones de re-ranking lado a lado
| Aspecto | Cross-encoder local | LLM-based | Cohere Rerank |
|---|---|---|---|
| Calidad típica (precision@5) | 90% | 94% | 93% |
| Latencia (rerank 20 docs) | 150ms | 1500ms | 200-300ms |
| Costo | $0 (gratis) | $0.001-0.005/query | $0.002/1K reranks |
| Setup | pip install + descarga modelo | API key | API key |
| Maintenance | Gestionar versiones del modelo | Cero | Cero |
| Multilingüe | Inglés bien, otros débil | Excelente | Excelente |
| Escalabilidad | CPU/GPU limit local | Rate limit OpenAI | Rate limit Cohere |
Cohere Rerank es el "intermedio sensato": mejor calidad multilingüe que cross-encoder local, mucho más rápido y barato que LLM rerank, sin overhead de mantener modelos.
Cuándo Cohere gana sobre cross-encoder local
Escenario 1: dataset multilingüe. Si tu corpus tiene queries en español, portugués, francés, alemán, japonés — los cross-encoders entrenados sobre MS MARCO (inglés) degradan ~10-15% en idiomas no-ingleses. Cohere rerank-multilingual-v3 mantiene calidad similar entre 100+ idiomas porque fue entrenado específicamente con datos multilingües.
Escenario 2: equipo sin bandwidth para mantener modelos. Cross-encoder requiere:
- Descargar el modelo en cada deploy
- Manejar carga del modelo en cold-start
- Decidir cuándo migrar a versiones nuevas
- Gestionar memoria si tu app tiene otros modelos cargados
Para equipos pequeños sin un MLE dedicado, esto es overhead operacional real. Cohere lo abstrae completamente — un API call y listo.
Cuándo Cohere NO gana
- Inglés monolingüe + equipo técnico sólido: cross-encoder local da 90%+ precision gratis. Cohere agrega ~3% calidad por $$/mes. No siempre vale.
- Compliance que prohíbe envío de datos a APIs externas: si tus chunks son sensibles (legal, médico privado), cross-encoder local mantiene los datos en tu infra.
- Producto a precio bajo con alto volumen: si cobras $5/mes/usuario y tienes 100K queries/mes, $200/mes en re-ranking puede no caber en márgenes.
Implementación correcta
Setup básico
# cohere_rerank.py
import cohere
import os
from dataclasses import dataclass
from typing import List
# Inicializar cliente con API key desde environment
co = cohere.Client(api_key=os.getenv("COHERE_API_KEY"))
@dataclass
class CohereRerankResult:
document: str
score: float
original_index: int
def cohere_rerank(
query: str,
documents: List[str],
top_k: int = 5,
model: str = "rerank-v3.5",
) -> List[CohereRerankResult]:
"""
Re-rank documents using Cohere's managed Rerank API.
Models:
- "rerank-v3.5": general purpose, English-optimized
- "rerank-multilingual-v3": 100+ languages (use for non-English content)
"""
response = co.rerank(
model=model,
query=query,
documents=documents,
top_n=top_k,
)
results = []
for result in response.results:
results.append(CohereRerankResult(
document=documents[result.index],
score=result.relevance_score,
original_index=result.index,
))
return results
Uso end-to-end
import chromadb
from chromadb.utils import embedding_functions
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key=os.getenv("OPENAI_API_KEY"),
model_name="text-embedding-3-small",
)
client_chroma = chromadb.PersistentClient(path="./chroma_db")
collection = client_chroma.get_collection("docs", embedding_function=openai_ef)
# Etapa 1: retrieval amplio
query = "¿cómo configuro autenticación OAuth2 en FastAPI?"
results = collection.query(query_texts=[query], n_results=20)
candidates = results['documents'][0]
# Etapa 2: re-ranking con Cohere (multilingüe para query en español)
top_5 = cohere_rerank(
query=query,
documents=candidates,
top_k=5,
model="rerank-multilingual-v3", # ← multilingüe porque la query es en español
)
print(f"Top 5 después de Cohere rerank:")
for i, item in enumerate(top_5, 1):
print(f"\n#{i} (score: {item.score:.3f}, was rank #{item.original_index+1})")
print(f" {item.document[:120]}...")
Output típico:
Top 5 después de Cohere rerank:
#1 (score: 0.987, was rank #4)
FastAPI proporciona OAuth2PasswordBearer para autenticación con username/password...
#2 (score: 0.953, was rank #1)
Para implementar OAuth2 en FastAPI, primero importar las clases de fastapi.security...
#3 (score: 0.842, was rank #6)
La configuración de JWT con OAuth2 en FastAPI requiere un secret key y un algoritmo...
Selección de modelo correcto
| Modelo | Cuándo usar |
|---|---|
rerank-v3.5 | Inglés primario, queries y documentos consistentemente en inglés |
rerank-multilingual-v3 | Cualquier mezcla de idiomas (español, portugués, francés, alemán, etc.) |
rerank-english-v3.0 | Versión anterior, mantener si ya estás en producción con ella |
Regla simple: si dudas, usar rerank-multilingual-v3. Pierde ~1% de calidad sobre inglés puro vs rerank-v3.5 pero gana 10-15% en cualquier otro idioma.
Calculando el costo total de propiedad
Cohere Rerank cobra por documento procesado, no por query:
Pricing (mayo 2026):
rerank-v3.5: $0.002 por 1,000 documentos
rerank-multilingual-v3: $0.002 por 1,000 documentos
Ejemplo concreto:
# Configuración típica
QUERIES_PER_DAY = 5_000
TOP_K_TO_RERANK = 25 # candidatos por query
DAYS_PER_MONTH = 30
# Cálculo
documents_processed_per_day = QUERIES_PER_DAY * TOP_K_TO_RERANK
documents_processed_per_month = documents_processed_per_day * DAYS_PER_MONTH
cost_per_thousand_docs = 0.002 # USD
monthly_cost = (documents_processed_per_month / 1000) * cost_per_thousand_docs
print(f"Documentos re-rankeados por mes: {documents_processed_per_month:,}")
print(f"Costo mensual Cohere: ${monthly_cost:.2f}")
Output:
Documentos re-rankeados por mes: 3,750,000
Costo mensual Cohere: $7.50
$7.50/mes para 5K queries/día rerankeando 25 candidatos. Realmente barato comparado con LLM rerank (~$200/mes en escenario similar).
TCO comparado: las tres opciones para un caso real
Volumen: 5K queries/día, 25 candidatos rerankeados, dataset multilingüe.
| Opción | Costo mensual API | Costo de mantenimiento | Costo total estimado |
|---|---|---|---|
| Cross-encoder local | $0 | ~4hrs/mes ingeniería × $50/h = $200 | $200/mes |
| LLM rerank (GPT-4o-mini) | $190/mes | $0 | $190/mes |
| Cohere Rerank (multilingual) | $7.50/mes | $0 | $7.50/mes |
Lectura: para este volumen, Cohere Rerank es 15-25x más barato que las alternativas si cuentas el costo de mantener cross-encoder. Y la calidad multilingüe es notablemente mejor que cross-encoder MS MARCO.
Cuando cross-encoder gana: volumen MUY alto (millones de queries/mes) donde el costo lineal de Cohere supera el costo fijo de mantener un modelo.
Patrón de fallback: cuando la API falla
Riesgo crítico: si tu pipeline RAG depende de Cohere Rerank y Cohere tiene un outage, tu sistema falla. Solución: fallback automático a cross-encoder local.
from sentence_transformers import CrossEncoder
import logging
logger = logging.getLogger(__name__)
# Carga el cross-encoder al startup (un solo costo, no por query)
fallback_reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
def rerank_with_fallback(
query: str,
documents: List[str],
top_k: int = 5,
) -> List[CohereRerankResult]:
"""
Re-rank con Cohere primero. Si falla (timeout, rate limit, error), usa cross-encoder.
Garantiza que el pipeline RAG siempre devuelve algo, aunque la API caiga.
"""
try:
# Intentar Cohere
return cohere_rerank(
query=query,
documents=documents,
top_k=top_k,
model="rerank-multilingual-v3",
)
except (cohere.CohereAPIError, cohere.CohereConnectionError) as e:
logger.warning(f"Cohere rerank failed ({e}), falling back to local cross-encoder")
# Fallback: cross-encoder local
pairs = [(query, doc) for doc in documents]
scores = fallback_reranker.predict(pairs)
# Convertir al mismo formato
scored = sorted(
enumerate(scores),
key=lambda x: -x[1],
)[:top_k]
return [
CohereRerankResult(
document=documents[idx],
score=float(score),
original_index=idx,
)
for idx, score in scored
]
Por qué importa:
- Sin fallback, un outage de Cohere = down de tu sistema RAG.
- Cross-encoder local cargado en memoria al startup garantiza respuesta en <200ms aún en outage.
- La calidad baja ~3-5% durante el fallback, pero el sistema sigue funcionando.
Bonus: loguear cuándo el fallback se activa permite detectar patrones (¿outage de Cohere? ¿problema de red local?). Si el fallback se activa frecuentemente, considerar suplir con redundancia o cambiar de proveedor.
Trampas y errores comunes
Trampa 1: API key en el código fuente
El error:
co = cohere.Client(api_key="co-abc123...") # commiteado a git
Síntoma: key leakeada en GitHub, alguien la usa para sus propios queries, factura inesperada.
Cómo prevenir: siempre desde environment. .env en .gitignore. Pre-commit hook que detecte el patrón.
Trampa 2: usar rerank-v3.5 (English) con queries multilingües
El error:
co.rerank(model="rerank-v3.5", query="¿cómo configurar OAuth2?", ...)
Síntoma: la query en español falla en hacer match correcto con docs en inglés. Resultados degradados sin error explícito.
Cómo prevenir: si hay cualquier mezcla de idiomas, usar rerank-multilingual-v3 aunque pierdas ~1% en queries puramente inglesas.
Trampa 3: re-rankear documentos enormes
El error:
co.rerank(query=q, documents=[doc_de_5000_chars], ...)
Síntoma: Cohere trunca docs a sus tokens máximos (~512 tokens por defecto). El re-ranking solo "ve" la parte inicial del documento.
Cómo prevenir: chunkear correctamente antes de re-rankear (ver M02). Cada documento candidato debería ser un chunk de 300-1500 caracteres, no un documento completo.
Trampa 4: no manejar rate limits
El error: picos de tráfico exceden el rate limit del tier de Cohere. Las queries empiezan a fallar.
Síntoma: errores 429 en horas pico. Usuarios afectados.
Cómo prevenir:
- Conocer el rate limit del tier (verificar en dashboard de Cohere).
- Implementar exponential backoff en retry.
- Para volumen alto, escalar a tier superior o cachear resultados de queries comunes.
import time
def rerank_with_retry(query, docs, top_k=5, max_retries=3):
for attempt in range(max_retries):
try:
return cohere_rerank(query, docs, top_k)
except cohere.CohereRateLimitError:
wait = (2 ** attempt) * 2 # 2, 4, 8s
logger.warning(f"Rate limit, waiting {wait}s")
time.sleep(wait)
raise RuntimeError("Cohere rerank failed after retries")
Trampa 5: vendor lock-in sin plan de migración
El error: todo el pipeline asume Cohere. Si los precios suben, no hay alternativa rápida.
Cómo prevenir: abstraer la interfaz de re-ranking detrás de una clase con métodos que no exponen el vendor:
class Reranker:
def rerank(self, query: str, documents: List[str], top_k: int) -> List[RerankResult]:
raise NotImplementedError
class CohereReranker(Reranker):
def rerank(self, query, documents, top_k):
# implementación Cohere
...
class CrossEncoderReranker(Reranker):
def rerank(self, query, documents, top_k):
# implementación local
...
# El resto del pipeline usa Reranker abstracto
reranker: Reranker = CohereReranker() # puedes cambiar implementación con una sola línea
Trampa 6: asumir que el orden de Cohere es el final
El error: ignoras los scores. Tomas los top_k que devuelve Cohere y listo.
Síntoma: algunos resultados con score muy bajo (ej: 0.15) se incluyen aunque sean de baja relevancia. Ensucian el contexto del LLM.
Cómo prevenir: filtrar por score threshold después del rerank:
results = cohere_rerank(query, candidates, top_k=10)
# Solo incluir docs con score > 0.5
relevant = [r for r in results if r.score > 0.5]
El threshold óptimo se determina empíricamente sobre tu eval set.
Ejercicio aplicado
Escenario: eres AI Engineer en una startup de e-commerce con presencia en LATAM y España. El producto: chatbot que responde preguntas de catálogo a usuarios.
- 200K productos chunkeados (descripción, especificaciones, reviews) en español, portugués e inglés
- 30K queries/día (mezcla de idiomas)
- Pipeline actual: cosine + cross-encoder
ms-marco-MiniLM-L-12-v2 - Métricas: precision@5 = 78% (bajo, debería ser ≥90%)
- Equipo: 3 ingenieros, ningún MLE dedicado
Tu trabajo:
- Diagnostica por qué precision@5 está tan baja.
- Decide entre las tres opciones de re-ranking. Justifica con números.
- Diseña el plan de implementación incluyendo fallback.
Solución
1. Diagnóstico
La precision baja (78%) en un sistema con cross-encoder ya implementado tiene tres posibles causas:
- Hipótesis 1: chunking pobre. No es probable porque el problema sería más recall que precision.
- Hipótesis 2: cross-encoder MS MARCO no maneja bien el multilingüe. Es la hipótesis más fuerte.
ms-marco-MiniLM-L-12-v2está entrenado en inglés. Si 60-70% del tráfico es en español/portugués, la calidad cae 10-15% sobre esas queries. - Hipótesis 3: corpus técnico-comercial muy distinto de MS MARCO. Los cross-encoders MS MARCO se entrenaron sobre queries y respuestas tipo "search engine". Catálogos de e-commerce tienen estructura distinta.
Las dos hipótesis combinadas explican fácilmente el ~12% de pérdida de precision.
Validación rápida: medir precision@5 segmentado por idioma. Si español/portugués son ~70% pero inglés es ~88%, la hipótesis 2 está confirmada.
2. Decisión: Cohere Rerank multilingual
Comparación de opciones para este escenario:
| Opción | Calidad esperada | Costo mensual estimado | Setup time |
|---|---|---|---|
| Mantener cross-encoder MS MARCO | 78% (actual) | $0 + maintenance | 0 hrs |
| Cambiar a cross-encoder multilingüe local | 85% | $0 + maintenance | 1-2 días |
| LLM rerank (GPT-4o-mini) | 90% | ~$135/mes | 1 día |
| Cohere Rerank multilingual-v3 | 88% | $45/mes | 2-3 hrs |
Cálculo del costo Cohere:
queries_per_day = 30_000
top_k_rerank = 25
docs_per_month = queries_per_day * top_k_rerank * 30 # 22.5M
cost = (docs_per_month / 1000) * 0.002 # $45/mes
Justificación:
- La startup necesita salir del problema rápido (3 ingenieros, no hay MLE para optimizar cross-encoder local).
- $45/mes es trivial para una startup de e-commerce con 30K queries/día.
- Multilingual-v3 está hecho exactamente para este caso (LATAM + España).
- Setup en horas vs días.
LLM rerank también funcionaría pero a 3x el costo y 5x la latencia, sin ganar tanto sobre Cohere para este caso.
3. Plan de implementación con fallback
# reranker.py
import cohere
import os
from sentence_transformers import CrossEncoder
from dataclasses import dataclass
from typing import List, Protocol
class Reranker(Protocol):
def rerank(self, query: str, documents: List[str], top_k: int) -> List[dict]: ...
# Cliente Cohere
_cohere_client = cohere.Client(api_key=os.getenv("COHERE_API_KEY"))
# Fallback cross-encoder cargado al startup
_fallback_model = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
def rerank_with_fallback(query: str, documents: List[str], top_k: int = 5):
try:
response = _cohere_client.rerank(
model="rerank-multilingual-v3",
query=query,
documents=documents,
top_n=top_k,
)
return [
{"document": documents[r.index], "score": r.relevance_score}
for r in response.results
]
except Exception as e:
# Fallback: cross-encoder local (sabemos que da 78% pero el sistema funciona)
log_event("cohere_rerank_fallback", error=str(e))
pairs = [(query, doc) for doc in documents]
scores = _fallback_model.predict(pairs)
scored = sorted(enumerate(scores), key=lambda x: -x[1])[:top_k]
return [
{"document": documents[i], "score": float(s)}
for i, s in scored
]
Plan de rollout:
-
Día 1 (3-4 horas):
- Setup de cuenta Cohere, API key en environment
- Implementar
rerank_with_fallbacken código - Tests unitarios (Cohere OK, Cohere falla → fallback funciona)
-
Día 2 (2-3 horas):
- Deploy a staging
- Correr eval set de 100 queries multilingües (50 español, 25 portugués, 25 inglés)
- Medir precision@5 antes y después por idioma
-
Día 3 (medio día):
- Si precision en multilingüe ≥85%, deploy a producción con feature flag
- Monitoreo activo: latencia, error rate de Cohere, fallback rate
- Rollback inmediato si hay regresión
-
Semanas 2-4:
- A/B test: 50% Cohere, 50% cross-encoder original
- Métricas: precision, NPS, latencia, costo
- Decisión final basada en datos
Monitoreo continuo:
cohere_rerank_fallbackrate: debería ser <1%. Si sube, investigar.- Costo mensual real vs estimado: alerta si supera $80/mes (75% sobre presupuesto).
- Precision por idioma: alerta si cualquier idioma cae bajo 80%.
Plan B si Cohere no alcanza el target:
- Si precision queda en 84-86% pero el target es 90%: cambiar a LLM rerank en cascada (cross-encoder Cohere → GPT-4o-mini sobre top-10).
- Si Cohere tiene problemas de disponibilidad recurrentes: evaluar Voyage AI rerank o build cross-encoder multilingüe in-house.
Resumen y siguiente paso
Lo que aprendiste:
- Cohere Rerank es opción managed que ofrece calidad cercana a LLM rerank a costo cercano a cross-encoder local.
- Brilla en dos casos: corpus multilingüe y equipos sin recursos para mantener modelos.
- Modelos:
rerank-v3.5para inglés puro,rerank-multilingual-v3para cualquier mezcla de idiomas. - Pricing por documento procesado: $0.002 por 1K docs. Volumen típico = $5-50/mes.
- Implementación robusta requiere: API key en environment, fallback a cross-encoder local, manejo de rate limits, threshold de score para descartar resultados de baja relevancia.
- Fallback automático a cross-encoder local protege contra outages — el pipeline siempre funciona, aunque con calidad ligeramente menor.
- Vendor lock-in es riesgo real; abstraer la interfaz facilita migrar entre proveedores.
Checkpoint: antes de avanzar, deberías poder:
- Decidir entre cross-encoder local, LLM rerank y Cohere para un escenario dado.
- Calcular el costo mensual de Cohere para un volumen específico de queries.
- Implementar fallback automático a cross-encoder local si Cohere falla.
Siguiente cápsula: 06 — Trade-offs y optimizaciones de re-ranking.
Cubrimos las tres técnicas de re-ranking. Pero hay decisiones operativas más finas que las tres comparten: ¿cuántos candidatos pasar al re-ranker? ¿cómo cachear resultados? ¿cuándo re-rankear vs cuándo confiar en el retrieval directo? La cápsula 06 cubre estas optimizaciones que pueden mejorar 10-20% la performance sin cambiar la técnica subyacente.
Recursos
- Cohere Rerank Documentation — Documentación oficial completa
- Cohere Rerank Models Guide — Comparación de modelos disponibles
- Cohere Pricing — Precios actualizados
- Multilingual Reranking — Cohere Blog — Casos de uso multilingüe
- Voyage AI Rerank — Alternativa managed a Cohere
- Anthropic — Contextual Retrieval with Reranking — Patrones combinados con rerank
Tiempo estimado: 25-30 minutos Siguiente: 06-tradeoffs-optimizations.md