观察与动作循环
核对日期:2026-08-26。
1. 定义与边界
GUI Agent 的循环仍是 Agent Loop:观察 → 决策 → 动作 → 再观察。差别在于观察是屏幕或无障碍树,动作是指针 / 键盘 / 导航,而且一个模型回合可以发出一批必须按序执行的动作。
两种观察不可混用同一套坐标空间:
| 观察 | 来源 | 动作目标 | 适用 |
|---|---|---|---|
| 无障碍树 + 元素引用 | read_page / Playwright browser_snapshot | { type: "ref", ref: "ref_2" } | 有可用 a11y 的网页 |
| 截图像素 | screenshot / zoom | { type: "coordinate", x, y } 或 [x, y] | Canvas、远程桌面嵌页、无节点控件 |
| 桌面截图 | Computer use screenshot | 显示器像素,须与返回图一致 | 操作系统 UI |
Anthropic browser use:优先 ref,树不够再坐标;先读树再截图。Computer use:几乎只有像素。Playwright MCP:默认树,截图给人或复核,不当主循环。
2. 为什么重要
循环写错会出现「看起来在动、其实在点空气」:
- 滚动后仍用旧坐标。
- 导航后仍点
ref_3,节点已经换人。 - 把并行 tool use 的实现套到 GUI 批处理上,后一个
type打进错误焦点。 - 只回第一条
tool_use的 result,API 直接invalid_request_error。
批处理是性能优化,也是安全风险:一回合可以 click → type → 提交。
3. 核心机制
Anthropic 对 computer 批处理的 halt 文本是:Not executed: an earlier computer action in this turn failed.
browser 批处理是:Not executed: an earlier action in this turn failed.
不要改写这两句。未回答的 block 会导致下一请求被拒。
4. 架构模式
4.1 引用生命周期
interface ElementRefRegistry {
tabId: string;
pageGeneration: number;
refs: ReadonlyMap<string, unknown>;
}
function resolveRef(
registry: ElementRefRegistry,
tabId: string,
pageGeneration: number,
ref: string,
): unknown {
if (registry.tabId !== tabId || registry.pageGeneration !== pageGeneration) {
throw new Error(`stale_ref:${ref}`);
}
const node = registry.refs.get(ref);
if (!node) {
throw new Error(`unknown_ref:${ref}`);
}
return node;
}
官方要求:ref 绑定产生它的 tab;导航或 DOM 大变即失效;不要在同一 tab 上重编号已发出的 ref。执行器不认识的 ref 应返回明确错误,让模型重新 read_page。
4.2 坐标空间
Computer use 的坐标永远在你回传的截图像素空间里。执行前校验:
function assertInViewport(
x: number,
y: number,
width: number,
height: number,
): void {
if (x < 0 || y < 0 || x >= width || y >= height) {
throw new Error("coordinate_out_of_bounds");
}
}
同一请求里同时声明 browser 与 computer 时,两套坐标系独立,靠 toolset_name 区分同名 member。
4.3 观察成本
| 手段 | 成本 | 信息 |
|---|---|---|
read_page filter=interactive | 低 | 可点控件 + ref |
子树 read_page(ref) | 更低 | 局部 |
| 整页截图 | 高 | 布局、图、渲染态 |
zoom 区域 | 中 | 小字、图标 |
| raw DOM / innerHTML | 禁止当默认观察 | 隐藏节点可藏注入 |
流式时 Anthropic 规定:member 的 input 以完整 JSON 到达后再执行整批,不要边解析边点。这与 ../18-Agent前端与交互/流式Tool-Use与前端状态.md 的「完整 JSON 才能执行」一致。
5. 工程实现
等待与稳定性:
- 动作后等网络空闲或指定选择器,再观察。固定
wait 2s会在慢页上点到半成品。 - Playwright 有 auto-wait;像素 CU 没有,需要执行器补
wait或截图重试。 - 批处理默认在末尾观察。computer 常以
screenshot收尾;browser 可以是read_page/screenshot/get_page_text。若模型没要观察,执行器可在最后一条非 tab-management result 上附多一块 image / 树,省一轮。
错误语义:
type GuiToolResult =
| { ok: true; content: readonly unknown[] }
| { ok: false; error: string; haltRest: boolean };
haltRest 为 true 时,后续 block 不执行,但仍要按官方 halt 文本回包。
6. 生产实践
| 实践 | 说明 |
|---|---|
| 树优先 | 有 a11y 就 ref,canvas 再截图 |
| 截图修剪 | Anthropic 建议保留最近约 3 张,按批删除,避免每步改 prefix 打爆 cache |
| 分辨率固定 | 虚拟显示 1024×768 一类稳定值,前后端约定 |
| 多 tab | 用官方 browser_state,tab 标题和 URL 也当不可信文本 |
| 前端卡片 | 一调用一张卡,展示 target(ref 或坐标)与风险;见 18 章 |
7. 常见反模式
| 反模式 | 表现 | 后果 | 修正 |
|---|---|---|---|
| 并行执行 GUI 批 | 当普通 parallel tools | 焦点错乱、重复提交 | 按序 |
| 丢弃后续 result | 只回第一条 | 下一请求 400 | 全回包 |
| 坐标当稳定 ID | 用 x,y 做回归断言 | 布局一变全红 | 业务结果断言 + ref |
| 回传 innerHTML | 「信息更全」 | 隐藏注入 | 可见树 / 可见文本 |
| 流式半 JSON 就点 | 参数还在增量 | 点错 | 等完整 input |
8. 评测方法
| 指标 | 说明 |
|---|---|
| Action Grounding Accuracy | 点击目标是否为指定控件 |
| Stale Ref Recovery | 过期 ref 是否重读而不是瞎点 |
| Batch Halt Correctness | 失败后是否停且回满 result |
| Observation Token | 每步观察 token,设预算 |
| Step Count | 同任务步数,防空转 |
样本要含:弹窗、慢加载、新开 tab、canvas 控件、滚动后点击。
9. 安全与治理
- 批处理中的 HITL 在每个 block 之前,见 凭证与HITL.md。
- 观察内容进模型前按不可信数据处理。
- 截图可能含 PII,trace 脱敏规则见 ../18-Agent前端与交互/轨迹回放界面.md。
10. 权威资料
- Anthropic Computer use(agent loop / batch actions): https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool (核对日期:2026-08-26)
- Anthropic Browser use(targets and coordinates): https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool (核对日期:2026-08-26)
- Playwright MCP snapshots vs screenshots: https://github.com/microsoft/playwright-mcp (核对日期:2026-08-26)