Saltar al contenido
Lección 10 de 12

Metricas de Evaluacion

9 min read

Por que la Evaluacion Importa

Construir un pipeline RAG es una cosa. Saber si realmente funciona bien es otra. Sin evaluacion rigurosa, estas volando a ciegas -- haciendo cambios a tu estrategia de chunking, modelo de embedding o parametros de recuperacion sin forma de medir si las cosas mejoraron o empeoraron.

La evaluacion de RAG es mas dificil que la evaluacion tradicional de ML porque hay multiples etapas que pueden fallar independientemente. El retriever podria encontrar los documentos correctos pero el LLM podria alucinar de todos modos. El LLM podria generar una respuesta perfecta pero desde contexto irrelevante. Necesitas metricas que evaluen cada etapa por separado y el pipeline como un todo.

Las Cuatro Metricas Clave

Fidelidad (Faithfulness)

La respuesta generada refleja con precision lo que dice el contexto recuperado? Una respuesta fiel no agrega informacion que no esta en el contexto y no contradice el contexto.

  • Alta fidelidad: La respuesta solo afirma cosas que estan en los documentos recuperados.
  • Baja fidelidad: La respuesta incluye afirmaciones que no se encuentran en el contexto (alucinaciones).

Relevancia de la Respuesta

La respuesta generada realmente aborda la pregunta del usuario? Una respuesta puede ser fiel al contexto pero perder completamente el punto de la pregunta.

  • Alta relevancia: La respuesta aborda directamente lo que se pregunto.
  • Baja relevancia: La respuesta discute temas tangencialmente relacionados o malinterpreta la pregunta.

Precision del Contexto

De los fragmentos recuperados, cuantos son realmente relevantes para la pregunta? Una alta precision de contexto significa que el retriever no esta desperdiciando espacio de ventana de contexto en documentos irrelevantes.

  • Alta precision: La mayoria de los fragmentos recuperados son utiles para responder la pregunta.
  • Baja precision: El retriever retorna muchos fragmentos que no son relevantes.

Recall del Contexto

De toda la informacion relevante en la base de conocimiento, cuanto encontro realmente el retriever? Un alto recall significa que el retriever no esta perdiendo documentos importantes.

  • Alto recall: El retriever encuentra toda (o la mayoria) de la informacion relevante.
  • Bajo recall: El retriever pierde documentos clave que contienen la respuesta.

El Framework RAGAS

RAGAS (Retrieval Augmented Generation Assessment) es el framework mas ampliamente usado para evaluar sistemas RAG. Proporciona metricas automatizadas para las cuatro dimensiones.

Configurando RAGAS

from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)
from datasets import Dataset

# Preparar tu dataset de evaluacion
eval_data = {
    "question": [
        "Cual es la politica de vacaciones para nuevos empleados?",
        "Como envio un reporte de gastos?",
        "Cual es el codigo de vestimenta?",
    ],
    "answer": [
        # Respuestas generadas por tu pipeline RAG
        "Los nuevos empleados reciben 15 dias de PTO en su primer ano.",
        "Envia reportes de gastos a traves del portal de RRHH dentro de 30 dias.",
        "El codigo de vestimenta es casual de negocios de lunes a jueves.",
    ],
    "contexts": [
        # Contextos recuperados (lista de strings por pregunta)
        ["Los nuevos empleados tienen derecho a 15 dias de tiempo libre pagado..."],
        ["Los reportes de gastos deben enviarse via el portal de RRHH..."],
        ["Nuestra politica de codigo de vestimenta requiere vestimenta casual de negocios..."],
    ],
    "ground_truth": [
        # Respuestas de referencia (para calculo de recall)
        "Los nuevos empleados obtienen 15 dias de PTO, acumulando 1.25 dias por mes.",
        "Usa el portal de RRHH para enviar reportes de gastos dentro de 30 dias del gasto.",
        "Casual de negocios de lunes a jueves, casual los viernes.",
    ],
}

dataset = Dataset.from_dict(eval_data)

# Ejecutar evaluacion
results = evaluate(
    dataset,
    metrics=[
        faithfulness,
        answer_relevancy,
        context_precision,
        context_recall,
    ],
)

print(results)
# {'faithfulness': 0.92, 'answer_relevancy': 0.88,
#  'context_precision': 0.85, 'context_recall': 0.78}

Interpretando Puntuaciones RAGAS

  • Faithfulness > 0.9: Tu LLM se mantiene fundamentado en el contexto. Bien.
  • Answer Relevance > 0.85: Las respuestas abordan las preguntas correctamente.
  • Context Precision > 0.8: Tu retriever esta encontrando documentos relevantes.
  • Context Recall > 0.75: Tu retriever no esta perdiendo demasiado.

Puntuaciones por debajo de estos umbrales indican areas especificas a mejorar. Baja fidelidad significa que necesitas mejor prompting o un LLM mas confiable. Baja precision de contexto significa que tu recuperacion es demasiado amplia. Bajo recall significa que tu recuperacion es demasiado estrecha.

Construyendo un Dataset de Evaluacion

La calidad de tu evaluacion depende enteramente de la calidad de tu conjunto de datos de prueba. Asi es como construir uno:

Curacion Manual (Estandar de Oro)

Haz que expertos del dominio creen pares de pregunta-respuesta de tus documentos reales. Consume tiempo pero produce los datos de evaluacion mas confiables.

# Estructura para un dataset de evaluacion curado manualmente
eval_questions = [
    {
        "question": "Cual es la duracion maxima del permiso parental?",
        "ground_truth": "Los empleados pueden tomar hasta 16 semanas de permiso parental.",
        "source_document": "politicas_rrhh/permiso_parental.md",
        "difficulty": "easy",  # facil, medio, dificil
    },
    {
        "question": "Pueden los empleados combinar permiso parental con PTO?",
        "ground_truth": "Si, los empleados pueden usar PTO acumulado para extender el permiso parental.",
        "source_document": "politicas_rrhh/permiso_parental.md",
        "difficulty": "medium",
    },
]

Generacion Sintetica (Escalable)

Usa un LLM para generar preguntas de tus documentos. Esto escala mejor pero requiere validacion.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOpenAI(model="gpt-4o", temperature=0.7)

def generate_eval_questions(document_text: str, n_questions: int = 5) -> list[dict]:
    """Generar preguntas de evaluacion de un documento."""
    prompt = ChatPromptTemplate.from_messages([
        ("system", """Genera {n} pares de pregunta-respuesta de este documento.
Cada par debe:
- Probar un hecho especifico del documento
- Tener una respuesta clara y verificable
- Variar en dificultad

Retorna como arreglo JSON con campos "question" y "answer".

Documento:
{document}"""),
        ("human", "Genera los pares de pregunta-respuesta."),
    ])

    response = (prompt | llm).invoke({
        "n": n_questions,
        "document": document_text,
    })
    return response.content

# Generar preguntas de cada documento en tu base de conocimiento
# Luego haz que un humano revise y corrija

Consejo: Siempre haz que un humano revise las preguntas de evaluacion generadas sinteticamente. Los LLMs pueden generar preguntas ambiguas, demasiado faciles o con respuestas incorrectas. Una revision de 30 minutos atrapa la mayoria de los problemas.

Evaluacion LLM-como-Juez

Cuando no tienes respuestas de referencia, puedes usar un LLM para evaluar la calidad de tus respuestas RAG. Esto se llama LLM-como-Juez.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

judge_llm = ChatOpenAI(model="gpt-4o", temperature=0)

JUDGE_PROMPT = ChatPromptTemplate.from_messages([
    ("system", """Eres un evaluador imparcial. Califica la calidad de la
respuesta de un asistente de IA a una pregunta del usuario, dado el contexto fuente.

Evalua en tres dimensiones (1-5 cada una):
1. PRECISION: Es la respuesta factualmente correcta basada en el contexto?
2. COMPLETITUD: La respuesta aborda completamente la pregunta?
3. CONCISION: La respuesta es apropiadamente breve sin perder informacion?

Responde con JSON:
{{"accuracy": N, "completeness": N, "conciseness": N, "reasoning": "..."}}"""),
    ("human", """Contexto: {context}

Pregunta: {question}

Respuesta: {answer}

Evalua esta respuesta."""),
])

def evaluate_response(question: str, answer: str, context: str) -> dict:
    """Usar LLM-como-juez para evaluar una respuesta RAG."""
    result = (JUDGE_PROMPT | judge_llm).invoke({
        "context": context,
        "question": question,
        "answer": answer,
    })
    return result.content

Pruebas A/B de Configuraciones RAG

Cuando cambias un componente de tu sistema RAG (nuevo modelo de embedding, diferente tamano de fragmento, re-ranking agregado), necesitas comparar la configuracion vieja y nueva en el mismo conjunto de pruebas.

def ab_test_configs(eval_dataset: list, config_a, config_b) -> dict:
    """Comparar dos configuraciones RAG en el mismo conjunto de evaluacion."""
    results_a = []
    results_b = []

    for item in eval_dataset:
        question = item["question"]

        # Ejecutar configuracion A
        answer_a = config_a["chain"].invoke(question)
        score_a = evaluate_response(question, answer_a, item.get("ground_truth", ""))
        results_a.append(score_a)

        # Ejecutar configuracion B
        answer_b = config_b["chain"].invoke(question)
        score_b = evaluate_response(question, answer_b, item.get("ground_truth", ""))
        results_b.append(score_b)

    return {
        "config_a_avg": sum(results_a) / len(results_a),
        "config_b_avg": sum(results_b) / len(results_b),
        "config_a_details": results_a,
        "config_b_details": results_b,
    }

Protocolos de Evaluacion Humana

Las metricas automatizadas son valiosas pero no son el cuadro completo. La evaluacion humana captura matices que los LLM-jueces pierden: tono de la respuesta, calidad del formato, utilidad y si la respuesta realmente seria util para el usuario final.

Protocolo Simple de Pulgar Arriba/Abajo

Para cada respuesta RAG, haz que los evaluadores respondan:

  1. La respuesta es correcta? (Si/No)
  2. La respuesta es completa? (Si/No)
  3. Confiarias en esta respuesta? (Si/No)
  4. Falta alguna informacion? (Texto libre)

Protocolo Comparativo

Muestra a los evaluadores la misma pregunta respondida por dos configuraciones RAG diferentes. Preguntales cual respuesta es mejor y por que. Esto es mas confiable que la puntuacion absoluta porque los humanos son mejores en comparaciones que en juicios absolutos.

Evaluacion Continua en Produccion

La evaluacion no es una actividad de una sola vez. Configura evaluacion automatizada que se ejecute en un horario:

import json
from datetime import datetime

def run_eval_suite(chain, eval_dataset: list, output_file: str):
    """Ejecutar suite de evaluacion y guardar resultados."""
    results = []

    for item in eval_dataset:
        answer = chain.invoke(item["question"])
        score = evaluate_response(
            item["question"], answer, item.get("ground_truth", "")
        )
        results.append({
            "question": item["question"],
            "answer": answer,
            "score": score,
            "timestamp": datetime.now().isoformat(),
        })

    # Guardar resultados
    with open(output_file, "w") as f:
        json.dump(results, f, indent=2)

    # Calcular promedios
    avg_score = sum(r["score"] for r in results if isinstance(r["score"], (int, float))) / len(results)
    print(f"Puntuacion promedio: {avg_score:.2f}")

    return results

Consejos para Evaluacion Efectiva

  • Comienza con 50-100 preguntas curadas a mano. Esto es suficiente para obtener resultados estadisticamente significativos y atrapar problemas mayores.
  • Incluye casos limite. Preguntas sin respuesta en la base de conocimiento, preguntas ambiguas, preguntas que abarcan multiples documentos.
  • Rastrea metricas a lo largo del tiempo. Un dashboard mostrando tendencias de fidelidad, relevancia, precision y recall te ayuda a detectar regresiones antes de que los usuarios las noten.
  • Separa la evaluacion de recuperacion de la evaluacion de generacion. Si la fidelidad baja, es porque el retriever encontro los documentos equivocados o porque el LLM alucino? Prueba cada etapa independientemente.
  • Evalua con consultas reales de usuarios. Una vez que tu sistema esta en vivo, registra las consultas reales de usuarios e incluyelas en tu conjunto de evaluacion. Las consultas reales son a menudo mas desordenadas y variadas que las sinteticas.

En la siguiente leccion, aprenderas como endurecer tu sistema RAG para produccion con cache, monitoreo, seguridad y optimizacion de costos.