使用Durable Object重构AI编码Agent:Pi、Agents SDK与Code Mode实践

vercantez 发布于 2026-07-29 10:45 阅读 10

camelAI团队分享了将其AI编码Agent从虚拟机迁移到Cloudflare Durable Objects的过程。最初使用Claude Code harness在自建容器服务上运行,但成本高昂且难以扩展。团队分三步重构:首先将代理逻辑移出虚拟机,放入Durable Object,只远程调用虚拟机执行命令,降低了延迟;然后用基于SQLite和R2的文件系统完全取代虚拟机,并利用Cloudflare Shell项目;最后移除bash命令,让代理使用JavaScript沙箱(通过Code Mode和动态Worker执行),并针对构建、笔记本等任务保留短期容器。最终架构更便宜、延迟低、易于扩展,所有代码已开源。

图像

我们最近完成了将 camelAI Agent 从虚拟机中迁移出来的工作。现在该 Agent 运行在 Cloudflare Durable Object 内部,其文件系统存放在 SQLite 和 R2 中,并且它编写 JavaScript 而非 bash。大多数团队都在完整的 Linux 虚拟机或容器沙箱中运行编码 Agent,我们以前也是如此。

我们想放弃虚拟机,是因为为每个用户提供一台始终在线、带有附加磁盘的机器,成本高昂,难以扩展。难点在于编码 Agent 假定运行在 Linux 上。它们被训练成习惯使用 bash,而我们最初启动的框架需要完整的虚拟机,因此我们经历了三次重新设计才达到目前的状态。作为权衡,Agent 现在只能执行我们已经构建了明确方法的事情,这听起来有限制,但对产品来说是有益的。

我是 camelAI 的 CTO Miguel。我们的代码库最近开源了,因此本文中的所有内容你都可以在 github.com/qaml-ai/camelAI 上阅读。我会在过程中链接相关文件。以下是整个演进过程。

第零步:虚拟机时代

我们最开始使用的是 Claude Code 框架,它需要完整的虚拟机来运行。我们尝试了几家虚拟机提供商,但没有一家能满足我们的持久性和性能要求,最终我们构建了自己的容器服务。那篇文章仍然在线,但我们已不再运行任何相关基础设施了。

容器服务能用,但太重了。为每个用户提供一台始终在线的虚拟机成本高昂,将每个用户的文件保存在快速附加磁盘上也是如此。扩展意味着需要扩展真实的机器和真实的磁盘,这对于我们目标用户数量来说将是非常昂贵的。因此,我们没有在虚拟机编排上耍花招,而是开始从根本不需要 VM 的角度进行设计。

第一步:将 Agent 从虚拟机中取出

Claude Code 框架与其虚拟机密不可分,因此第一步是构建我们自己的框架。我们基于 pi(Mario Zechner 的开源编码 Agent)构建了它。pi 是一个库栈。最高层假定有正常的操作系统,但较低层为你提供了 Agent 原语,比如 Agent 循环和状态管理,而不关心它们在何处运行。我们没有修改任何 pi 代码。我们导入这些较低层并在其之上构建了我们自己的框架,该框架运行在 Cloudflare Durable Object 内部,而不是 Linux 环境中。

Durable Object 是一个小型有状态计算实例,在 Cloudflare 边缘启动,靠近创建它的用户。每个聊天线程都有自己的 Durable Object,与将所有流量路由到中心化虚拟机主机相比,这本身就降低了延迟。

在这个阶段,我们保留了虚拟机,但 Agent 不再位于虚拟机内部。当 Agent 需要运行命令时,它远程调用虚拟机。Anthropic 对其托管 Agent 也描述了同样的分离方式:大脑与双手分离。这给了我们一些不错的特性:

  • Agent 在虚拟机启动之前就开始响应,因为它不需要等待机器启动。
  • 当 Agent 继续工作时,虚拟机可以进入休眠状态,如果这一轮不需要任何命令,甚至可以永远不唤醒。
  • 一个大脑可以控制多个双手。单个 Agent 可以同时操作多个虚拟机。

我们将这些“双手”称为项目。每个项目都有一个用于执行命令的虚拟机,以及一个通过 Cloudflare Artifacts 以编程方式创建的 git 仓库。Artifacts 是一种与 git 兼容的存储,你可以从 Worker 即时配置。Agent 实际上并不知道它运行在虚拟机之外。它仍然拥有 bash,并且像其他编码 Agent 一样工作。

问题在于,这只能解决延迟问题,其他问题依旧存在。我们仍然为每个用户配备了一台虚拟机,因此原来设计中的所有成本和扩展问题依然存在。

第二步:移除虚拟机

下一个版本保持了相同的项目结构,但取消了背后的虚拟机。每个项目现在由一个位于 Durable Object 内部的文件系统支持,大型文件则使用 R2

这不是我们的发明。Cloudflare 的 Agent 团队构建了 Shell,这是一个用于 Worker 的实验性文件系统和执行运行时,我们大量重用了他们的代码。其机制很简单。Durable Object 的存储是一个容量上限为 10 GB 的 SQLite 数据库,每一行都有最大大小。小文件直接存储在 SQLite 行中。超过约 1.5 MB 的文件会被写入 R2,而 SQLite 行只保存一个指针。对于 Agent 来说,这看起来像一个普通的文件系统,但底层是数据库和对象存储,因此持久化是存储的数据,而不是我们必须保持运行的基础设施。

版本历史仍然通过 Artifacts 运行,因此每个项目都保留着 git 历史,而我们无需托管 git 服务器。

第三步:移除 bash

移除 bash 感觉是个大动作。编码 Agent 被训练成习惯使用 bash,而 bash 正是所有人一开始将 Agent 运行在虚拟机中的原因。这也是一个超出成本范畴的问题。一个拥有 bash 和网络访问权限的 Agent,需要凭据才能执行任何有用操作,而我们尝试的经过身份验证的代理 URL 方法变得既 hacky 又难以执行。

因此,我们移除了它。Agent 不再使用 bash,而是编写 JavaScript,通过 Code Mode 和 Cloudflare 的动态 Worker 加载器 执行。每个执行都在一个全新的 V8 隔离环境中运行,启动时间毫秒级,内存占用仅几 MB。沙箱预加载了用户的数据连接以及平台能做的一切方法。凭据永远不会进入沙箱。Agent 调用连接的方法,身份验证由我们这边处理。

当你审视 Agent 实际使用 bash 做什么时,失去它带来的损失比你想象的要小。大部分是文件操作,Agent 有原生的工具来处理这些。我们提供了读取、写入和编辑,以及我们自己的 grep 和 glob 实现。这覆盖了 80-20 的场景。其余的是针对特定任务的具体命令,这些变成了明确的方法:

  • 通过代理执行的 wrangler deploy 变成了一个我们完全控制的 deploy_project 方法。由于我们确切知道部署何时发生,我们可以 Hook 它并自动打开一个实时预览。以前,我们必须嗅探代理的 wrangler 流量来猜测哪个线程部署了某些内容。
  • 构建用户的应用和运行 Python notebook 变成了它们自己的方法,两者都基于短生命周期的容器。

我们保留了这两个任务的容器,因为它们确实需要 Linux。用户的应用使用 Vite、Tailwind 和 React Router 构建,添加依赖需要运行 bun install。我们考虑过在 Worker 内部运行构建,因为正在构建的东西本身就是一个 Worker,但是这个路径支持不太好,并且 Worker 有 128 MB 的内存限制和一小部分 CPU。构建会非常缓慢,而且很多项目会超过内存上限。因此,构建转而通过 Cloudflare Sandbox SDK 启动一个容器,将项目复制进去,运行任务,返回结果,然后关闭容器。Notebook 运行也是如此。我们仍然使用完整的 Linux,但仅限于真正需要它的那几秒钟工作。

诚实地说,缺点是我们必须预见到 Agent 需要什么。有了 bash,它可以自己解决问题。现在,如果缺少某个功能,我们必须添加它。在实践中,这种压力对产品是有益的,因为它迫使我们思考用户正在做什么,并为此构建一个一流的路径,而不是让 Agent 即兴发挥。

还有一个意想不到的好处。Bash 是开放式的,便宜的模型在开放环境中表现明显更差。使用一组更小的明确方法,它们的表现明显更好,这一点很重要,因为保持 camelAI 运行成本低廉正是这种架构的目的所在。

我们现在的情况

现在的架构是:Durable Objects 用于 Agent 及其文件系统,R2 用于大型文件,Artifacts 用于 git 历史,pi 作为框架,Code Mode 配合动态 Worker 用于执行。它像任何其他 Cloudflare 应用一样部署,无需管理外部容器服务。

动态 Worker 按每次执行计费,而不是按正常运行秒数。数千次执行的成本大约相当于我们过去评估的服务中几分钟的容器时间。延迟很低,因为所有内容都在靠近用户的边缘运行,扩展是 Cloudflare 的问题,而不是我们的问题。

用户仍然可以构建和部署全栈应用到实时 URL,Agent 仍然可以读取、写入、grep 和部署。从用户的角度来看,什么都没变。

太长不看

我们最初在自建的虚拟机服务上使用 Claude Code 框架,成本高昂且难以扩展。首先,我们将 Agent 本身移入 Cloudflare Durable Object,并让其远程控制虚拟机,这解决了延迟问题,但没有解决成本问题。然后,我们基于 Cloudflare 的 Shell 项目,用存储在 Durable Object SQLite 和 R2 中的文件系统完全取代了虚拟机,并通过 Cloudflare Artifacts 提供 git 历史。最后,我们移除了 bash,通过 Code Mode 和动态 Worker 为 Agent 提供了一个 JavaScript 沙箱,并为部署、构建和 notebook 提供了明确的方法。结果成本降低了几个数量级,延迟更低,操作更简单,并且更易于小型模型驱动。所有代码都在 github.com/qaml-ai/camelAI 开源。

  • 原文链接: x.com/Vercantez/status/2...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论