浏览器自动化并不新。Playwright、Puppeteer、Selenium 这类工具已经能完成页面打开、元素定位、点击、输入、截图、表单提交等任务。
但这些工具的默认使用方式,通常假设操作者是程序员。
程序员会提前知道页面结构,然后写出类似这样的脚本:
await page.goto("https://example.com/login")
await page.locator("#username").fill("alice")
await page.locator("#password").fill("secret")
await page.locator("button[type=submit]").click()
这套模式的核心是:
代码逻辑 + 元素选择器 + 固定流程
对于传统自动化测试、爬虫、后台任务来说,这很合理。问题在于,AI Agent(人工智能代理)并不是这样工作的。
Agent 更像是在浏览器里边观察边行动:它看到页面上有什么,再决定下一步点哪里、输入什么、是否继续等待、是否回退。它无法总是提前写好完整脚本,也不适合在每一步都推理复杂的 CSS 选择器。
agent-browser 解决的正是这个问题:它把浏览器自动化改造成更适合 Agent 使用的 CLI(命令行界面)。
它的设计重点不是让人类写脚本更舒服,而是让 Agent 更容易理解页面、更稳定地执行动作。
传统浏览器自动化为什么不适合 Agent
传统自动化工具通常围绕 DOM(文档对象模型)和选择器工作。DOM 结构很完整,但对 Agent 来说信息量太大,而且很多信息并不直接服务于“下一步该操作什么”。
一个真实页面里可能包含:
- 大量嵌套的
div - 样式类名
- 隐藏元素
- 前端框架生成的中间节点
- 广告、布局、装饰性内容
- 重复出现的按钮和链接
- 动态渲染后的复杂 DOM 层级
如果把这些内容原样塞给 Agent,Agent 面临的不是“看网页”,而是“读一大坨 HTML”。
传统模式大致是这样:
flowchart LR
A[自动化脚本] --> B[CSS / XPath 选择器]
B --> C[DOM 节点]
C --> D[浏览器动作]
D --> E[页面状态变化]
这条链路对程序员友好,因为程序员可以写选择器;但对 Agent 不友好,因为 Agent 需要先理解页面,再生成一个足够准确的选择器。
选择器还有一个现实问题:页面稍微改版,选择器就可能失效。
| 方式 | 适合对象 | 主要依赖 | 问题 |
|---|---|---|---|
| Playwright / Puppeteer 脚本 | 程序员、测试工程师 | CSS 选择器、XPath、固定脚本 | Agent 需要自己生成选择器,容易受 DOM 噪声影响 |
| 直接读取 HTML | 爬虫、结构化解析任务 | DOM 文本 | 上下文过大,交互语义不清晰 |
| agent-browser 快照 | AI Agent | 可访问性树、交互元素引用 | 更适合“观察—决策—行动”的循环 |
agent-browser 的核心思路是:不要让 Agent 直接面对完整 DOM,而是给它一份更像“可操作页面摘要”的快照。
agent-browser 是什么
agent-browser 是一个用 Rust 编写的浏览器自动化 CLI,目标使用者是 AI Agent,而不是直接操作浏览器的人类用户。
它有几个关键特点:
-
面向 Agent 设计
命令和输出都围绕 Agent 的工作方式组织,让 Agent 可以先观察页面,再基于观察结果执行动作。 -
直连 Chrome DevTools Protocol
Chrome DevTools Protocol(Chrome 开发者工具协议,简称 CDP)是 Chrome 暴露给调试器和自动化工具的一组接口。agent-browser 直接使用 CDP 控制浏览器,不依赖 Node.js,也不依赖 Playwright。 -
用 Rust 实现
Rust 适合编写单文件 CLI、后台服务和系统工具。用 Rust 实现可以减少运行时依赖,让工具更接近一个独立浏览器控制器。 -
引入 snapshot 快照机制
快照会把当前页面中适合交互的元素整理出来,并给每个元素分配短引用,例如@e1、@e2、@e3。Agent 后续执行点击或填充时,可以直接引用这些编号。
整体结构可以理解为:
flowchart TD
A[AI Agent] -->|自然语言目标 / skills| B[agent-browser CLI]
B -->|CDP 调用| C[Chrome 浏览器]
C -->|页面状态 / 可访问性树| B
B -->|snapshot 快照| A
A -->|click @e1 / fill @e2| B
B -->|执行浏览器动作| C
这里最重要的变化是:Agent 不需要写 #submit、.btn-primary:nth-child(2) 这种选择器,而是可以根据快照里的语义描述选择 @e1 这样的稳定引用。
snapshot:把网页变成 Agent 能读懂的操作清单
agent-browser 最关键的能力是 snapshot。
它不是简单返回 HTML,也不是把 DOM 序列化后丢给 Agent。它会调用 Chrome 的可访问性接口:
Accessibility.getFullAXTree
这个接口返回的是 Accessibility Tree(可访问性树)。
可访问性树原本是为了屏幕阅读器、辅助技术、无障碍访问设计的。它关心的不是页面如何排版,而是页面上有哪些对用户有意义的对象,例如:
- 按钮
- 链接
- 输入框
- 复选框
- 下拉框
- 文本区域
- 标题
- 表单控件
- 可点击区域
DOM 更接近“页面如何构造”,可访问性树更接近“用户能感知和操作什么”。
两者差异可以这样理解:
| 维度 | DOM | Accessibility Tree |
|---|---|---|
| 关注点 | HTML 结构、节点层级、样式关联 | 用户可感知的语义和交互对象 |
| 信息量 | 很大,包含大量布局和框架节点 | 更精简,过滤掉不少无交互意义的内容 |
| 对 Agent 的价值 | 需要额外推理哪些节点可操作 | 更直接暴露按钮、输入框、链接等语义 |
| 常见用途 | 前端渲染、脚本操作、样式计算 | 无障碍访问、屏幕阅读器、语义理解 |
agent-browser 在拿到完整可访问性树后,还会继续做裁剪和重排,把真正有交互价值的元素整理成快照。
一个简化后的快照可能长这样:
Current page: Login
@e1 link "Home"
@e2 textbox "Email"
@e3 textbox "Password"
@e4 checkbox "Remember me"
@e5 button "Sign in"
@e6 link "Forgot password?"
Agent 看到这份快照后,就不需要研究页面 DOM,也不需要猜测按钮选择器。它可以直接决定:
fill @e2 "alice@example.com"
fill @e3 "secret"
click @e5
这就是快照机制的价值:把“页面理解”和“页面操作”之间的桥梁变短。
为什么短引用比选择器更适合 Agent
短引用看起来只是把元素编号了,但它解决了 Agent 操作浏览器时的几个关键问题。
1. 降低上下文长度
完整 DOM 可能非常长,尤其是现代前端页面会包含大量框架生成的节点。Agent 的上下文窗口虽然越来越大,但上下文越大,推理成本越高,干扰也越多。
可访问性树经过裁剪后,只保留与用户操作相关的信息,可以显著减少输入给 Agent 的内容。
flowchart LR
A[完整 DOM] -->|过滤布局节点 / 隐藏节点 / 非交互节点| B[可访问性树]
B -->|裁剪 / 重排 / 编号| C[snapshot]
C --> D[Agent 决策]
Agent 需要的是“页面上有哪些能点、能填、能选的东西”,而不是页面所有 div 的嵌套关系。
2. 避免生成复杂选择器
让 Agent 生成 CSS 选择器是一件风险很高的事。它可能生成不存在的选择器,也可能选中多个元素,还可能在页面变化后失效。
短引用把选择器问题转移给 agent-browser。Agent 只需要使用快照里已经存在的引用。
不需要:
page.locator("div.container > form > div:nth-child(3) button.primary").click()
只需要:
click @e5
这种交互方式更接近人类使用网页:看到“登录”按钮,然后点击它。
3. 支持多轮观察和行动
Agent 的浏览过程不是一次性脚本,而是循环:
flowchart TD
A[生成页面快照] --> B[Agent 理解当前页面]
B --> C[选择下一步动作]
C --> D[agent-browser 执行动作]
D --> E[页面发生变化]
E --> A
每一次页面变化后,Agent 可以重新获取快照,再基于新的页面状态继续行动。
这比提前写死完整流程更适合处理动态页面,例如:
- 登录后出现验证码提示
- 表单校验失败后出现错误信息
- 搜索结果需要翻页
- 页面加载慢,需要等待某个按钮出现
- 不同账号看到的页面结构不完全一样
4. 让命令更像 Agent 的动作语言
对 Agent 来说,理想的浏览器控制接口应该接近动作描述,而不是编程 API。
例如:
snapshot
click @e1
fill @e2 "hello"
press Enter
wait
go_back
这类命令短、明确、容易组合,也方便放进 Agent 的 skills 或工具调用描述里。
agent-browser 的工作链路
agent-browser 可以拆成四层来看。
flowchart TB
A[Agent 层] --> B[CLI 命令层]
B --> C[浏览器控制层]
C --> D[Chrome DevTools Protocol]
D --> E[Chrome 页面]
E --> F[Accessibility Tree]
F --> G[snapshot 生成器]
G --> B
B --> A
各层职责如下:
| 层级 | 职责 |
|---|---|
| Agent 层 | 根据任务目标决定下一步要做什么 |
| CLI 命令层 | 接收 snapshot、click、fill 等动作命令 |
| 浏览器控制层 | 将命令转换为 CDP 调用 |
| CDP 层 | 与 Chrome 通信,执行导航、点击、输入、获取页面信息等操作 |
| snapshot 生成器 | 从可访问性树中提取交互元素,并分配 @e1 这类短引用 |
关键路径是:
sequenceDiagram
participant Agent as AI Agent
participant CLI as agent-browser
participant Chrome as Chrome
participant AX as Accessibility Tree
Agent->>CLI: snapshot
CLI->>Chrome: Accessibility.getFullAXTree
Chrome-->>AX: 返回完整可访问性树
AX-->>CLI: 节点信息
CLI-->>Agent: 返回带 @e 引用的快照
Agent->>CLI: click @e5
CLI->>Chrome: 通过 CDP 执行点击
Chrome-->>CLI: 页面状态变化
CLI-->>Agent: 动作结果
这条链路里,Agent 始终不需要直接操作 DOM。DOM 仍然存在,只是被封装在浏览器和 CDP 之后。
和 Playwright 的差异
agent-browser 并不是要替代 Playwright 的所有场景。两者面向的问题不一样。
| 对比项 | Playwright | agent-browser |
|---|---|---|
| 主要使用者 | 程序员、测试工程师 | AI Agent |
| 典型输入 | 脚本代码 | CLI 命令、动作引用 |
| 元素定位方式 | locator、CSS、XPath、文本选择器 | snapshot 中的短引用 |
| 页面理解方式 | 人提前理解页面结构并写脚本 | Agent 读取快照后动态决策 |
| 依赖 | 通常依赖 Node.js 生态 | Rust 实现,直连 CDP |
| 适合任务 | 自动化测试、稳定流程、可维护脚本 | Agent 浏览网页、动态任务执行、自然语言驱动操作 |
Playwright 更适合“流程已知、目标明确、需要长期维护脚本”的场景。
agent-browser 更适合“Agent 需要临场判断页面状态”的场景。
例如,自动化测试里要验证登录按钮是否可用,Playwright 脚本很合适;如果 Agent 要在陌生网站上查找资料、填写表单、处理不确定页面,基于快照的交互模型会更自然。
和直接让 Agent 看截图有什么不同
浏览器 Agent 还有另一种常见做法:给 Agent 截图,让它像看屏幕一样判断点击位置。
截图方式有一个优点:页面视觉信息完整。Agent 可以看到布局、颜色、位置、图标和整体外观。
但截图也有几个问题:
- 需要视觉模型参与,成本更高
- 点击通常依赖坐标,坐标容易受窗口大小、缩放比例影响
- 表单字段、按钮语义不一定容易从截图中稳定识别
- 对纯文本和结构化信息的抽取效率不如语义树
agent-browser 的快照方式更偏“语义浏览器自动化”,它不重点描述页面长什么样,而是描述页面能做什么。
| 方式 | 优点 | 局限 |
|---|---|---|
| 截图 + 坐标点击 | 保留视觉布局,适合复杂视觉界面 | 成本高,坐标脆弱,语义不稳定 |
| DOM / HTML 输入 | 信息完整,可精确定位 | 上下文大,噪声多,Agent 负担重 |
| Accessibility Tree 快照 | 语义清晰,交互元素明确,上下文较小 | 对纯视觉元素、canvas、自定义控件可能不够完整 |
如果页面主要由标准 HTML 控件组成,快照方式会非常高效;如果页面大量依赖 canvas、自绘 UI 或复杂视觉交互,可能还需要结合截图能力。
适合使用 agent-browser 的场景
agent-browser 的优势集中在“Agent 需要操作真实网页”的任务里。
| 场景 | 是否适合 | 原因 |
|---|---|---|
| Agent 根据自然语言目标浏览网页 | 适合 | 快照能给 Agent 提供紧凑的页面语义 |
| 自动填写标准网页表单 | 适合 | 输入框、按钮、复选框等元素可以通过可访问性树识别 |
| 页面状态不确定的多轮任务 | 适合 | Agent 可以每一步重新 snapshot |
| 固定流程的端到端测试 | 不一定 | Playwright 这类脚本化工具更成熟 |
| 大规模网页抓取 | 不一定 | 抓取更关注吞吐、反爬、数据抽取,未必需要 Agent 交互 |
| canvas 游戏、复杂图形应用 | 不太适合 | 可访问性树可能无法表达完整视觉状态 |
| 需要像素级视觉判断的任务 | 不太适合 | 需要截图和视觉模型配合 |
一个典型 Agent 浏览任务可以这样建模:
目标:进入某个网站,搜索关键词,打开最相关结果,提取页面摘要。
循环:
1. 获取 snapshot
2. 找到搜索框引用
3. 填入关键词
4. 提交搜索
5. 再次获取 snapshot
6. 找到结果列表中的目标链接
7. 点击进入
8. 获取页面内容或继续操作
这类任务的难点不是单次点击,而是每一步都要基于页面变化重新决策。snapshot 正好提供了这个循环所需的观察接口。
Agent First 原则意味着什么
“Agent First”不是简单地给工具加一个自然语言外壳,而是从接口设计开始就考虑 Agent 的限制和优势。
Agent 擅长:
- 根据语义描述做判断
- 在多轮过程中调整计划
- 从候选动作中选择下一步
- 处理不完全确定的页面状态
Agent 不擅长:
- 稳定生成复杂 CSS 选择器
- 从超长 HTML 中筛出关键节点
- 记住动态页面中节点的细节结构
- 精确处理大量低层浏览器 API
所以 agent-browser 把低层浏览器能力封装起来,只暴露更适合 Agent 使用的操作层。
flowchart LR
A[低层能力: CDP / DOM / AX Tree] --> B[agent-browser 封装]
B --> C[Agent 友好接口: snapshot / ref / action]
这和传统“给人用的浏览器工具”不同。给人用的工具通常强调可视化界面、调试体验、配置能力;给 Agent 用的工具更强调输出紧凑、动作明确、状态可恢复。
snapshot 机制的边界
快照机制很有用,但它不是万能的。
可访问性信息依赖页面质量
如果网页没有正确设置无障碍属性,快照中的语义可能不完整。例如按钮没有文本、输入框没有 label、图标按钮没有 aria-label,Agent 拿到的描述就会变弱。
一个不友好的按钮可能长这样:
<button>
<svg>...</svg>
</button>
更适合可访问性树识别的写法是:
<button aria-label="Search">
<svg>...</svg>
</button>
agent-browser 依赖可访问性树,页面无障碍质量越好,Agent 看到的快照越清晰。
动态页面需要重新获取快照
短引用来自某次 snapshot。页面发生变化后,旧引用可能不再代表同一个元素,甚至元素已经消失。
因此,Agent 执行动作后应该重新观察页面,而不是长期复用旧引用。
推荐:
snapshot
click @e5
snapshot
fill @e2 "new value"
不推荐:
snapshot
click @e5
等待页面变化很久后继续使用旧的 @e2
复杂视觉任务仍需要其他输入
可访问性树描述的是语义结构,不是完整视觉画面。对于验证码、图表、地图、canvas、自绘控件等内容,仅靠 snapshot 可能不够。
这类场景通常需要结合截图、OCR(光学字符识别)或视觉模型。
上手时应该关注的能力
由于 agent-browser 的核心不在“写脚本”,而在“让 Agent 能循环操作浏览器”,评估和使用时可以重点看四个动作是否顺畅。
| 能力 | 作用 |
|---|---|
| 启动或连接 Chrome | 建立浏览器控制通道 |
| 获取 snapshot | 让 Agent 观察当前页面 |
| 基于引用执行动作 | 用 @e1 这类 ref 点击、输入、选择 |
| 页面变化后再次观察 | 形成“观察—行动—再观察”的闭环 |
一个抽象的使用流程可以写成:
# 1. 打开目标页面
open https://example.com
# 2. 获取当前页面快照
snapshot
# 3. 根据快照中的元素引用执行动作
fill @e2 "alice@example.com"
fill @e3 "secret"
click @e5
# 4. 页面变化后重新观察
snapshot
这里的命令展示的是交互模型,实际命令名称以工具提供的 CLI 为准。关键不在具体拼写,而在这种引用式操作方式:Agent 通过快照拿到页面语义,再用短引用执行动作。
设计上的关键取舍
agent-browser 的设计可以概括为几个取舍。
| 取舍 | 选择 | 带来的结果 |
|---|---|---|
| 面向人还是面向 Agent | 面向 Agent | 输出更紧凑,命令更动作化 |
| 用 DOM 还是可访问性树 | 可访问性树 | 降低上下文噪声,更突出交互语义 |
| 用选择器还是短引用 | 短引用 | Agent 不需要生成复杂 CSS |
| 依赖 Playwright 还是直连 CDP | 直连 CDP | 减少外部运行时依赖,控制链路更直接 |
| 完整描述页面还是提取可操作元素 | 提取可操作元素 | 更适合多轮决策,但对复杂视觉界面表达有限 |
这套取舍背后的目标很明确:让 Agent 用更少的上下文完成更稳定的网页操作。
小结
agent-browser 把浏览器自动化从“程序员写脚本”转向“Agent 观察并行动”。
它不把完整 HTML 暴露给 Agent,而是通过 Chrome DevTools Protocol 获取 Accessibility Tree,再生成带有 @e1、@e2 这类短引用的 snapshot。Agent 可以基于快照理解页面,并用引用执行点击、输入等操作。
这种设计尤其适合多轮、动态、不确定的网页任务。只要页面的可访问性语义足够清晰,Agent 就能用更小的上下文、更少的选择器推理完成浏览器操作。