Más allá de la similitud coseno: comparación de cinco técnicas de recuperación RAG
Coseno, BM25, RRF híbrido, reclasificación con codificador cruzado y MMR explicados con código, trade-offs y un enfoque centrado en la consulta para decidir qué técnica de recuperación necesita su RAG.
Fuentes: **Beyond Cosine Similarity: The 5 RAG Retrieval Techniques That Actually Move the Needle**
Dos oraciones, “el gato se sentó en la alfometa” y “un felino descansó sobre la colcha”, no comparten ninguna palabra en absoluto, pero un modelo de embedding les asigna una puntuación de aproximadamente 0.85. Así es como la similitud coseno gana su reputación, y también ahí es donde la mayoría de los tutoriales sobre RAG se detienen: muestran el cálculo del coseno, pegan un fragmento y pasan a otra cosa.
collection.query(query_embeddings=embedding, n_results=5)
Esa técnica funciona. Además, es solo una de las cinco técnicas de recuperación, cada una diseñada para un tipo diferente de problema. Depender únicamente del coseno significa que categorías enteras de consultas fallan en silencio, sin generar error alguno, y los usuarios reciben simplemente respuestas incorrectas. A continuación se explica qué mide realmente el coseno, dónde falla y las otras cuatro técnicas, además de una forma de decidir cuál utilizar.
Qué mide el coseno
Un modelo de embedding convierte el texto en un vector, es decir, una lista de cientos o miles de números. Los textos que significan cosas similares terminan siendo vectores orientados en la misma dirección. La similitud coseno compara el ángulo que separa dos vectores en lugar de la distancia entre ellos.
Ese es el punto clave. Una oración corta y un párrafo completo pueden significar lo mismo. Si sus vectores apuntan en la misma dirección, el coseno indica una puntuación alta. La longitud, que se refleja en la magnitud, es ruido, mientras que la dirección representa el significado.
Las puntuaciones típicas son las siguientes:
| Pareja | Puntuación |
|---|---|
| "El gato se sentó en la alfombra" y "Un felino descansó sobre la esterilla" | 0.85 |
| "¿Cómo funciona la atención?" y "Explique el mecanismo del transformer" | 0.79 |
| "Lenguaje de programación Python" y ">Python, la especie de serpiente" | 0.38 |
| "Me encanta el café de la mañana" y ">Teoría del entrelazamiento cuántico" | 0.03 |
La primera fila demuestra por qué el coseno es impresionante: no hay palabras en común y la puntuación es de 0.85. El modelo ha aprendido que "gato" y "felino" se encuentran en zonas cercanas del espacio semántico, y el coseno lo detecta sin necesidad de coincidencia de palabras clave.
¿Por qué no la distancia euclidiana?
La alternativa obvia es la distancia euclidiana, que literalmente mide cuán separados están dos vectores. El problema es que si se repite un documento diez veces, su vector se vuelve diez veces más grande, por lo que parece muy distinto del original aunque el significado no haya cambiado en absoluto. El coseno ignora eso; solo cuenta la dirección.
Una advertencia sobre las puntuaciones
Las puntuaciones de coseno no son universales. Un valor de 0.7 obtenido con all-MiniLM-L6-v2 es un indicador diferente al de 0.7 obtenido con text-embedding-3-large, ya que cada modelo tiene su propio espacio de incrustación con su propia densidad. Calibre los umbrales de puntuación en su propio conjunto de evaluación y no copie números de tutoriales que utilicen otro modelo.
Una analogía de festival para quienes no son ingenieros
Antes de hablar del código, imagine un modelo mental de las cinco técnicas. Está en un festival de música buscando a un amigo entre la multitud, con tres estrategias disponibles.
- Por dirección (coseno). Ambos acuerdan mirar hacia el escenario. La misma dirección significa que se trata de la misma persona, sin importar cuán separados estén. Importa el ángulo en el que apuntan, no la distancia entre ellos.
- Por nombre en la placa (búsqueda por palabras clave, BM25). Gritan “¿Alguien se llama Alex?”. Funciona perfectamente si el nombre en la placa coincide exactamente, pero no identifica a personas como Alexis, Al o Sandy, que son la misma persona con un nombre diferente.
- Por rostro y nombre en la placa (híbrido). Se verifica ambos elementos. Quien coincida en ambos sale primero, y quien solo coincida en uno también será detectado. Esto ofrece la cobertura más amplia.
La lección que la mayoría de los tutoriales pasan por alto: ningún método solo puede encontrar a todos. La técnica que elijas determinará qué respuestas y qué personas pasarás por alto de forma permanente.
Cinco técnicas, una a la vez
1. Similitud coseno, la opción predeterminada
Qué hace. Compara la dirección semántica de los vectores de la consulta y del documento.
Cuándo usarlo. Cuando las consultas están en lenguaje natural y no se requieren términos exactos: RAG general, respuesta a preguntas sobre documentos, cualquier situación que implique mucho parafraseo.
Dónde falla. En cadenas literales. Un código de producto, un número de factura o el nombre de una persona que apenas aparece en los datos de entrenamiento puede hacer que la similitud coseno falle por completo. Los vectores de “GPT-4o” y “GPT-4” pueden estar lo suficientemente cerca como para generar ruido en lugar de una señal clara.
En código:
collection.query(
query_embeddings=query_embedding,
n_results=5
)
Compromiso. El significado prevalece sobre la redacción exacta. Es rápido, razonablemente preciso y no requiere configuración adicional.
2. Búsqueda por palabras clave BM25, la herramienta de precisión
Qué hace. Evalúa los documentos según la frecuencia con que aparecen las palabras de la consulta, descontando según qué tan comunes son esas palabras en todo el corpus. No utiliza embeddings, solo conteo.
Úsalo cuando. La consulta depende de un identificador exacto que debe coincidir carácter por carácter, como un número de factura, el nombre de un modelo con fecha de lanzamiento o una referencia CVE.
Qué deja de lado. Cualquier sentido de significado. “Feline” no coincidirá con documentos que digan “gato”. Los sinónimos y las paráfrasis le son invisibles.
Un resultado revelador. En un pequeño proyecto desarrollado desde cero, la adición de BM25 junto con el algoritmo de coseno elevó la tasa de recuperación de 0,25 a 0,75. La razón fue que las consultas reales de los usuarios contenían nombres de productos exactos que el algoritmo de coseno confundía con coincidencias parciales en lugar de identificarlas directamente. Considérelo como un punto de datos, no como una cifra universal.
Compromiso. Precisión en las coincidencias exactas a costa de una total falta de generalización semántica.
3. Búsqueda híbrida, la opción predeterminada en producción
Qué hace. Ejecuta simultáneamente el algoritmo de coseno y BM25, y fusiona las dos listas ordenadas mediante la técnica de Fusión de Rangos Recíprocos (RRF). Ninguno de estos métodos abarca por sí solo todos los tipos de consultas.
Úselo cuando. Las consultas combinan lenguaje natural con términos específicos, lo cual describe casi todos los sistemas de producción. Un usuario que pregunta "¿cuál es la política de reembolso para el pedido #8821?" incluye tanto un elemento semántico (política de reembolso) como una coincidencia exacta (#8821).
El paso de fusión. Cada técnica devuelve su propia lista ordenada. RRF asigna a cada documento una puntuación basada en su posición en cada lista, 1 dividido entre (k más el rango), donde k es una constante, comúnmente 60, y luego suma las puntuaciones obtenidas de todas las técnicas. Los documentos que ocupan posiciones altas en ambas listas aparecen arriba.
# Pseudocode for RRF merge
def rrf_score(rank, k=60):
return 1 / (k + rank)
def merge_results(cosine_results, bm25_results):
scores = {}
for rank, doc in enumerate(cosine_results):
scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
for rank, doc in enumerate(bm25_results):
scores[doc.id] = scores.get(doc.id, 0) + rrf_score(rank)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
En AWS, OpenSearch lo soporta de forma nativa: se configura una consulta híbrida con un parámetro de peso y el sistema gestiona internamente la fusión de resultados.
Compromiso. Se obtiene la mejor tasa general de recuperación, pero a un costo aproximadamente el doble, lo cual suele ser un precio aceptable.
4. Reclasificación con un cross-encoder
Qué hace. Es un enfoque en dos etapas. En la primera etapa, se recuperan los 20 mejores candidatos mediante búsqueda por coseno o híbrida. En la segunda etapa, cada candidato se introduce junto con la consulta en un cross-encoder, que evalúa su relevancia al considerar ambos elementos al mismo tiempo.
Cuándo usarlo. Cuando los resultados principales son relevantes pero están en el orden incorrecto, y la precisión es más importante que la latencia. Debe utilizarse en la segunda etapa y nunca en la primera pasada.
¿Por qué dos etapas? Un codificador cruzado evalúa la relevancia mucho mejor que el coseno, pero no se puede aplicar a toda una base de datos. Veinte llamadas al modelo en lugar de una son aceptables. Diez mil en el momento de la consulta no lo son.
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')# Stage 1: retrieve candidates
candidates = collection.query(query_embeddings=embedding, n_results=20)# Stage 2: rerank
pairs = [(query, chunk) for chunk in candidates['documents'][0]]
scores = reranker.predict(pairs)
top_5 = sorted(zip(scores, candidates['documents'][0]), reverse=True)[:5]
Advertencia importante. No utilice el reordenamiento como paso inicial. El costo por latencia es elevado, ya que se sustituye una búsqueda de embedding por veinte inferencias completas del modelo.
Compromiso. Ofrece la mayor precisión, pero también el mayor costo, por lo que debe usarse únicamente como segunda etapa.
5. Máxima relevancia marginal (MMR) para variedad
Qué hace. Equilibra la cercanía a la consulta con la similitud con los fragmentos ya seleccionados. Cada nueva selección debe ser relevante y diferente de lo ya elegido.
Úselo cuando. Los fragmentos principales dicen lo mismo, por ejemplo en una pregunta de resumen general donde cada resultado reitera un mismo hecho.
El ajuste lambda.
lambda = 1.0significa relevancia pura, igual que el coseno estándar
lambda = 0.0 significa diversidad pura, ignorando por completo la relevancialambda = 0.5 es un punto de partida equilibrado del cual se puede ajustardef mmr_select(query_embedding, candidates, lambda_param=0.5, k=5):
selected = []
remaining = list(candidates)
while len(selected) < k and remaining:
mmr_scores = []
for doc in remaining:
relevance = cosine_similarity(query_embedding, doc.embedding)
if selected:
redundancy = max(cosine_similarity(doc.embedding, s.embedding)
for s in selected)
else:
redundancy = 0
mmr_scores.append(lambda_param * relevance - (1 - lambda_param) * redundancy)
best = remaining[mmr_scores.index(max(mmr_scores))]
selected.append(best)
remaining.remove(best)
return selected
Dónde brilla. Resúmenes, preguntas de investigación y cualquier caso en el que el lector desee abarcar varias ideas en lugar de profundizar en una sola.
Compromiso. Elimina la redundancia, pero lambda requiere ajustes.
Elegir: deja que tus consultas decidan
Antes de elegir una técnica, estudia 20 consultas reales de tus usuarios o dominio reales. Las hipotéticas no cuentan.
- El 80% o más son en lenguaje natural simple. Cosine es tu opción por defecto. Comienza con ella, ya que es rápida y precisa, además de no requerir infraestructura adicional.
- El 30% o más contiene términos exactos, códigos, IDs o nombres propios. Agrega BM25. Una vez que observes ese patrón, la búsqueda híbrida se convierte en la opción por defecto en producción, así que implementa la fusión RRF. La mejora en el recuerdo suele ser rápida y significativa.
Lo que omiten los tutoriales
Las técnicas pueden entrar en conflicto, no solo sumarse. En un experimento, aplicar la expansión de consultas, que genera varias variantes de la consulta y realiza búsquedas para cada una, sobre la recuperación híbrida parecía ser una solución segura. Se pensaba que mayor cobertura significaría mejores resultados. Sin embargo, las puntuaciones cayeron de 0.807 a 0.702. Cada señal adicional de recuperación amplifica tanto el ruido como la información útil, y las variantes adicionales incluían fragmentos cercanos pero incorrectos. La recuperación híbrida ya funcionaba bien, y la expansión solo generó interferencias. Añada una técnica a la vez, mida cada una por separado antes de combinarlas y recuerde que el orden es importante, ya que algo útil por sí solo puede perjudicar cuando se combina con otros elementos.
El producto escalar no es el coseno. Algunas bases de datos vectoriales usan por defecto el producto escalar. Ambos solo coinciden cuando los vectores están normalizados a unidad. Si su modelo de embedding no normaliza sus resultados, las puntuaciones del producto escalar no pueden compararse entre consultas; por lo tanto, un valor de 0.9 en una consulta y otro de 0.9 en otra significan cosas diferentes. Verifique qué es lo que realmente calcula su base de datos. Por ejemplo, ChromaDB se describe generalmente como utilizando una métrica por defecto distinta a la de Qdrant, así que confirme ambos en la documentación actual.
Las consultas determinan la técnica, no los documentos. Los ingenieros suelen dedicar tiempo a clasificar su corpus como técnico o conversacional, largo o corto. Eso es importante para el procesamiento en bloques. Para elegir una técnica de recuperación, el análisis de las consultas es mucho más relevante. Un corpus técnico buscado con preguntas en lenguaje natural es un problema de coseno, mientras que el mismo corpus buscado por número de parte es un problema híbrido.
El proceso completo
Este es el diseño en capas con el que terminan muchos sistemas RAG en producción:
User Query
↓
[Optional: HyDE — if query is vague]
↓
Stage 1 Retrieval: Hybrid (Cosine + BM25 → RRF merge)
→ Top 20 candidates
↓
[Optional: Cross-encoder reranking — if precision matters]
→ Top 5 candidates
↓
[Optional: MMR — if results are redundant]
→ Final k candidates
↓
LLM Context Assembly + Generation
No todo sistema necesita todas las capas. Comience con el método de coseno, añada el enfoque híbrido cuando aparezcan fallos en las búsquedas exactas, incorpore el reordenamiento cuando el orden esté incorrecto y utilice MMR cuando los resultados se repitan. Mida en cada paso, ya que lo que funciona para un sistema puede perjudicar a otro.
El número que importa
Los informes de los experimentos de recuperación suelen mostrar una diferencia en el recuerdo entre las búsquedas basadas únicamente en coseno y las híbridas en conjuntos de consultas mixtos; en un pequeño proyecto, este valor pasó de 0.25 a 0.75. Si esto se aplica, aunque sea de forma aproximada, a sus datos, significa que aproximadamente tres veces más respuestas correctas llegan al modelo de lenguaje antes de que escriba una palabra, sin necesidad de ingeniería de prompts, actualizaciones del modelo ni reformas en la infraestructura. Todo se reduce a tomar una buena decisión respecto a la recuperación de información.