Localización de errores por paso: usar la evaluación de trayectoria para encontrar dónde fallan los agentes
Usa el esquema trajectory_eval de Potato para localizar errores paso a paso con taxonomías jerárquicas, puntuación por severidad y seguimiento de una puntuación corriente en trazas de agentes.
El problema: saber que el agente falló no basta
A trajectory error taxonomy
Ejecutas tu agente sobre un benchmark. Saca un 63% en tasa de finalización de tareas. ¿Y ahora qué?
Un número de aprobado/suspenso te dice que el agente falló en el 37% de las tareas y nada más. No te dice en qué punto de la traza se torció la cosa, qué tipo de error cometió el agente ni cómo de grave fue. ¿Fue un único fallo catastrófico en el paso 2, o quince pasos de errores menores de razonamiento acumulándose? ¿El agente usó mal una herramienta o razonó a partir de una premisa falsa?
Sin localización de errores por paso no puedes diagnosticar los modos de fallo, decidir qué arreglar primero ni construir datos de entrenamiento para modelos de recompensa de proceso. Estás ajustando hiperparámetros a ciegas.
El esquema de anotación trajectory_eval de Potato resuelve esto. Los anotadores recorren cada paso de una traza y registran:
- Corrección: ¿este paso es correcto o incorrecto?
- Tipo de error: seleccionado de una taxonomía jerárquica que tú defines
- Nivel de severidad: menor, mayor o crítico, con pesos de puntuación configurables
- Justificación: explicación en texto libre del error (opcional)
- Puntuación corriente: una puntuación acumulada que se decrementa según la severidad y te da una curva de calidad por traza
Esta guía cubre la configuración completa: definir tu taxonomía de errores, llevar a cabo la anotación y analizar los datos recogidos. Para la referencia de configuración del esquema, consulta la documentación fuente.
Visión general del esquema de evaluación de trayectoria
El esquema trajectory_eval está pensado para evaluar en secuencia trazas de agente de varios pasos. En lugar de una única valoración global de calidad, produce una anotación de error estructurada para cada paso, de modo que acabas con un mapa detallado de dónde y por qué falló el agente.
Esto es lo que hace la interfaz de anotación en cada paso:
- El anotador ve el contenido del paso actual (pensamiento, acción, observación, código, etc.)
- Marca el paso como correcto o incorrecto
- Si es incorrecto, selecciona un tipo de error de la taxonomía jerárquica
- Asigna un nivel de severidad (menor, mayor o crítico)
- Opcionalmente, escribe una justificación que explique el error
- La puntuación corriente en la parte superior de la interfaz se actualiza sola
El anotador avanza por la traza paso a paso hasta componer un perfil de errores completo.
La interfaz de evaluación de trayectoria muestra cada paso con su puntuación:
Each step gets a correctness rating, error type, and severity level with a running score that decrements based on severity
Diseñar una taxonomía de errores jerárquica
La taxonomía es lo que hace que la evaluación de trayectoria merezca la pena. Si aciertas con ella, puedes agregar errores entre trazas y detectar patrones de fallo sistemáticos; si te equivocas, tus etiquetas no sumarán nada. Esta es la taxonomía por la que yo empezaría, con cuatro categorías de primer nivel.
Errores de razonamiento
Ocurren cuando el razonamiento del agente es defectuoso, aunque lo que ve y lo que hace esté bien por lo demás.
| Tipo de Error | Descripción | Ejemplo |
|---|---|---|
logical_error | Inferencia lógica inválida | «Como A implica B, y B es verdadero, A tiene que ser verdadero» (afirmación del consecuente) |
incorrect_assumption | Da por supuesto algo que la evidencia no respalda | Asume que un archivo existe sin comprobarlo |
over_generalization | Extrae una conclusión demasiado amplia de evidencia limitada | «Esta función falló una vez, así que toda la API está rota» |
circular_reasoning | Usa la conclusión como premisa | «La respuesta es X porque X es correcta» |
incorrect_calculation | Error de cálculo matemático o lógico | Error de uno en el razonamiento sobre el límite de un bucle |
Errores de percepción
Ocurren cuando el agente lee mal, malinterpreta o pasa por alto información en sus observaciones.
| Tipo de Error | Descripción | Ejemplo |
|---|---|---|
missed_element | No advierte información relevante | Pasa por alto un mensaje de error en la salida del terminal |
misidentified_element | Malinterpreta lo que ve | Lee un error 404 como una respuesta correcta |
hallucinated_element | Se refiere a algo que no está presente | Menciona un parámetro de función que no existe |
outdated_reference | Usa información obsoleta de un paso anterior | Usa el valor de una variable que ya fue sobrescrita |
Errores de acción
Ocurren cuando el agente toma la acción equivocada, o la acción correcta de forma equivocada.
| Tipo de Error | Descripción | Ejemplo |
|---|---|---|
wrong_tool | Elige una herramienta inadecuada para la tarea | Usa grep cuando hace falta find |
wrong_arguments | Herramienta correcta pero parámetros incorrectos | Pasa una ruta de archivo equivocada a un comando de edición |
premature_termination | Se detiene antes de completar la tarea | Devuelve una respuesta tras encontrar información parcial |
unnecessary_action | Realiza una acción que no aporta nada | Vuelve a leer un archivo que acaba de leer |
destructive_action | Realiza una acción que causa daño | Borra un archivo sin copia de seguridad |
Errores de comunicación
Aparecen en las respuestas del agente al usuario o en cómo narra su propio trabajo.
| Tipo de Error | Descripción | Ejemplo |
|---|---|---|
unclear_explanation | La explicación es confusa o ambigua | Describe un arreglo sin decir qué estaba roto |
missing_context | Omite contexto crítico en la respuesta | Informa de éxito sin mencionar salvedades |
incorrect_summary | El resumen no coincide con las acciones reales | Afirma haber editado 3 archivos cuando solo cambiaron 2 |
overconfident_claim | Presenta como certeza lo que es incierto | «Esto arreglará el problema seguro» sobre un cambio sin probar |
Niveles de severidad y pesos de puntuación
Cada error recibe un nivel de severidad. Los pesos por defecto son:
| Severidad | Peso | Descripción |
|---|---|---|
minor | -1 | Problemas pequeños que no descarrilan la traza (p. ej., acción innecesaria, explicación poco clara) |
major | -5 | Errores importantes que desperdician esfuerzo o producen resultados parcialmente equivocados (p. ej., herramienta incorrecta, suposición incorrecta) |
critical | -10 | Errores que rompen la traza de raíz (p. ej., acción destructiva, terminación prematura con respuesta equivocada) |
La puntuación corriente empieza en 100 y baja según el peso de severidad de cada error. Una traza que termina en 85 tuvo unos pocos problemas menores; una que termina en 40 tuvo varios fallos graves.
Puedes cambiar estos pesos en la configuración:
severity_levels:
- name: minor
weight: -1
description: "Small issue, does not derail the overall trace"
- name: major
weight: -5
description: "Significant error that wastes effort or produces wrong intermediate results"
- name: critical
weight: -10
description: "Fundamental failure that breaks the trace or causes harm"Configuración YAML completa
Este es un config.yaml completo para evaluación de trayectoria con la taxonomía entera:
annotation_task_name: "Agent Trajectory Error Localization"
data_files:
- "data/traces.jsonl"
item_properties:
id_key: "trace_id"
text_key: "task"
# Display agent traces with step-by-step rendering
display:
type: "agent_trace"
trace_key: "trace"
step_display:
thought: { label: "Thought", color: "#E8F0FE" }
action: { label: "Action", color: "#FFF3E0" }
observation: { label: "Observation", color: "#F1F8E9" }
code: { label: "Code", color: "#F3E5F5" }
annotation_schemes:
- annotation_type: "trajectory_eval"
# Per-step correctness check
# Hierarchical error taxonomy (shown when step is marked incorrect)
- category: "perception"
label: "Perception Error"
types:
- name: "missed_element"
label: "Missed Element"
description: "Fails to notice relevant information in observations"
- name: "misidentified_element"
label: "Misidentified Element"
description: "Misinterprets what it observes"
- name: "hallucinated_element"
label: "Hallucinated Element"
description: "Refers to something not present in the context"
- name: "outdated_reference"
label: "Outdated Reference"
description: "Uses stale information from a previous step"
- category: "action"
label: "Action Error"
types:
- name: "wrong_tool"
label: "Wrong Tool"
description: "Selects an inappropriate tool for the task"
- name: "wrong_arguments"
label: "Wrong Arguments"
description: "Correct tool but incorrect parameters"
- name: "premature_termination"
label: "Premature Termination"
description: "Stops before the task is complete"
- name: "unnecessary_action"
label: "Unnecessary Action"
description: "Takes an action that adds no value"
- name: "destructive_action"
label: "Destructive Action"
description: "Takes an action that causes harm or data loss"
- category: "communication"
label: "Communication Error"
types:
- name: "unclear_explanation"
label: "Unclear Explanation"
description: "Explanation is confusing or ambiguous"
- name: "missing_context"
label: "Missing Context"
description: "Omits critical context from the response"
- name: "incorrect_summary"
label: "Incorrect Summary"
description: "Summary does not match the actual actions taken"
- name: "overconfident_claim"
label: "Overconfident Claim"
description: "States uncertain outcomes as certainties"
# Severity levels with score weights
# Running score configuration
# Optional rationale field
# Overall trace quality (optional, shown at the end)
- annotation_type: "radio"
# Annotator settings
annotator_config:
allow_back_navigation: true
require_all_steps: true
# Output settings
output:
path: "output/"
format: "jsonl"Puesta en marcha paso a paso
1. Prepara tus trazas de agente
Los datos de traza van en formato JSONL, una traza por línea. Cada traza necesita un ID, una descripción de la tarea y una lista de pasos:
{
"trace_id": "trace_042",
"task": "Find the bug in the calculate_discount function and fix it",
"trace": [
{
"type": "thought",
"content": "I need to look at the calculate_discount function to find the bug. Let me search for it."
},
{
"type": "action",
"content": "search",
"action_input": "def calculate_discount"
},
{
"type": "observation",
"content": "Found in pricing.py line 45:\ndef calculate_discount(price, discount_pct):\n return price * discount_pct / 100"
},
{
"type": "thought",
"content": "The function calculates the discount amount but doesn't subtract it from the price. It should return price - (price * discount_pct / 100)."
},
{
"type": "action",
"content": "edit_file",
"action_input": "pricing.py:45: return price - (price * discount_pct / 100)"
},
{
"type": "observation",
"content": "File edited successfully."
},
{
"type": "action",
"content": "finish",
"action_input": "Fixed the calculate_discount function. It was returning the discount amount instead of the discounted price."
}
]
}Si tus trazas están en otro formato (mensajes de OpenAI, ejecuciones de LangChain, registros de conversación de Claude), usa el conversor de trazas de Potato:
python -m potato.trace_converter \
--input raw_traces/ \
--output data/traces.jsonl \
--input-format react2. Configura tu taxonomía
Empieza con la taxonomía completa de arriba y luego recórtala o amplíala según tu agente. Para un agente de coding, por ejemplo, puedes añadir una categoría code_quality:
- category: "code_quality"
label: "Code Quality Error"
types:
- name: "syntax_error"
label: "Syntax Error"
description: "Generated code has syntax errors"
- name: "runtime_error"
label: "Runtime Error"
description: "Code runs but produces an error"
- name: "logic_bug"
label: "Logic Bug"
description: "Code runs without errors but produces wrong output"
- name: "style_violation"
label: "Style Violation"
description: "Code works but violates project conventions"Para trazas de agentes de coding, la evaluación renderiza diffs y salida de terminal junto a los controles de puntuación:
CodingTraceDisplay renders diffs, terminal blocks, and file reads alongside trajectory evaluation controls
3. Arranca el servidor de anotación
potato start config.yaml -p 8000Abre http://localhost:8000 en el navegador. Verás la primera traza con la visualización paso a paso.
4. Escribe las pautas de anotación
Da instrucciones claras a los anotadores. Como mínimo, documenta:
- Cuándo marcar un paso como incorrecto frente a correcto pero subóptimo
- Cómo elegir entre categorías de error cuando aplican varias (usar la más específica)
- Cuándo asignar cada nivel de severidad, con ejemplos concretos
- Si hay que evaluar los pasos con la información disponible en ese momento o con perspectiva retrospectiva
El flujo de anotación
Cuando un anotador abre una traza, la descripción de la tarea queda arriba y el primer paso debajo. La puntuación corriente marca 100 en la esquina superior derecha.
Para cada paso, el anotador:
- Lee el contenido del paso en el contexto de los pasos anteriores
- Marca la corrección pulsando «Correct» o «Incorrect»
- Si es incorrecto, selecciona la categoría de error (p. ej., «Reasoning Error») y luego el tipo concreto (p. ej., «Incorrect Assumption»)
- Asigna la severidad: menor, mayor o crítica
- Escribe una justificación (si está habilitada): «El agente asume que el archivo está en el directorio actual sin comprobarlo, pero los resultados de búsqueda mostraban que está en src/utils/»
- Avanza al siguiente paso pulsando «Next Step» o la tecla de flecha derecha
La puntuación corriente se actualiza después de cada error. Marca el paso 3 como error mayor (-5) y la puntuación baja de 100 a 95. Marca el paso 7 como crítico (-10) y cae a 85.
Al final de la traza, el anotador da la valoración global de éxito/parcial/fallo y envía.
Analizar los resultados
Cargar los datos de anotación
import json
import pandas as pd
from collections import Counter
from pathlib import Path
# Load all annotation files
annotations = []
output_dir = Path("output/")
for f in output_dir.glob("*.jsonl"):
with open(f) as fh:
for line in fh:
annotations.append(json.loads(line))
print(f"Loaded {len(annotations)} annotated traces")Análisis de la distribución de errores
# Extract all errors across all traces
errors = []
for ann in annotations:
for step_ann in ann.get("error_localization", []):
if step_ann["correctness"] == "incorrect":
errors.append({
"trace_id": ann["trace_id"],
"step_index": step_ann["step_index"],
"category": step_ann["error_category"],
"error_type": step_ann["error_type"],
"severity": step_ann["severity"],
"rationale": step_ann.get("rationale", ""),
})
error_df = pd.DataFrame(errors)
print(f"Total errors found: {len(error_df)}")
print()
# Error distribution by category
print("Errors by category:")
print(error_df["category"].value_counts())
print()
# Most common specific error types
print("Top 10 error types:")
print(error_df["error_type"].value_counts().head(10))
print()
# Severity distribution
print("Severity distribution:")
print(error_df["severity"].value_counts())Análisis de la posición de los errores
Ver en qué punto de la traza tienden a caer los errores suele revelar patrones sistemáticos:
import matplotlib.pyplot as plt
import numpy as np
# Normalize step positions to [0, 1] range
for ann in annotations:
trace_length = len(ann.get("error_localization", []))
for step_ann in ann["error_localization"]:
if step_ann["correctness"] == "incorrect":
step_ann["normalized_position"] = step_ann["step_index"] / max(trace_length - 1, 1)
# Collect normalized positions
positions = [
step_ann["normalized_position"]
for ann in annotations
for step_ann in ann.get("error_localization", [])
if step_ann["correctness"] == "incorrect"
and "normalized_position" in step_ann
]
plt.figure(figsize=(10, 4))
plt.hist(positions, bins=20, edgecolor="black", alpha=0.7)
plt.xlabel("Normalized Position in Trace (0 = start, 1 = end)")
plt.ylabel("Error Count")
plt.title("Where Do Agent Errors Occur?")
plt.tight_layout()
plt.savefig("error_position_distribution.png", dpi=150)
print("Saved error_position_distribution.png")Distribuciones de la puntuación corriente
# Extract final running scores
final_scores = []
for ann in annotations:
score = 100
severity_weights = {"minor": -1, "major": -5, "critical": -10}
for step_ann in ann.get("error_localization", []):
if step_ann["correctness"] == "incorrect":
score += severity_weights.get(step_ann["severity"], 0)
score = max(score, 0)
final_scores.append({
"trace_id": ann["trace_id"],
"final_score": score,
"overall_success": ann.get("overall_success", "unknown"),
})
score_df = pd.DataFrame(final_scores)
print("Score statistics:")
print(score_df["final_score"].describe())
print()
# Score distribution by overall success
for label in ["success", "partial", "failure"]:
subset = score_df[score_df["overall_success"] == label]
if len(subset) > 0:
print(f"{label}: mean={subset['final_score'].mean():.1f}, "
f"median={subset['final_score'].median():.1f}, "
f"n={len(subset)}")Modos de fallo más comunes
# Group errors by category + type for a failure mode analysis
failure_modes = (
error_df.groupby(["category", "error_type"])
.agg(
count=("severity", "size"),
avg_severity_weight=("severity", lambda x: x.map(
{"minor": 1, "major": 5, "critical": 10}
).mean()),
)
.sort_values("count", ascending=False)
)
print("Top failure modes (by frequency):")
print(failure_modes.head(15).to_string())
print()
# Impact-weighted failure modes (frequency x average severity)
failure_modes["impact"] = failure_modes["count"] * failure_modes["avg_severity_weight"]
print("Top failure modes (by impact):")
print(failure_modes.sort_values("impact", ascending=False).head(10).to_string())Contexto de investigación
La localización de errores por paso encaja con varias líneas recientes en evaluación de agentes:
TRAIL (Patronus AI, 2025) anotó 148 trazas de agentes de GAIA y SWE-bench Lite contra una taxonomía de más de 20 tipos de error, 841 errores en total. Lo que conviene retener es lo difícil que resultó la localización: el mejor modelo de razonamiento de contexto largo que probaron llegó al 11 % de precisión conjunta en categoría de error y ubicación. Ese es el trabajo que trajectory_eval entrega a anotadores humanos, y por eso las etiquetas valen lo que cuestan.
AgentRewardBench (McGill NLP, 2025) fue a por los jueces. Reúne 1.302 trayectorias de agentes web en cinco benchmarks, hace que una persona experta revise cada una en cuanto a éxito, efectos secundarios y repetición, y luego puntúa a doce jueces LLM contra esas revisiones. Ningún juez lideró en todos los benchmarks, y las evaluaciones basadas en reglas que traen los propios benchmarks subestimaron cuántas veces los agentes acertaban. Si piensas automatizar parte de esta taxonomía con un modelo, esa es la forma de comprobación que necesitas.
Las etiquetas de corrección y severidad por paso de trajectory_eval también alimentan directamente el entrenamiento de modelos de recompensa de proceso: cada paso anotado es un ejemplo de entrenamiento con una señal de calidad de referencia.
El artículo de Anthropic Demystifying evals for AI agents plantea la versión operativa del mismo argumento. Califica la transcripción y no solo el resultado, y usa evaluadores basados en modelos con rúbricas explícitas sobre cómo el agente llamó a las herramientas y habló con la persona usuaria. También advierte contra puntuar respecto de una secuencia de pasos prescrita, porque los agentes encuentran caminos válidos que quien diseñó la evaluación no había previsto. Tenlo presente al aplicar esta taxonomía: un paso es un error porque estuvo mal, no porque fuera inesperado.
La puntuación corriente ponderada por severidad también se corresponde con las señales de recompensa que se usan en RLHF. Una curva de puntuación que cae en picado en el paso 5 de una traza de 20 pasos te dice exactamente dónde necesita trabajo el agente, algo bastante más accionable que una única recompensa al final de la traza.
Resumen
El esquema trajectory_eval convierte la evaluación de agentes de una comprobación de aprobado/suspenso en un diagnóstico. Con una taxonomía jerárquica, puntuación por severidad y una puntuación corriente, puedes ver qué paso salió mal, de qué tipo de error se trató, cómo de grave fue y dónde tienden a agruparse los errores entre trazas. Las etiquetas a nivel de paso, además, ya sirven como datos de entrenamiento para modelos de recompensa de proceso.
Empieza con la taxonomía completa de esta guía y luego afínala según tu agente y los patrones de error que veas de verdad. La mejor taxonomía es la que apunta a arreglos que puedes hacer.