1. 总体架构:Client-Daemon 模式
agent-browser 采用经典的 Client-Daemon (客户端-守护进程) 架构。这种设计是为了结合 Rust CLI 的快速启动/响应能力与 Node.js/Playwright 强大的浏览器控制生态,同时实现浏览器实例的持久化,避免每次执行命令都重启浏览器的巨大开销。
graph TD
User[用户/AI Agent] --> CLI[Rust CLI - Client]
subgraph "IPC Communication"
CLI -- JSON Command --> Socket[Unix Socket / TCP]
Socket -- JSON Response --> CLI
end
subgraph "Daemon Process (Node.js)"
Daemon[Daemon Server]
BrowserMgr[Browser Manager]
Playwright[Playwright Engine]
StreamSvr[WebSocket Stream Server]
Daemon --> BrowserMgr
BrowserMgr --> Playwright
Daemon --> StreamSvr
end
Playwright -- CDP/WebDriver --> Browser[Chromium/Firefox/WebKit]2. 核心组件详解
2.1 Rust CLI (客户端)
- 位置:
cli/ - 职责:
- 命令解析: 使用 Rust 的
clap或类似库解析用户输入的命令行参数。 - 守护进程管理:
- 检查守护进程是否存活 (通过 PID 文件和 Socket 连接)。
- 如果守护进程未运行,自动启动一个新的 Node.js 进程 (
node daemon.js)。
- 通信: 将解析后的命令序列化为 JSON,通过 IPC 发送给守护进程。
- 输出: 接收守护进程的 JSON 响应,并格式化输出到终端(支持人类可读格式或 JSON 格式)。
- 跨平台通信:
- Unix/Linux/macOS: 使用 Unix Domain Sockets (
.sock文件)。 - Windows: 使用 TCP 端口 (动态分配端口,端口号写入
.port文件)。
- Unix/Linux/macOS: 使用 Unix Domain Sockets (
- 命令解析: 使用 Rust 的
2.2 Node.js Daemon (守护进程)
- 位置:
src/daemon.ts - 职责:
- 长驻后台: 独立于 CLI 运行,维护浏览器状态。
- 服务器: 监听 Socket/TCP 连接,处理并发请求。
- 生命周期管理: 自动超时关闭,或在收到显式
close命令时退出。 - 会话管理: 支持多会话隔离 (
AGENT_BROWSER_SESSION),每个会话拥有独立的 Cookie、Storage 和历史记录。
2.3 Protocol (通信协议)
- 位置:
src/protocol.ts - 格式: 基于 JSON 的请求/响应模型。
- 验证: 使用
zod进行严格的 Schema 验证,确保命令参数的类型安全。 - 命令示例:
{ "id": "cmd1", "action": "navigate", "url": "https://example.com" }
2.4 Browser Manager (浏览器管理)
- 位置:
src/browser.ts - 职责:
- 封装 Playwright 的
Browser,Context,Page对象。 - 快照增强 (Snapshotting): 这是该项目的核心创新点之一(见下文)。
- CDP 集成: 支持通过 Chrome DevTools Protocol 连接到现有浏览器或 Electron 应用。
- 封装 Playwright 的
3. 核心特性实现原理
3.1 AI 友好的 "Refs" 系统
为了解决 AI Agent 难以准确定位 DOM 元素的问题,agent-browser 引入了一套 "Refs" (引用) 机制:
- 生成快照 (
src/snapshot.ts): 遍历 DOM 生成 Accessibility Tree (可访问性树)。 - 分配 ID: 为关键元素(按钮、输入框等)分配简短唯一的 ID(如
@e1,@e2)。 - 缓存映射: 在 Daemon 内存中维护 RefMap (
{ "@e1": "Playwright Locator" })。 - 交互: 当 AI 发出
click @e1指令时,Daemon 直接查找内存映射,转换为 Playwright 的 Locator 执行操作。- 优势: 极大减少了 Token 消耗,且比 CSS 选择器更稳定。
3.2 实时流 (Streaming)
- 位置:
src/stream-server.ts - 原理:
- 利用 Playwright 的 CDP 会话 (
Page.startScreencast) 获取页面帧数据 (Base64 图片)。 - 启动一个 WebSocket 服务器广播这些帧。
- 允许客户端通过 WebSocket 发送鼠标/键盘事件,实现远程控制。
- 利用 Playwright 的 CDP 会话 (
- 用途: 为人类提供 "上帝视角",或用于调试 Agent 的操作。
3.3 持久化与状态隔离
Daemon 将关键信息存储在系统临时目录 (os.tmpdir()):
agent-browser-<session>.pid: 进程 ID。agent-browser-<session>.sock: 通信 Socket。agent-browser-<session>.port: Windows 下的 TCP 端口。- 通过 Session ID 后缀实现多实例并行,互不干扰。
4. 目录结构映射
| 路径 | 架构组件 | 说明 |
|---|---|---|
cli/ |
Client | Rust 编写的命令行入口,负责启动和通信。 |
src/daemon.ts |
Daemon | Node.js 服务器入口,处理 IPC 请求。 |
src/browser.ts |
Core | 封装 Playwright,管理浏览器实例。 |
src/protocol.ts |
Protocol | 定义所有命令的 JSON Schema (Zod)。 |
src/snapshot.ts |
Feature | 生成带 Refs 的可访问性树。 |
src/actions.ts |
Logic | 实现 click, fill, scroll 等具体动作。 |
5. 总结
架构设计亮点
agent-browser 的架构设计非常务实且高效:它利用 Rust 解决了 CLI 启动速度慢的问题,利用 Node.js/Playwright 解决了浏览器控制复杂性的问题,并通过 Daemon 机制实现了高性能的连续操作。
其 "Refs" 系统更是专门针对 LLM/Agent 场景的优化,体现了对 AI 交互模式的深刻理解。