跳到主要内容

BrowserOS — 架构与原理

30 秒导读: BrowserOS 是一个开源的 Chromium 分支浏览器,内置能自己开标签页、点按钮、填表单、读网页的 AI agent。它的核心不在「调用大模型」,而在怎么让模型可靠地操作一个真实网页:把页面渲染成一棵带稳定编号(ref)的无障碍树发给模型当「视野」,模型回一个编号 BrowserOS 就经 Chrome DevTools Protocol 精确点中那个元素,每次动作后只回传一个「页面变了哪几行」的 diff 当反馈。


1. 这是什么(零基础也能懂)

一句话定义: BrowserOS 是一个「会自己上网」的浏览器——一个 Chromium 分支,里面跑着一个能用自然语言驱动的 AI agent,帮你在真实网页上完成任务。

解决什么问题 / 给谁用: 假设你想让 AI「去这三个购物网站比一下这台显示器的价格,把最便宜的报给我」。普通聊天机器人做不到——它看不到网页、点不了按钮。BrowserOS 把一个完整的浏览器交到 agent 手里:它能开标签页、导航、点击、填表、把页面读成 markdown,再把结果汇报给你。而且用你自己的 API key 或本地模型(Ollama),数据不离开你的机器——这是它对标 ChatGPT Atlas / Perplexity Comet 的卖点:隐私优先。

它能做什么:

  • 用自然语言驱动浏览器:导航、点击、输入、滚动、抓数据。
  • 多标签并行:为每个信息源开一个后台标签页,互不抢占用户焦点。
  • 当 MCP server:让 Claude Code 等外部 agent 通过 MCP 协议反过来控制这个浏览器。
  • 定时任务:让 agent 在隐藏页面上按日/小时自动跑。
  • 连 40+ 外部应用(Gmail / Slack / Linear...)走直接 API,而不是慢吞吞地点网页。

用起来什么样: 在侧边栏对它说一句话,它就开始一轮一轮地操作浏览器。一次典型的内部「思考」长这样(示意):

用户: 在 Hacker News 上找出现在排第一的帖子标题

agent → snapshot(page=2) # 先「看」一眼页面
← - link "Show HN: ..." [ref=e14]
- link "A new ..." [ref=e22]
...
agent → act(page=2, kind=click, ref=e14) # 点中第一条
← ok (click)
[Page 2 diff]
+ - heading "Show HN: ..." [ref=e31] # 只回变化的几行
agent: 现在排第一的是 "Show HN: ..."

一句话直觉/类比: 把它想成「给盲人 agent 配的导盲设备」。模型看不见像素,于是 BrowserOS 把网页翻译成一份带编号的结构化清单(无障碍树):「① 一个写着登录的按钮、② 一个邮箱输入框……」。模型说「点 ①」,设备就替它精确点中——再把「点完页面多了一行错误提示」这个变化念给它听。


2. 顶层全景(它大概怎么转)

BrowserOS 是个 monorepo,分两半:浏览器(Chromium 分支,C++/Python 构建系统)和agent 平台(TypeScript/Go)。这套文档讲的是 agent 平台——浏览器那半提供的是「一个可以被 CDP 远程控制的 Chromium 实例」这一前提。

2.1 五个角色

部件干什么在哪
Chromium 分支一个开了调试端口(CDP, 默认 9000)的浏览器实例packages/browseros/(C++/Python)
Server (Bun)agent 循环 + MCP 端点 + /chat 流式接口,作为 CDP 客户端连进浏览器apps/server/
browser-mcp16 个浏览器工具(snapshot/act/diff/navigate...)的定义与执行框架packages/browser-mcp/
browser-core工具底下的真功夫:无障碍树快照、ref 管理、CDP 输入派发、diffpackages/browser-core/
cdp-protocol类型安全的 Chrome DevTools Protocol 绑定packages/cdp-protocol/

注意一个反直觉点:Server 是 CDP 的客户端,浏览器是服务端。浏览器开着 9000 端口等连接,Bun server 连进去发命令。见 README.md 的架构图与 packages/browser-core/src/backends/cdp.ts:63(connect)。

2.2 数据流(一次工具调用)

模型(LLM)
│ 「点 e14」 = 一个 tool call

┌──────────────────────────────────────────┐
│ ToolLoopAgent(AI SDK) apps/server │
│ 把 tool call 路由到对应工具的 execute │
└──────────────────────────────────────────┘
│ act(kind=click, ref=e14)

┌──────────────────────────────────────────┐
│ browser-mcp 工具层 (act.ts) │
│ 解析 kind → 调 browser-core 的 input │
└──────────────────────────────────────────┘
│ input.click("e14")

┌──────────────────────────────────────────┐
│ browser-core │
│ ① ref → 真实 DOM 节点 (resolve) │
│ ② 算出元素中心坐标 │
│ ③ 经 CDP 派发鼠标事件 │
│ ④ 重新快照、和上次比 → diff │
└──────────────────────────────────────────┘
│ CDP: Input.dispatchMouseEvent ...

Chromium(真实网页发生点击)
│ diff 文本(「多了一行错误提示」)
▲────────────────────────── 回传给模型当反馈

2.3 主线走一遍(高层)

  1. 用户在侧边栏发一句话 → apps/server/src/api/routes/chat.ts 收到 → ChatService.processMessage
  2. ChatService 解析 LLM 配置、建立或复用一个 AiSdkAgent(apps/server/src/agent/ai-sdk-agent.ts),它内部是 AI SDK 的 ToolLoopAgent
  3. agent 把系统提示 + 工具集 + 对话历史发给模型,模型开始一轮一轮地发 tool call。
  4. 每个浏览器 tool call 落到 browser-mcp 的工具,工具调 browser-core 真正操作 Chromium。
  5. 工具结果(尤其是 diff)回传模型,直到模型不再调工具、给出最终答复;全程流式推给前端。

这条主线里最有教学价值的是第 4 步那套「眼睛—手—反馈」三件套,也是接下来三章的主题。第四章再回到外层循环(提示、压缩、安全)。


3. 阅读地图

建议顺序就是 agent 操作一个页面的天然顺序:先有眼睛、再有手、再有反馈、最后是包住这一切的循环与安全

章节讲什么适合谁先读
01-snapshot-and-refs.md模型的「眼睛」:无障碍树 → 带 [ref=eN] 的缩进文本;ref 为什么要稳定、怎么稳定想理解 grounding(把模型的话落到真实元素)的人
02-act-and-input.md模型的「手」:一个 ref 怎么变成 CDP 鼠标事件;陈旧 ref 的两级容错重定位想理解可靠操作的人
03-diff-loop.md反馈:为什么动作后只回 diff 而非整棵树;LCS 行级 diff;snapshot→act→diff 主循环想理解 token 经济与反馈设计的人
04-agent-loop-and-safety.md外层:ToolLoopAgent、分段系统提示、上下文压缩、把网页当「不可信数据」的注入防护想理解 agent 工程与安全的人

4. 横向对比(放在这里建立坐标)

browser-agents 这一支的共同难题是grounding:模型说「点登录」,系统怎么知道哪个 DOM 节点是「登录」。不同项目下注不同:

取法代表代价
截图 + 视觉模型点像素坐标纯 computer-use 路线慢、贵、对小元素不稳
无障碍树 + 稳定 refBrowserOS依赖页面无障碍语义,但快、稳、token 省
DOM + CSS/XPath 选择器传统自动化(Playwright 脚本)选择器脆,页面一改就断

BrowserOS 选了无障碍树这条路,并补了两个兜底:无障碍树没标的可点元素用「鼠标光标命中」补(cursor-augment),refs 失效时按 (role, name, nth) 重新定位而非缓存选择器(见 02 章)。这让它在「稳」和「省」之间取得了不错的平衡。

各机制的源码锚点见每章末尾的代码地图。