Cloudflare Containers,为扩展智能体沙箱而重构

今天,我们让 Cloudflare Containers 更具可编程性,并针对智能体工作负载进行了优化。智能体不会提前部署沙箱。它们按需为每个任务创建沙箱,期望沙箱立即可用,并且能够暂停和恢复。因此,我们重新架构了 Containers 以满足这些需求:你的代码现在可以在运行时选择每个沙箱的镜像和实例类型,Containers 的启动速度提升了 6 倍,文件系统快照已进入公开测试阶段。
为了实现这一点,我们从底层重新思考了 Containers 的基础设施。新的调度策略将每个沙箱的控制权移入应用代码,而重新设计的运行时则提供了更快的容器启动路径。在 ComputeSDK 的独立基准测试中,启动时间中位数从略高于四秒降至 648 毫秒,而在我们自己的初步测试中,突发测试成功在数秒内创建了数十万个容器。
所有这些都建立在 Cloudflare 上 Containers 一直以来的独特之处:每个 Container 都拥有自己的 Durable Object——一个持久、可编程的控制器,就运行在它旁边,管理其生命周期、出站流量等。我们正在将更多能力直接引入原生 ctx.container
API,这样 Durable Object 无需中间包装类即可控制其 Container,并且我们正在将这一模式带入 Sandbox SDK 1.0。
正如我们今年早些时候所写,你的智能体需要一台计算机。 当智能体需要完整的 Linux 工作空间时,这些变化使 Containers 成为 Workers、Dynamic Workers 和 Durable Objects 的更好补充。
为智能体重思 Containers 的运行时
到目前为止,Cloudflare Containers 一直围绕应用部署来组织。你在部署时选择镜像和计算资源,将该配置推广到整个应用,并进行集中管理。应用是配置和发布的基本单位。
智能体工作空间则不同:它是在智能体工作过程中按需创建的。任务决定了它的镜像、资源、工具和初始文件系统。它可能只存在几分钟,在请求之间休眠,或在数天后被恢复。这些决策需要与处理任务的应用代码放在一起,而且智能体的沙箱需要快速启动,因为启动的每一秒都是用户等待的时间。
我们在 Base44 的应用构建工作空间和 Kilo Code 的云智能体会话中看到了这种模式。它也出现在我们与 Cursor Cloud Agents、、
Devin Outposts以及
OpenAI Agents API的集成中。
__Claude 托管代理__这些工作负载对工作空间的需求各不相同。编码代理需要代码仓库、包管理器、编译器、测试运行器和开发服务器。评估需要从已知状态开始的沙箱。强化学习系统需要创建、评分和重置大量环境。长时间运行的任务需要保留代理生成的文件,以便后续继续工作。
这些需求促使我们从根本上重新思考 Cloudflare Containers 的配置、调度和保存方式。其结果是一种全新的容器配置和调度方式:durable_object
调度策略。它让你的代码可以在运行时选择每个沙箱的镜像和计算资源,启动容器的速度提升超过 6 倍,并支持文件系统快照,因此工作空间可以被保存和恢复。
“在 Base44,我们帮助任何人将想法变成可用的应用。Cloudflare Containers 为每个应用提供隔离的开发环境,我们的 AI 可以在其中执行命令、安装依赖,并在实时预览中将更改变为现实。”
Dolev Epshtein,Base44 应用基础设施软件工程师
“在 Kilo Code,每个云代理会话都需要自己的工作空间和环境,包括正确的代码仓库、工具和用户配置。Cloudflare Containers 让我们能够按需创建这些隔离环境,因此我们的代理可以快速开始运行命令,为我们的客户投入工作。”
Emilie Schario,Kilo Code 联合创始人兼工程副总裁,Anaconda AI 工作空间
从代码中选择你的代理所需的沙箱
从一开始,每个 Cloudflare Container 实例都附加到一个 Durable Object。Durable Object 为环境提供稳定的身份标识,并让应用代码控制其启动、休眠和停止的时机。这种模式已被证明特别适合代理沙箱。
然而,到目前为止,对代理沙箱最重要的两个决策在部署时就被锁定了:运行哪个镜像以及获得多少计算资源。每种镜像和实例类型的组合都是独立的 Containers 应用,拥有自己的 Durable Object 命名空间,并通过 wrangler deploy
提前设置。
假设一个代理需要一个小型 Node.js 沙箱,另一个需要大型 Python 沙箱用于构建。使用我们之前的方法,这需要两个应用、两个命名空间,以及在你的 Worker 中编写路由逻辑,将每个任务发送到正确的沙箱。每个新环境都意味着又一次部署。
新的 durable_object
调度策略消除了这一点。镜像和实例类型现在是你的代码在沙箱启动时传入的参数。要启用此功能,请设置调度策略并声明你的 Durable Object 可以选择的镜像:
// wrangler.jsonc
{
"containers": [
{
"class_name": "AgentSandbox",
"scheduling_policy": "durable_object",
"images": {
"node": { "dockerfile": "./images/node/Dockerfile" },
"python": { "dockerfile": "./images/python/Dockerfile" }
}
}
],
"durable_objects": {
"bindings": [{ "name": "SANDBOX", "class_name": "AgentSandbox" }]
}
}
你声明的每个镜像都可以在 Durable Object 内通过 this.ctx.container.images.<name> 使用。当任务到达时,你的代码为该任务选择镜像和实例类型:
import { DurableObject } from "cloudflare:workers";
export class AgentSandbox extends DurableObject {
async startWorkspace(workspace) {
if (this.ctx.container.running) {
return;
}
const image =
workspace.toolchain === "python"
? this.ctx.container.images.python
: this.ctx.container.images.node;
const instance =
workspace.workload === "build"
? "standard-2"
: "standard-1";
this.ctx.container.start({
image,
instance,
enableInternet: true,
});
}
}
这段代码在任务已知后做出两个决定。它选择工作区所需的工具链,以及为其分配多少计算资源。过去需要单独的应用和单独的 wrangler deploy
现在变成了一个 if
语句。一个 Durable Object 类可以同时启动不同大小的 Node.js 和 Python 沙箱,而添加新环境只需修改代码,无需重新部署。这就是整个更新的核心理念:基础设施变成在请求时运行的代码,一直深入到环境本身。
发布现在只是代码
在启动时选择镜像也解决了运行 Containers 最痛苦的部分之一:发布。
以前,更新镜像意味着更新整个应用。你需要设置宽限期,让运行中的实例可以排空,定义百分比拆分来逐步迁移流量,并调用我们的 API 推送新配置。在整个过程中,平台决定哪些实例被替换以及何时替换,无论代理是否正在执行任务。
使用 durable_object
调度策略,完全没有发布配置。一个 Container 可以继续运行它启动时的镜像,直到你的代码停止它。下次该 Durable Object 启动 Container 时,它会使用你的代码选择的任何镜像。这意味着你想要的任何发布策略都只需几行代码:
const image =
(await this.ctx.storage.get("pinned-image")) ??
(isCanary(this.ctx.id)
? this.ctx.container.images.nodeV2
: this.ctx.container.images.node);
例如,你可以:
金丝雀发布:通过对 Durable Object ID 进行哈希,在 5% 的新沙箱上试用新工具链。固定:将活跃项目固定到其当前镜像,这样智能体的环境就不会在任务中途被替换。迁移:在自然的检查点迁移工作区,比如下一个会话或快照之后。回滚:通过更改未来启动所选择的镜像来回滚。无需推送配置,无需等待排空。
发布策略就存在于你的 Durable Object 代码中,与其他逻辑放在一起,并且可以按需简单或复杂。
这些改进都源于进一步深入 Durable Object,它本就拥有工作区的身份、状态和生命周期。让它选择并控制其 Container,让你对每个实例及其发布拥有更多控制权。它还为调度器提供了更好的 Container 启动位置:Durable Object 已经在运行的地方。这正是让智能体更快执行第一条命令的原因。
更快的首条命令
以前,启动 Container 需要我们的全局控制平面解析应用配置、寻找容量并协调放置。这种模型适用于应用级集群,但它把部署机制放在了智能体首条命令的路径上。
使用 durable_object
调度策略后,需求从 Durable Object 开始。为其提供服务的 Containers 基础设施会首先在同一台机器上寻找容量,如果需要,再在同一位置内扩大搜索范围。它还优先选择本地存储中已有该 Container 镜像或快照的主机,这样 Container 无需先下载即可启动。
我们还削减了 Container 到达主机后的工作。新的运行时不再从头启动新的虚拟机,而是恢复一台尚未分配的已准备好的虚拟机。它复用网络和文件系统设置,批量处理重复操作,并且不再等待首条命令不需要的服务。
这些变化共同大幅缩短了从创建沙箱到在其中运行命令所需的时间。在 ComputeSDK 的独立 Burst TTI Benchmark 中,该基准并发启动 100 个沙箱并从客户端测量交互时间:
| 启动测量 | 先前的调度路径 | 新的调度策略 | 改进 |
|---|---|---|---|
| 中位数 | 4.049 秒 | 648 毫秒 | 快 6.2 倍 |
| 第 95 百分位 | 5.839 秒 | 910 毫秒 | 快 6.4 倍 |
| 第 99 百分位 | 6.717 秒 | 1129 毫秒 | 快 5.9 倍 |
新路径在突发负载下也表现稳定。在我们的初步突发测试中,单个账户在 5.387 秒内跨六个位置启动了 100,000 个 Container。
从准备好的系统镜像开始
随着调度路径变得更快,准备镜像在剩余等待时间中占据的比例更大。在 Container 启动之前,其镜像必须位于主机上并解包到文件系统中。当这项工作在请求到达后才发生时,智能体就只能等待。
这就是我们推出 cloudflare/debian-trixie
的原因:一个面向可在运行时配置其环境的智能体的即用型系统镜像,包含 Debian Trixie Slim 和 Node.js 24.20.0 LTS:
this.ctx.container.start({
image: "cloudflare/debian-trixie",
instance: "standard-2",
enableInternet: true,
entrypoint: ["/bin/sleep", "infinity"]
});
这意味着你的 agent 无需先创建 Dockerfile、构建镜像或将其推送到 Cloudflare,就能启动一个 Linux 沙箱。沙箱运行后,你的 agent 可以使用 exec()
来克隆仓库、安装软件包,并为其任务配置环境。
而且由于 Cloudflare 掌控着这个镜像,我们可以在请求到达之前,将其分发并预先准备到符合条件的 Containers 主机上。初创公司无需在用户等待时下载或解包基础镜像。
保存工作区,稍后再返回
快速启动仍然留下了一个等待环节:设置工作区。克隆仓库、安装依赖项和配置工具链所花费的时间,可能远多于启动 Container 本身。在 agent 工作过程中,它还会生成你希望保留的文件。每次启动都重复设置会浪费时间,而丢失 agent 的更改则会让任务难以继续。
这就是我们为 Containers 添加原生文件系统快照(公开测试版)的原因。快照让 agent 可以在准备好的环境中开始任务,在任务暂停时保存其工作区,并在会话恢复时还原这些文件。
async saveWorkspace() {
const snapshot = await this.ctx.container.snapshotContainer({
name: "project-ready",
});
await this.ctx.storage.put("workspace-snapshot", snapshot);
}
async restoreWorkspace() {
const snapshot = await this.ctx.storage.get("workspace-snapshot");
if (!snapshot) {
throw new Error("No workspace snapshot found");
}
this.ctx.container.start({
containerSnapshot: snapshot,
instance: "standard-2",
enableInternet: true,
});
}
快照支持两种有用的模式。
首先,一个工作区可以跨多个会话持续存在。对于编码代理来说,这可能意味着在用户完成工作时保存工作区,并在第二天返回时恢复它。仓库、已安装的依赖项、构建缓存、配置和编辑都可用,无需重建环境。
其次,快照可以为多个沙箱提供共享检查点。由于快照是不可变且可重用的,多个容器可以从同一个准备好的环境独立启动,并在此基础上进行各自的更改。
代理评估就是一个很好的例子。评估可能会在不同的系统提示、技能、模型或代理版本上运行相同的任务。为了比较结果,其他所有内容都必须保持不变:仓库、依赖项、工具和输入文件。一个快照可以从同一基线启动多个隔离环境,减少设置时间并防止环境漂移影响结果。
快照还补充了我们上面介绍的新系统镜像。代理可以从 cloudflare/debian-trixie 开始
,使用 exec() 设置其环境
,并将结果保存为快照。未来的沙箱然后从该快照启动,仓库、依赖项和工具链已经就位。
通过新的 durable_object 调度策略提供快照
,容器可以作为持久代理工作区。计算可以在工作暂停时停止,新的容器可以从最新快照启动以继续之前的工作。
代理沙箱的 Durable Object 优势
更快的调度路径、运行时镜像选择和文件系统快照都来自同一个设计选择:进一步深入将 Durable Object 作为其附加容器的控制器。
代理系统需要在容器外部有一个可编程、有状态的环境来保存状态、持有凭证并控制沙箱的生命周期。你可以按照 Anthropic 描述的“将大脑与手解耦”模式在那里运行代理:当代理与其工作的沙箱分离时,代理保持可用,而其沙箱和工具可以独立启动、停止、失败或替换。或者,如果你在沙箱内运行代理,外部环境允许你监督它并向用户报告进度。
这就是 Durable Object 和容器架构变得独特适合的地方。每个容器都附加到一个有状态的 Durable Object,其自身的计算和存储就在旁边运行。你可以在 Durable Object 中运行代理,并使用容器作为其工作区,或者在容器中运行代理,并使用 Durable Object 来监督它。添加 Dynamic Workers 用于轻量级隔离执行,应用程序可以选择每个任务所需的执行环境。
durable_object 调度策略的新功能是
Durable Object 现在可以直接控制其容器,中间没有包装类。exec()
直接在 Workers 运行时中运行,出站请求拦截、运行时镜像和实例选择以及文件系统快照都可以在 ctx.container. 上使用
你可以将它们与 Durable Object 存储、警报、WebSockets、RPC 以及其余代码结合使用。
这使得 Container 成为 Durable Object 的计算扩展。Container 提供 Linux 环境,而你的 Durable Object 保留沙箱的身份、状态、策略和生命周期。这种拆分特别适合以下几种模式:

代理可以在其 Linux 工作区休眠时保持可用。 代理循环可以在 Durable Object 中运行,在那里维护会话状态、通过 WebSockets 与用户通信并调用模型。当需要 shell、编译器或开发服务器时,它可以唤醒 Container,然后在等待用户或模型时停止该计算,不为空闲的 Linux 计算付费。
Durable Object 可以围绕其 Container 编程安全边界。 它可以记住用户已授权的服务、仓库和操作,然后更新 Container 的出站请求处理器,以注入新授予的凭证、执行新策略或记录额外活动。这类似于 Cloudflare OS 使用的 Gatekeeper 模式,应用于每个代理计算机。
评估和强化学习系统可以从被测试环境外部监督每次尝试。 协调器对基础工作区进行快照,并将其分叉为 N 次尝试,每次尝试都有自己的 Durable Object 和一个 Container。每个 Durable Object 运行其尝试、监控运行并保留结果,即使 Container 崩溃。协调器对尝试进行评分,对最佳的一次进行快照,然后从那里再次分叉。
这些模式并不适合一种通用的生命周期。原生 API 让你可以将 Container 与应用程序所需的 Durable Object 原语结合使用,同时在有帮助的地方仍然使用更高级别的实用工具。你可以保持对 Container 的生命周期、策略和状态的控制。
这对 Container 类和 Sandbox SDK 意味着什么
当我们推出 Containers 时,我们有意将 Durable Object 隐藏在 Container 类之后。我们希望沙箱感觉熟悉,并符合开发者对其他平台的期望。Sandbox SDK 建立在该类之上,它填补了真实的空白:当时,运行时没有原生命令执行、出站请求拦截或快照,因此我们在用户空间中构建了它们。
从那时起,代理工作区已成为塑造 Containers 的主要工作负载之一,而这种抽象的成本已变得清晰。通过隐藏 Durable Object,我们让你更难看到并将其提供的身份、状态和协调与其控制的 Container 结合起来。我们合作过的几乎每个团队都需要与通用生命周期略有不同的东西:他们自己的休眠策略、他们自己的凭证处理、他们自己跟踪评估运行的方式。
这些能力现在是原生的,因此我们在开发者体验中明确 Durable Object:
- 新能力仅限原生。
durable_object
调度策略、更快的启动、运行时镜像和实例选择以及文件系统快照仅通过ctx.container
提供。 - 我们将维护
Container
类和旧版Sandbox
类至 2026 年 12 月 31 日。现有部署在该日期之后继续运行,但这些类将不再获得更新。我们建议迁移到ctx.container
- Sandbox SDK 1.0 是一组实用工具,而不是一个基类。它的辅助函数在你自己的 Durable Object 类中运行,与 ctx.container 并存。
- 如需更高层次的环境,
@cloudflare/computer
将 Dynamic Workers 和 Containers 与同步文件系统结合在一起。
迁移通常意味着将 extends Container
改为 extends DurableObject
并直接调用 this.ctx.container
。详情请参阅迁移指南。或者,从你的智能体开始:
开始使用
如今,大多数智能体是以它们在单次会话中能完成的任务来衡量的。随着智能体开始负责跨越数小时、数天乃至数周才逐步展开的项目,它们所处的工作环境也需要跟上步伐。
我们希望每个智能体都能为手头的任务创建沙箱,在工作暂停时释放计算资源,并在项目继续时回到同一个工作区。今天的这些变化让我们更接近这样的沙箱:它们像使用它们的智能体一样可编程、持久,并且随时可以投入工作。
试试新的 durable_object 调度策略,今天已在公开测试版中向所有人开放,看看更快的启动速度、文件系统快照和运行时配置能为你的智能体解锁什么:
为 Containers 使用新的 Durable Object 调度策略____使用文件系统快照保存和恢复文件____使用来自 GitHub 的 Durable Object 调度策略部署一个完整的沙箱示例- 从以下集成开始
Cursor Cloud Agents____Devin Outposts____OpenAI Agents API
致谢:本项目也离不开 Greg Anders、Andrew Martinez、Nafeez Nazer、Kian Newman-Hazel、Sebastien Pahl、Naresh Ramesh、Cody Roseborough、Nikita Sharma 和 Sarah Snell 的贡献。
