Skip to content
Guides12 min de lecture

Annoter les agents de navigation web : des traces WebArena à l'évaluation humaine

Comment utiliser l'affichage de traces d'agents web de Potato pour évaluer des agents de navigation web autonomes, avec des captures étape par étape, des superpositions SVG et des schémas d'annotation par étape.

Potato Team

Convertissez la trace de l'agent au format d'agent web de Potato, affichez-la avec le visualiseur web_agent_trace pour que chaque capture porte une superposition indiquant où l'agent a cliqué, et notez les étapes avec un schéma trajectory_eval.

Un agent de navigation web se juge sur les actions qu'il effectue sur une page, donc l'évaluation a besoin des deux moitiés de chaque étape, l'état de la page que l'agent a vu et l'action qu'il y a effectuée. Un journal d'actions seul ne suffit pas pour juger. « Clicked element product-101 » n'indique pas au relecteur s'il s'agissait de l'ordinateur portable le moins cher de la page, et une capture sans marqueur le laisse deviner lequel d'une douzaine de liens était la cible.

Ce guide met en place cette évaluation pour des traces WebArena. La même démarche fonctionne pour VisualWebArena, Mind2Web, les journaux d'Anthropic Computer Use et les enregistrements bruts de navigateur, puisqu'un seul convertisseur les couvre tous. Pour la référence complète de configuration, consultez la documentation source.

Ce qu'il vous faut

bash
pip install potato-annotation

Il vous faut aussi les traces elles-mêmes, qui pour WebArena sont des captures d'écran plus un journal d'actions JSON par épisode. VisualWebArena enregistre la même structure avec des informations supplémentaires d'ancrage visuel, et les enregistrements bruts de navigateur contiennent à la place des données de viewport et de trajet de la souris.

Ce que contient une trace WebArena brute

Un épisode WebArena contient la description de la tâche, la séquence d'actions et le chemin de chaque capture :

json
{
  "trace_id": "wa_001",
  "task": "Find the cheapest laptop on the electronics store and add it to the cart",
  "website": "shopping",
  "steps": [
    {
      "step": 0,
      "url": "http://shop.example.com/",
      "action_type": "click",
      "action_target": "Electronics category link",
      "element_id": "nav-electronics",
      "coordinates": [245, 82],
      "screenshot": "screenshots/wa_001_step_00.png"
    },
    {
      "step": 1,
      "url": "http://shop.example.com/electronics",
      "action_type": "click",
      "action_target": "Laptops subcategory",
      "element_id": "cat-laptops",
      "coordinates": [180, 310],
      "screenshot": "screenshots/wa_001_step_01.png"
    }
  ],
  "success": true
}

Convertir la trace

Le visualiseur de Potato lit un format d'étapes normalisé plutôt que le format propre à chaque framework, donc les épisodes bruts passent d'abord par le convertisseur :

bash
python -m potato.trace_converter -i traces.json -f web_agent -o data/web_traces.jsonl

Cette commande écrit une instance par épisode, et chaque étape porte step_index, screenshot_url, action_type, l'element cible et sa boîte englobante, coordinates, un mouse_path facultatif, ainsi que le thought et l'observation de l'agent lorsque le journal source les a enregistrés. En remplaçant -f web_agent par --auto-detect, le convertisseur identifie lui-même le format, ce qui est l'option à retenir quand un répertoire contient des traces de plusieurs frameworks.

La configuration du projet

Le visualiseur est un type d'affichage et non un type d'annotation, donc il se place sous instance_display.fields et les schémas d'annotation restent séparés de lui. La taille des captures est le réglage à décider en premier. Avec 900 pixels de large, une page de bureau complète reste lisible sans repousser les contrôles d'annotation sous le bas de l'écran.

yaml
annotation_task_name: "WebArena Agent Evaluation"
task_dir: "."
 
data_files:
  - "data/web_traces.jsonl"
 
item_properties:
  id_key: id
  text_key: task_description
 
output_annotation_dir: "output/"
export_annotation_format: "jsonl"
 
instance_display:
  layout:
    direction: vertical
    gap: 16px
  fields:
    - key: task_description
      type: text
      label: "Task"
 
    - key: steps
      type: web_agent_trace
      label: "Agent Browsing Trace"
      display_options:
        show_overlays: true
        show_filmstrip: true
        show_thought: true
        show_observation: true
        show_element_info: true
        screenshot_max_width: 900
        screenshot_max_height: 600
        filmstrip_size: 80
 
annotation_schemes:
  - annotation_type: radio
    name: task_success
    description: "Did the agent complete the task?"
    labels:
      - "Success"
      - "Partial success"
      - "Failure"
    label_requirement:
      required: true
 
  - annotation_type: radio
    name: task_efficiency
    description: "Was the agent's path to the goal efficient?"
    labels:
      - "Optimal path"
      - "Reasonable but not optimal"
      - "Inefficient, unnecessary steps"
      - "Completely wrong direction"
    label_requirement:
      required: true
 
  - annotation_type: trajectory_eval
    name: step_evaluation
    description: "Judge each action against the task"
    steps_key: steps
    step_text_key: action_type
    correctness_options:
      - correct
      - acceptable
      - incorrect
      - unnecessary
    error_types:
      - name: wrong_element_clicked
      - name: wrong_page_navigated_to
      - name: missed_better_option
      - name: incorrect_form_input
      - name: premature_completion
      - name: unnecessary_navigation
      - name: failed_to_scroll
      - name: wrong_page_section
      - name: other
    severities:
      - name: minor
        weight: -1
      - name: major
        weight: -5
      - name: critical
        weight: -10
    show_score: true
    max_score: 100
 
user_config:
  allow_all_users: true

Un seul schéma trajectory_eval couvre toute la passe par étape. Il affiche chaque étape sous forme de carte et recueille sur chacune la justesse, un type d'erreur, une gravité et une justification écrite, puis calcule un score de qualité de la trace à partir des poids de gravité. Avec les poids ci-dessus, une erreur majeure coûte cinq points à la trace et une erreur critique dix. Fixez-les délibérément, car ils décident du classement d'une trace comportant un échec grave par rapport à une trace comportant quatre petits.

Ce que voit l'annotateur

Visualiseur de traces d'agents web dans Potato

La capture de l'étape courante occupe le panneau principal, avec des superpositions SVG dessinées par-dessus. Chaque superposition marque une partie différente de l'étape, et leurs couleurs sont fixes :

SuperpositionMarque
Cercle rouge avec réticuleLes coordonnées du clic
Surbrillance jauneLe champ dans lequel l'agent a tapé
Flèche verteLa direction et l'amplitude d'un défilement
Rectangle bleu en pointillésLa boîte englobante de l'élément cible
Ligne courbe orangeLe trajet de la souris jusqu'à la cible

Une pellicule de miniatures court en bas de l'écran, et cliquer sur l'une d'elles mène à l'étape correspondante. Sur les traces de plus d'une dizaine d'étapes, la pellicule fait la différence entre un relecteur qui voit la forme de l'exécution et un relecteur qui fait défiler à l'aveugle. Le panneau de détails de l'étape présente les informations sur l'élément, le raisonnement de l'agent et l'observation qu'il a enregistrée, et chacun peut être désactivé dans display_options quand le journal source n'y contient rien d'utile.

Une rangée de cases à cocher sous le visualiseur active et désactive les superpositions :

ContrôleSuperposition
ClicksLe réticule rouge du clic
Bounding BoxesLe rectangle bleu en pointillés
Mouse PathLa ligne courbe orange
ScrollLa flèche verte de défilement

Désactiver des superpositions compte sur les pages denses, où un marqueur de clic peut recouvrir le texte qui vous dirait si le clic était le bon. Notez que la surbrillance jaune de saisie n'a pas de contrôle propre. Quatre des cinq superpositions se désactivent individuellement, et la surbrillance du champ saisi est toujours dessinée. Ce visualiseur n'a pas de raccourcis clavier, donc la navigation entre étapes passe par la pellicule et les contrôles d'étape.

La passe d'annotation

Un relecteur traite une trace en cinq temps :

  1. Lire la description de la tâche. Tout ce qui suit est un jugement par rapport à elle.
  2. Parcourir la pellicule. Saisir la forme de l'exécution avant de noter quoi que ce soit, pour ne pas marquer une étape précoce comme correcte sur la foi d'éléments qui n'arrivent que plus tard.
  3. Passer les étapes une à une. Pour chacune, lire l'état de la page, regarder la superposition pour voir sur quoi l'agent a agi, et noter l'action. Si elle est incorrecte, choisir le type d'erreur et une gravité, et indiquer dans la justification ce que l'agent aurait dû faire à la place.
  4. Noter la trace. Juger la réussite globale et l'efficacité une fois toutes les étapes vues.
  5. Soumettre et passer à la suivante.

Les quatre options de justesse répartissent les étapes selon la ligne qui compte pour les données d'entraînement. Les actions correctes progressent vers l'objectif de la manière attendue. Les actions acceptables progressent par un chemin plus lent, par exemple passer par une page de catégorie au lieu d'utiliser le champ de recherche. Les actions incorrectes sont des erreurs, comme un mauvais élément, une page sans rapport ou un texte erroné dans un formulaire. Les actions inutiles n'aident ni ne nuisent, comme un clic suivi immédiatement d'un retour en arrière, et il vaut la peine de les séparer des erreurs, car un agent qui erre pose un autre problème qu'un agent qui se trompe.

La taxonomie des erreurs

Les types d'erreur sont ce qui transforme une pile de traces ratées en quelque chose sur quoi un développeur d'agents peut agir, donc les catégories doivent correspondre à des causes distinctes plutôt qu'à des degrés d'erreur :

Type d'erreurCe qu'il signifieExemple
Mauvais élément cliquéL'agent a agi sur le mauvais élément d'interfaceA cliqué sur « Tablets » au lieu de « Laptops »
Mauvaise page atteinteL'agent s'est retrouvé à un endroit sans rapportEst allé sur « About Us » au lieu de la liste de produits
Meilleure option manquéeUne meilleure action était disponibleA parcouru les catégories alors que le champ de recherche était sous ses yeux
Saisie de formulaire incorrecteL'agent a saisi le mauvais texteA cherché « labtop » au lieu de « laptop »
Fin prématuréeL'agent a déclaré la réussite trop tôtA ajouté le mauvais article au panier et s'est arrêté
Navigation inutileL'étape ne contribue pas à l'objectifA visité la page d'accueil entre deux pages de catégorie
Défilement manquantLa cible était sous le viewportL'élément n'a jamais été visible et l'agent n'a jamais fait défiler
Mauvaise section de la pageBonne page, mauvaise zoneA cliqué sur l'en-tête au lieu du contenu principal

Traiter les traces difficiles

Sur une trace de plus de quinze étapes, noter chaque étape avec la même profondeur dépense l'essentiel de l'effort sur les étapes qui allaient manifestement bien. Parcourez la pellicule à la recherche des trois motifs qui signalent un problème, puis concentrez l'effort à ces endroits. Ces motifs sont une URL qui change de façon inattendue, une étape où l'agent revient en arrière, et une suite de captures presque identiques, signe habituel d'un agent coincé dans une boucle.

Sur une trace ratée, l'annotation qu'il faut réussir est la première étape incorrecte. Tout ce qui suit se déroule dans un état que l'agent n'aurait jamais dû atteindre, donc les erreurs ultérieures décrivent les conséquences plutôt que la cause.

Certaines actions ne peuvent pas être jugées sur la seule capture, en général quand plusieurs éléments se chevauchent au point du clic. Les informations sur l'élément dans le panneau de l'étape donnent la balise, le texte et la boîte englobante de la cible, ce qui suffit normalement à établir ce qui a réellement été cliqué ; show_element_info garde ce panneau visible.

VisualWebArena

Les traces VisualWebArena passent par le même convertisseur, qui reconnaît les deux formats grâce aux champs action_type et element de leurs étapes d'action. Les informations d'ancrage que portent ces traces apparaissent sous forme de superposition de boîte englobante, donc une passe centrée sur l'ancrage dépend de ce que les annotateurs gardent à l'écran et non d'une modification de la configuration. Laisser Bounding Boxes cochée et décocher Clicks donne la vue qui montre si l'agent a visé le bon élément et pas seulement le bon pixel.

Lire les résultats

Les erreurs des agents web ont tendance à se regrouper à certains points d'une trace, et le taux d'erreur par position d'étape est le moyen le plus rapide de voir où. Chaque annotation trajectory_eval stocke une liste d'enregistrements par étape, chacun avec son step_index et sa correctness :

python
import json
 
annotations = []
with open("output/exports/jsonl/annotations.jsonl") as f:
    for line in f:
        annotations.append(json.loads(line))
 
step_counts = {}
for ann in annotations:
    evaluation = ann["labels"].get("step_evaluation", {})
    for step in evaluation.get("steps", []):
        pos = step["step_index"]
        counts = step_counts.setdefault(pos, {})
        label = step.get("correctness", "unrated")
        counts[label] = counts.get(label, 0) + 1
 
print("Error rate by step position:")
for pos in sorted(step_counts):
    counts = step_counts[pos]
    total = sum(counts.values())
    errors = counts.get("incorrect", 0) + counts.get("unnecessary", 0)
    print(f"  Step {pos}: {errors / total:.1%} error rate ({total} observations)")

La distribution des types d'erreur répond à l'autre question, celle de savoir en quoi l'agent se trompe plutôt que quand :

python
error_counts = {}
for ann in annotations:
    evaluation = ann["labels"].get("step_evaluation", {})
    for step in evaluation.get("steps", []):
        error = step.get("error_type")
        if error:
            error_counts[error] = error_counts.get(error, 0) + 1
 
for error, count in sorted(error_counts.items(), key=lambda x: -x[1]):
    print(f"  {error}: {count}")

Passer à l'échelle

Pour un résultat que vous comptez publier, un seul relecteur par trace ne suffit pas, car les jugements par étape portent exactement le genre d'ambiguïté que les statistiques d'accord servent à mesurer. Fixez l'objectif de couverture et l'ordre d'attribution au niveau supérieur de la configuration :

yaml
num_annotators_per_item: 3
assignment_strategy: random

Comparez ensuite les annotateurs sur l'étiquette au niveau de la trace, celle où un désaccord est sans ambiguïté. Exportez d'abord en Parquet, pour que la comparaison porte sur des colonnes et non sur du JSON analysé :

bash
python -m potato.export -c config.yaml -f parquet -o ./parquet_export/
python
from sklearn.metrics import cohen_kappa_score
import pandas as pd
 
df = pd.read_parquet("parquet_export/annotations.parquet")
success = df[df["schema_name"] == "task_success"]
pivot = success.pivot(index="instance_id", columns="annotator", values="value")
 
annotators = pivot.columns.tolist()
for i in range(len(annotators)):
    for j in range(i + 1, len(annotators)):
        pair = pivot[[annotators[i], annotators[j]]].dropna()
        kappa = cohen_kappa_score(pair[annotators[i]], pair[annotators[j]])
        print(f"Kappa ({annotators[i]} vs {annotators[j]}): {kappa:.3f}")

Sur des évaluations de plusieurs centaines de traces, Solo Mode place un modèle dans la même file que le relecteur humain. Le modèle propose des étiquettes et l'humain les corrige jusqu'à ce qu'ils s'accordent assez souvent pour que le modèle termine le reste :

yaml
solo_mode:
  enabled: true
  labeling_models:
    - endpoint_type: "anthropic"
      model: "claude-sonnet-4-20250514"
      api_key: "${ANTHROPIC_API_KEY}"
  thresholds:
    end_human_annotation_agreement: 0.90
    minimum_validation_sample: 50

Le réglage auquel il faut réfléchir est le seuil d'accord, pas le choix du modèle. À 0,90, l'humain continue d'annoter jusqu'à ce que neuf étiquettes du modèle sur dix correspondent aux siennes, mesuré sur au moins cinquante comparaisons, et l'abaisser échange de la qualité d'étiquetage contre des heures de relecture d'une manière difficile à détecter après coup.

Pour aller plus loin