浏览器 Agent 感知流派 (Browser Agent Perception Paradigms)
浏览器/桌面 Computer Use Agent 的核心分岔点,不是模型、不是框架,而是「模型靠什么看到页面」——感知方式。感知方式决定了三件事:精度(点得准不准)、token 成本(省不省钱)、稳定性(页面改版后还能不能用)。
本文对比三大流派,并解剖两个真实实现(OpenAI Codex CUA、OpenMinis)的源码级细节。分析日期:2026-09-20。
一、三大感知流派总览
| 流派 | 感知输入 | 代表实现 | 精度 | token 成本 | 弱点 |
|---|---|---|---|---|---|
| 纯视觉 (Pure Vision / Screenshot-first) | 截图 + 多模态模型 | Midscene.js、browser-use(Set-of-Marks 标号)、UI-TARS | 高(对所见即所得) | 最高(每步一张图) | 贵、慢、坐标易漂移 |
| DOM 树 (DOM Tree) | 简化 DOM / 可读文本 / 自研骨干树 | OpenMinis get_backbone、简单 text 提取 | 中 | 低 | 动态页面脆弱、canvas/iframe 抓瞎 |
| 无障碍树 (Accessibility Tree, a11y) | 浏览器语义树(role+name+index) | Playwright MCP、Stagehand、OpenAI Codex CUA | 高(语义稳定) | 低 | 依赖站点 a11y 质量、需要把树算出来 |
一句话总结:纯视觉看"长得像什么",DOM 树看"源码是什么",a11y 树看"读屏器读出来是什么"。后者是 agent 的甜点区——既便宜又有语义。
二、a11y 树到底是什么(和 DOM 树不是一回事)
无障碍树 (Accessibility Tree) 是浏览器为辅助技术(读屏器)单独计算出来的一棵语义树。它不是 DOM,虽然从 DOM 派生。
核心区别:
- DOM 树:原始 HTML 结构,包含
<div>、<span>、<style>、布局元素、脚本注入的垃圾节点。对 agent 来说噪音巨大。 - a11y 树:浏览器自己把 DOM"翻译"成读屏器需要的语义结构——折叠表现层节点、合并冗余、给每个有意义元素算 role(角色)和 name(名字)。一棵几十层的 DOM 常常压成一棵 3~4 层的 a11y 树。
agent 用它天然合适,因为 读屏器面对的问题 = agent 面对的问题:都要在不可见的页面里找到"可交互的东西",并且需要稳定、可指向的标识。a11y 树给每个元素编号(elementIndex / element_index),模型点 element_index=12 就行。
为什么会有 wasm 的事
页面里的 JS(content script / 油猴 / 注入脚本)拿不到浏览器算好的 a11y 树——那棵树只在浏览器内核里,不对页面 JS 暴露(读屏器走的是原生 accessibility API)。
所以要在页面内拿 a11y 树,只有两条路:
- 重算:把 Chromium 计算 accessibility 树的逻辑(ARIA 解析、role/name 计算、树折叠)自己实现一份。
- 编译:把那个逻辑编译成 wasm,注入页面执行——这正是 OpenAI 干的事。
Codex 的 browser-service.mjs 里带一个 browser-accessibility.wasm.br(Brotli 压缩的 wasm 模块),注入页面后用 wasm 在页面上下文里算 a11y 树。选 wasm 的原因:纯 JS 重写整套 ARIA 计算太重、太慢,wasm 是二进制体积和性能的最优解。
参考:Playwright 的ariaSnapshot也是同思路——自己实现 a11y 快照生成,而不是依赖浏览器原生。@oai/browser-desktop/scripts/里同时有browser-accessibility.wasm.br和zxing_reader.wasm(二维码识别),说明 wasm 是它做页面内重活的通用手段。
流派的澄清
a11y 流派不是新流派,它是"结构化文本流派"里最精细的进化版:DOM 树提取 → 可读文本提取 → 语义树提取。三者在 token 价格上同档(都是文本),但语义树的精度天花板最高,因为浏览器替你做了去噪和语义标注。
三、实现解剖 1:OpenAI Codex CUA
位置(私有 npm 包,装上才有,npm 上是 404):
AppData\Local\OpenAI\Codex\runtimes\cua_node\<hash>\bin\node_modules\@oai\包:@oai/cua(17M)、@oai/sky(57M)、@oai/browser-desktop(7.6M)、@oai/cua-repl(103K)。
架构:不是工具调用,是"模型写 JS"
Codex 的 computer use 不用 JSON 参数的工具调用,而是给模型一个 node_repl(Node.js REPL,状态跨调用持久),模型直接写 JavaScript 调 Sky/CUA 的 API,nodeRepl.write() 输出。这是它和 OpenMinis 最大的架构差异。
var sky = (globalThis.sky ??= (await import("@oai/sky")).sky);
var state = await sky.get_window_state({ window, include_screenshot: true, include_text: true });
nodeRepl.write(String(state.accessibility?.tree || state.accessibility?.document_text || ""));两层
| 层 | 包 | 管什么 | 关键接口 |
|---|---|---|---|
| 整机级 (Computer Use) | @oai/sky | Windows/macOS/Linux 原生 app | list_apps / get_window_state / click(element_index 或坐标) / type_text / scroll / set_value / drag / perform_secondary_action / activate_window |
| 浏览器级 (Browser Use) | @oai/cua 的 tinysky_alt | 浏览器 tab | getAXState() / getScreenshot() / getAXStateAndScreenshot() / click(element_index) / selectText / setValue / drag / scroll / performSecondaryAction |
Tab = BrowserTab & Target——浏览器 tab 直接增强出共享交互面。浏览器通过 @oai/browser 的 GlobalAgentApi(agent.browsers.get() / browser.tabs)枚举。
提示词怎么拼
- 整机级:
@oai/sky/docs/skills/oai_sky_lib/windows/SKILL.md(231 行)就是提示词本体,完整 TS API 参考整个嵌在文件里,模型作为 skill 强制先读。 - 浏览器级:
tinysky_alt/documentation.js通过nodeRepl.requestMeta按需分发docs/tinysky-alt-*.md(confirmations / core-cua-repl / core-node-repl / other-browser-apis),不是一次性全塞。
感知与省 token
browser-service.mjs(1.3MB,注入页面的 agent 脚本,自带 processShim)关键词统计:screenshot×230、elementIndex×42、getAXState×12、ariaSnapshot×5、disableDiffing×12。
- 主感知 = a11y 树(wasm 在页面内算),截图是辅助/视觉确认。
- state diffing(
disableDiffing默认关掉才算关):状态只给变化部分,不是整棵树重发。 - 截图自动展示、禁止重复 emit:SKILL.md 明确"不要 decode/save/print 截图 payload 再次检查"。
- 批量输入再抓一次状态:"treat
get_window_stateas an expensive point-in-time snapshot. Batch related inputs, then capture a new state." - Playwright locators 只是 fallback("Other Browser APIs"):文档明说它比 a11y API 啰嗦,除非能省掉多次
getAXState()才值得用。
详见已归档笔记:Windows 桌面自动化 Computer Use (Codex Computer Use via node_repl)
四、实现解剖 2:OpenMinis(端侧 agent)
位置:OpenMinis/OpenMinis,Swift 实现,浏览器 agent 在 src/ios/Agent/BrowserUse/,7641 行 10 个文件。基于 WKWebView + 注入页面 JS。
| 文件 | 行数 | 职责 |
|---|---|---|
BrowserUseManager.swift | 2897 | runtime 循环、action 分发、DOM 沉降检查 |
BrowserTabPool.swift | 1517 | 多标签池 |
BrowserUseJavaScript.swift | 858 | 注入页面的 JS(DOM 提取 + 操作) |
BrowserUseActions.swift | 218 | 22 种 action 枚举 |
范式:自研 DOM 骨干树 + 结构化工具调用
- 工具调用形态:一个
browser_use工具、22 种 action、约 30 个参数(枚举BrowserAction)。 - 主感知 =
get_backbone:自研"矩形合并骨干树"——收集可见叶子 → 按矩形重叠向上合并 → 注入含≥2 叶子的祖先做分组 → 生成短选择器(#id或#ancestor > tag:nth(n))→ 文本截 120 字符。不是 a11y 树,是它自己的 DOM 流派。 - 省 token 大招 = DOM 变更摘要(
BrowserUseManager.swift):click/type/navigate 后等 DOM 沉降(MutationObserver),返回"页面变了什么"的文本摘要,而不是重截图。快照只给 UI 预览,不进模型。 - 其他:
get_readable(正文提取)、scroll_and_collect(无限滚动去重,30k 上限)、wait_for_dom_stable(突变率梯度稳定判定)。 - 视觉兼容:模型能看图→截图给像素;纯文本模型→Vision Group 描述成文字(
activeModelHasNativeVision)。
原创性
自研。THIRD_PARTY_LICENSES.md 无 browser-use/Stagehand/Midscene 归因,fork 的只有 ish-arm64 / proot(沙盒基础设施)。
五、省 token 手段对比
| 手段 | Codex | OpenMinis |
|---|---|---|
| 主感知 | a11y 树(wasm 页面内算) | 自研矩形合并骨干树 |
| 状态去重 | state diffing(只给变化部分) | DOM 变更摘要(MutationObserver) |
| 截图策略 | 自动展示,禁止重复 emit | 快照只给 UI,不进模型 |
| 操作目标 | element_index(稳定语义) | 短选择器(#id / nth) |
| 失败兜底 | Playwright locators | CSS selector / 坐标 |
结论:两者同属"结构化文本流派",都极度在意省 token。Codex 靠浏览器语义基建(a11y),OpenMinis 靠自研 DOM 压缩。Codex 的 diffing 更系统(整棵树级),OpenMinis 的变更摘要在"动作后"场景更细。
六、选型框架(给油猴/插件项目的决策依据)
| 场景 | 推荐流派 | 理由 |
|---|---|---|
| 长任务、重复性操作 | a11y 树 | element_index 稳定,不易被页面刷新破坏 |
| 快速一次性任务 | DOM 树(骨干提取) | 便宜、零依赖,OpenMinis get_backbone 可直接抄 |
| 复杂动态 UI / canvas / iframe | 纯视觉 | 只有图能解决,认账 token 成本 |
| 油猴脚本(页面内注入) | DOM 树为主 | 页面 JS 拿不到浏览器原生 a11y 树,要么重算(重)要么自己压缩 DOM(轻)。油猴场景下 OpenMinis 路线性价比最高;a11y 树需要引入 wasm 或 JS 版 ARIA 计算,成本高 |
关键权衡:油猴里三种都能做,但——纯视觉最贵、a11y 最稳但最重(要自带树计算)、DOM 骨干树最轻但最脆。做产品先选"够用且便宜"的 DOM 骨干树,遇到痛点再局部上 a11y 或视觉。
参考
- 本机 Codex CUA 源码:
C:\Users\18086\AppData\Local\OpenAI\Codex\runtimes\cua_node\4004642ff3fabdc7\bin\node_modules\@oai\ - OpenMinis 浏览器 agent:
C:\Users\18086\.workspace\git program\OpenMinis\src\ios\Agent\BrowserUse\ - 公开逆向项目:
JimLiu/decode-codex(macOS,解 ChatGPT.app 的 asar) - 关联:Windows 桌面自动化 Computer Use (Codex Computer Use via node_repl)
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps