Skip to content
Guides16 min read

Localisation des erreurs étape par étape : trouver où les agents échouent avec l'évaluation de trajectoire

Utilisez le schéma trajectory_eval de Potato pour localiser les erreurs étape par étape, avec des taxonomies d'erreurs hiérarchiques, un score de gravité et un score courant suivi sur toute la trace d'un agent.

Potato Team

Le problème : savoir qu'un agent a échoué ne suffit pas

Une taxonomie hiérarchique des erreurs d'agent, avec quatre catégories et une échelle de gravitéUne taxonomie des erreurs de trajectoire

Vous lancez votre agent sur un banc d'essai. Il obtient 63 % de tâches accomplies. Et maintenant ?

Un score réussite/échec vous apprend que l'agent a échoué sur 37 % des tâches, et rien d'autre. Il ne dit pas les choses ont dérapé dans la trace, quel type d'erreur l'agent a commis, ni à quel point elle était grave. Était-ce une seule bévue catastrophique à l'étape 2, ou quinze étapes de petites erreurs de raisonnement qui se sont accumulées ? L'agent a-t-il mal utilisé un outil, ou raisonné à partir d'une prémisse fausse ?

Sans localisation des erreurs étape par étape, vous ne pouvez ni diagnostiquer les modes d'échec, ni décider quoi corriger en premier, ni constituer des données d'entraînement pour des modèles de récompense de processus. Vous réglez des hyperparamètres à l'aveugle.

Le schéma d'annotation trajectory_eval de Potato répond à cela. Les annotateurs parcourent chaque étape d'une trace et consignent :

  • Justesse : cette étape est-elle correcte ou erronée ?
  • Type d'erreur : choisi dans une taxonomie hiérarchique que vous définissez
  • Niveau de gravité : mineur, majeur ou critique, avec des poids de score configurables
  • Justification : explication en texte libre de l'erreur (optionnel)
  • Score courant : un score cumulé qui se décrémente selon la gravité, et vous donne une courbe de qualité par trace

Ce guide couvre l'installation complète : définir votre taxonomie d'erreurs, mener l'annotation et analyser les données recueillies. Pour la référence de configuration du schéma, voir la documentation source.


Vue d'ensemble du schéma trajectory_eval

Le schéma trajectory_eval est conçu pour évaluer les traces d'agents à plusieurs étapes, dans l'ordre. Au lieu d'une seule note de qualité globale, il produit une annotation d'erreur structurée pour chaque étape, si bien que vous obtenez une carte détaillée de l'endroit et de la raison de l'échec de l'agent.

Voici ce que fait l'interface d'annotation à chaque étape :

  1. L'annotateur voit le contenu de l'étape courante (raisonnement, action, observation, code, etc.)
  2. Il marque l'étape comme correcte ou erronée
  3. Si elle est erronée, il choisit un type d'erreur dans la taxonomie hiérarchique
  4. Il attribue un niveau de gravité (mineur, majeur ou critique)
  5. Il peut écrire une justification qui explique l'erreur
  6. Le score courant en haut de l'interface se met à jour tout seul

L'annotateur avance dans la trace une étape à la fois, et construit ainsi un profil d'erreurs complet.

L'interface d'évaluation de trajectoire montre chaque étape avec son score :

Évaluation de trajectoire avec compteur de score courantChaque étape reçoit une note de justesse, un type d'erreur et un niveau de gravité, avec un score courant qui se décrémente selon la gravité


Concevoir une taxonomie d'erreurs hiérarchique

C'est la taxonomie qui rend l'évaluation de trajectoire utile. Bien conçue, elle vous permet d'agréger les erreurs sur l'ensemble des traces et de repérer les motifs d'échec systématiques ; mal conçue, vos étiquettes ne mèneront à rien. Voici la taxonomie dont je partirais, avec quatre catégories de premier niveau.

Erreurs de raisonnement

Elles surviennent quand le raisonnement de l'agent est vicié, même si ce qu'il voit et ce qu'il fait sont par ailleurs corrects.

Type d'erreurDescriptionExemple
logical_errorInférence logique invalide« Puisque A implique B et que B est vrai, A doit être vrai » (affirmation du conséquent)
incorrect_assumptionSuppose quelque chose que les indices n'étayent pasSuppose qu'un fichier existe sans vérifier
over_generalizationTire une conclusion trop large d'indices limités« Cette fonction a échoué une fois, donc toute l'API est cassée »
circular_reasoningLa conclusion sert de prémisse« La réponse est X parce que X est correct »
incorrect_calculationErreur de calcul mathématique ou logiqueErreur d'indice sur la borne d'une boucle

Erreurs de perception

Elles surviennent quand l'agent lit mal, interprète mal ou manque une information dans ses observations.

Type d'erreurDescriptionExemple
missed_elementNe remarque pas une information pertinentePasse à côté d'un message d'erreur dans la sortie du terminal
misidentified_elementInterprète mal ce qu'il voitPrend une erreur 404 pour une réponse réussie
hallucinated_elementFait référence à quelque chose d'absentMentionne un paramètre de fonction qui n'existe pas
outdated_referenceUtilise une information périmée d'une étape précédenteUtilise la valeur d'une variable qui a été écrasée

Erreurs d'action

Elles surviennent quand l'agent fait la mauvaise action, ou la bonne action de la mauvaise manière.

Type d'erreurDescriptionExemple
wrong_toolChoisit un outil inadapté à la tâcheUtilise grep alors qu'il faut find
wrong_argumentsBon outil, mais mauvais paramètresPasse un mauvais chemin de fichier à une commande d'édition
premature_terminationS'arrête avant que la tâche soit terminéeRend une réponse après n'avoir trouvé qu'une information partielle
unnecessary_actionEffectue une action sans valeur ajoutéeRelit un fichier qui vient d'être lu
destructive_actionEffectue une action qui cause des dégâtsSupprime un fichier sans sauvegarde

Erreurs de communication

Elles apparaissent dans les réponses de l'agent aux utilisateurs, ou dans la façon dont il raconte son propre travail.

Type d'erreurDescriptionExemple
unclear_explanationL'explication est confuse ou ambiguëDécrit un correctif sans dire ce qui était cassé
missing_contextOmet un contexte essentiel dans la réponseAnnonce un succès sans mentionner les réserves
incorrect_summaryLe résumé ne correspond pas aux actions réellesAffirme avoir modifié 3 fichiers alors que 2 seulement ont changé
overconfident_claimPrésente l'incertain comme certain« Cela va régler le problème, c'est sûr » à propos d'un changement non testé

Niveaux de gravité et poids de score

Chaque erreur reçoit un niveau de gravité. Les poids par défaut sont les suivants :

GravitéPoidsDescription
minor-1Petits problèmes qui ne font pas dérailler la trace (par ex. action inutile, explication peu claire)
major-5Erreurs importantes qui gaspillent des efforts ou produisent des résultats partiellement faux (par ex. mauvais outil, supposition erronée)
critical-10Erreurs qui cassent fondamentalement la trace (par ex. action destructrice, arrêt prématuré avec une mauvaise réponse)

Le score courant part de 100 et baisse du poids de gravité à chaque erreur. Une trace qui finit à 85 a connu quelques petits problèmes ; une trace qui finit à 40 a connu plusieurs échecs majeurs.

Vous pouvez modifier ces poids dans la configuration :

yaml
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"

Configuration YAML complète

Voici un config.yaml complet pour l'évaluation de trajectoire, avec la taxonomie entière :

yaml
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"

Mise en place, étape par étape

1. Préparez vos traces d'agents

Les données de trace se présentent au format JSONL, une trace par ligne. Chaque trace a besoin d'un identifiant, d'une description de tâche et d'une liste d'étapes :

json
{
  "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 vos traces sont dans un autre format (messages OpenAI, exécutions LangChain, journaux de conversation Claude), utilisez le convertisseur de traces de Potato :

bash
python -m potato.trace_converter \
  --input raw_traces/ \
  --output data/traces.jsonl \
  --input-format react

2. Configurez votre taxonomie

Partez de la taxonomie complète ci-dessus, puis élaguez-la ou étendez-la pour votre agent. Pour un agent de coding, par exemple, vous pourriez ajouter une catégorie code_quality :

yaml
- 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"

Pour les traces d'agents de coding, l'évaluation affiche les diffs et la sortie du terminal à côté des contrôles de notation :

Évaluation d'un agent de coding avec rendu des diffsCodingTraceDisplay affiche les diffs, les blocs de terminal et les lectures de fichiers à côté des contrôles d'évaluation de trajectoire

3. Lancez le serveur d'annotation

bash
potato start config.yaml -p 8000

Ouvrez http://localhost:8000 dans votre navigateur. Vous verrez la première trace avec l'affichage étape par étape.

4. Rédigez des consignes d'annotation

Donnez aux annotateurs des instructions claires. Documentez au minimum :

  • Quand marquer une étape comme erronée plutôt que correcte-mais-perfectible
  • Comment choisir entre plusieurs catégories d'erreur quand plusieurs s'appliquent (prenez la plus spécifique)
  • Quand attribuer chaque niveau de gravité, avec des exemples concrets
  • S'il faut évaluer les étapes à partir de l'information disponible à ce moment-là, ou avec le recul

Le déroulé de l'annotation

Quand un annotateur ouvre une trace, la description de la tâche se trouve en haut et la première étape juste en dessous. Le score courant affiche 100 dans le coin supérieur droit.

Pour chaque étape, l'annotateur :

  1. Lit le contenu de l'étape dans le contexte des étapes précédentes
  2. Marque la justesse en cliquant sur « Correct » ou « Erroné »
  3. Si l'étape est erronée, choisit la catégorie d'erreur (par ex. « Erreur de raisonnement »), puis le type précis (par ex. « Supposition erronée »)
  4. Attribue une gravité : mineure, majeure ou critique
  5. Écrit une justification (si le champ est activé) : « L'agent suppose que le fichier est dans le répertoire courant sans vérifier, alors que les résultats de recherche montraient qu'il est dans src/utils/ »
  6. Passe à l'étape suivante en cliquant sur « Étape suivante » ou en appuyant sur la flèche droite

Le score courant se met à jour après chaque erreur. Marquez l'étape 3 comme erreur majeure (-5) et le score passe de 100 à 95. Marquez l'étape 7 comme critique (-10) et il tombe à 85.

À la fin de la trace, l'annotateur donne la note globale succès / partiel / échec, puis soumet.


Analyser les résultats

Charger les données d'annotation

python
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")

Analyse de la distribution des erreurs

python
# 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())

Analyse de la position des erreurs

Voir les erreurs tombent dans une trace révèle souvent des motifs systématiques :

python
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")

Distribution des scores courants

python
# 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)}")

Les modes d'échec les plus fréquents

python
# 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())

Contexte de recherche

La localisation des erreurs étape par étape rejoint plusieurs travaux récents en évaluation d'agents :

TRAIL (Patronus AI, 2025) a annoté 148 traces d'agents issues de GAIA et de SWE-bench Lite selon une taxonomie de plus de 20 types d'erreurs, pour 841 erreurs au total. Ce qu'il faut en retenir, c'est la difficulté de la localisation : le meilleur modèle de raisonnement à long contexte testé atteint 11 % de justesse conjointe sur la catégorie d'erreur et sa position. C'est exactement la tâche que trajectory_eval confie à des annotateurs humains, et c'est pourquoi ces annotations valent leur coût.

AgentRewardBench (McGill NLP, 2025) s'est attaqué aux juges. Le travail rassemble 1 302 trajectoires d'agents web sur cinq benchmarks, fait relire chacune par une personne experte sur le succès, les effets de bord et les répétitions, puis évalue douze juges LLM à l'aune de ces relectures. Aucun juge ne domine sur tous les benchmarks, et les évaluations à base de règles fournies avec les benchmarks sous-estiment la fréquence des réussites. Si vous comptez automatiser une partie de cette taxonomie avec un modèle, c'est ce type de vérification qu'il vous faut.

Les étiquettes de justesse et de gravité par étape produites par trajectory_eval alimentent aussi directement l'entraînement des modèles de récompense de processus : chaque étape annotée est un exemple d'entraînement assorti d'un signal de qualité de référence.

L'article d'Anthropic Demystifying evals for AI agents propose la version opérationnelle du même argument. Notez la transcription et pas seulement le résultat, et employez des correcteurs à base de modèles avec des grilles explicites sur la façon dont l'agent a appelé les outils et parlé à l'utilisateur. Il met aussi en garde contre la notation par rapport à une séquence d'étapes imposée, car les agents trouvent sans cesse des chemins valides que le concepteur de l'évaluation n'avait pas prévus. Gardez-le en tête en appliquant cette taxonomie : une étape est une erreur parce qu'elle était fausse, pas parce qu'elle était inattendue.

Le score courant pondéré par la gravité correspond lui aussi aux signaux de récompense employés en RLHF. Une courbe de score qui chute brutalement à l'étape 5 d'une trace de 20 étapes vous dit exactement où l'agent a besoin de travail, ce qui est bien plus exploitable qu'une unique récompense de fin de trace.


En résumé

Le schéma trajectory_eval fait passer l'évaluation d'agents du contrôle réussite/échec au diagnostic. Avec une taxonomie hiérarchique, un score de gravité et un score courant, vous voyez quelle étape a dérapé, de quel type d'erreur il s'agissait, à quel point elle était grave, et où les erreurs ont tendance à se concentrer d'une trace à l'autre. Les étiquettes au niveau de l'étape servent aussi telles quelles de données d'entraînement pour un modèle de récompense de processus.

Partez de la taxonomie complète de ce guide, puis affinez-la pour votre agent et les motifs d'erreur que vous observez réellement. La meilleure taxonomie est celle qui désigne des corrections que vous pouvez faire.