SEXTANTEcursos técnicos de IA
métodobackward-design
árbitroel dato
Entrar
N3 · Evals por arquitectura/L3

El retriever a examen: métricas IR

Objetivo de maestría

medir el retriever de Aurora con las métricas IR clásicas (precision@k, recall@k, MRR, NDCG@k), elegir la apropiada según lo que importe, justificar el k, y conectar todo con el context precision de la RAG triad. Sin esto, sabes que el retrieval falla, pero no cómo arreglarlo.


3.1"Context relevance baja" no te dice qué romper

Vuelves al caso de las zapatillas usadas. La RAG triad de L2 te marcó context relevance baja en doce conversaciones de Aurora. Veredicto claro: el retriever falla.

Te sientas a arreglarlo y te frenas en seco. ¿Falla cómo?

  • ¿consultar_politica trae basura en el top —chunks irrelevantes que ensucian el contexto—?
  • ¿O trae poca basura, pero se deja fuera el chunk de devoluciones que sí respondía?
  • Y cuando lo trae, ¿lo pone en la posición 1 o sepultado en la 7, donde el modelo casi no lo mira?

Cada respuesta apunta a un arreglo distinto. "Trae basura" se ataca con un reranker o un filtro. "Se deja fuera el bueno" se ataca con más k o mejor índice. "Lo trae pero abajo" se ataca con reordenado. Tres diagnósticos, tres palancas opuestas.

Un score binario de "context relevance: baja" no distingue ninguno de los tres. Para arreglar un retriever necesitas saber en qué eje falla. Ese lenguaje preciso lo aporta Information Retrieval (IR), una disciplina con cuarenta años de métricas afinadas justo para esto.


3.2Qué vas a poder hacer

Al terminar esta lección sabrás:

  • Calcular precision@k, recall@k, MRR y NDCG@k sobre un retrieval real de Aurora, a mano y en código.
  • Distinguir qué eje de fallo mide cada una: cobertura, ruido o posición.
  • Elegir y justificar la métrica y el valor de k apropiados para un objetivo concreto de Aurora.
  • Conectar estas métricas IR con el context precision de Ragas que ya viste en L2.

Necesitas saber antes:

  • La RAG triad y su vértice de retrieval (L2): context relevance mira los chunks recuperados.
  • Los qrels de tu dataset (de N1): para cada query etiquetaste qué chunks eran relevantes. Qrels —del inglés query relevance judgments— es la lista de "respuestas correctas" del retriever.
  • Por qué un fallo de retrieval y uno de generación piden arreglos opuestos (L1).

Esta lección añade un solo concepto: medir el retriever como un problema de IR. No toca la generación ni la trayectoria; esas van en L2 y L4.


3.3Recupera

Antes de seguir, responde mentalmente. No mires lo de abajo hasta tener una respuesta.

  1. De la RAG triad (L2), ¿qué vértice miraba el retrieval, y qué pregunta hacía sobre los chunks?
  2. De N1, para una query como "¿puedo devolver unas zapatillas usadas?", ¿qué guardaste como chunks relevantes (los qrels)?
  3. De L1, ¿por qué arreglar un fallo de retrieval y uno de generación lleva a dos sitios distintos del sistema?

El vértice de retrieval era context relevance: ¿cada chunk recuperado es relevante a la query? Los qrels son tu verdad de referencia: para esa query, el chunk relevante es el de la política de devoluciones (30 días, sin usar), no el de envíos. Y el porqué de la 3: un retrieval malo se arregla en el índice o el reranker; una generación infiel, en el prompt o el modelo. Misma respuesta mala, ramas opuestas del sistema.

Las métricas de esta lección operan sobre esos qrels. Sin ellos, no hay verdad contra la que medir.


3.4El concepto: cuatro lentes sobre el mismo top-K

Empecemos por un retrieval concreto y subamos hacia las fórmulas.

El montaje

consultar_politica("devoluciones zapatillas") devuelve los K chunks más parecidos a la query. En este ejemplo, K = 5 (Aurora pasa los 5 primeros chunks al modelo como contexto). Los qrels del dataset dicen que, para esta query, hay 2 chunks relevantes en toda la base de conocimiento.

El retriever devuelve estos 5, en este orden:

text
1posición 1:  chunk "devoluciones-base" (30 días, sin usar)   ← RELEVANTE
2posición 2:  chunk "envios-internacionales"                   ← irrelevante
3posición 3:  chunk "garantia-fabricante"                      ← irrelevante
4posición 4:  chunk "devoluciones-excepciones" (productos higiene) ← RELEVANTE
5posición 5:  chunk "horarios-atencion"                        ← irrelevante

De los 2 relevantes que existen, recuperó los 2: en las posiciones 1 y 4. Sobre este mismo resultado, cuatro métricas dicen cuatro cosas distintas. Vamos una a una.

Precision@K — de lo que traigo, ¿cuánto sirve?

La Precision@K mide qué fracción de los K chunks recuperados es relevante (corpus D.5, Weaviate, may 2024).

text
1Precision@K = (relevantes en el top-K) / K

Analogía: es la pureza de lo que sirves al modelo. Su límite: no sabe nada de cuántos relevantes existían fuera del top-K. En el ejemplo: 2 relevantes de 5 traídos → Precision@5 = 2/5 = 0,40.

Detalle que importa: precision@k no es rank-aware —no le importa la posición—. Rank-aware significa que la métrica premia colocar lo relevante arriba. Da igual que los 2 relevantes estén en las posiciones 1 y 4 o en la 4 y la 5: precision@5 vale 0,40 en ambos casos.

Recall@K — de lo bueno que existe, ¿cuánto traigo?

La Recall@K mide qué fracción de todos los chunks relevantes que existen aparece en el top-K (corpus D.5).

text
1Recall@K = (relevantes en el top-K) / (total de relevantes)

Analogía: es la cobertura. Recall responde a la pregunta opuesta a precision. Precision pregunta "lo que traigo, ¿es bueno?"; recall pregunta "lo bueno, ¿lo traigo?". En el ejemplo: 2 relevantes recuperados de 2 que existen → Recall@5 = 2/2 = 1,00.

Recall@k tampoco es rank-aware. Y, como precision, sube y baja con el valor de K: agrandar K nunca puede bajar el recall, pero suele bajar la precision (entra más ruido).

Es común confundir las dos al principio. Truco para no perderte: el denominador lo delata. Precision divide por K (lo que trajiste); recall divide por el total de relevantes (lo que existía).

MRR — ¿está el primer acierto arriba?

La MRR (Mean Reciprocal Rank, rango recíproco medio) mide la posición del primer chunk relevante (corpus D.5).

text
1RR de una query = 1 / (rank del primer relevante)
2MRR = media de los RR sobre todas las queries

Analogía: premia "acertar pronto". Su límite: solo mira el primer acierto; ignora todo lo demás. En el ejemplo, el primer relevante está en la posición 1 → RR = 1/1 = 1,00. Si estuviera en la posición 3, sería 1/3 ≈ 0,33.

MRR sí es rank-aware. Es la métrica natural cuando basta un buen chunk para responder: si una sola política contesta la pregunta, lo que importa es que llegue arriba.

NDCG@K — calidad del orden, con grados de relevancia

La NDCG@K (Normalized Discounted Cumulative Gain) mide la calidad del orden completo, descontando los aciertos según lo abajo que estén (corpus D.5). Es la métrica por defecto del benchmark MTEB Retrieval.

Antes de la fórmula, una advertencia: NDCG es la más densa de las cuatro. Tiene tres piezas encadenadas. Léelas como una receta de tres pasos, no como una sola ecuación.

Paso 1 — DCG (ganancia acumulada descontada). Suma la relevancia de cada chunk, pero dividida por un descuento que crece con la posición. Lo de abajo pesa menos:

text
1DCG@K = Σ  rel(i) / log2(i + 1)      para i = 1 .. K

Con relevancia binaria (rel = 1 si relevante, 0 si no) y nuestro resultado (relevantes en posiciones 1 y 4):

text
1DCG@5 = 1/log2(2)  +  0  +  0  +  1/log2(5)  +  0
2      = 1/1.000     +        +  1/2.322
3      = 1.000 + 0.431 = 1.431

Paso 2 — IDCG (DCG ideal). El DCG del orden perfecto: los 2 relevantes en las posiciones 1 y 2.

text
1IDCG@5 = 1/log2(2) + 1/log2(3) = 1.000 + 0.631 = 1.631

Paso 3 — normalizar. NDCG es DCG dividido por IDCG, así que cae siempre entre 0 y 1:

text
1NDCG@5 = DCG@5 / IDCG@5 = 1.431 / 1.631 = 0.877

NDCG es rank-aware y, a diferencia de las otras tres, admite grados de relevancia: un chunk puede valer rel=2 (perfecto), rel=1 (parcial) o rel=0 (irrelevante), no solo sí/no. Eso la hace la lente más fina cuando tus qrels distinguen "responde del todo" de "responde a medias".

El mapa de las cuatro lentes

Cuatro métricas, un mismo retrieval, cuatro lecturas:

MétricaMide¿Rank-aware?Para Aurora cuando…
Precision@Kpureza del top-KNoimporta no meter ruido al modelo
Recall@Kcobertura de lo relevanteNohace falta traer todos los chunks que aplican
MRRposición del 1er aciertobasta un buen chunk para responder
NDCG@Kcalidad del orden (graduada)importa el orden y hay grados de relevancia

Elegir la métrica = decidir qué importa en Aurora. Si una sola política basta para responder (la mayoría de preguntas de soporte), MRR y precision@k mandan. Si hace falta cubrir varios chunks —p. ej. la política base de devoluciones más la excepción de productos de higiene—, entonces recall@k pasa al frente: dejarte fuera la excepción produce una respuesta peligrosamente incompleta.

Y el k se justifica solo. No es un número mágico: es cuántos chunks pasa Aurora al modelo como contexto. Si el agente inyecta los 5 primeros, mides @5. Cambiar el k de la métrica sin cambiar el del sistema mide una realidad que no existe.

El puente con la triad: context precision

Aquí cierra el círculo con L2. La métrica Context Precision de Ragas es, conceptualmente, la Precision@K de IR (corpus D.5, equivalencia conceptual). Misma pregunta —de lo recuperado, ¿cuánto es relevante—, distinta forma de decidir "relevante":

  • Precision@K de IR: la relevancia la fijan los qrels humanos de tu dataset (lo que etiquetaste en N1).
  • Context Precision de Ragas: la relevancia la decide un juez LLM o un reference (corpus D.2).

Ese juez LLM es, ni más ni menos, el juez calibrado que validaste en N2. La triad no inventa un juez nuevo; reutiliza el tuyo, con su TPR/TNR ya medidos.

Un matiz del que pocos avisan (corpus D.2): en Ragas existe LLMContextPrecisionWithoutReference, que mide context precision sin ground truth (usa el response). En cambio, LLMContextRecall siempre exige reference. Tiene sentido: para saber qué te dejaste fuera, hace falta saber qué era el conjunto completo de lo correcto.


3.5Míralo funcionar: las cuatro métricas en código

Vamos a calcular las cuatro métricas sobre el retrieval del montaje, en Python puro. Sin librerías de IR: las fórmulas son cortas y verlas explícitas fija la intuición mejor que una caja negra.

Lee el bloque entero primero. Después analizamos la pregunta de auto-explicación.

python
1import math
2
3# El retrieval del montaje: K=5 chunks, en orden.
4# True = relevante según los qrels del dataset; False = irrelevante.
5recuperados = [True, False, False, True, False]   # posiciones 1..5
6total_relevantes = 2   # de los qrels: cuántos relevantes existen en toda la KB
7K = len(recuperados)    # = 5, los chunks que Aurora pasa al modelo
8
9def precision_at_k(recuperados, k):
10    top_k = recuperados[:k]
11    return sum(top_k) / k
12
13def recall_at_k(recuperados, total_relevantes, k):
14    top_k = recuperados[:k]
15    return sum(top_k) / total_relevantes
16
17def reciprocal_rank(recuperados):
18    for i, es_relevante in enumerate(recuperados, start=1):
19        if es_relevante:
20            return 1 / i        # rank del PRIMER relevante
21    return 0.0
22
23def dcg_at_k(relevancias, k):
24    # relevancias: lista de grados (aquí 1/0). i empieza en 1.
25    return sum(rel / math.log2(i + 1)
26               for i, rel in enumerate(relevancias[:k], start=1))
27
28def ndcg_at_k(relevancias, k):
29    dcg = dcg_at_k(relevancias, k)
30    ideal = dcg_at_k(sorted(relevancias, reverse=True), k)  # el orden perfecto
31    return dcg / ideal if ideal > 0 else 0.0
32
33relevancias = [1 if r else 0 for r in recuperados]
34
35print(f"Precision@5 = {precision_at_k(recuperados, K):.3f}")        # 0.400
36print(f"Recall@5    = {recall_at_k(recuperados, total_relevantes, K):.3f}")  # 1.000
37print(f"MRR (1 query) = {reciprocal_rank(recuperados):.3f}")        # 1.000
38print(f"NDCG@5      = {ndcg_at_k(relevancias, K):.3f}")             # 0.877

Salida:

text
1Precision@5 = 0.400
2Recall@5    = 1.000
3MRR (1 query) = 1.000
4NDCG@5      = 0.877

Coinciden con los cálculos a mano de §3.4. Ahora la pregunta de auto-explicación. Respóndela antes de leer la respuesta:

Si reordenas el resultado para subir el relevante de la posición 4 a la 2, ¿qué métricas cambian y cuáles no?

recuperados pasaría a [True, True, False, False, False]. Cambian las rank-aware: NDCG@5 sube (ahora DCG = 1/log2(2) + 1/log2(3) = 1,631 = el ideal → NDCG = 1,000). El MRR no se mueve, porque el primer relevante ya estaba en la posición 1. Y precision@5 y recall@5 no cambian: siguen 0,40 y 1,00, porque cuentan presencia en el top-K, no orden. Esa es, en una frase, la diferencia entre las dos familias.


3.6Hazlo tú

Ejercicio 1 — andamiaje parcial

Otro retrieval de Aurora para la query "¿cuánto tarda un envío a Canarias?". K = 4. Los qrels marcan 3 chunks relevantes en la KB. El retriever devuelve, en orden:

text
1posición 1:  "envios-peninsula"          ← irrelevante
2posición 2:  "envios-canarias-plazos"    ← RELEVANTE
3posición 3:  "envios-canarias-costes"    ← RELEVANTE
4posición 4:  "devoluciones-base"         ← irrelevante

Calcula las dos primeras a mano; las dejamos resueltas para que verifiques el método:

  • Precision@4 = relevantes en top-4 / 4 = 2/4 = 0,50.
  • Recall@4 = relevantes en top-4 / total relevantes = 2/3 ≈ 0,67.

Ahora completa tú las dos rank-aware:

  • MRR (esta query) = 1 / (rank del primer relevante) = 1 / ____ = ____.
  • NDCG@4: calcula DCG@4 e IDCG@4. Pista: el primer relevante está en la posición 2; el orden ideal pondría los 2 recuperados relevantes en las posiciones 1 y 2.

Ejercicio 2 — autónomo

Producto: Aurora necesita responder preguntas sobre devoluciones que casi siempre tienen una excepción aplicable (productos de higiene, artículos rebajados, electrónica abierta). Una respuesta que omite la excepción aplicable es peor que inútil: induce a error al cliente.

Sin mirar la solución, decide y justifica en dos o tres frases:

  1. ¿Qué métrica IR pondrías como principal para este objetivo?
  2. ¿Qué valor de k usarías, y de qué dato del sistema lo derivas?

Antes de seguir, una pregunta de interrogación elaborativa. Respóndela tú primero: ¿por qué un precision@5 alto con un recall@5 bajo es exactamente el patrón a temer en este caso de Aurora? Piénsalo antes de leer la línea siguiente.

Porque "precision alta, recall bajo" significa: lo poco que traigo es limpio, pero me dejo fuera chunks relevantes que existían. En un caso donde omitir la excepción daña al cliente, ese es el fallo más caro. La pureza no te salva si te falta la mitad de la respuesta.


3.7Comprueba

Sin pistas. Aurora debe cubrir todas las excepciones de su política de devoluciones; una respuesta que se deja una excepción fuera se considera un fallo. Te dan, para una query del dataset, estos números del retriever:

text
1Precision@5 = 0.80      (4 de 5 chunks del top-5 son relevantes)
2Recall@5    = 0.50      (de los relevantes que existen, recupera la mitad)

Responde tres cosas: (a) ¿está el retriever sano para este objetivo? (b) ¿qué métrica IR es la decisiva aquí y por qué? (c) ¿qué arreglo concreto propondrías?

Ver la respuesta razonada

(a) No, no está sano para este objetivo. El precision@5 de 0,80 es alto: el top-5 trae poco ruido. Pero el recall@5 de 0,50 dice que la mitad de las excepciones relevantes se queda fuera del contexto que ve el modelo. Para un objetivo de "cubrir todas las excepciones", recuperar solo la mitad es un fallo, por muy limpia que sea esa mitad.

(b) La métrica decisiva es recall@k. El objetivo penaliza las omisiones, no el ruido. Recall mide exactamente la omisión: de lo relevante que existe, cuánto traes. El precision alto es una distracción aquí —resuelve un problema que no tienes—.

(c) Arreglo orientado a recall: subir el k (pasar más chunks al modelo), revisar el chunking (¿las excepciones están troceadas de forma que el retriever las separa de la query?), o añadir una etapa que recupere específicamente excepciones. Lo que no ayuda: un reranker que mejore la pureza —eso sube precision, no recall—.


Feedback formativo:

  • Si acertaste que recall manda y propusiste subir k o revisar chunking: dominas el criterio central de la lección —la métrica se elige por el objetivo, no por costumbre—. Es justo la dimensión 2 de la rúbrica del checkpoint C3 ("métricas IR apropiadas, k justificado"). En L6 lo aplicarás a la suite entera.
  • Si dijiste "el retriever está bien porque precision es 0,80": leíste el eje equivocado. Tu lectura sería correcta para un objetivo de "no meter ruido"; aquí el objetivo es "no dejarte nada". Vuelve al §3.4 y verbaliza qué pregunta responde cada denominador: K vs. total de relevantes.
  • Si elegiste MRR: MRR encaja cuando basta un chunk. Aquí hacen falta todos los relevantes, así que mirar solo el primer acierto ignora justo lo que te juegas. La diferencia: MRR optimiza "acertar pronto"; tu objetivo es "acertar entero". Relee la tabla de §3.4.

3.8Conecta

Vuelve a las doce conversaciones con "context relevance baja" del principio.

Ahora no te frenas. Abres una, miras los qrels y, en treinta segundos, sabes cómo falla el retriever. Si el precision@k es bajo, trae ruido: necesitas un reranker. Si el recall@k es bajo, se deja fuera el chunk bueno: necesitas más k o mejor índice. Si ambos están bien pero el MRR es flojo, el chunk correcto llega sepultado: necesitas reordenar. "El retriever falla" se ha convertido en un diagnóstico con palanca.

Esto encaja directo en el checkpoint C3 de este nivel. Su dimensión 2 pide exactamente esto: métricas IR apropiadas, con el k justificado. La suite que montarás en L6 calculará estas cuatro métricas sobre el retriever de Aurora de forma sistemática.

Y ya llevas dos de las tres capas del mapa de L1:

  • Retrieval → métricas IR (esta lección) + context precision de la triad (L2).
  • Generación → groundedness / answer relevance (L2).
  • Orquestación / trayectoria → falta. Qué tools llamó el agente, con qué argumentos, en qué orden. Eso es L4.

¿Dónde lo aplicarías en tu trabajo? Cualquier sistema RAG que hayas tocado tiene un retriever silencioso. Si hoy te llega una queja de "respuesta incompleta", ¿sabrías decir si fue precisión o recall? Si la respuesta es "no", ya sabes qué medir primero.


3.9Reflexiona

Tómate dos minutos. Estas preguntas consolidan más que releer.

  • Dos retrievals tienen el mismo precision@5. Uno pone el relevante en la posición 1; el otro, en la 5. ¿Qué métrica los distingue y por qué las otras no?
  • Con tus palabras: ¿qué relación hay entre Precision@K de IR y Context Precision de Ragas, y en qué se diferencian al decidir "relevante"?
  • ¿Qué sigue sin estar claro? Anótalo. Si es "cómo evalúo qué tools llamó el agente, no solo lo que recuperó", es la pregunta correcta —la responde L4—.

Referencia rápida

  • Precision@K = relevantes en top-K / K. Pureza del contexto. No rank-aware (corpus D.5).
  • Recall@K = relevantes en top-K / total de relevantes. Cobertura. No rank-aware (corpus D.5).
  • MRR = media de 1/(rank del primer relevante). Rank-aware. Úsala cuando basta un chunk (corpus D.5).
  • NDCG@K = DCG/IDCG, relevancia graduada, descuento por posición. Rank-aware. Por defecto en MTEB Retrieval (corpus D.5).
  • Elegir métrica = elegir el objetivo: pureza (precision), cobertura (recall), primer acierto (MRR), orden graduado (NDCG). k = chunks que el sistema pasa al modelo.
  • Puente con la triad: Context Precision ≈ Precision@K, pero con juez LLM (el de N2) en vez de qrels humanos (corpus D.5). LLMContextPrecisionWithoutReference no exige reference; LLMContextRecall sí (corpus D.2).