Un equipo que conozco lanzo un agente de soporte al cliente despues de tres dias de pruebas manuales: unas cuarenta preguntas, les gustaron las respuestas y lo dieron por listo. En menos de una semana, el agente estaba citando con seguridad una politica de reembolsos obsoleta. Le dijo a tres clientes que eran elegibles para reembolsos completos en articulos de venta final. El agente no alucino ni se cayo. Simplemente dio respuestas incorrectas que sonaban plausibles, y nadie lo detecto durante cinco dias.
Esta guia te lleva paso a paso a construir un framework real de evaluacion, uno que puedas ejecutar antes de cada despliegue, detectar regresiones automaticamente y en el que realmente puedas confiar. Construiremos un harness funcional en TypeScript, cubriremos las seis estrategias de evaluacion y te dejaremos con patrones que escalan desde un proyecto personal hasta produccion.
| Lo que aprenderas | Por que importa |
|---|---|
| Puntuacion con LLM-as-judge | Automatiza la evaluacion de calidad con rubricas estructuradas en lugar de revision manual |
| Rubricas multi-criterio | Evalua precision, tono y completitud de forma independiente para identificar fallas con precision |
| Lineas base de regresion | Detecta cambios en prompts y modelos que degradan silenciosamente la calidad |
| Integracion con CI | Bloquea despliegues automaticamente cuando las puntuaciones de eval caen por debajo del umbral |
| Comparacion A/B de prompts | Compara versiones de prompts con numeros, no con intuicion |
| Evals de conversaciones multi-turno | Prueba flujos de dialogo completos, no solo pares individuales de pregunta y respuesta |
Por que los agentes de IA necesitan evals en lugar de pruebas tradicionales
Las pruebas tradicionales son binarias: una funcion devuelve el valor correcto o no. Los agentes de IA no funcionan asi. Hazle la misma pregunta al mismo agente dos veces y obtendras dos respuestas diferentes, ambas potencialmente correctas, ambas redactadas de forma distinta. "El agente hizo un buen trabajo?" no es un booleano. Es un espectro que abarca precision, tono, completitud y adherencia a politicas.
Sin evals, te encontraras con problemas predecibles: ajustes en prompts que arreglan preguntas de facturacion pero degradan silenciosamente las respuestas de envios en un 15%, actualizaciones de modelos que rompen el formato del que dependen tus sistemas downstream, y ninguna forma de comparar enfoques con algo mejor que la intuicion. Los evals te dan numeros donde antes tenias solo sensaciones.
“La evaluacion es el sistema inmunologico de una aplicacion de IA. Sin ella, cada cambio es una infeccion potencial que no detectaras hasta que los sintomas sean obvios.”
Cuales son los seis tipos de evals para agentes de IA?
No todas las evaluaciones funcionan de la misma manera. Cada tipo apunta a un aspecto diferente de la calidad del agente, y los sistemas en produccion tipicamente combinan varios.
1. Evals de coincidencia exacta y heuristicos
El tipo mas simple. La salida contiene una cadena especifica? Es un JSON valido? Esta por debajo de cierta longitud?
function evalFormatting(output: string): boolean {
// Must not contain internal system tags
if (output.includes("[INTERNAL]") || output.includes("{{")) return false;
// Must stay under 500 words
if (output.split(/\s+/).length > 500) return false;
// Must not quote a dollar amount without a disclaimer
const hasDollar = /\$\d+/.test(output);
const hasDisclaimer = /subject to change|may vary|contact.*for.*pricing/i.test(output);
if (hasDollar && !hasDisclaimer) return false;
return true;
}Los evals heuristicos son rapidos, deterministicos y economicos. Usalos como un primer filtro para detectar fallas estructurales obvias antes de gastar dinero en puntuacion con LLM-as-judge.
2. LLM-as-judge
La pieza central de los frameworks modernos de evaluacion. Usas un LLM para evaluar la salida de otro. El judge recibe la pregunta original, la respuesta del agente y una rubrica de puntuacion, y luego devuelve puntuaciones estructuradas con razonamiento.
El prompt del judge importa enormemente. Un prompt vago produce puntuaciones inconsistentes. Uno preciso con rubricas y ejemplos produce puntuaciones que correlacionan fuertemente con el juicio humano.
Input: "What's your return policy?"
Agent output: "You can return any item within 30 days for a
full refund, no questions asked!"
Judge prompt:
- Score ACCURACY (1-5): Is the information factually correct
given the reference policy?
- Score COMPLETENESS (1-5): Did the agent cover all relevant
details (timeframe, conditions, exceptions)?
- Score TONE (1-5): Was the response appropriately helpful
without being misleading?
Judge output:
accuracy: 3 (correct timeframe but omitted the
"original packaging required" condition)
completeness: 2 (missing restocking fee, packaging
requirement, and gift card exception)
tone: 4 (friendly and clear, slightly overpromises
with "no questions asked")3. Evals basados en referencia
Proporcionas una respuesta "estandar de oro" y mides que tan cercana es la respuesta del agente, no como coincidencia exacta de cadenas, sino como similitud semantica o comparacion de significado juzgada por un LLM. Excelente para preguntas factuales con respuestas claramente correctas. Menos util para conversaciones abiertas donde muchas respuestas diferentes podrian ser igualmente buenas.
4. Evals basados en rubrica
En lugar de comparar contra una respuesta de referencia, defines una rubrica, un conjunto estructurado de criterios con niveles de puntuacion. Esto es lo que usaras mas en la practica. Una rubrica para un agente de soporte al cliente podria evaluar precision, empatia, adherencia a politicas y efectividad en la resolucion como dimensiones separadas.
El poder aqui esta en la descomposicion. Un agente puede obtener 5/5 en precision mientras obtiene 2/5 en empatia. Eso te dice exactamente que arreglar, algo que una puntuacion general unica nunca hara. Este es el mismo principio detras de los sistemas estructurados de scorecards.
5. Evals de preferencia humana
Muestras a un humano dos respuestas del agente y preguntas cual es mejor. Con suficientes preferencias agregadas obtienes rankings confiables usando calificaciones Elo o modelos Bradley-Terry.
Los evals de preferencia humana son costosos y lentos, pero son el estandar de oro para la calidad subjetiva. Usalos para calibrar tus evals automatizados: si tu LLM judge constantemente discrepa con las preferencias humanas, tu prompt del judge necesita trabajo.
6. Completitud de tareas de extremo a extremo
El agente realmente logro el objetivo? Se resolvio el problema? Se hizo la reservacion correctamente? Se completaron los campos correctos?
Los evals de completitud de tareas frecuentemente requieren integracion con tus sistemas reales, verificando que se creo un ticket o que se hizo la llamada API correcta. Son el tipo de eval mas realista, pero tambien el mas complejo de configurar. Para agentes que manejan flujos de trabajo de multiples pasos, las pruebas basadas en escenarios te permiten simular conversaciones completas con personas y validar el estado final.
Como construir un harness de evaluacion en TypeScript?
Aqui tienes una implementacion completa y ejecutable. Cuatro componentes: definiciones de casos de prueba, un ejecutor del agente, un evaluador LLM-as-judge y un generador de reportes.
import Anthropic from "@anthropic-ai/sdk";
// — Types ---
interface TestCase {
id: string;
input: string;
context?: string; // optional reference info for the judge
criteria: string[]; // what the judge should evaluate
expectedBehavior: string; // natural language description
}
interface EvalScore {
criterion: string;
score: number; // 1-5
reasoning: string;
}
interface EvalResult {
testCase: TestCase;
agentOutput: string;
scores: EvalScore[];
averageScore: number;
pass: boolean;
latencyMs: number;
}
// — Agent Under Test ---
async function runAgent(
client: Anthropic,
systemPrompt: string,
userMessage: string
): Promise<{ output: string; latencyMs: number }> {
const start = Date.now();
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: systemPrompt,
messages: [{ role: "user", content: userMessage }],
});
const output =
response.content[0].type === "text" ? response.content[0].text : "";
return { output, latencyMs: Date.now() - start };
}
// — LLM-as-Judge ---
const JUDGE_PROMPT = `You are an expert evaluator for AI agent responses.
You will be given:
1. The user's input message
2. The agent's response
3. Context about what the correct behavior should be
4. A list of criteria to evaluate
For each criterion, provide:
- A score from 1-5 (1=terrible, 2=poor, 3=adequate, 4=good, 5=excellent)
- A brief reasoning explaining the score
Think step-by-step before scoring. Consider edge cases and subtle issues.
Respond in this exact JSON format:
{
"scores": [
{
"criterion": "<criterion name>",
"score": <1-5>,
"reasoning": "<1-2 sentence explanation>"
}
]
}`;
async function judgeResponse(
client: Anthropic,
testCase: TestCase,
agentOutput: string
): Promise<EvalScore[]> {
const message = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: JUDGE_PROMPT,
messages: [
{
role: "user",
content: `## User Input
${testCase.input}
## Agent Response
${agentOutput}
## Expected Behavior
${testCase.expectedBehavior}
${testCase.context ? "## Reference Context\n" + testCase.context : ""}
## Criteria to Evaluate
${testCase.criteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}`,
},
],
});
const text =
message.content[0].type === "text" ? message.content[0].text : "{}";
const jsonMatch = text.match(/\{[\s\S]*\}/);
if (!jsonMatch) throw new Error("Judge did not return valid JSON");
const parsed = JSON.parse(jsonMatch[0]);
return parsed.scores;
}
// — Test Runner ---
async function runEvals(
testCases: TestCase[],
systemPrompt: string,
passThreshold: number = 3.5
): Promise<EvalResult[]> {
const client = new Anthropic();
const results: EvalResult[] = [];
for (const testCase of testCases) {
console.log(`Running: ${testCase.id}...`);
const { output, latencyMs } = await runAgent(
client, systemPrompt, testCase.input
);
const scores = await judgeResponse(client, testCase, output);
const avg =
scores.reduce((sum, s) => sum + s.score, 0) / scores.length;
results.push({
testCase,
agentOutput: output,
scores,
averageScore: Math.round(avg * 100) / 100,
pass: avg >= passThreshold,
latencyMs,
});
}
return results;
}
// — Report ---
function printReport(results: EvalResult[]): void {
console.log("\n" + "=".repeat(60));
console.log("EVALUATION REPORT");
console.log("=".repeat(60));
const passed = results.filter((r) => r.pass).length;
console.log(`\nOverall: ${passed}/${results.length} passed\n`);
for (const r of results) {
const icon = r.pass ? "PASS" : "FAIL";
console.log(`[${icon}] ${r.testCase.id} — avg: ${r.averageScore} (${r.latencyMs}ms)`);
for (const s of r.scores) {
console.log(` ${s.criterion}: ${s.score}/5 — ${s.reasoning}`);
}
console.log();
}
}
// — Test Cases ---
const SUPPORT_AGENT_PROMPT = `You are a customer support agent for TechCo.
Our return policy: 30-day returns with original packaging. Restocking
fee of 15% for opened electronics. Gift cards are final sale.
Business hours: Mon-Fri 9am-6pm EST.
Always be helpful, accurate, and empathetic.`;
const testCases: TestCase[] = [
{
id: "eval-001",
input: "I bought a laptop 3 weeks ago and want to return it. I opened the box though.",
context: "30-day return window. Opened electronics have 15% restocking fee.",
criteria: ["Accuracy", "Completeness", "Empathy"],
expectedBehavior:
"Should confirm the return is within the 30-day window, mention the " +
"15% restocking fee for opened electronics, and be empathetic.",
},
{
id: "eval-002",
input: "Can I return a gift card?",
context: "Gift cards are final sale and cannot be returned.",
criteria: ["Accuracy", "Tone", "Policy adherence"],
expectedBehavior:
"Should clearly state that gift cards are final sale and cannot be " +
"returned. Should be empathetic but firm. Must not offer alternatives " +
"that contradict the policy.",
},
{
id: "eval-003",
input: "Your product broke after 2 days! This is unacceptable!",
context: "Defective items within 30 days get full refund, no restocking fee.",
criteria: ["Empathy", "Accuracy", "De-escalation", "Resolution"],
expectedBehavior:
"Should acknowledge frustration, apologize, explain that defective items " +
"qualify for full refund without restocking fee, and offer clear next steps.",
},
{
id: "eval-004",
input: "What are your hours? Also can I return something I bought 45 days ago?",
context: "Hours: Mon-Fri 9-6 EST. Returns within 30 days only.",
criteria: ["Accuracy", "Completeness", "Clarity"],
expectedBehavior:
"Should answer BOTH questions. State business hours correctly AND explain " +
"that the 45-day return is outside the 30-day window. Must not skip either question.",
},
];
// — Run ---
runEvals(testCases, SUPPORT_AGENT_PROMPT).then(printReport);Instala el SDK (npm install @anthropic-ai/sdk), configura tu variable de entorno ANTHROPIC_API_KEY y ejecutalo con npx tsx eval-harness.ts.
Esto es lo que hace cada pieza:
Los casos de prueba definen la entrada, el comportamiento esperado, el contexto de referencia y criterios especificos. Cada criterio obtiene su propia puntuacion; no estas colapsando todo en un solo numero.
El ejecutor del agente llama a tu LLM y captura tanto la salida como la latencia. En produccion, reemplazarias esto por una llamada a la API real de tu agente.
El LLM judge recibe el caso de prueba, la respuesta y una rubrica. Usa razonamiento de cadena de pensamiento antes de puntuar, lo que mejora significativamente la consistencia. Devuelve JSON estructurado con puntuaciones por criterio.
El reporte muestra aprobado/reprobado con un desglose detallado para que puedas ver que criterios fallaron y por que.
Una nota sobre el diseno del prompt del judge
El prompt del judge es la pieza mas importante de tu framework de evaluacion. Tres principios:
Se especifico sobre lo que significa cada nivel de puntuacion. "Puntua del 1 al 5" es demasiado vago. Agrega ejemplos anclados: "Una puntuacion de 3 significa que la respuesta es factualmente correcta pero incompleta. Una puntuacion de 5 significa que la respuesta es correcta, completa y aborda proactivamente las preguntas de seguimiento probables."
Pide razonamiento antes de la puntuacion. Cuando el judge explica su pensamiento primero, las puntuaciones son mas consistentes. Esto es prompting de cadena de pensamiento aplicado a la evaluacion.
Usa un modelo fuerte para juzgar. Tu judge debe ser al menos tan capaz como el modelo que estas evaluando. Un judge mas debil produce resultados poco confiables.
Que metricas de eval realmente importan?
Metricas de calidad
Precision -- Es la respuesta factualmente correcta? No negociable para agentes en produccion. Midela por respuesta con puntuacion LLM-as-judge contra hechos conocidos o documentos de referencia.
Fidelidad -- La respuesta se mantiene fundamentada en el contexto proporcionado? Un agente que es "preciso" pero se basa en datos de entrenamiento en lugar de tu base de conocimiento es un riesgo. La fidelidad mide si las afirmaciones estan respaldadas por el contexto recuperado, no solo si resultan ser verdaderas.
Relevancia -- El agente respondio lo que el usuario pregunto? Una respuesta precisa y fiel que no contesta la pregunta sigue siendo un fallo.
Completitud -- La respuesta cubrio todo lo que debia? Omitir la tarifa de reposicion al explicar la politica de devoluciones no es impreciso, es incompleto. Modo de falla diferente, puntuacion diferente.
Metricas operacionales
Latencia -- Rastrea tanto p50 como p95. Para agentes conversacionales, cualquier cosa por encima de 3 segundos en p95 se siente roto.
Costo por evaluacion -- Si tu suite completa de evals cuesta $50, no la ejecutaras con suficiente frecuencia. Optimiza para centavos por ejecucion para poder ejecutar en cada PR.
Uso de tokens -- Rastrea tokens de entrada y salida por separado. Los agentes verbosos cuestan mas y frecuentemente ofrecen peores experiencias.
Metricas agregadas
Tasa de aprobacion -- Porcentaje de casos de prueba que pasan tu umbral. Rastreala en el tiempo. Una tasa de aprobacion decreciente es una senal de alerta temprana.
Puntuacion promedio por criterio -- Precision promedio en todos los casos, empatia promedio, y asi sucesivamente. Muestra que dimensiones son fuertes y cuales necesitan trabajo.
Varianza de puntuacion -- Alta varianza significa comportamiento inconsistente. Tu agente podria aprobar 8 de 10 pruebas de empatia pero fallar completamente las otras 2. Promedios bajos son un problema sistematico; alta varianza es un problema de robustez.
Promedios por criterio a lo largo de una suite de pruebas. De-escalation y completitud necesitan trabajo, aunque el promedio general se ve aceptable.
Como deberias disenar tu conjunto de evals?
Tu conjunto de evals es la coleccion de casos de prueba que ejecutas contra tu agente. La calidad de la cobertura importa mucho mas que la cantidad.
Cobertura sobre volumen
Veinte casos de prueba bien disenados que cubran tus escenarios clave superan a doscientos aleatorios. Estructura por categorias de conversacion:
| Categoria | Casos de prueba de ejemplo |
|---|---|
| Camino feliz | Preguntas estandar con respuestas claras |
| Casos limite | Condiciones de frontera (dia 30 de una ventana de devolucion de 30 dias) |
| Conflictos de politica | El usuario quiere algo que la politica no permite |
| Preguntas de multiples partes | Dos o tres preguntas en un solo mensaje |
| Usuarios emocionales | Llamadores frustrados, confundidos o molestos |
| Entradas ambiguas | Preguntas que podrian significar multiples cosas |
| Fuera de alcance | Preguntas que el agente no deberia intentar responder |
| Adversariales | Intentos de hacer que el agente rompa sus reglas |
El conjunto de pruebas dorado
Mantiene un conjunto curado de 20 a 50 casos de prueba como tu suite de regresion. Estos no cambian a menos que la politica subyacente lo haga. Cada edicion de prompt, cambio de modelo y actualizacion de configuracion se ejecuta contra este conjunto antes del despliegue.
Cuando un bug de produccion aparece, agrega un caso de prueba para el. Tu conjunto dorado debe crecer con el tiempo, acumulando conocimiento ganado con esfuerzo de cada falla.
Versionado y seguimiento
Versiona tu conjunto de evals como codigo. Cuando cambies un caso de prueba, deberias saber por que. Cuando las puntuaciones cambien entre ejecuciones, necesitas poder distinguir si cambio el agente o la prueba.
Almacena los resultados de eval con metadatos: version del prompt, modelo, version del conjunto de evals, marca de tiempo. Esto crea la pista de auditoria que necesitas para depurar regresiones. El monitoreo en produccion complementa esto detectando problemas que tu conjunto de evals no anticipo.
Como ejecutar evals en CI en cada pull request?
Aqui tienes un workflow de GitHub Actions que ejecuta tu suite de evals y bloquea el merge si las puntuaciones caen:
name: Agent Evals
on:
pull_request:
paths:
- "prompts/**"
- "src/agent/**"
- "eval/**"
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm ci
- name: Run eval suite
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: npx tsx eval/run.ts --output eval-results.json
- name: Check thresholds
run: |
node -e "
const r = require('./eval-results.json');
const failed = r.results.filter(t => !t.pass);
if (failed.length > 0) {
console.log('FAILED EVALS:');
failed.forEach(f => console.log(' ' + f.testCase.id + ': ' + f.averageScore));
process.exit(1);
}
const avgScore = r.results.reduce((s,t) => s + t.averageScore, 0) / r.results.length;
if (avgScore < 4.0) {
console.log('Average score ' + avgScore + ' below threshold 4.0');
process.exit(1);
}
console.log('All evals passed. Average: ' + avgScore.toFixed(2));
"
- name: Comment results on PR
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = JSON.parse(fs.readFileSync('eval-results.json', 'utf8'));
const passed = results.results.filter(r => r.pass).length;
const total = results.results.length;
const avg = (results.results.reduce((s,r) => s + r.averageScore, 0) / total).toFixed(2);
let body = '## Agent Eval Results\n\n';
body += '| Test | Score | Status |\n|------|-------|--------|\n';
results.results.forEach(r => {
const status = r.pass ? 'Pass' : 'Fail';
body += '| ' + r.testCase.id + ' | ' + r.averageScore + ' | ' + status + ' |\n';
});
body += '\n**Average: ' + avg + '** | **' + passed + '/' + total + ' passed**';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});El workflow se activa con cambios en prompts o codigo del agente. Ejecuta la suite completa de evals, verifica los umbrales y publica un resumen en el PR. Las puntuaciones fallidas bloquean el merge.
Control de costos. Cada ejecucion llama a tu LLM dos veces por caso de prueba (agente + judge). Con 30 casos, son 60 llamadas, tipicamente entre $0.50 y $2.00 en total.
Inestabilidad. Las puntuaciones del LLM-as-judge tienen varianza natural. Una prueba que obtiene 3.8 en una ejecucion podria dar 3.4 la proxima vez. Establece tu umbral de aprobacion con margen, o ejecuta cada caso tres veces y toma la mediana.
Velocidad. Ejecuta los casos de prueba en paralelo cuando sea posible. Una suite de 30 casos ejecutandose secuencialmente tarda alrededor de 3 minutos. Lotes de 10 la reducen a menos de un minuto.
Como detectar regresiones con lineas base de eval?
Almacena una linea base de puntuaciones aprobatorias en un archivo JSON commiteado en tu repositorio. Despues de cada ejecucion, compara las puntuaciones actuales contra la linea base y marca cualquier criterio que caiga mas alla de tu umbral.
interface Baseline {
[testCaseId: string]: {
[criterion: string]: number; // baseline score
};
}
function checkRegressions(
results: EvalResult[],
baseline: Baseline,
regressionThreshold: number = 1.0
): { testId: string; criterion: string; drop: number }[] {
const regressions: { testId: string; criterion: string; drop: number }[] = [];
for (const result of results) {
const baselineScores = baseline[result.testCase.id];
if (!baselineScores) continue;
for (const score of result.scores) {
const baseScore = baselineScores[score.criterion];
if (baseScore === undefined) continue;
const drop = baseScore - score.score;
if (drop >= regressionThreshold) {
regressions.push({
testId: result.testCase.id,
criterion: score.criterion,
drop,
});
}
}
}
return regressions;
}
// Usage: after running evals, check for regressions
const regressions = checkRegressions(results, previousBaseline);
if (regressions.length > 0) {
console.error("REGRESSIONS DETECTED:");
regressions.forEach((r) =>
console.error(` ${r.testId} / ${r.criterion}: dropped ${r.drop} points`)
);
process.exit(1);
}Actualiza tu linea base despues de cada ejecucion exitosa de eval con la que estes conforme. Esto crea un mecanismo de calidad tipo trinquete: las puntuaciones solo pueden subir, nunca degradarse silenciosamente.
Patrones avanzados
Comparacion A/B de evals
Cuando pruebes una nueva version de prompt, ejecuta los mismos casos contra ambos prompts y compara:
async function comparePrompts(
testCases: TestCase[],
promptA: string,
promptB: string
): Promise<void> {
const resultsA = await runEvals(testCases, promptA);
const resultsB = await runEvals(testCases, promptB);
console.log("\nA/B COMPARISON");
console.log("=" .repeat(50));
console.log("Test ID | Prompt A | Prompt B | Delta");
console.log("-".repeat(50));
let totalA = 0, totalB = 0;
for (let i = 0; i < testCases.length; i++) {
const a = resultsA[i].averageScore;
const b = resultsB[i].averageScore;
const delta = b - a;
const arrow = delta > 0 ? "+" : "";
totalA += a;
totalB += b;
console.log(
`${testCases[i].id.padEnd(18)}| ${a.toFixed(2).padEnd(9)}| ${b.toFixed(2).padEnd(9)}| ${arrow}${delta.toFixed(2)}`
);
}
const avgA = totalA / testCases.length;
const avgB = totalB / testCases.length;
console.log("-".repeat(50));
console.log(
`Average | ${avgA.toFixed(2).padEnd(9)}| ${avgB.toFixed(2).padEnd(9)}| ${(avgB - avgA > 0 ? "+" : "")}${(avgB - avgA).toFixed(2)}`
);
}Esto es esencial para flujos de trabajo de ingenieria de prompts. En lugar de adivinar si un cambio ayudo, obtienes una tabla de comparacion clara.
Evals de conversaciones multi-turno
Los agentes reales manejan conversaciones completas, no preguntas aisladas. Evaluar interacciones multi-turno requiere rastrear el contexto a traves de los turnos:
interface ConversationTestCase {
id: string;
turns: { role: "user" | "assistant"; content: string }[];
// The last turn is the one we evaluate; earlier turns are context
criteria: string[];
expectedBehavior: string;
}
async function runConversationEval(
client: Anthropic,
systemPrompt: string,
testCase: ConversationTestCase
): Promise<EvalResult> {
// Build message history from all turns except the last user message
const messages = testCase.turns.slice(0, -1).map((t) => ({
role: t.role as "user" | "assistant",
content: t.content,
}));
// Add the final user message
const lastTurn = testCase.turns[testCase.turns.length - 1];
messages.push({ role: "user", content: lastTurn.content });
const start = Date.now();
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: systemPrompt,
messages,
});
const output = response.content[0].type === "text"
? response.content[0].text : "";
// Judge with full conversation context
const scores = await judgeResponse(client, {
id: testCase.id,
input: testCase.turns.map(
(t) => `${t.role}: ${t.content}`
).join("\n"),
criteria: testCase.criteria,
expectedBehavior: testCase.expectedBehavior,
}, output);
const avg = scores.reduce((s, sc) => s + sc.score, 0) / scores.length;
return {
testCase: {
id: testCase.id,
input: lastTurn.content,
criteria: testCase.criteria,
expectedBehavior: testCase.expectedBehavior,
},
agentOutput: output,
scores,
averageScore: Math.round(avg * 100) / 100,
pass: avg >= 3.5,
latencyMs: Date.now() - start,
};
}Los evals multi-turno detectan perdida de contexto: un agente que maneja bien preguntas individuales podria olvidar detalles de antes en la conversacion. Los analytics en produccion te diran donde ocurren estos quiebres con mayor frecuencia.
Evaluacion consciente de costos
Rastrea los costos de eval para poder optimizarlos. Aqui tienes un estimador rapido:
function estimateCost(
results: EvalResult[],
pricePerKInput: number = 0.003,
pricePerKOutput: number = 0.015
): { totalCost: number; costPerCase: number } {
// ~200 input tokens per agent call, ~300 per judge call, ~200 output each
const totalInputTokens = results.length * 500;
const totalOutputTokens = results.length * 400;
const inputCost = (totalInputTokens / 1000) * pricePerKInput;
const outputCost = (totalOutputTokens / 1000) * pricePerKOutput;
const totalCost = Math.round((inputCost + outputCost) * 10000) / 10000;
return {
totalCost,
costPerCase: Math.round(totalCost / results.length * 10000) / 10000,
};
}Que frameworks de eval deberias conocer?
No tienes que construir todo tu mismo. El ecosistema ha madurado.
Braintrust conecta la puntuacion de eval con el rastreo en produccion, la gestion de datasets y la aplicacion de reglas de lanzamiento basadas en CI. Buena opcion si quieres una plataforma gestionada que cubra todo el ciclo de vida de las evaluaciones.
DeepEval es open-source con metricas plug-and-play e integracion con pytest. Se integra directamente en tu suite de pruebas sin necesidad de una plataforma separada.
RAGAS se enfoca en la evaluacion de RAG con metricas de recuperacion y generacion respaldadas por investigacion. Si tu agente depende de la generacion aumentada por recuperacion, las metricas de RAGAS como fidelidad y relevancia de respuesta valen la pena agregarlas.
Langfuse ofrece observabilidad open-source con evaluacion integrada. Buena para equipos que quieren auto-hospedar.
Promptfoo se enfoca en red-teaming y validacion de seguridad junto con evals estandar.
El harness que construiste antes te da los patrones fundamentales. Estas plataformas agregan infraestructura gestionada, metricas preconstruidas y dashboards sobre las mismas ideas.
Lista de verificacion de mejores practicas
- Comienza con 20-30 casos de prueba bien disenados que cubran caminos felices, casos limite y entradas adversariales
- Usa LLM-as-judge con una rubrica detallada, no un prompt vago de "califica esto del 1 al 5"
- Evalua multiples criterios de forma independiente (precision, completitud, tono, adherencia a politicas)
- Ejecuta evals en CI en cada PR que modifique prompts o codigo del agente
- Mantiene un conjunto de pruebas dorado que crezca con cada bug de produccion
- Almacena lineas base y verifica regresiones: la calidad debe subir como trinquete, nunca degradarse silenciosamente
- Rastrea costo y latencia junto con las puntuaciones de calidad
- Ejecuta comparaciones A/B cuando pruebes cambios en prompts, nunca adivines
- Usa un modelo fuerte como judge (al menos tan capaz como el modelo que estas evaluando)
- Agrega evals de conversaciones multi-turno, no solo Q&A de un solo turno
- Versiona tu conjunto de evals y rastrea los cambios junto con los cambios de codigo
- Revisa las puntuaciones del judge contra el juicio humano trimestralmente para verificar la calibracion
A donde ir desde aqui
Tienes los bloques de construccion: diseno de casos de prueba, puntuacion con LLM-as-judge, deteccion de regresiones, integracion con CI y codigo funcional en TypeScript que puedes copiar directamente. Eso es suficiente para detectar la mayoria de los problemas antes de que lleguen a produccion.
Si estas empezando, pon a funcionar el harness y escribe casos de prueba para tus diez interacciones con clientes mas comunes. Ya ejecutas evals? Enfocate en la integracion con CI y las lineas base de regresion. Ya tienes todo eso? Explora la evaluacion multi-turno y la comparacion A/B para optimizacion de prompts.
Si prefieres no construir desde cero, los sistemas de scorecard y pruebas de escenarios de Chanl proporcionan flujos de trabajo de evaluacion listos para produccion, pero los principios aqui aplican independientemente de las herramientas que uses.
Empieza a medir. Deja de adivinar.
Co-founder
Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.
Aprende IA Agéntica
Una lección por semana: técnicas prácticas para construir, probar y lanzar agentes IA. Desde ingeniería de prompts hasta monitoreo en producción. Aprende haciendo.



