← logs/

沙箱化 agent:应用层空跑 vs 系统级隔离

当有人说一个 agent 是「沙箱化」的,我想知道它防的是哪种失败模式。一个改动生产状态的坏计划,和一次读取宿主 SSH 密钥的 shell 逃逸,是在完全不同的层上失败的;把两者混为一谈,造出来的沙箱要么太弱,要么太贵。

遏制有两类。语义遏制在应用层:模拟这个世界,在计划碰到任何真实东西之前先检查它。机械遏制在系统层:隔离执行本身,让运行起来的任何东西都伤不到宿主,不论计划对错。一个回答的是「这个计划是错的吗?」,另一个回答的是「这段代码能伤到我吗?」。二者可以组合,但各自的成本结构与失败方式不同。

精读:ToolSandbox,一次忠实的模拟需要什么

ToolSandbox(Lu 等人,Findings of NAACL 2025)是一个评测 benchmark,但它同时可以当作模拟沙箱的设计规格。此前的工具 benchmark 评测的是无状态 web 服务、单轮交互或 off-policy 轨迹。ToolSandbox 加上了有状态的工具执行、工具之间隐式的状态依赖、一个支持 on-policy 对话式评测的内置用户模拟器,以及对任意轨迹上中间与最终里程碑的动态评分。

有两个发现值得注意——开放模型与专有模型之间存在显著的能力差距;State Dependency、Canonicalization、Insufficient Information 这类由状态定义的任务,即使对最强的模型也依然困难——我在沙箱化设计笔记里展开了这两点。

对空跑设计的启示:一个模拟沙箱的好坏取决于它的状态模型。当一个工具写入的文件会被另一个工具读取时,无状态的 mock 会放行那些在现实中会失败的计划。语义沙箱里贵的部分不是 LLM;是把工具之间的依赖建模得足够真实,让模拟拒绝的东西,现实也会拒绝。

精读:ToolEmu,把仿真当作空跑引擎

ToolEmu(Ruan 等人,ICLR 2024)走得更远:由一个 LM 来仿真工具执行,再由一个基于 LM 的安全评估器给 agent 的行为打分。核心数字——人工评估判定,被仿真器标记的失败中有 68.8% 是真实世界成立的失败;即便是最安全的 agent,按安全评估器的口径也在 23.9% 的时间里失败,覆盖 36 个高风险工具与 144 个测试用例——完整拆解见沙箱化设计笔记

吸引力在成本与覆盖:不需要工具实现、没有真实副作用、可以大规模 red-teaming。风险在于仿真器与模型共享盲区:它是工具会做什么的一个采样,不是一份保证。仿真是一个过滤器,不是一个判定。它抓得住常见的、合理的、模式化的失败,却可能漏掉真实环境会撞上的长尾。

精读:Firecracker,serverless 规模下的机械隔离

Firecracker(Agache 等人,NSDI 2020)是机械遏制的参照点。AWS 造了一个专为 serverless 负载特化的虚拟机监视器,因为传统的取舍不可接受:要么虚拟化,安全性强但开销高;要么容器,开销极小但安全性弱。Firecracker 部署在 AWS Lambda 和 Fargate 中,支撑每月数百万生产负载与数万亿请求。

这正是 agent 隔离如今在复制的模式。E2B 的沙箱就是 Firecracker microVM,用他们自己的话说,是「为运行不可信工作流而造的 microVM」:每个 agent 一台按需启动的 Linux 虚拟机,付费档位下最长可运行 24 小时。这个形态与 agent 天然契合:一次性的、突发式的、不可信的计算,宿主与 agent 的代码不共享内核、不共享内存。

各自何时适用

question:        is the plan wrong?        can the code hurt me?
defense:         semantic dry-run          mechanical isolation
tooling:         ToolEmu-style simulation  containers, gVisor, microVMs
cost:            cheap, approximate        heavier, definitive
best for:        eval, red-teaming, gates  code execution, untrusted plugins

当问题关乎计划的语义、且副作用重要时,空跑是对的:评估候选计划、red-teaming、训练时的 rollout。当问题关乎遏制、且你无法预测代码会做什么时,系统级隔离是对的。你不需要理解这段代码,你只需要它被遏制住。

二者可以组合。空跑以低成本过滤候选计划;隔离遏制住漏网的部分;显式门禁让剩下的副作用可见、可审。

两个系统,两层

在 PiPlan.ai,用于候选计划的 eval 沙箱是一个模拟沙箱,提案先行:agent 写一份计划,系统对照当前状态算出精确的 delta,由人签核这份 delta 之后,任何东西才会落地:

draft plan -> simulate in sandbox -> render diff -> human commit -> real environment

设计选择在于:diff 是那个可审的工件。agent 从不直接触碰真实状态,所以它的错误是提案,不是变更。代价是提交这一步要花人的注意力,而注意力本来就该花在那里。关于我自己的沙箱,一句诚实备注:模拟是对照类型化图来验证计划的,它捕捉不到外部 API 的漂移,也捕捉不到模型在执行计划期间于计划内部的行为,所以我给 ToolEmu 打的 68.8% 折扣,同样适用于 PiPlan——一个过滤器,不是一个判定。

在状态这一侧,SafeRoutes 展示了我反复采用的不变量强制执行模式:每一次状态写入都有门禁,检查失败即回滚。行程数据放在一棵可逆的行程树里,plan、update、undo、status 共享这棵树。模型的角色限于观察与评估;对路线的每一次编辑都经过一个持有状态的纯函数编排器。安全性质不依赖模型表现良好,因为写路径不在模型手里。

贯穿二者的想法是:在模拟中做决定,给每一次写入设门禁,让人的提交成为最后一道检查。harness 侧的细节我写在了沙箱化设计笔记里。

本文引用的来源均已抓取并核实。