agent-browser 与 CDP:浏览器自动化的底层原理
本文基于对 vercel-labs/agent-browser v0.26.0 源码的完整分析,深入剖析其架构设计与 Chrome DevTools Protocol 的交互原理。
一、agent-browser 是什么
agent-browser 是 Vercel Labs 开源的浏览器自动化 CLI 工具,专为 AI Agent 设计。与传统工具不同,它的定位是"AI 友好的浏览器自动化"——输出 accessibility tree 而非原始 DOM,让 LLM 能直接理解页面结构。
关键特性:
- Rust 原生实现:核心约 36,000 行 Rust 代码,Node.js 仅作为跨平台 wrapper
- CDP 直连:通过 WebSocket 与 Chrome DevTools Protocol 通信,无需 Playwright/Puppeteer 中间层
- Accessibility Tree:snapshot 命令输出可交互元素的层级结构,自带 @ref 标记
- 多 Backend 支持:CDP(Chrome)、WebDriver、Appium、Lightpanda
二、CDP 基础:Chrome DevTools Protocol
2.1 什么是 CDP
CDP 是 Chrome 内置的远程调试协议。当你打开 Chrome 的「开发者工具」时,DevTools 前端就是通过 CDP 与 Chrome 后端通信的。agent-browser 本质上就是用一个程序替代了 DevTools 前端。
2.2 CDP 的两种通信方式
| HTTP | HTTP/JSON | 发现可用页面 |
| WebSocket | JSON-RPC | 实时命令和事件传输 |
关键发现:agent-browser 与 Chrome 的通信全是 WebSocket,没有 HTTP REST API。这意味着每个命令都是异步的——发一个请求,通过 id 字段匹配响应。
2.3 CDP 消息格式
// 命令(Client → Chrome)
{"id": 1, "method": "Runtime.evaluate", "params": {"expression": "document.title"}}
// 响应(Chrome → Client)
{"id": 1, "result": {"value": "Example Domain"}}
// 事件(Chrome → Client,无 id)
{"method": "Page.loadEventFired", "params": {"timestamp": 1234567890}}
三、agent-browser 架构总览
3.1 分层架构
┌─────────────────────────────────────────┐
│ CLI 层(Rust) │
│ – 命令解析(open/snapshot/click/fill) │
│ – 状态管理(DaemonState) │
├─────────────────────────────────────────┤
│ Action 层(actions.rs, 9000+ 行) │
│ – handle_navigate / handle_evaluate │
│ – handle_snapshot / handle_click │
│ – handle_screenshot / handle_route │
├─────────────────────────────────────────┤
│ Browser 管理层(browser.rs) │
│ – Chrome 进程启动/发现/清理 │
│ – 页面导航(含 waitUntil 策略) │
│ – 多 Target/Session 管理 │
├─────────────────────────────────────────┤
│ CDP 客户端层(cdp/client.rs) │
│ – WebSocket 连接管理 │
│ – 命令/响应 id 匹配 │
│ – 事件广播(broadcast channel) │
│ – Keepalive(30s Ping) │
├─────────────────────────────────────────┤
│ WebSocket(tokio-tungstenite) │
│ ↕ │
│ Chrome DevTools Protocol │
└─────────────────────────────────────────┘
3.2 为什么用 Rust 而非 Node.js
package.json 中有一行关键说明:"Fast native Rust CLI"。
agent-browser 的 bin/agent-browser.js 实际上只是一个跨平台 wrapper——检测操作系统和架构,然后调用对应的原生二进制。核心逻辑全部在 Rust 中。
Rust 带来的优势:
四、核心能力深度解析
4.1 Chrome 进程管理
agent-browser 不只是「连接到一个已运行的 Chrome」,它还负责完整的 Chrome 生命周期管理。
启动流程(cdp/chrome.rs):
进程清理:
- Unix 系统使用 kill(-pgid, SIGKILL) 杀掉整个进程组
- 包括 GPU 进程、渲染进程、工具进程、crashpad 等
- 防止孤儿进程阻塞用户的正常 Chrome
4.2 WebSocket CDP 客户端
cdp/client.rs 是 agent-browser 最底层的模块,约 360 行 Rust 代码实现了一个生产级的 CDP WebSocket 客户端。
核心设计:
- next_id: AtomicU64 —— 自增命令 ID
- pending: HashMap<u64, oneshot::Sender> —— 等待响应
- event_tx: broadcast::Sender —— 事件广播
命令发送流程:
Keepalive:每 30 秒发送 WebSocket Ping 帧,防止中间代理(nginx/Envoy/云 LB)断开空闲连接。
4.3 Accessibility Tree 快照
snapshot 是 agent-browser 最核心的 AI 友好特性。
传统工具的痛点:Playwright 的 page.content() 返回原始 HTML,LLM 难以理解;querySelector 需要精确的 CSS 选择器,对动态生成内容无效。
agent-browser 的方案:
agent-browser snapshot
输出格式:
[3] link "登录"
[7] textbox "用户名"
[12] button "提交"
实现原理(snapshot.rs, 1586 行):
4.4 交互能力
点击(interaction.rs):
agent-browser 的点击不是简单的 element.click(),而是模拟真实的鼠标事件序列:
这比 JavaScript 的 click() 更真实,能触发 CSS :hover、鼠标事件监听器等。
输入(fill / type):先聚焦元素,清空现有内容(Ctrl+A + Delete),然后逐字符输入。
4.5 Network 拦截
agent-browser 支持通过 CDP 的 Fetch domain 拦截和修改网络请求:
agent-browser route "**/api/**" –mock '{"status": 200, "body": "{}"}'
实现原理:
4.6 多 Backend 架构
agent-browser 不仅支持 CDP,还抽象了 WebDriver 和 Appium 后端:
pub enum BrowserBackend {
Cdp(CdpBackend),
WebDriver(WebDriverBackend),
Appium(AppiumManager),
}
设计意义:
- CDP:本地 Chrome,功能最全(snapshot、network 拦截、录屏)
- WebDriver:远程浏览器(Selenium Grid、BrowserStack)
- Appium:移动端浏览器(iOS Safari、Android Chrome)
所有 backend 实现相同的 BrowserBackend trait,上层 actions 代码无需关心底层协议差异。
五、为什么不是 shell 脚本
很多开发者看到 CDP 是 JSON over WebSocket,会直觉地认为:"用 curl + websocat + jq 就能搞定"。实际上 agent-browser 做了大量 shell 难以实现的事情:
| WebSocket 全双工 | ❌ 极难 | tokio-tungstenite 异步读写 |
| 命令/响应匹配 | ❌ 难 | HashMap<id, oneshot::Sender> |
| 事件持续监听 | ❌ 极难 | broadcast::channel(4096) |
| Chrome 进程管理 | ⚠️ 中等 | 启动→发现→清理全生命周期 |
| Accessibility Tree 解析 | ❌ 极难 | 1586 行专用逻辑 |
| iframe 穿透 | ❌ 难 | 跨 session 递归解析 |
| Network 拦截 | ❌ 难 | Fetch domain + 实时事件处理 |
shell 能做的:简单的 Runtime.evaluate 执行 JS
WS=$(curl -s http://localhost:9222/json/version | jq -r .webSocketDebuggerUrl)
echo '{"id":1,"method":"Runtime.evaluate","params":{"expression":"document.title"}}' | websocat "$WS"
shell 不能做的:同时监听事件流、匹配异步响应、管理多 session、解析 AX 树。
六、实际应用场景
6.1 AI Agent 网页操作
agent-browser 最初的设计目标就是让 LLM 能「看懂」网页并操作:
LLM ← accessibility tree(带 @ref)
LLM → click @7 / fill @12 "username"
这比让 LLM 直接看 HTML 或截图更高效。
6.2 自动化测试
agent-browser open "https://example.com/login"
agent-browser fill @email "test@example.com"
agent-browser fill @password "secret"
agent-browser click @submit
agent-browser wait-for "Dashboard"
agent-browser screenshot –output login-success.png
6.3 网页数据采集
agent-browser open "https://example.com/products"
DATA=$(agent-browser eval "JSON.stringify([…document.querySelectorAll('.product')].map(…))")
6.4 录屏与回放
agent-browser 支持 Page.screencastFrame CDP 事件,实时捕获页面变化帧,可用于操作回放、视觉回归测试、AI 训练数据采集。
七、总结
agent-browser 的核心价值不在于「能用 CDP」,而在于将 CDP 的底层能力封装成 AI 友好的高层抽象。
| 底层 | WebSocket + JSON-RPC | 中等 |
| 中间层 | CDP 命令封装、事件循环、session 管理 | 高 |
| 上层 | Accessibility Tree、Ref 映射、多 Backend | 很高 |
| 应用层 | AI 友好的 CLI 接口 | 高 |
如果你只是偶尔需要执行一段 JavaScript,shell + websocat 完全够用。但如果你需要让 AI 理解页面结构并操作、处理 iframe、动态内容、network 拦截、跨平台跨后端统一部署,那么 agent-browser 这样的工具是不可替代的。
参考链接:
- agent-browser GitHub
- Chrome DevTools Protocol 文档
- Accessibility.getFullAXTree


