Annotare gli agenti di navigazione web: dalle tracce WebArena alla valutazione umana
Come usare il display delle tracce degli agenti web di Potato per valutare agenti autonomi di navigazione web, con screenshot passo per passo, overlay SVG e schemi di annotazione per passo.
Converti la traccia dell'agente nel formato per agenti web di Potato, visualizzala con il viewer web_agent_trace in modo che ogni screenshot porti un overlay che mostra dove ha cliccato l'agente, e valuta i passi con uno schema trajectory_eval.
Un agente di navigazione web si giudica dalle azioni compiute su una pagina, quindi la valutazione ha bisogno di entrambe le metà di ogni passo, lo stato della pagina che l'agente ha visto e l'azione che vi ha compiuto. Un log delle azioni da solo non basta a sostenere il giudizio. "Clicked element product-101" non dice a un revisore se quello era il laptop più economico della pagina, e uno screenshot senza marcatore lo lascia a indovinare quale di una dozzina di link fosse il target.
Questa guida imposta quella valutazione per le tracce WebArena. Lo stesso percorso funziona per VisualWebArena, Mind2Web, i log di Anthropic Computer Use e le registrazioni grezze del browser, perché un unico convertitore li copre tutti. Per il riferimento completo della configurazione, consulta la documentazione sorgente.
Cosa ti serve
pip install potato-annotationTi servono anche le tracce stesse, che per WebArena sono screenshot più un log delle azioni in JSON per episodio. VisualWebArena registra la stessa struttura con informazioni aggiuntive di grounding visivo, mentre le registrazioni grezze del browser contengono invece dati sul viewport e sul percorso del mouse.
Cosa contiene una traccia WebArena grezza
Un episodio WebArena contiene la descrizione del task, la sequenza di azioni e il percorso di ogni screenshot:
{
"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
}Convertire la traccia
Il viewer di Potato legge un formato di passi normalizzato invece di quello proprio di ciascun framework, quindi gli episodi grezzi passano prima dal convertitore:
python -m potato.trace_converter -i traces.json -f web_agent -o data/web_traces.jsonlIl comando scrive un'istanza per episodio, e ogni passo contiene step_index, screenshot_url, action_type, l'element target e il suo bounding box, coordinates, un mouse_path opzionale, e il thought e l'observation dell'agente quando il log di origine li ha registrati. Sostituendo -f web_agent con --auto-detect il convertitore identifica da solo il formato, ed è l'opzione da usare quando una directory contiene tracce di più framework.
La configurazione del progetto
Il viewer è un tipo di display e non un tipo di annotazione, quindi va sotto instance_display.fields e gli schemi di annotazione restano separati da esso. La dimensione dello screenshot è l'impostazione da decidere per prima. Con 900 pixel di larghezza una pagina desktop completa resta leggibile senza spingere i controlli di annotazione oltre il fondo dello schermo.
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: trueUn solo schema trajectory_eval copre l'intero passaggio per passo. Mostra ogni passo come una scheda e raccoglie su ciascuna la correttezza, un tipo di errore, una gravità e una motivazione scritta, poi calcola un punteggio di qualità a livello di traccia a partire dai pesi di gravità. Con i pesi qui sopra un errore grave costa alla traccia cinque punti e uno critico dieci. Impostali con cura, perché decidono come si classifica una traccia con un solo errore grave rispetto a una con quattro errori piccoli.
Cosa vede l'annotatore

Lo screenshot del passo corrente occupa il pannello principale, con gli overlay SVG disegnati sopra. Ogni overlay segna una parte diversa del passo, e i colori sono fissi:
| Overlay | Segna |
|---|---|
| Cerchio rosso con mirino | Le coordinate del clic |
| Evidenziazione gialla | Il campo in cui l'agente ha digitato |
| Freccia verde | La direzione e l'ampiezza di uno scorrimento |
| Rettangolo blu tratteggiato | Il bounding box dell'elemento target |
| Linea curva arancione | Il percorso del mouse fino al target |
Un filmstrip di miniature scorre lungo il fondo, e cliccarne una porta a quel passo. Sulle tracce oltre i dieci passi circa, il filmstrip fa la differenza tra un revisore che vede la forma dell'esecuzione e uno che scorre alla cieca. Il pannello dei dettagli del passo mostra le informazioni sull'elemento, il ragionamento dell'agente e l'osservazione che ha registrato, e ciascuno di questi si può disattivare in display_options quando il log di origine non contiene nulla di utile.
Una riga di checkbox sotto il viewer attiva e disattiva gli overlay:
| Controllo | Overlay |
|---|---|
| Clicks | Il mirino rosso del clic |
| Bounding Boxes | Il rettangolo blu tratteggiato |
| Mouse Path | La linea curva arancione |
| Scroll | La freccia verde di scorrimento |
Disattivare gli overlay conta sulle pagine dense, dove un marcatore di clic può coprire proprio il testo che dice se il clic era giusto. L'evidenziazione gialla della digitazione non ha un controllo proprio. Quattro dei cinque overlay si possono attivare singolarmente, mentre l'evidenziazione del campo digitato viene sempre disegnata. Questo viewer non ha scorciatoie da tastiera, quindi la navigazione tra i passi avviene con il filmstrip e con i controlli dei passi.
Il passaggio di annotazione
Un revisore lavora una traccia in cinque mosse:
- Leggi la descrizione del task. Tutto ciò che segue è un giudizio rispetto a essa.
- Scorri il filmstrip. Fatti un'idea della forma dell'esecuzione prima di valutare qualsiasi cosa, così un passo iniziale non viene segnato come corretto sulla base di prove che arrivano solo dopo.
- Percorri i passi. Per ognuno leggi lo stato della pagina, controlla l'overlay per vedere su cosa ha agito l'agente e valuta l'azione. Se è sbagliata, scegli il tipo di errore e una gravità, e scrivi nella motivazione cosa avrebbe dovuto fare invece l'agente.
- Valuta la traccia. Giudica il successo complessivo e l'efficienza dopo aver visto tutti i passi.
- Invia e passa alla successiva.
Le quattro opzioni di correttezza dividono i passi lungo la linea che conta per i dati di addestramento. Le azioni corrette avanzano verso l'obiettivo nel modo previsto. Le azioni accettabili fanno progressi per una strada più lenta, per esempio navigando a una pagina di categoria invece di usare la casella di ricerca. Le azioni errate sono errori, come un elemento sbagliato, una pagina irrilevante o un testo sbagliato in un modulo. Le azioni inutili non aiutano né danneggiano, come un clic seguito subito da un ritorno alla pagina precedente, e vale la pena separarle dagli errori perché un agente che vaga è un problema diverso da un agente che sbaglia.
La tassonomia degli errori
Sono i tipi di errore a trasformare un mucchio di tracce fallite in qualcosa su cui chi sviluppa l'agente può intervenire, quindi le categorie devono corrispondere a cause distinguibili e non a gradi di errore:
| Tipo di errore | Cosa significa | Esempio |
|---|---|---|
| Wrong element clicked | L'agente ha agito sull'elemento UI sbagliato | Ha cliccato "Tablets" invece di "Laptops" |
| Wrong page navigated to | L'agente è finito in un punto irrilevante | Ha navigato ad "About Us" invece che all'elenco dei prodotti |
| Missed better option | Era disponibile un'azione migliore | Ha sfogliato le categorie quando la casella di ricerca era lì |
| Incorrect form input | L'agente ha inserito il testo sbagliato | Ha cercato "labtop" invece di "laptop" |
| Premature completion | L'agente ha dichiarato il successo troppo presto | Ha aggiunto l'articolo sbagliato al carrello e si è fermato |
| Unnecessary navigation | Il passo non contribuisce all'obiettivo | Ha visitato la homepage tra due pagine di categoria |
| Failed to scroll | Il target era sotto il viewport | L'elemento non è mai stato visibile e l'agente non ha mai scorso |
| Wrong page section | Pagina giusta, area sbagliata | Ha cliccato l'intestazione invece del contenuto principale |
Lavorare sulle tracce difficili
Su una traccia oltre i quindici passi, valutare ogni passo con la stessa profondità spende gran parte dello sforzo sui passi che erano palesemente a posto. Scorri il filmstrip cercando i tre schemi che segnalano un problema, poi concentra lì lo sforzo. Gli schemi sono un URL che cambia inaspettatamente, un passo in cui l'agente torna indietro e una serie di screenshot quasi identici, che di solito indica un agente bloccato in un loop.
Su una traccia fallita, l'annotazione che conta fare bene è il primo passo errato. Tutto ciò che viene dopo accade in uno stato che l'agente non avrebbe mai dovuto raggiungere, quindi gli errori successivi descrivono le conseguenze e non la causa.
Alcune azioni non si possono giudicare dal solo screenshot, di solito quando più elementi si sovrappongono nel punto del clic. Le informazioni sull'elemento nel pannello del passo riportano il tag, il testo e il bounding box del target, e di norma bastano a stabilire cosa è stato cliccato davvero; show_element_info tiene visibile quel pannello.
VisualWebArena
Le tracce VisualWebArena passano dallo stesso convertitore, che riconosce entrambi i formati dai campi action_type e element nei loro passi di azione. Le informazioni di grounding che quelle tracce portano compaiono come overlay del bounding box, quindi un passaggio centrato sul grounding dipende da cosa gli annotatori tengono sullo schermo e non da una modifica alla configurazione. Lasciando spuntato Bounding Boxes e deselezionando Clicks si ottiene la vista che mostra se l'agente ha puntato l'elemento giusto e non soltanto il pixel giusto.
Leggere i risultati
Gli errori degli agenti web tendono a concentrarsi in punti precisi di una traccia, e il tasso di errore per posizione del passo è il modo più rapido per vedere dove. Ogni annotazione trajectory_eval memorizza una lista di record per passo, ciascuno con il suo step_index e la sua correctness:
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 distribuzione dei tipi di errore risponde all'altra domanda, cioè cosa sbaglia l'agente e non quando:
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}")Scalare la valutazione
Per un risultato che intendi pubblicare, un solo revisore per traccia non basta, perché i giudizi per passo contengono esattamente il tipo di ambiguità che le statistiche di accordo servono a misurare. Imposta l'obiettivo di copertura e l'ordine di assegnazione al livello superiore della configurazione:
num_annotators_per_item: 3
assignment_strategy: randomPoi confronta gli annotatori sull'etichetta a livello di traccia, quella in cui un disaccordo non è ambiguo. Esporta prima in Parquet, così il confronto lavora su colonne e non su JSON da analizzare:
python -m potato.export -c config.yaml -f parquet -o ./parquet_export/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}")Nelle valutazioni con centinaia di tracce, Solo Mode mette un modello sulla stessa coda del revisore umano: il modello propone le etichette e l'umano le corregge finché i due non concordano abbastanza spesso da lasciare al modello il resto:
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: 50L'impostazione su cui riflettere è la soglia di accordo, non la scelta del modello. A 0.90 l'umano continua ad annotare finché nove etichette del modello su dieci non coincidono con le sue, misurate su almeno cinquanta confronti, e abbassarla scambia qualità delle etichette con ore di revisione in un modo difficile da rilevare a posteriori.
Ulteriori letture
- Annotazione agentica per il riferimento completo su convertitori e display
- Annotazione di agenti web per le opzioni di display del viewer
- Valutare gli agenti AI per la valutazione degli agenti oltre il browser
- Esportazione Parquet per le colonne che l'analisi qui sopra legge