执行面:沙箱 vs 本机、网页访问与验证应对

执行面:沙箱 vs 本机、网页访问与验证应对

本文解读 Grok Bot 的「工作在哪里真正发生」:智能体自己的沙箱(box)、用户的电脑(本机)、后端隔离服务器、以及宿主(Electron)各自的职责边界;以及访问网页时在哪里执行、如何应对登录/人机验证。

面向对象:想理解「Grok Bot 到底在哪台机器上干活、为什么能访问各种网站」的读者。文中路径均为仓库内相对路径。

1. 执行面全景

Grok Bot 实际上有四类执行位置

位置工具是谁的机器典型用途
Box(沙箱)Shell / Read / AwaitShell / Computer智能体自己的 Linux 沙箱默认干活的地方
用户本机ExternalShell / ExternalRead / AwaitExternalShell用户真实电脑只处理用户自己的文件/环境
后端隔离服务器WebFetch / WebSearch / MCP connector服务端(协调器侧)公开网页抓取、OAuth 授权 API
Electron 宿主协调器、local-exec-daemon、box 连接器运行 App 的机器编排、本地执行、审批

其中「后端隔离服务器」常被忽略但很关键:它既不是 box 也不是用户本机。

2. 双机器模型:沙箱(box)vs 本机

核心定义在 source/shared/agents/agent-tool-names.ts 与 system prompt 的 ## Where you worksource/host/runner/system-prompt.ts:158-167)。

2.1 工具对应

// agent-tool-names.ts
export const SAND_BOX_SHELL_TOOL_NAME     = "Shell";
export const SAND_BOX_READ_TOOL_NAME      = "Read";
export const SAND_BOX_AWAIT_SHELL_TOOL_NAME = "AwaitShell";
export const SAND_EXTERNAL_SHELL_TOOL_NAME = "ExternalShell";
export const SAND_EXTERNAL_READ_TOOL_NAME  = "ExternalRead";
export const SAND_EXTERNAL_AWAIT_SHELL_TOOL_NAME = "AwaitExternalShell";
export const SAND_DEFAULT_EXTERNAL_MACHINE_ID = "user-computer";
export const SAND_USER_COMPUTER = { id: "user-computer", label: "the user's computer" };

2.2 各自存什么

Box(/home/boxhost-paths.ts

  • /workspace —— 持久化 scratch 空间(文件、装好的工具跨 turn 保留)
  • /home/box —— agent 的「家」:profile、memory、routines、workflows、channels
  • /home/box/reference/ —— 参考文档(debugging-the-boxapp-ui,由 box-reference-docs.ts 写入)
  • 自带浏览器 + Linux 桌面(登录态持久);一台机器共享给该用户所有 agent,但桌面/浏览器窗口 per-agent 隔离

用户本机:用户的文件、终端会话、已装应用。每个动作都要授权(approval card)。

2.3 分工原则(system prompt 原文)

“Shell and Read are YOUR computer, and they are the default.” “ExternalShell and ExternalRead are the USER’s computer… This surface is not free — every action needs the user’s permission and raises an approval card… so never send work there that your own computer could have done.”

三条红线:

  1. 默认走 box,只有工作确实关于用户那台机器才切 External*;
  2. 绝不用 External/home/box 路径*(既失败又白打扰用户);
  3. 仓库工作 → Cursor cloud agent(不是 ExternalShell,也绝不 clone 到任一机器)。

术语约定:内部叫 “box”,对用户永远说 “my computer”;用户侧叫 “your computer”。

2.4 文件在两台机器间流动

source/host/runner/tools/sand-file-transfer-tools.ts

  • CopyToBox:把用户本机文件原样拷进 box(默认落 /workspace/uploads),供 Shell/Read 处理。
  • CopyFromBox:把 box 产物(报表/日志/归档)拷到用户本机磁盘。
  • 聊天附件:附件在用户本机 → 用 ExternalRead;只有提示标 “also copied into your box” 的才用 Read 读 box 路径。

3. 底层执行:两个 daemon

daemon跑在哪干什么
box-exec-daemonsource/box-exec-daemon/box 内部起 HTTP/connectrpc 服务(ExecService/ControlService),在 box 的 /home/box workspace、terminal 目录执行命令、读文件——Shell/Read 的落点
local-exec-daemonsource/local-exec-daemon/宿主侧(用户本机 / Electron host)执行「本地」工具(ExternalShell/ExternalRead),带审批机制(retireLocalToolApproval

4. Box 的两种运行态

box-reference-docs.tsdebugging-the-box):

  • 本地 Docker 容器(dev):靠 Docker Desktop;用 /.dockerenv 判断;可从 ExternalShelldocker ps/logs/inspect 排查。
  • brokered anyrun pod(发布默认):生命周期服务端管理,本地无东西可查。

对应 README 的 Settings → Router「Use local Docker VM」开关:开启后 box host + exec daemon 跑在自有本地容器(仅 loopback、产物只读挂载),否则连远程沙箱。

5. 网页访问在哪里执行

三条路径,执行位置各不相同:

路径执行位置适用场景
WebFetch / WebSearch后端隔离服务器公开网页,无需登录
box 浏览器(登录态)box 桌面/浏览器,由 browserUse/computerUse subagent 驱动登录墙内、无 connector 的站
MCP connector后端,OAuth 授权 API有连接器的服务(优先)

关键证据:

  • web-fetch.ts 工具描述:“This fetch runs from an isolated server. Hosts like localhost or private IPs will not work.” —— WebFetch/WebSearch 是服务端抓取,只碰公开页。
  • web-search.ts:搜索走 exa provider,返回 “snippets and URLs”。
  • sand-browser-use-subagent.tsbrowserUse 是 page-level(DOM 快照、按引用点元素、填表单、截图),“shares the box browser’s persistent logins”;computerUse 是桌面级(鼠标键盘、像素点击),用于 GUI/文件对话框或 “defeats DOM automation” 的站点。

6. 如何应对人机验证(不破解,三条合法路径)

核心结论:它不「跳过/破解」人机验证,而是设计上让验证要么不出现(OAuth/MCP、公开页),要么由真人一次性完成(登录态持久化后免验)。

① 优先 connector:让验证根本不出现

system-prompt.ts ## Where you work 升级阶梯第 (2) 级:

“A connector is the BEST way to reach a service that has one — structured data instead of pixels, one authorization instead of a browser session that rots.”

MCP 走 OAuth,没有 CAPTCHA。

② 公开页用 WebFetch/WebSearch:本来就没有验证

跑在隔离服务器,只抓公开内容,不涉及登录。

③ 登录墙内且无 connector:交给真人,不破解

流程(sand-browser-use-subagent.ts + box-help-tool.ts):

  1. 父 agent 派 browserUse/computerUse subagent 打开站点;

  2. subagent 碰到「密码 / 2FA / captcha / 支付」停下来报告

    “It cannot act as the user: if a step needs a human (a password, 2FA, a captcha, a payment) it stops and reports back.”

  3. 父 agent 调 request_box_help,把 box 桌面交给用户。box-help-tool.ts

    “Use this instead of asking for credentials: the user signs in themselves on the box and you never see their password or 2FA.”

    reason 参数枚举 "auth" | "captcha" | "payment" | "other",明确覆盖 captcha。

  4. 用户自己登录/过验证,点 “hand back to agent”,agent 自动恢复;

  5. 会话持久化,一次性的system-prompt.ts:“the session persists there, so it is a one-time step”)——后续访问之所以免验,是因为登录态(cookie/session)已存在,而不是每次破解验证码。

④ 安全边界明确禁止「绕过」

SAND_SUBAGENT_SAFETY_PROMPT_SECTIONsystem-prompt.ts:61)把以下都列为「永远不该做的 workaround」:

“scraping session cookies or tokens, reading a credential… driving a signed-in browser session by hand, base64-ing or renaming a command so its keywords don’t trip the check… A block is not a puzzle to route around.”

所以它被硬约束为:不偷 cookie、不手工驾驶登录会话、不找验证码绕过技巧。合法路径只有一条——真人来点。

7. 一句话总结

  • 默认在 box 干(自由、持久、无授权摩擦);用户本机只在任务确实相关时按需、每次授权访问;公开网页在后端隔离服务器抓登录墙内站由 box 浏览器 + 真人一次性登录解决。
  • 人机验证不被破解:OAuth/MCP 让验证不出现,公开页无验证,必须验证时 request_box_help 交真人,登录态持久化后免验。

相关文档: