DanLevy.net

¡Combate el Caos con Evals!

Los benchmarks miden benchmarks. Tu sistema necesita sus propias métricas.

Cada modelo nuevo llega vestido con un esmoquin de benchmarks.

MMLU: 92,4 %. HumanEval: 87,2 %. LLeMU: 88,7 %. MATH: 73,6 %. AGI: ¡127 %!

Sin embargo, para el 99 % de las empresas que construyen procesos y productos con IA, nada de eso importa.

¿Qué importa? ¿Cómo le va a TUS cargas de trabajo? ¿Mejorando o empeorando? La única forma sensata de saberlo es escribir Evals (pruebas para LLMs) que reflejen las tareas específicas, los datos y los modos de fallo de tu sistema.

Los benchmarks no mienten. Están respondiendo a la pregunta de otra persona.


Lo Que Realmente Cuesta la “Evaluación Basada en Corazonadas”

El enfoque estándar: lanzar un cambio de modelo, vigilar los canales de quejas, hacer rollback si la sala se pone ruidosa.

Eso se pierde casi todo lo interesante:

Solo capturas fallos ruidosos. ¿Los usuarios que reciben una respuesta confidentemente incorrecta y no se dan cuenta? Silencio. ¿Los usuarios que reciben una peor respuesta y abandonan la función? Silencio. Los tickets de soporte y las tasas de error capturan solo una fracción de la regresión de calidad.

No puedes distinguir regresiones de mejoras. Si el nuevo modelo es mejor en la tarea A y peor en la tarea B, las quejas sobre B se ven idénticas a un genérico “la IA empeoró”. No sabes qué arreglar.

Estás usando a tus usuarios como infraestructura de pruebas. No se apuntaron para eso.


El Espectro de Evaluación (y Dónde la Mayoría de los Equipos se Equivoca)

Los enfoques de evaluación se sitúan en un espectro que va de “rápido pero frágil” a “costoso pero válido”.

Un diagrama de espectro que compara verificaciones deterministas, LLM como juez y evaluación humana por velocidad, costo y validez.

Usa el método de evaluación más barato que pueda detectar honestamente el fallo.

LLM como juez es la favorita actual: pedirle a un modelo potente que califique las salidas de otro modelo. Rápido, escalable, barato. El problema: incorpora los sesgos del modelo calificador, puede ser manipulado y crea una dependencia circular. Si usas GPT-5 para calificar las salidas de GPT-5, estás midiendo algo así como “cuánto está de acuerdo GPT-5 consigo mismo”. Eso no es nada, pero no es lo que crees.

Evaluación humana es el estándar de oro que todos intentan saltarse. Conseguir que humanos evalúen salidas es caro, lento, inconsistente entre evaluadores y molesto de programar. Pero es lo único que valida si tu sistema es útil para humanos reales.

Verificaciones automatizadas específicas de tarea es donde la mayoría de los equipos debería dedicar más tiempo. No son glamurosas, pero son rápidas, deterministas y están vinculadas a lo que importa en tu sistema.


Lo Que Realmente Funciona

1. Define el Fallo Antes de Lanzar

Antes de cambiar un modelo o prompt, escribe cómo se ve lo malo. Específicamente.

No “la salida debe ser precisa”. Eso no es una prueba. Más bien algo como:

Puedes verificar esto programáticamente. Sin modelo juez necesario.

Arnés de evaluación: verificaciones deterministas

type EvalResult = { passed: boolean; reason?: string };
const evals: Record<string, (output: string, context: EvalContext) => EvalResult> = {
// JSON debe parsearse
validJson: (output) => {
try {
JSON.parse(output);
return { passed: true };
} catch (e) {
return { passed: false, reason: `JSON inválido: ${e.message}` };
}
},
// Sin citas alucinadas — cada afirmación debe aparecer en el contexto
groundedCitations: (output, { retrievedChunks }) => {
const claims = extractCitations(output);
const ungrounded = claims.filter(
(claim) => !retrievedChunks.some((chunk) => chunk.includes(claim))
);
return ungrounded.length === 0
? { passed: true }
: { passed: false, reason: `Afirmaciones sin fundamento: ${ungrounded.join(', ')}` };
},
// Verificación de longitud de respuesta — detectar truncamiento o generación descontrolada
reasonableLength: (output) => {
const words = output.split(/\s+/).length;
return words >= 10 && words <= 2000
? { passed: true }
: { passed: false, reason: `Recuento de palabras ${words} fuera de rango` };
},
};

2. Construye un Conjunto Dorado Desde Tus Peores Días

Tus mejores datos de evaluación son el material vergonzoso: las salidas que hicieron que alguien presentara un ticket, capturar una alucinación en captura de pantalla, o dejara de usar la función en silencio.

Cada vez que un usuario reporta una mala salida, marca una alucinación, o notas un fallo manualmente, añádelo a tu conjunto dorado: la entrada, el contexto y el comportamiento correcto. Mantén 50-100 casos y ejecútalos en cada cambio de modelo.

Esto parece manual al principio. Después de seis meses, tienes un conjunto de pruebas que ningún benchmark público puede manipular, porque cada caso vino de tu propia historia de fallos.

Un diagrama de flujo que muestra cómo los malos incidentes de producción se convierten en casos dorados, luego se ejecutan evals en CI, luego se bloquean regresiones o se aprueban lanzamientos.

Un conjunto dorado convierte el material vergonzoso en un conjunto de pruebas de regresión.

Forma de un caso dorado

interface GoldenCase {
id: string;
input: string;
context: Record<string, unknown>;
expectedBehavior: {
mustContain?: string[];
mustNotContain?: string[];
structureCheck?: (output: string) => boolean;
minSimilarityToReference?: number; // similitud de coseno con una respuesta de referencia
};
sourceIncident?: string; // enlace al informe de bug o ticket
}

3. Pruebas de Regresión, No Solo Pruebas de Aceptación

La mayoría de los equipos ejecutan evals solo cuando consideran un cambio de modelo. Eso es prueba de aceptación: “¿es esta nueva cosa lo suficientemente buena?”

También necesitas pruebas de regresión: “¿rompió esto algo que antes funcionaba?”

Ejecuta tu conjunto dorado en cada cambio de prompt, no solo en cambios de modelo. Un prompt que estaba funcionando bien puede degradarse silenciosamente cuando añades una nueva herramienta, cambias una estrategia de recuperación RAG, o actualizas tu plantilla de contexto. No lo sabrás sin una línea base. Herramientas como Langfuse adjuntan puntuaciones de eval a trazas de producción para que la regresión aparezca en dashboards, no solo en informes de incidentes.

Arnés de evaluación: comparación de línea base vs candidato
async function compareModelVersions(
goldenCases: GoldenCase[],
baselinePipeline: Pipeline,
candidatePipeline: Pipeline
) {
const results = await Promise.all(
goldenCases.map(async (tc) => {
const [baseline, candidate] = await Promise.all([
baselinePipeline.run(tc.input, tc.context),
candidatePipeline.run(tc.input, tc.context),
]);
return {
id: tc.id,
baselinePassed: runEvals(baseline, tc.expectedBehavior),
candidatePassed: runEvals(candidate, tc.expectedBehavior),
regression: /* línea base pasó */ && /* candidato falló */,
improvement: /* línea base falló */ && /* candidato pasó */,
};
})
);
const regressions = results.filter((r) => r.regression);
const improvements = results.filter((r) => r.improvement);
console.log(`Regresiones: ${regressions.length} / ${goldenCases.length}`);
console.log(`Mejoras: ${improvements.length} / ${goldenCases.length}`);
if (regressions.length > 0) {
console.error('Regresiones bloqueantes encontradas:');
regressions.forEach((r) => console.error(` - ${r.id}`));
}
return { regressions, improvements };
}

Si un candidato retrocede en fallos conocidos, la conversación de actualización se vuelve maravillosamente específica: qué casos mejoraron, qué casos se rompieron, y si el intercambio vale la pena.

4. Usa LLM como Juez Para Exactamente Una Cosa

LLM como juez es útil para salidas abiertas donde no hay una respuesta determinista correcta: “¿es esta respuesta útil?”, “¿este resumen preserva los puntos clave?”, “¿esta explicación es adecuada para un principiante?”

Úsalo ahí. No lo uses para respuestas deterministas. Cuando lo uses, haz explícita la rúbrica de calificación:

Arnés de evaluación: juez basado en rúbrica

async function judgeHelpfulness(
userQuery: string,
modelResponse: string
): Promise<{ score: number; reasoning: string }> {
const judgePrompt = `
Estás evaluando una respuesta de soporte al cliente.
Pregunta del usuario: ${userQuery}
Respuesta: ${modelResponse}
Califica la respuesta en una escala del 1 al 5:
5 = Responde directamente la pregunta con información precisa y accionable
4 = Responde la pregunta pero podría ser más específica o accionable
3 = Aborda parcialmente la pregunta; falta información clave
2 = Relacionado tangencialmente pero no responde la pregunta
1 = Fuera de tema, factualmente incorrecto o dañino
Responde con JSON: {"score": <number>, "reasoning": "<una oración>"}
`;
const result = await judgeModel.generate(judgePrompt);
return JSON.parse(result);
}

Una rúbrica explícita reduce la varianza del evaluador, te da una salida interpretable y facilita auditar cuándo el juez se equivoca. Bibliotecas como Autoevals y Braintrust incluyen rúbricas predefinidas para tareas comunes — vale la pena robarlas antes de escribir las tuyas desde cero.


Herramientas Que Vale la Pena Conocer

No tienes que construir todo esto desde cero. Varias herramientas han avanzado seriamente en el problema de la infraestructura de evaluación:

Braintrust — Plataforma completa de evaluación con seguimiento de experimentos, gestión de datasets y funciones de puntuación. Organiza ejecuciones de evaluación por prompt, modelo y despliegue para que puedas comparar la calidad a lo largo del tiempo, no solo entre lanzamientos. Funciona bien con su biblioteca de código abierto Autoevals, que incluye funciones de puntuación predefinidas calibradas por modelo para tareas comunes (precisión factual, utilidad, toxicidad, similitud semántica).

Langfuse — Observabilidad LLM de código abierto que se sitúa entre tu aplicación y tus modelos. Rastrea cada llamada, adjunta puntuaciones de evaluación (humanas o automatizadas) a spans individuales, y muestra tendencias de calidad sobre el tráfico de producción. Buena opción si quieres observabilidad y evaluación en la misma herramienta en lugar de un arnés de evaluación separado.

Evalite — Framework de evaluación nativo de TypeScript creado por Matt Pocock. Baja ceremonia: define una tarea, define un puntuador, ejecútalo en tu configuración de pruebas existente. Apunta a equipos que quieren evaluaciones que se sientan como pruebas unitarias en lugar de una plataforma separada de experimentos de ML.

promptfoo — Ejecutor de evaluación CLI-first centrado en la comparación de prompts y pruebas de penetración. Fácil de configurar vía YAML, se integra con la mayoría de proveedores de modelos, y tiene soporte integrado para detectar inyección de prompts y otras entradas adversarias.

deepeval — Framework de evaluación en Python con una gran biblioteca de métricas integradas (G-Eval, fidelidad RAG, relevancia de respuestas, detección de alucinaciones). Útil para pipelines RAG donde quieres calificación específica para la calidad de recuperación, no solo la calidad de generación.

La herramienta correcta depende de tu stack y de dónde estás empezando. Lo que importa más que la elección de framework es la disciplina de ejecutar evaluaciones en absoluto — de forma consistente, en cada cambio significativo.


La Parte Incómoda

La mayoría de los equipos saltan esto porque plantea una pregunta irritante pronto: ¿cómo se vería lo “bueno” aquí?

Eso es genuinamente difícil para una nueva función de IA. También es no negociable si te importa la fiabilidad. Los equipos que lanzan IA confiable están haciendo lo mismo que harían para cualquier ruta de código crítica: definir comportamiento esperado, probarlo, y ejecutar esas pruebas continuamente.

Los benchmarks no mienten. Están respondiendo a la pregunta de otra persona. Deja de leerlos como hojas de ruta de producto y empieza a escribir pruebas que coincidan con tu sistema.

Tus usuarios lo notarán antes que tus dashboards. Construye el conjunto de pruebas primero.