OpenClaw 已经拥有成熟的 browser 工具,但面对 agent-browser 的元素编号创新,我们有三个层次的集成选择:直接调用、功能融合、深度整合。本报告分析每种方案的技术路径、实现成本和预期收益。
1现状分析
OpenClaw 当前 Browser 架构
OpenClaw 的 browser 工具基于 Playwright,提供以下核心功能:
- snapshot:获取页面结构(使用 role-based refs)
- click/type/fill:基于 ref 的元素操作
- screenshot:页面截图
- navigate:页面导航
┌─────────────────────────────────────────────────────────┐
│ OpenClaw Gateway │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ browser tool│───▶│ Playwright │───▶│ Chromium │ │
│ │ │ │ Controller │ │ Browser │ │
│ └─────────────┘ └──────────────┘ └───────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Current: role-based refs (e.g., "button-Submit") │ │
│ │ Target: numeric refs (e.g., "@e12") │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
当前方案的局限性
- Ref 格式冗长:"button-提交表单" 比 "@e2" 多 10+ 个字符
- 语义歧义:多个同名按钮时难以区分
- 无稳定 ID:页面刷新后 ref 可能变化
- Token 成本高:每次操作都要传输完整描述
2技术原理:元素编号系统
ARIA 无障碍树(Accessibility Tree)
agent-browser 的核心创新是使用浏览器的无障碍树而非 DOM 树:
// DOM 树(传统方案)- 复杂且易变
<div class="container">
<button class="btn btn-primary" id="submit-btn">提交</button>
</div>
// ARIA 树(agent-browser)- 简洁且稳定
[button] "提交" // 只关心「这是什么」,不关心「怎么实现」
编号生成算法
编号系统的关键在于可预测的映射:
- 遍历 ARIA 树,按文档顺序收集所有可交互元素
- 为每个元素分配递增编号(e1, e2, e3...)
- 维护「编号→元素」的映射表
- 页面变化时重新生成编号
核心优势ARIA 树是语义的而非视觉的,不受 CSS 样式变化影响,比 DOM 选择器稳定得多。
3三种集成方案
方案 A:直接调用(最低成本)
将 agent-browser 作为外部 CLI 工具调用
- 实现:在 OpenClaw 中封装 agent-browser CLI
- 成本:1-2 天开发
- 收益:立即可用,Token 节省 90%+
- 缺点:依赖外部二进制,Rust 编译环境要求
方案 B:功能融合(推荐)
在 OpenClaw 现有 Playwright 基础上实现编号系统
- 实现:修改 snapshot 生成逻辑,添加元素编号
- 成本:1 周开发 + 测试
- 收益:完全内嵌,无外部依赖,可定制
- 优点:保持现有架构,渐进式升级
方案 C:深度整合(长期)
重构 browser 工具,原生支持元素编号和状态缓存
- 实现:新的 browser API 设计,支持 session 状态
- 成本:2-4 周开发
- 收益:最优性能,最简洁 API
- 风险:破坏性变更,需要迁移
4推荐方案 B:详细设计
核心组件
┌──────────────────────────────────────────────────────────────┐
│ OpenClaw Browser Tool │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ Element Mapper │◄───────▶│ Playwright Page │ │
│ │ (new) │ │ (existing) │ │
│ └────────┬────────┘ └─────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Snapshot Generator (modified) │ │
│ │ • 遍历 ARIA tree │ │
│ │ • 分配 numeric IDs (e1, e2, e3...) │ │
│ │ • 生成紧凑表示 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Action Handler (modified) │ │
│ │ • 解析 @eN 格式 │ │
│ │ • ID → Element 映射 │ │
│ │ • 执行 Playwright 操作 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
关键实现代码(伪代码)
// 1. 生成带编号的 Snapshot
async function generateNumericSnapshot(page) {
const elements = await page.accessibility.snapshot();
const numbered = [];
let counter = 1;
traverseTree(elements, (node) => {
if (node.role !== 'none' && node.name) {
numbered.push({
id: `e${counter}`, // e1, e2, e3...
role: node.role, // button, link, input...
name: node.name, // "提交", "搜索"...
backendNodeId: node.backendNodeId
});
counter++;
}
});
return numbered;
}
// 2. 紧凑输出格式
// 传统格式(高 Token)
[button "提交表单"], [input "用户名"], [link "忘记密码"]
// 新格式(低 Token)
e1=button[提交表单] e2=input[用户名] e3=link[忘记密码]
// 3. 执行操作
async function executeById(page, id, action, value) {
const element = await findElementByNumericId(page, id);
switch (action) {
case 'click': await element.click(); break;
case 'fill': await element.fill(value); break;
// ...
}
}
API 变更
| 命令 | 当前格式 | 新格式 | Token 节省 |
|---|---|---|---|
| snapshot | role-based refs | numeric refs (e1, e2) | ~70% |
| click | click "button-提交" | click @e2 | ~85% |
| fill | fill "input-用户名" "test" | fill @e1 "test" | ~90% |
| 综合场景 | 5 步操作 ~200 tokens | 5 步操作 ~20 tokens | ~90% |
5实施路线图
第一阶段:基础实现(Week 1)
- 修改 snapshot 生成器,支持 numeric ID 分配
- 实现 ID → Element 的映射缓存
- 添加 @eN 格式的指令解析
- 向后兼容:保留现有 role-based refs
第二阶段:优化迭代(Week 2)
- 添加 compact 输出模式(可选)
- 实现 session 状态保持(减少重复 snapshot)
- 性能测试和基准对比
- 文档和示例更新
第三阶段:生态整合(Week 3-4)
- 更新 skills 使用新的 browser API
- 探索与其他工具的集成(如 playwright-scraper)
- 社区反馈收集和功能调优
6预期收益与风险
收益
- Token 成本:浏览器自动化场景节省 85-93%
- 响应速度:更短的指令 = 更快的解析和执行
- 准确性:消除语义歧义,减少误操作
- 用户体验:更简洁的 API,更易理解的输出
风险与缓解
| 风险 | 影响 | 缓解方案 |
|---|---|---|
| 向后兼容性 | 现有 workflows 可能失效 | 双模式支持,渐进式迁移 |
| ID 稳定性 | 页面变化后 ID 可能改变 | 每次操作前重新 snapshot |
| 学习成本 | 用户需要理解新格式 | 清晰的文档和可视化工具 |
| ARIA 支持 | 某些页面 ARIA 标记不完整 | 回退到 DOM-based 选择器 |
7下一步行动
建议的立即行动
1. 创建原型分支,实现基础版 numeric snapshot
2. 选取 3-5 个典型场景进行 PoC 验证
3. 测量实际的 Token 节省和性能提升
4. 根据结果决定是否全面推广
需要的技术准备
- Playwright accessibility API 的深入了解
- OpenClaw browser 工具的代码审查
- 测试用例设计(覆盖主流网站类型)
- 性能基准测试框架
元素编号不是简单的「优化」,而是浏览器自动化范式的转变——从「描述视觉」到「引用语义」。这正是 ContextBench 论文强调的「简洁原语优于复杂脚手架」的实践体现。 本报告核心观点