Kimi WebBridge原理

Kimi WebBridge原理
pfa目录
- 1. 一句话概括
- 2. 三层架构图
- 3. 各层职责详解
- 4. 完整调用链路
- 5. CDP 协议映射表
- 6. 会话隔离机制
- 7. 为什么用 Extension + CDP 而不是裸 CDP
- 8. 数据安全保障
- 9. isTrusted 限制(产品边界)
- 10. 面试高频追问
- 11. 与 nanobot browser_v4 架构对比
- 12. 对比深度追问
- 引用
Kimi WebBridge 工作原理(面试解析)
1. 一句话概括
Kimi WebBridge = 本地 Daemon(Go HTTP Server) + 浏览器 Extension(Chrome Debugger API → CDP),AI Agent 通过 HTTP 发指令,Extension 在用户真实浏览器中用 CDP 执行操作,全链路 127.0.0.1 闭环,登录态不出设备。
2. 三层架构图
1 | flowchart LR |
3. 各层职责详解
三层架构里,Daemon 负责协议中转和会话管理,Extension 负责进入浏览器执行 CDP 指令,AI Agent 只需要面向本地 HTTP 接口发起操作。
3.1 本地 Daemon(Go 二进制)
- 编译为原生 Mach-O / ELF 二进制,本地运行的 HTTP Server
- 监听
127.0.0.1:10086,只接受本机请求 - 职责:
- 作为 AI Agent 的 HTTP 入口,接收 JSON 指令
- 通过 WebSocket 将指令转发给浏览器 Extension
- 等待 Extension 执行完毕,将结果以 HTTP Response 返回
- 管理 session ↔ tab group 的映射
- 日志示例:
1 | [agent-extension-daemon] listening on 127.0.0.1:10086 |
3.2 浏览器 Extension(Chrome/Edge 插件)
- 用户安装在自己日常使用的浏览器中
- 启动时通过 WebSocket 主动连接 Daemon(长连接,不轮询)
- 利用
chrome.debugger权限 attach 到标签页,获得 CDP 入口 - 天然携带用户的所有 Cookie、Session、LocalStorage
- 执行操作后通过 WebSocket 回传结果给 Daemon
Extension 是方案里真正接触浏览器的一层:它既能继承用户当前浏览器环境,又能通过 chrome.debugger 把高层 action 落到 CDP 命令上。
3.3 AI Agent(Claude Code / Kimi / Gemini 等)
- 通过
curl或代码发 HTTP POST 到127.0.0.1:10086/command - 请求格式:
1 | { |
- 支持的 action:
navigate,find_tab,snapshot,click,fill,evaluate,screenshot,network,upload,save_as_pdf,list_tabs,close_tab,close_session
这意味着 Agent 不需要理解浏览器插件和 CDP 的细节,只要把动作抽象成固定 action,剩下的路由和执行都交给 Daemon 与 Extension。
4. 完整调用链路
以 Agent 执行一次「打开 Kimi 首页 → 截图」为例:
- Step 1: Agent → Daemon
1 | curl -X POST http://127.0.0.1:10086/command |
这一步只是把用户意图封装成 HTTP 请求。后续执行会沿着 Daemon、Extension、CDP、浏览器页面逐层传递,再按相反方向返回结果。
- Step 2: Daemon → Extension(WebSocket)
转发 navigate 指令 - Step 3: Extension → 浏览器(CDP)
chrome.debugger.attach({tabId})chrome.debugger.sendCommand({tabId}, 'Page.navigate', {url: 'https://kimi.com'}) - Step 4: 浏览器 → Extension(CDP Response)
页面加载完成 - Step 5: Extension → Daemon(WebSocket)
{success: true, url: "https://kimi.com", tabId: xxx} - Step 6: Daemon → Agent(HTTP Response)
{success: true, url: "https://kimi.com", tabId: xxx} - Step 7: Agent 发起截图
{"action":"screenshot","args":{"format":"png"}}
→ Daemon → Extension → CDPPage.captureScreenshot→ 返回 base64
全程都在本机 127.0.0.1 闭环。
5. CDP 协议映射表
WebBridge 对外暴露的是语义化 action,对内再映射到不同 CDP 域。面试时重点说明:Agent 调 action,Extension 负责翻译成具体 CDP Method。
| WebBridge Action | CDP 域 | CDP Method | 说明 |
|---|---|---|---|
| navigate | Page | Page.navigate | 导航到指定 URL |
| snapshot | Accessibility | Accessibility.getFullAXTree | 获取无障碍树(非 DOM),元素用 @ae ref 定位 |
| click | Input | Input.dispatchMouseEvent | 合成鼠标事件 |
| fill | Runtime | Runtime.evaluate | JS 设置 .value + dispatchEvent('input') |
| evaluate | Runtime | Runtime.evaluate | 在页面上下文执行任意 JS |
| screenshot | Page | Page.captureScreenshot | 页面截图,返回 base64 |
| network | Network | Network.enable + 事件监听 | 启用网络监控后监听 request/response |
| save_as_pdf | Page | Page.printToPDF | 渲染当前页面为 PDF |
6. 会话隔离机制
- 每个
session名映射到浏览器的一个 Tab Group - 不同 session 操作不同 tab group,互不干扰
- 同一 session 下的连续操作共享同一个 tab
- 示例:
1 | {"action":"navigate","args":{"url":"https://a.com"},"session":"task-a"} |
- task-a 和 task-b 在不同的 tab group 中并行执行
7. 为什么用 Extension + CDP 而不是裸 CDP
这个选择本质上是在降低用户接入成本:裸 CDP 更直接,但要求用户用特殊参数启动浏览器;Extension 方案多了一层插件,却能做到装一次后长期可用。
| 对比维度 | 裸 CDP(--remote-debugging-port) | Kimi WebBridge 方案 |
|---|---|---|
| 启动方式 | 需要用户手动加 --remote-debugging-port=9222 启动参数 | Extension 随浏览器自启,零感知 |
| 安全暴露 | 监听端口可被局域网访问(如有端口转发) | 只走本机 127.0.0.1:10086 |
| 用户感知 | 每次启动浏览器都要记住加参数 | 装一次 Extension,永久生效 |
| 版本绑定 | 不绑定 | Daemon + Extension 版本 1:1 配对 |
核心:Extension 的 chrome.debugger 权限 = CDP 入口门票,无需改浏览器启动参数。
8. 数据安全保障
安全设计围绕一个原则展开:页面数据和登录态只在本机浏览器、Extension、Daemon 之间流转,不把浏览器上下文上传到远端服务。
- 网络边界:Daemon 只监听
127.0.0.1,外部网络无法访问 - 数据闭环:登录态、Cookie、页面内容全程不离开用户设备
- 仅有的外连:匿名化的遥测事件(
webbridge_daemon_alive、webbridge_command_call),只上报 tool 名称和 session 名,不包含页面内容
9. isTrusted 限制(产品边界)
Kimi WebBridge 走的是 DOM 合成事件(el.click()、dispatchEvent),所以:
1 | event.isTrusted === false // Kimi WebBridge 产生的所有事件 |
后果:
- ✅ 绝大多数网站正常响应(React/Vue 的事件委托机制不依赖
isTrusted) - ❌ 银行级安全控件、CAPTCHA 验证码等检查
event.isTrusted的站点无法自动化 - 官方定性为 产品边界,不是 bug——因为要产生
isTrusted=true的事件需要操作系统级的输入注入,会引入安全风险
10. 面试高频追问
下面这些问题主要考察三点:通信模型、会话管理、以及为什么用无障碍树作为页面状态表示。
Q1: Extension 和 Daemon 之间为什么用 WebSocket 而不是 HTTP?
A: Extension 不能开 HTTP Server(浏览器安全限制),所以 Extension 主动发起 WebSocket 连接连到 Daemon。WebSocket 是全双工长连接,Daemon 有指令时直接 Push,Extension 执行完直接 Push 回去,不需要轮询。
Q2: 多少个 Daemon 实例?
A: 一个。Daemon 以单进程运行,通过 pid 文件防止重复启动。所有 session 共享同一个 Extension WebSocket 连接。
Q3: snapshot 为什么返回无障碍树而不是 DOM?
A: ① 无障碍树比 DOM 小得多(语义摘要 vs 完整 HTML),节省 Agent 上下文窗口;②
@aeref 基于语义角色定位,不像 CSS 选择器受 class hash 变化影响;③ LLM 理解无障碍树的效果好于解析 DOM。
Q4: 多 tab 并行时如何处理?
A: Extension 对每个 tab 独立调用
chrome.debugger.attach(tabId),CDP 协议天然支持多 target。Daemon 通过 session 名路由到正确的 tabId。
11. 与 nanobot browser_v4 架构对比
对比 nanobot browser_v4 时,核心不是谁更先进,而是两套方案服务的场景不同:Kimi WebBridge 偏用户真实浏览器接入,nanobot browser_v4 偏可控、可并发、可程序化的企业自动化环境。
11.1 架构全景对比
1 | flowchart LR |
Kimi WebBridge 用 attach() 用用户的真实浏览器;nanobot 自启动独立 Chromium 实例。
11.2 核心差异对比表
| 维度 | Kimi WebBridge | nanobot browser_v4 |
|---|---|---|
| 架构层数 | 三层:Agent → Daemon → Extension → Chrome | 两层:Agent → SDK/Playwright → Chromium |
| 浏览器来源 | 用户真实浏览器(已登录) | 自启动独立 Chromium(需程序化登录) |
| CDP 接入方式 | chrome.debugger.attach() – Extension 间接获取 | Playwright 启动时建立 CDP WebSocket – 直接持有 |
| 登录态 | 天然继承,零成本 | BUC REST API → JWT → CDP Network.setCookie 注入 |
| 事件可信度 | isTrusted=false(JS 合成事件) | isTrusted=true(CDP Input.dispatchMouseEvent 内核级事件) |
| 会话隔离 | Tab Group(同浏览器不同标签组) | 独立 user_data_dir(完全隔离的浏览器实例) |
| 部署依赖 | Go Daemon + Chrome Extension + 浏览器 | Python + Chromium binary(自包含) |
| 状态表示 | Accessibility tree + @ae ref 引用 | SDK DOM 序列化 + [index] 数字索引 + overlay 优先渲染 |
| 反检测 | 无(用户真实浏览器,无自动化特征) | --disable-blink-features=AutomationControlled |
这张表可以按“浏览器来源、登录态、事件可信度、会话隔离”四条主线来讲,基本覆盖了两种架构取舍的重点。
11.3 事件可信度 - 最大的架构差异
Kimi WebBridge 的 click/fill 走 el.click() + dispatchEvent,产生的事件 isTrusted=false。银行、验证码等安全敏感站点会检测这个。
nanobot V4 走 CDP Input.dispatchMouseEvent / Input.dispatchKeyEvent,这些是浏览器内核级别的输入事件,isTrusted=true,和真实用户点击无区别。
1 | Kimi: JS → el.click() → isTrusted=false (合成事件) |
面试话术: Kimi 选了 Extension 路线拿到用户真实登录态,代价是事件注入只能走 JS 层,isTrusted 永远是 false。我们选了 Playwright + 独立 Chromium 路线,获得内核级事件可信度。
11.4 登录态 - 零成本 vs 程序化
Kimi 直接操作用户的浏览器,Cookie/Session 天然存在。nanobot 启动全新 Chromium,需要完整的登录流程:
- BUC REST API 获取 JWT(HMAC-SHA256 签名 + RSA 加密密码)
- 通过 CDP
Network.setCookie注入到.alipay.com/.alipay-inc.com/.antgroup-inc.cn - JWT 过期前 30 分钟自动刷新,LRU 缓存管理 token
面试话术: Kimi 的 Extension 方案天然继承登录态,这是它的核心优势。我们的场景是企业内网,需要支持多账号切换和并发会话,所以选择了 API 程序化登录 + 独立浏览器实例。
11.5 为什么 Kimi 要三层,我们只要两层?
Kimi 的三层架构解决了三个问题:
- AI Agent 只能发 HTTP,不能直接连 WebSocket → Daemon 做 HTTP→WS 转换
- Extension 不能开 HTTP Server → Daemon 做本地监听
- 需要统一会话管理 → Daemon 做 session→Tab Group 映射
nanobot 不需要 Daemon 层,因为:
- Agent 和 browser-use SDK 在同一进程,直接函数调用,不需要 HTTP 中转
- SDK 内部管理 Playwright 连接,不需要 Extension 中转
contextvars做协程级会话隔离,不需要额外的 session 管理层
面试话术: Kimi 的 Daemon 层本质是一个协议适配器,解决的是 Agent 和 Extension 之间通信协议不匹配的问题。我们因为 Agent 和浏览器驱动在同一个 Python 进程里,所以可以省去中间层。
11.6 状态表示差异
两套方案都需要把页面压缩成 Agent 能理解的文本状态,但取数来源不同:Kimi 更依赖浏览器无障碍树,nanobot V4 更依赖 SDK 的 DOM 序列化和自定义 overlay 处理。
| 对比项 | Kimi WebBridge | nanobot V4 |
|---|---|---|
| 数据源 | Accessibility tree(Accessibility.getFullAXTree) | SDK DOM 序列化 + JS overlay 检测 |
| 元素引用 | @ae ref 属性(语义角色定位) | [index] 数字索引(selector_map) |
| 特殊处理 | 无 | overlay 优先渲染(z-index 扫描,确保 LLM 优先看到弹窗) |
| 截断策略 | - | 30k 字符截断,overlay 内容优先保留 |
nanobot V4 的 overlay 优先渲染是一个实用优化:JS 扫描 body 直接子元素的 z-index,找到最顶层的 modal/drawer/popover,将其内容放在状态描述最前面。
11.7 反检测策略对比
- Kimi: 用户真实浏览器 → 无
navigator.webdriver→ 无自动化特征,但isTrusted=false→ 可被前端 JS 检测 - nanobot: 启动参数
--disable-blink-features=AutomationControlled覆盖navigator.webdriver = false,但 Chrome DevTools 标记仍可能被高级检测发现,优势是isTrusted=true→ 内核级事件不可被前端区分
11.8 nanobot V4 双协议栈设计
nanobot V4 并没有只用一种协议,而是SDK + CDP 双栈:
| 操作类型 | 走 SDK event bus | 走直接 CDP |
|---|---|---|
| 导航 | NavigateToUrlEvent | - |
| 点击 | ClickElementEvent / ClickCoordinateEvent | - |
| 输入 | TypeTextEvent | - |
| 下拉选择 | SelectDropdownOptionEvent | - |
| 滚动 | ScrollEvent | - |
| 快捷键 | SendKeysEvent | - |
| 悬停/双击/右键 | - | Input.dispatchMouseEvent |
| 逐字输入 | - | Input.dispatchKeyEvent + insertText |
| JS 执行 | - | Runtime.evaluate |
| Cookie 管理 | - | Network.getCookies / setCookie |
| 元素取值 | - | DOM.resolveNode + Runtime.callFunctionOn |
| 获取坐标 | - | DOM.getBoxModel |
| 滚动到可见 | - | DOM.scrollIntoViewIfNeeded |
设计原则:SDK 能做的走 SDK(事件语义清晰、状态同步好),SDK 不暴露的走 CDP(灵活但需手动管理状态)。
12. 对比深度追问
这部分适合在面试里把“为什么不直接照搬 Kimi”讲清楚:不是否定 Extension 方案,而是说明企业 Agent 场景更看重隔离、并发和可运维性。
Q1: 为什么不采用 Kimi WebBridge 的 Extension 方案?
A: 三个原因。① 企业场景需要多账号并发,Extension 方案的 Tab Group 隔离力度不够,Cookie 会串扰;② 我们的 Agent 和浏览器驱动在同一进程,不需要中间的 Daemon 协议转换层;③ 安全敏感操作(如支付验证)需要
isTrusted=true的内核级事件,Extension 方案做不到。
Q2: nanobot 的会话隔离为什么用独立 user_data_dir 而不是 Tab Group?
A: Tab Group 共享同一个浏览器进程和 Cookie Store,不同 session 的 Cookie、LocalStorage、SessionStorage 会互相影响。独立 user_data_dir 是完全隔离的浏览器沙箱,支持同一设备上同时登录多个企业账号,不会有状态污染。
Q3: overlay 优先渲染是怎么做的?
A: V4 在返回 DOM 状态前,先跑一段 JS 扫描
document.body的直接子元素,按 z-index 排序找到最顶层的 modal/drawer/popover。然后把这部分 DOM 提取到状态描述最前面,最后做 30k 字符截断时优先保留 overlay 内容,确保 LLM 不会忽略弹窗。
Q4: nanobot 的 BUC 登录流程具体怎么做的?
A: 四步。① 用 RSA 公钥加密密码;② 用 HMAC-SHA256 签名请求参数,调用 BUC REST API
sso/login;③ 拿到 JWT(IAM_TOKEN)后,通过 CDPNetwork.setCookie写入所有相关域名;④ 启动一个后台定时器,JWT 剩余有效期小于 30 分钟时自动刷新。
前四个问题回答完后,可以自然收束到架构选择本身:同样是浏览器自动化,不同业务场景会导向不同的工程取舍。
Q5: 如果让你重新设计,会怎么选?
A: 取决于场景。面向 C 端用户(Kimi 的场景),Extension 方案体验更好——零配置、继承登录态、用户无需理解浏览器自动化。面向企业 Agent 场景(我们的场景),多账号并发、事件可信度、可运维性更重要,所以选择 Playwright + 独立 Chromium + 程序化登录。
总结一句话: Kimi WebBridge 用”三层中转 + 真实浏览器”换取零成本登录态,代价是 JS 层事件不可信;nanobot V4 用”两层直连 + 自启动 Chromium”换取内核级事件可信度和强会话隔离,代价是需要程序化登录。







