跳到主要内容

04 — agent 入口与安全护栏

本章讲什么: agent-browser 给 AI 提供了三种用法——纯 CLI、MCP 工具、和把 LLM 直接塞进来的 chat 模式。它们共享同一套动作。最后讲两道安全护栏:域名白名单和动作策略。

4.1 三个 agent 入口

同一套动作(第 02 章 execute_command 那 150+ 个 handle_*),对外有三张脸:

入口谁用形态文件
CLI任何能跑 shell 的 agentagent-browser click @e2cli/src/main.rs
MCP server支持 MCP 的客户端(Claude 等)JSON-RPC over stdio,工具化cli/src/mcp.rs
chat终端里直接对话自然语言 → 内置 LLM 循环cli/src/chat.rsstream/chat.rs

核心理念:一处实现,三处复用。AGENTS.md 把它列为硬规则——任何 CLI 命令/标志变更,必须同步更新 MCP,且加测试证明两面对齐。

4.2 MCP server:复用 CLI 解析器

MCP(Model Context Protocol)让 agent 客户端以「工具」形式调用 agent-browser。run_mcp(cli/src/mcp.rs:488)起一个 JSON-RPC 服务,stdout 专门留给换行分隔的 JSON-RPC(mcp.rs 文件头注释),分发三个标准方法:

initialize → 握手,回报支持的协议版本 (mcp.rs:608 initialize_result)
tools/list → 列出可用工具 (mcp.rs:610 list_tools)
tools/call → 执行某工具 (mcp.rs:611 call_tool)

关键设计:MCP 工具不另写一套逻辑,而是尽量把调用喂回 CLI 的解析器,再走同一个 daemon。这样 CLI 和 MCP 行为天然一致。

这种一致性不是靠自觉,而是靠测试钉死。cli/src/native/parity_tests.rs 就是专门证明「CLI 面和 MCP 面对同一命令产生一致行为」的回归测试——AGENTS.md 的「CLI/MCP Parity」一节把它写成贡献者必守的纪律。

4.3 chat:把 LLM 装进 CLI 的自动循环

chat 是最「全自动」的入口:用户说人话,内置 LLM 自己决定调哪些 agent-browser 命令。它需要 AI_GATEWAY_API_KEY,否则直接退出(chat.rs:run_chat 开头)。

系统提示怎么约束模型

get_system_prompt(cli/src/native/stream/chat.rs:124)拼出系统提示,几条硬规则很说明设计意图:

(系统提示节选,chat.rs:139 附近)
- 每个浏览器动作都必须真的调用 agent_browser 工具,绝不能假装做了
- 一条命令一次工具调用,不许用 && 或 ; 串联
- 不许加 --json
- 不许跑非 agent-browser 程序
- 截图省略路径(自动内联显示),且不要再用 markdown 图片语法重复贴

这些规则在收紧模型的行动空间:防止它幻觉「我已经点了」、防止它串命令绕过单步审计、防止它执行任意程序。

只给一个工具

CHAT_TOOLS(chat.rs:156)只暴露一个工具 agent_browser,参数就一个 command 字符串:

(chat.rs:156,工具定义节选)
name: "agent_browser"
description: "Execute an agent-browser command..."
parameters: { command: string } // 如 'agent-browser snapshot -i'、'agent-browser click @e3'

模型每轮输出一个 command 字符串,execute_chat_tool(chat.rs:457)拿去跑,结果回灌给模型,循环到任务完成。系统提示里还内联了 skill 文档(load_skills),教模型该用哪些命令、怎么用 @e 引用——把第 01 章的「快照+ref」工作流直接灌进 LLM 的脑子。

4.4 安全护栏一:域名白名单

--allowed-domains 让你把 agent 锁在指定站点内。实现是 DomainFilter(cli/src/native/network.rs:80),匹配支持精确域名和 *. 通配:

// network.rs:92 真实片段(节选)
pub fn is_allowed(&self, hostname: &str) -> bool {
if self.allowed_domains.is_empty() { return true; } // 空 = 不限制
let hostname = hostname.to_lowercase();
for pattern in &self.allowed_domains {
if let Some(suffix) = pattern.strip_prefix("*.") {
// *.example.com 匹配 example.com 及其子域
if hostname == suffix || hostname.ends_with(&format!(".{}", suffix)) {
return true;
}
} else if hostname == *pattern {
return true;
}
}
false
}

双层拦截才是重点。光在 CLI 校验 URL 不够——页面里的 JS 可以 fetchlocation.href 偷偷跳别处。所以白名单还注入到页面运行时:

  • install_domain_filter_script(network.rs:161)往页面注脚本拦截导航;
  • install_domain_filter_fetch(network.rs:233)拦 fetch;
  • install_domain_filter(network.rs:253)把两者一起装上。

也就是说,白名单既挡「agent 主动发的命令」,也挡「页面自己发起的请求」。对防御页面驱动的数据外泄 / 提示注入(prompt injection) 很关键——恶意页面就算说服了 agent,也跳不出白名单。

4.5 安全护栏二:动作策略

ActionPolicy(cli/src/native/policy.rs)从 JSON 文件加载一份「哪些动作允许/拒绝/需确认」的规则,经 AGENT_BROWSER_ACTION_POLICY 指向(兼容旧名 AGENT_BROWSER_POLICY):

// policy.rs:8 真实定义
pub enum PolicyResult {
Allow, // 放行
Deny(String), // 拦截,附原因
RequiresConfirmation, // 需要人确认才继续
}

策略文件结构是 default + allow / deny / confirm 三组列表(ActionPolicy 字段)。另有环境变量 AGENT_BROWSER_CONFIRM_ACTIONS(ConfirmActions::from_env)按类别要求确认。

这给了部署者一道闸:比如「允许导航和读取,但 uploaddownload、提交表单类动作必须人工确认」。配合第 03 章的对话框处理(daemon 默认自动消解阻塞性 dialog,免得 agent 卡死),形成「自动跑 + 危险动作留人确认」的折中。

4.6 巧妙之处小结

  • 一份动作,三面复用,测试钉死对齐。 避免 CLI 改了 MCP 忘改的经典漂移(parity_tests.rs)。
  • 域名白名单注入页面运行时。 把安全边界下沉到「页面也跳不出去」,而非只在命令层做君子协定(network.rs)。
  • chat 只给一个工具 + 强约束系统提示。 把模型的行动面收到最小,降低幻觉和越权(chat.rs)。

4.7 边界

  • chat 的具体流式解析(SSE → tool call)本章未逐行展开,只讲了工具定义与系统提示层面的约束。
  • 域名白名单是域级控制,不做路径级 / 方法级细粒度策略。
  • 动作策略文件格式与完整语义以 policy.rsActionPolicyagent-browser.schema.json 为准。

4.8 代码地图

主题文件路径关键符号
MCP 服务入口cli/src/mcp.rsrun_mcpinitialize_resultlist_toolscall_tool
CLI/MCP 对齐测试cli/src/native/parity_tests.rs(parity 测试用例)
chat 入口cli/src/chat.rsrun_chatrun_single_turn
chat 系统提示/工具cli/src/native/stream/chat.rsget_system_promptCHAT_TOOLSexecute_chat_tool
域名白名单cli/src/native/network.rsDomainFilteris_allowedinstall_domain_filter
动作策略cli/src/native/policy.rsActionPolicyPolicyResultConfirmActions