欢迎光临
我们一直在努力

agent-browser 与 CDP:浏览器自动化的底层原理

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 带来的优势:

  • 零依赖运行:不需要 Node.js 环境,单个二进制文件即可运行
  • 原生性能:WebSocket 通信、JSON 解析、Accessibility Tree 处理都在原生层面完成
  • 进程管理:启动/监控/清理 Chrome 进程树更可靠
  • 四、核心能力深度解析

    4.1 Chrome 进程管理

    agent-browser 不只是「连接到一个已运行的 Chrome」,它还负责完整的 Chrome 生命周期管理。

    启动流程(cdp/chrome.rs):

  • 检测系统中已有的 Chrome(Chrome/Edge/Brave/Playwright/Puppeteer)
  • 构建启动参数(headless、user-data-dir、window-size、proxy 等)
  • 启动 Chrome 子进程
  • 从 DevToolsActivePort 文件读取端口和 WebSocket 路径
  • 验证 WebSocket 端点是否可用
  • 进程清理:

    • 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 —— 事件广播

    命令发送流程:

  • 生成唯一 id(AtomicU64 自增)
  • 将 id → oneshot::Sender 存入 pending HashMap
  • 通过 WebSocket 发送 JSON
  • 在 Reader 任务中,收到响应后根据 id 找到对应的 Sender,发送结果
  • 调用方通过 oneshot::Receiver 等待结果(30 秒超时)
  • 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 行):

  • 启用 Accessibility Domain:Accessibility.enable
  • 获取完整 AX 树:Accessibility.getFullAXTree
  • 构建树结构:Chrome 返回的 AX 节点是扁平数组,需要通过 childIds 重建层级
  • 生成 Ref 映射:每个可交互元素分配一个 @ref,后续 click @3 时通过 RefMap 解析为具体 DOM 操作
  • iframe 穿透:遍历所有 iframe,为每个 frame 创建独立的 CDP session
  • 4.4 交互能力

    点击(interaction.rs):

    agent-browser 的点击不是简单的 element.click(),而是模拟真实的鼠标事件序列:

  • 解析 ref/selector,获取元素中心坐标(考虑 iframe 偏移)
  • 发送鼠标移动事件(Input.dispatchMouseEvent mouseMoved)
  • 发送鼠标按下事件(Input.dispatchMouseEvent mousePressed)
  • 发送鼠标释放事件(Input.dispatchMouseEvent mouseReleased)
  • 这比 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": "{}"}'

    实现原理:

  • Fetch.enable 启用拦截(urlPattern: "*")
  • 监听 Fetch.requestPaused 事件
  • 匹配 URL 模式,决定是放行、mock 响应还是 abort
  • 通过 Fetch.fulfillRequest 或 Fetch.continueRequest 响应
  • 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 难以实现的事情:

    能力shell 难度agent-browser 实现
    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
    赞(0)
    未经允许不得转载:171主机测评 » agent-browser 与 CDP:浏览器自动化的底层原理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址