Skip to content
Guides6 min read

标注网页浏览智能体:从 WebArena 轨迹到人工评测

如何用 Potato 的网页智能体轨迹展示来评测自主网页浏览智能体,包含逐步截图、SVG 覆盖层和逐步标注方案。

Potato Team

网页浏览智能体所处的模态与基于文本的智能体不同。它们在真实网页上导航、点击按钮、填写表单、滚动页面。要评测这样一个智能体,你需要看到智能体看到了什么(页面状态)和它做了什么(执行的动作),最好还带一层标出它究竟点在哪里的覆盖层。

Potato 的网页智能体轨迹展示正是为此而建。它渲染整页截图并叠加 SVG 动作覆盖层,提供一条便于快速导航的胶片条,并让你逐步给动作正确性打分。完整配置参考见源文档

本指南以评测 WebArena 轨迹为例,但同样的做法也适用于 VisualWebArena、原始浏览器录制,以及其他网页智能体格式。


前置条件

bash
pip install potato-annotation

你需要准备 WebArena 的轨迹文件,它们通常是截图加上一份 JSON 动作日志。VisualWebArena 使用类似的格式,有时还附带额外的视觉定位信息。


第 1 步:理解 WebArena 轨迹格式

一条 WebArena 轨迹是每个回合一个 JSON 文件,其中包含任务描述、动作序列和截图路径。下面是一个精简过的例子。

创建 data/web_traces.jsonl

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",
      "dom_snapshot": "dom/wa_001_step_00.html"
    },
    {
      "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"
    },
    {
      "step": 2,
      "url": "http://shop.example.com/electronics/laptops",
      "action_type": "click",
      "action_target": "Sort by: Price Low to High",
      "element_id": "sort-price-asc",
      "coordinates": [720, 155],
      "screenshot": "screenshots/wa_001_step_02.png"
    },
    {
      "step": 3,
      "url": "http://shop.example.com/electronics/laptops?sort=price_asc",
      "action_type": "click",
      "action_target": "First laptop: 'Budget Pro 14' - $349",
      "element_id": "product-101",
      "coordinates": [400, 380],
      "screenshot": "screenshots/wa_001_step_03.png"
    },
    {
      "step": 4,
      "url": "http://shop.example.com/product/101",
      "action_type": "click",
      "action_target": "Add to Cart button",
      "element_id": "add-to-cart-btn",
      "coordinates": [650, 520],
      "screenshot": "screenshots/wa_001_step_04.png"
    }
  ],
  "success": true,
  "final_screenshot": "screenshots/wa_001_final.png"
}

每一步都带有一张截图、所执行的动作、目标元素和点击坐标。Potato 的可视化覆盖层就是由这些信息绘制的。


第 2 步:配置项目

创建 config.yaml

yaml
annotation_task_name: "WebArena Agent Evaluation"
task_dir: "."
 
data_files:
  - "data/web_traces.jsonl"
 
item_properties:
  id_key: trace_id
  text_key: task
 
# --- Agentic annotation with web display ---
agentic:
  enabled: true
  trace_converter: webarena
  display_type: web_agent
 
  web_agent_display:
    # Screenshot rendering
    screenshot_max_width: 900
    screenshot_quality: 85
 
    # SVG overlays
    overlay:
      enabled: true
      click_marker: "circle"
      click_color: "#ef4444"
      click_radius: 20
      type_highlight: "#3b82f6"
      scroll_indicator: true
 
    # Filmstrip navigation
    filmstrip:
      enabled: true
      thumbnail_width: 150
      show_action_labels: true
 
    # Additional display options
    show_url_bar: true
    show_action_description: true
    show_dom_snapshot: false
 
# --- Annotation Schemas ---
annotation_schemes:
  # Overall task evaluation
  - annotation_type: radio
    name: task_success
    description: "Did the agent complete the task successfully?"
    labels:
      - "Success"
      - "Partial Success"
      - "Failure"
    label_requirement:
      required: true
 
  - annotation_type: radio
    name: task_efficiency
    description: "Was the agent's navigation path efficient?"
    labels:
      - "Optimal path"
      - "Reasonable but not optimal"
      - "Inefficient (unnecessary steps)"
      - "Completely wrong direction"
    label_requirement:
      required: true
 
  # Per-step evaluation
  - annotation_type: trajectory_eval
    name: action_correctness
    steps_key: agentic_steps
    description: "Was this action correct?"
    correctness_options:
      - "Correct"
      - "Acceptable (not optimal but progresses toward goal)"
      - "Incorrect"
      - "Unnecessary"
 
  - annotation_type: trajectory_eval
    name: action_error_type
    steps_key: agentic_steps
    description: "What went wrong?"
    correctness_options:
      - "Wrong element clicked"
      - "Wrong page navigated to"
      - "Missed a closer/better option"
      - "Incorrect form input"
      - "Premature task completion"
      - "Unnecessary navigation"
      - "Failed to scroll to target"
      - "Interaction with wrong page section"
      - "Other"
  - annotation_type: trajectory_eval
    name: action_notes
    steps_key: agentic_steps
    description: "Notes on this step"
 
output_annotation_dir: "output/"
export_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/parquet/"

第 3 步:理解网页智能体展示

网页智能体轨迹查看器会渲染截图,并用 SVG 覆盖层标出点击目标和导航路径:

Potato 中的网页智能体轨迹查看器

主截图视图

当前步骤的截图以全宽显示(最大 900px),上面叠加一层 SVG:

  • 红色圆圈位于点击坐标处,标出智能体究竟点在哪里
  • 蓝色高亮围绕智能体输入过文字的文本框
  • 箭头指示用于滚动动作,显示方向和幅度

截图下方会显示:

  • 地址栏显示该步骤的页面 URL
  • 动作描述(例如"在坐标 [245, 82] 处点击'Electronics category link'")

胶片条

底部的横向胶片条会显示每张截图的缩略图,每张都带一个标明动作类型(点击、输入、滚动)的小标签。点击任意缩略图即可跳到对应步骤。

在较长的轨迹(10 步以上)上,胶片条的价值就体现出来了,因为在主视图里一路滚动会很繁琐。

逐步标注

逐步标注的控件就放在每张截图旁边。给动作打分,如果判为错误,再选择错误类型。


第 4 步:标注工作流

走一遍网页智能体轨迹的典型流程:

  1. 阅读任务描述。 弄清智能体本应完成什么。

  2. 用胶片条通览全局。 在逐步打分之前,先快速扫一遍所有截图,对智能体的轨迹有个整体印象。

  3. 逐步查看:

    • 看截图,理解页面状态
    • 看 SVG 覆盖层,确认智能体点了什么
    • 读动作描述
    • 把动作评为正确、可接受、错误或多余
    • 如果判为错误,选择错误类型(可多选)
  4. 给整条轨迹打分。 查看完所有步骤后,评价任务成功度和效率。

  5. 提交,然后进入下一条轨迹。

该看什么

正确的动作以合理的方式推进目标:点对了元素、到对了页面,或输入了正确的信息。

可接受的动作并非最优,但仍在推进。比如智能体不用搜索框,而是一层层浏览到分类页。慢一些,但管用。

错误的动作就是失误:点错元素、进了无关页面,或在表单里填错文字。

多余的动作不会推进目标:点一下又立刻退回、滚过了目标,或者晃到无关紧要的页面上。


第 5 步:错误分类体系

Potato 附带一套为网页智能体动作设计的错误分类体系。各类别的适用情形如下:

错误类型说明示例
点错元素智能体点击了错误的界面元素点了"Tablets"而不是"Laptops"
导航到错误页面智能体最终停在了无关页面上进了"About Us"而不是商品列表
错过了更近/更好的选项当时存在更优的动作用分类浏览而没用搜索框
表单输入错误智能体在表单中填了错误文字搜索"labtop"而不是"laptop"
过早宣告完成智能体太早认定任务成功把错的商品加进购物车就停了
多余的导航该步骤对目标没有贡献在两个分类页之间又回了一趟首页
未滚动到目标目标位于视口下方元素不可见,智能体本应滚动页面
操作了页面的错误区域页面对了但区域错了点了页头而不是主体内容

第 6 步:处理复杂轨迹

长轨迹(15 步以上)

在长轨迹上,先用胶片条找出可疑的步骤。留意这些迹象:

  • URL 发生意外变化的步骤(导航错误)
  • 智能体看起来在往回走的步骤
  • 连续出现几乎相同的截图(智能体陷入循环)

然后把详细标注的精力集中在这些步骤上。

失败的轨迹

当智能体失败时,找出第一个错误的步骤。这对改进智能体来说是最有价值的标注。把它清楚地标出来,并说明智能体本应怎么做。

难以判断的动作

有些动作仅凭截图很难判断。如果有 DOM 快照,就把它打开:

yaml
web_agent_display:
  show_dom_snapshot: true

这会增加一个可折叠面板显示原始 HTML,在截图含混时很有用,比如智能体点在了几个元素重叠的位置上。


第 7 步:为 VisualWebArena 配置

VisualWebArena 的轨迹带有额外的视觉定位信息。配置与前面类似,但会使用视觉定位覆盖层:

yaml
agentic:
  enabled: true
  trace_converter: webarena         # same converter handles both
  display_type: web_agent
 
  web_agent_display:
    screenshot_max_width: 1000
    overlay:
      enabled: true
      click_marker: "crosshair"     # crosshair is better for precise grounding
      click_color: "#ef4444"
      click_radius: 15
      bounding_box: true            # show element bounding box if available
      bounding_box_color: "#f59e0b"
    filmstrip:
      enabled: true
      thumbnail_width: 180

第 8 步:分析结果

按步骤位置看动作正确性

网页智能体的错误往往集中在轨迹中的特定位置。看看它们出现在哪里:

python
import pandas as pd
import json
 
annotations = []
with open("output/annotations.jsonl") as f:
    for line in f:
        annotations.append(json.loads(line))
 
# Collect per-step correctness by position
step_errors = {}
for ann in annotations:
    correctness = ann["annotations"].get("action_correctness", {})
    for step_idx, label in correctness.items():
        pos = int(step_idx)
        if pos not in step_errors:
            step_errors[pos] = {"Correct": 0, "Acceptable": 0, "Incorrect": 0, "Unnecessary": 0}
        step_errors[pos][label] += 1
 
# Print error rate by step position
print("Error rate by step position:")
for pos in sorted(step_errors.keys()):
    counts = step_errors[pos]
    total = sum(counts.values())
    error_rate = (counts["Incorrect"] + counts["Unnecessary"]) / total
    print(f"  Step {pos}: {error_rate:.1%} error rate ({total} observations)")

错误类型分布

python
error_counts = {}
for ann in annotations:
    errors = ann["annotations"].get("action_error_type", {})
    for step_idx, error_list in errors.items():
        for error in error_list:
            error_counts[error] = error_counts.get(error, 0) + 1
 
print("\nError Type Distribution:")
for error, count in sorted(error_counts.items(), key=lambda x: -x[1]):
    print(f"  {error}: {count}")

按网站看成功率

python
# If traces span multiple websites
website_success = {}
for ann in annotations:
    # Assuming website info is in the original trace data
    success = ann["annotations"]["task_success"]
    website = ann.get("metadata", {}).get("website", "unknown")
    if website not in website_success:
        website_success[website] = {"Success": 0, "Partial Success": 0, "Failure": 0}
    website_success[website][success] += 1
 
for website, counts in website_success.items():
    total = sum(counts.values())
    rate = counts["Success"] / total
    print(f"{website}: {rate:.1%} success rate")

第 9 步:把评测规模化

多标注者与一致性

如果要写论文,就给每条轨迹安排多位标注者:

yaml
annotation_task_config:
  total_annotations_per_instance: 3
  assignment_strategy: random

在任务成功标签上计算标注者间一致性:

python
from sklearn.metrics import cohen_kappa_score
import pandas as pd
 
df = pd.read_parquet("output/parquet/annotations.parquet")
success = df[df["schema_name"] == "task_success"]
pivot = success.pivot(index="instance_id", columns="annotator", values="value")
 
# Pairwise kappa
annotators = pivot.columns.tolist()
for i in range(len(annotators)):
    for j in range(i + 1, len(annotators)):
        mask = pivot[[annotators[i], annotators[j]]].dropna()
        kappa = cohen_kappa_score(mask[annotators[i]], mask[annotators[j]])
        print(f"Kappa ({annotators[i]} vs {annotators[j]}): {kappa:.3f}")

与 Solo 模式结合

对于大规模评测(500 条以上轨迹),可以用 Solo 模式让 LLM 处理简单的轨迹:

yaml
solo_mode:
  enabled: true
  llm:
    endpoint_type: openai
    model: "gpt-4o"
    api_key: ${OPENAI_API_KEY}
  accuracy_threshold: 0.90
 
agentic:
  enabled: true
  trace_converter: webarena
  display_type: web_agent

人来评测困难的轨迹;LLM 处理那些一目了然的成功和明显的失败。


小结

要评测一个网页浏览智能体,你必须看到它究竟看到了什么、做了什么。Potato 的网页智能体展示提供:带覆盖层的完整截图,标出点击目标、输入框和滚动动作;便于通览和跳转的胶片条;追踪导航路径的地址栏;配有网页专用错误分类体系的逐步标注;以及在 WebArena、VisualWebArena 和原始浏览器录制之间通用的同一套配置。

如果看不到智能体实际点在哪里,你就无法可靠地判断那个动作是否正确,而这正是覆盖层的用途。


延伸阅读