AI Agent开发工具信任与治理

Agentic AI Sandbox 选型决策树

先判断任务会停在哪里,再选择 Sandbox

之前我们写过一篇文章,讨论 Coding Agent 为什么需要 Sandbox。现在,我们想把这个讨论再往前推一步:面对不同的开发步骤,如何选择具体的沙箱运行环境?

在这些同样叫做 Sandbox 的产品中,在确认隔离性满足任务的安全风险要求后,我们仍需要区分环境关闭后留下了什么、对外写入的操作能限制到什么程度,以及由谁来记录任务进度。要理清这些抉择,我们可以顺着一个具体的缺陷修复任务来看。

这个任务有四个步骤:Agent 需要先运行 npm install 安装依赖,运行 npm test 跑通测试,然后在私有工作区修改代码,接着暂停下来等待开发者评审,最后把修改好的分支推送到 GitHub。

在跑测试时,需要防止未知的测试脚本破坏宿主机系统。在等待评审时,开发者希望即使运行环境关闭,已经做好的工作也不会丢失。在推送分支时,则需要限制远端仓库出现非预期的变更。这三个具体问题,正好对应了选择沙箱时的不同抉择:如何隔离运行、如何恢复进度,以及如何限制外发操作。

软件缺陷修复任务在不同阶段下的沙箱选型决策树,展现运行、暂停与推送三个阶段中隔离运行、恢复进度与限制外连的不同抉择路径

第二天回来,先问要文件还是要活进程

Agent 前一天运行了 npm install 并修改了部分文件。为了等待开发者评审,运行环境在夜间关闭了。第二天早上,Agent 准备继续工作。

此时,我们首先要面对一个问题:运行环境关闭后,前一天已经修改好的文件还能不能找回来?

Azure Dynamic Sessions 中,会话在冷却期结束后就会销毁,保存在本地的临时工作区和依赖文件也随之清除。这意味着第二天任务重新启动时,本地的开发环境需要重新建立。

Cloudflare Sandbox 里,平台使用 Durable Object 来管理沙箱的身份和生命周期。只要专属的计算容器保持活跃,本地文件、运行中的进程和环境变量就会一直留存。但是,一旦专属容器结束运行,现有的公开文档并没有承诺能够找回这些文件。

如果平台能保留我们改动的文件,我们就要面对下一个问题:是只需要恢复磁盘上的文件,还是要把正在运行的程序和内存状态也一起带回来?

如果只需要恢复磁盘上的文件,Runloop 在挂起沙箱时会保存磁盘状态,也会保留实例 ID 和 SSH 密钥,但不会保存内存。当沙箱重新拉起时,之前运行中的程序和守护进程都需要重新拉起。在 Vercel Sandbox 中,停止沙箱会保存文件系统与配置的快照。下一次会话启动时会从该快照开始,但恢复运行中程序的内存并不在平台的承诺范围之内。

如果需要连同内存和运行中的进程一起恢复,E2B 提供了持久化机制,可以在暂停时保存文件系统和内存状态,包括正在运行的进程和已经加载的变量,直到我们发送 kill 指令,平台才会永久删除该沙箱及其保存的状态。而 Blaxel 在沙箱处于待机状态时,也会保存文件系统和运行中的进程。不过,外部网络连接在沙箱恢复后并不会自动重连。

即使磁盘文件和运行进程都找回来了,我们还要考虑最后一个问题:还有哪些状态是沙箱无法替我们保留、需要我们在外面单独处理的?例如,沙箱无法找回已经失效的临时访问凭证,也记不住人工审批的通过状态。系统依然需要在沙箱外部记录和管理这些任务进度与审批信息。

不同沙箱在运行环境关闭后的文件与进程恢复选择决策路径,对比关闭后文档不承诺恢复、仅恢复文件以及恢复文件与运行中进程和内存的差异

分支推回 GitHub,藏住 Token 还不够

本地的 npm test 通过后,Agent 需要将修改好的代码分支推送到 GitHub。要保护这个推送过程,在 Docker Sandboxes 里,我们可以看到一些具体的隔离机制。

如果我们直接使用 direct mode,沙箱运行在私有的 Docker Engine 上,所有的修改会直接作用在宿主机的当前工作目录。若要使用隔离的私有工作区,我们在创建沙箱时需要显式加上 --clone 参数,在虚拟机的副本里进行编辑。

执行推送命令时,沙箱在网络层默认会阻断所有非 HTTP/HTTPS 协议的访问。即使是普通的 HTTP/HTTPS 请求,代理服务器默认也是拒绝访问的。对于身份凭证,沙箱将 Token 存在宿主机那一侧,避免将其放入沙箱的文件系统或环境变量里。只有当发送的请求符合安全策略时,宿主机的代理才会把 Token 注入到请求的头部中。

然而,仅仅藏住 Token 并不代表沙箱只允许执行这次缺陷修复所需的特定写操作。当 Agent 准备推送代码时,我们可以依次进行三层由宽到窄的安全核对:

  1. 限制请求的目的地:比如限制网络只允许连接 github.com。这能拦截流向未知服务器的连接,但代理本身无法区分 Agent 是在推送当前修复的分支,还是在执行其他写入。
  2. 托管写入凭证:由宿主机的代理来保管 Token。这能防止沙箱内的第三方脚本直接读取凭证,但只要代理完成注入,该凭证在远端仓库依然拥有宽泛的写入权限。
  3. 校验具体的写入动作:比如只允许向本次任务指定的缺陷修复分支发起写操作。这需要系统能够理解任务意图,拦截不合规的写入路径。

不过,目前我们看到的这些产品资料里,并没有提供一种通用的、能自动理解任务意图的控制方案。如果代理注入的凭证权限过宽,即便隐藏了 Token,依然可能发生超出预期的修改。

最后一问:任务中断后由谁接着跑

当 Agent 在修改代码或者推送分支时,如果因为某些原因中途暂停,或者运行发生了超时中断,沙箱本身即使能恢复磁盘和进程,也无法决定任务下一步该执行什么。这时,我们需要一个能够调用模型、选择工具、记录执行进度并处理重试的控制程序,这就是 Harness。

我们需要决定是由团队自己来运行和维护这个控制程序,还是将其托管给外部平台。

如果团队选择自建,可以自行开发或者集成现有的队列、任务检查点、审批流以及重试逻辑,沙箱在其中仅作为一个隔离的容器运行。

如果选择托管平台,这些控制和协调工作就交给了厂商。例如在 Claude Managed Agents 中,Anthropic 在其托管云上管理整个 Agent 循环,并在服务器端保存会话历史、沙箱状态与执行输出。因为要在云端管理这些会话状态,该服务目前无法使用 Zero Data Retention 合同。如果选用自托管模式,代码的执行能力将取决于本地部署的环境配置。

相比之下,AWS Bedrock AgentCore 则展示了不同的拆分方式。在这个框架中,Code Interpreter 提供隔离的执行环境,Identity 负责部分身份验证与外部访问控制,Runtime 用于部署自定义框架,而 Harness 组件则独立出来,专门负责模型编排、工具调用、上下文内存以及生成最终的响应。

结语

回到最开始的那项缺陷修复任务。当修改好的分支终于推回 GitHub,整个缺陷修复工作便告一段落。在搭建这样的开发辅助系统时,提供一个隔离的运行容器正在变成一种通用的底线,但底线之上的具体实现仍然决定着系统怎么运转。对于整个系统的集成和迁移来说,真正的工程痛点往往集中在工作区怎么恢复、外部写入权限如何限制,以及厂商托管的任务进度在何处与本地逻辑连接。

在选型决策中,只有在理清环境关闭后能恢复什么、向 GitHub 写入时允许哪些操作,以及由谁来记住任务进度,并确定了具体的选型分支后,去测量和对比冷启动延迟、重建速度或者 P50/P95 性能指标才具有实际意义。否则,在不同的决策路径之间比较单纯的速度数字,很难得到能够指导落地的结论。

鸭哥每日手记

日更的深度AI新闻和分析