Anotando agentes de navegação web: de traços do WebArena à avaliação humana
Como usar a exibição de traços de agentes web do Potato para avaliar agentes autônomos de navegação web, com capturas de tela passo a passo, sobreposições SVG e esquemas de anotação por etapa.
Converta o traço do agente para o formato de agente web do Potato, exiba-o com o visualizador web_agent_trace para que cada captura de tela traga uma sobreposição mostrando onde o agente clicou, e avalie as etapas com um esquema trajectory_eval.
Um agente de navegação web é julgado pelas ações que executa sobre uma página, então a avaliação precisa das duas metades de cada etapa, o estado da página que o agente viu e a ação que ele executou nela. Um log de ações sozinho não sustenta o julgamento. "Clicked element product-101" não diz ao revisor se aquele era o notebook mais barato da página, e uma captura de tela sem marcador o deixa adivinhando qual de uma dúzia de links era o alvo.
Este guia monta essa avaliação para traços do WebArena. O mesmo caminho funciona para VisualWebArena, Mind2Web, logs do Anthropic Computer Use e gravações brutas de navegador, já que um único conversor cobre todos eles. Para a referência completa de configuração, veja a documentação de origem.
O que você precisa
pip install potato-annotationVocê também precisa dos próprios traços, que no WebArena são capturas de tela mais um log de ações em JSON por episódio. O VisualWebArena registra a mesma estrutura com informações extras de ancoragem visual, e as gravações brutas de navegador trazem, em vez disso, dados de viewport e do caminho do mouse.
O que um traço bruto do WebArena contém
Um episódio do WebArena traz a descrição da tarefa, a sequência de ações e o caminho de cada captura de tela:
{
"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
}Convertendo o traço
O visualizador do Potato lê um formato de etapas normalizado, e não o formato próprio de cada framework, então os episódios brutos passam primeiro pelo conversor:
python -m potato.trace_converter -i traces.json -f web_agent -o data/web_traces.jsonlIsso grava uma instância por episódio, e cada etapa traz step_index, screenshot_url, action_type, o element alvo e sua caixa delimitadora, coordinates, um mouse_path opcional, e o thought e a observation do agente quando o log de origem os registrou. Trocar -f web_agent por --auto-detect faz o conversor identificar o formato sozinho, e essa é a opção a usar quando um diretório contém traços de mais de um framework.
A configuração do projeto
O visualizador é um tipo de exibição, e não um tipo de anotação, então ele vai em instance_display.fields e os esquemas de anotação ficam separados dele. O tamanho da captura de tela é a configuração que vale decidir primeiro. Com 900 pixels de largura, uma página de desktop inteira continua legível sem empurrar os controles de anotação para fora da parte de baixo da tela.
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: trueUm único esquema trajectory_eval cobre toda a passagem por etapa. Ele exibe cada etapa como um cartão e coleta em cada uma a correção, um tipo de erro, uma gravidade e uma justificativa escrita, e depois calcula uma pontuação de qualidade do traço a partir dos pesos de gravidade. Com os pesos acima, um erro grave custa ao traço cinco pontos e um erro crítico custa dez. Defina esses pesos de propósito, porque eles decidem como um traço com uma falha séria se classifica em relação a um traço com quatro falhas pequenas.
O que o anotador vê

A captura de tela da etapa atual ocupa o painel principal, com sobreposições SVG desenhadas por cima. Cada sobreposição marca uma parte diferente da etapa, e as cores são fixas:
| Sobreposição | Marca |
|---|---|
| Círculo vermelho com mira | As coordenadas do clique |
| Destaque amarelo | O campo em que o agente digitou |
| Seta verde | A direção e a magnitude de uma rolagem |
| Retângulo azul tracejado | A caixa delimitadora do elemento alvo |
| Linha curva laranja | O caminho do mouse até o alvo |
Uma tira de filme com miniaturas corre ao longo da parte de baixo, e clicar em uma delas leva àquela etapa. Em traços com mais de umas dez etapas, a tira de filme é a diferença entre um revisor que enxerga a forma da execução e um que rola às cegas. O painel de detalhes da etapa mostra as informações do elemento, o raciocínio do próprio agente e a observação que ele registrou, e cada um deles pode ser desligado em display_options quando o log de origem não tem nada útil ali.
Uma fileira de caixas de seleção abaixo do visualizador liga e desliga as sobreposições:
| Controle | Sobreposição |
|---|---|
| Clicks | A mira vermelha do clique |
| Bounding Boxes | O retângulo azul tracejado |
| Mouse Path | A linha curva laranja |
| Scroll | A seta verde de rolagem |
Desligar sobreposições faz diferença em páginas densas, onde um marcador de clique pode ficar em cima justamente do texto que diz se o clique estava certo. Observe que o destaque amarelo de digitação não tem controle próprio. Quatro das cinco sobreposições podem ser ligadas e desligadas individualmente, e o destaque do campo digitado é sempre desenhado. Este visualizador não tem atalhos de teclado, então a navegação entre etapas é feita pela tira de filme e pelos controles de etapa.
A passagem de anotação
Um revisor trabalha um traço em cinco movimentos:
- Leia a descrição da tarefa. Tudo o que vem depois é um julgamento em relação a ela.
- Percorra a tira de filme. Entenda a forma da execução antes de avaliar qualquer coisa, para que uma etapa inicial não seja marcada como correta com base em evidências que só aparecem depois.
- Percorra as etapas. Em cada uma, leia o estado da página, confira a sobreposição para ver sobre o que o agente agiu e avalie a ação. Se estiver errada, escolha o tipo de erro e uma gravidade, e diga na justificativa o que o agente deveria ter feito.
- Avalie o traço. Julgue o sucesso geral e a eficiência depois de ver todas as etapas.
- Envie e siga para o próximo.
As quatro opções de correção dividem as etapas pela linha que importa para dados de treinamento. Ações corretas avançam em direção ao objetivo da forma esperada. Ações aceitáveis fazem progresso por um caminho mais lento, como navegar até uma página de categoria em vez de usar a caixa de busca. Ações incorretas são erros, como um elemento errado, uma página irrelevante ou um texto errado em um formulário. Ações desnecessárias nem ajudam nem atrapalham, como um clique seguido imediatamente de uma volta à página anterior, e vale separá-las dos erros porque um agente que vagueia é um problema diferente de um agente que erra.
A taxonomia de erros
São os tipos de erro que transformam uma pilha de traços com falha em algo sobre o qual quem desenvolve o agente pode agir, então as categorias devem corresponder a causas distinguíveis, e não a graus de erro:
| Tipo de erro | O que significa | Exemplo |
|---|---|---|
| Elemento errado clicado | O agente agiu sobre o elemento de interface errado | Clicou em "Tablets" em vez de "Laptops" |
| Página errada acessada | O agente foi parar em um lugar irrelevante | Navegou para "About Us" em vez da listagem de produtos |
| Opção melhor ignorada | Havia uma ação melhor disponível | Navegou pelas categorias quando a caixa de busca estava ali |
| Entrada de formulário incorreta | O agente digitou o texto errado | Buscou "labtop" em vez de "laptop" |
| Conclusão prematura | O agente declarou sucesso cedo demais | Adicionou o item errado ao carrinho e parou |
| Navegação desnecessária | A etapa não contribui para o objetivo | Visitou a página inicial entre duas páginas de categoria |
| Falha ao rolar | O alvo estava abaixo do viewport | O elemento nunca ficou visível e o agente nunca rolou |
| Seção errada da página | Página certa, área errada | Clicou no cabeçalho em vez do conteúdo principal |
Trabalhando traços difíceis
Em um traço com mais de quinze etapas, avaliar todas as etapas com a mesma profundidade gasta a maior parte do esforço nas etapas que obviamente estavam certas. Percorra a tira de filme em busca dos três padrões que indicam um problema e concentre o esforço ali. Os padrões são uma URL que muda inesperadamente, uma etapa em que o agente retrocede e uma sequência de capturas de tela quase idênticas, o que geralmente significa que o agente está preso em um loop.
Em um traço com falha, a primeira etapa incorreta é a anotação que precisa sair certa. Tudo o que vem depois acontece em um estado que o agente nunca deveria ter alcançado, então os erros posteriores descrevem as consequências, e não a causa.
Algumas ações não podem ser julgadas só pela captura de tela, geralmente quando vários elementos se sobrepõem no ponto do clique. As informações do elemento no painel da etapa trazem a tag, o texto e a caixa delimitadora do alvo, o que normalmente basta para resolver o que foi de fato clicado; show_element_info mantém esse painel visível.
VisualWebArena
Os traços do VisualWebArena passam pelo mesmo conversor, que reconhece os dois formatos pelos campos action_type e element nas etapas de ação. As informações de ancoragem que esses traços trazem aparecem como a sobreposição de caixa delimitadora, então uma passagem focada em ancoragem depende do que os anotadores mantêm na tela, e não de uma edição na configuração. Deixar Bounding Boxes marcado e desmarcar Clicks dá a visão que mostra se o agente mirou o elemento certo, e não apenas o pixel certo.
Lendo os resultados
Os erros de agentes web tendem a se concentrar em pontos específicos de um traço, e a taxa de erro por posição da etapa é o jeito mais rápido de ver onde. Cada anotação trajectory_eval guarda uma lista de registros por etapa, cada um com seu step_index e 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)")A distribuição dos tipos de erro responde à outra pergunta, que é o que o agente erra, e não 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}")Escalando a avaliação
Para um resultado que você pretende publicar, um revisor por traço não basta, porque os julgamentos por etapa trazem exatamente o tipo de ambiguidade que as estatísticas de concordância existem para medir. Defina a meta de cobertura e a ordem de atribuição no nível superior da configuração:
num_annotators_per_item: 3
assignment_strategy: randomDepois compare os anotadores no rótulo do traço, que é onde uma discordância não tem ambiguidade. Exporte primeiro para Parquet, para que a comparação rode sobre colunas e não sobre JSON a ser analisado:
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}")Em avaliações com centenas de traços, o Solo Mode coloca um modelo na mesma fila do revisor humano: o modelo propõe rótulos e o humano os corrige até que os dois concordem com frequência suficiente para o modelo terminar o restante:
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: 50A configuração que merece reflexão é o limiar de concordância, não a escolha do modelo. Em 0.90, o humano continua anotando até que nove em cada dez rótulos do modelo coincidam com os seus, medidos sobre pelo menos cinquenta comparações, e baixar esse valor troca qualidade dos rótulos por horas de revisão de um jeito difícil de detectar depois.
Leitura adicional
- Anotação agêntica para a referência completa de conversores e exibições
- Anotação de agentes web para as opções de exibição do visualizador
- Avaliando agentes de IA para avaliação de agentes além do navegador
- Exportação para Parquet para as colunas que a análise acima lê