
现在大多数 Coding Agent 都运行在完整的 Linux 虚拟机或容器中以保障 Agent 安全地读取文件、执行 Bash 命令、安装依赖并运行项目。目前来说这个方案够用也符合模型已经形成的工具使用习惯。一开始开源 AI 应用构建项目 camelAI采用的也是这条路线基于 Claude Code Harness 构建 Agent并为每位用户配置一台带持久磁盘的虚拟机。但随着用户规模的扩大这套架构逐渐暴露出成本和扩展问题。常驻虚拟机要持续占用计算资源用户文件还要保存在高性能磁盘中。每增加一名用户平台都要增加相应的机器和存储资源。camelAI 最终选择把 Agent、文件系统和代码执行逐步拆出虚拟机。拆出后Agent 会运行在 Cloudflare Durable Object 中项目文件则进入 SQLite 和 R2。像文件处理、部署之类的常见操作会通过 JavaScript 沙箱执行只有构建和 Notebook 等依赖完整 Linux 环境的任务才会临时启动容器。因此标题说的“Coding Agent 不需要 VM”重点在于 Agent 不用长期绑定一台完整的虚拟机。Linux 依然保留只是从默认运行环境转为按需调用的执行资源。图 1Coding Agent 运行架构演进会话与执行环境的耦合传统 Coding Agent 往往将 Agent Harness、会话状态、项目文件和命令执行集中在同一台虚拟机或容器中。这样一来一旦运行环境发生故障任务状态和会话恢复也可能受到影响。Anthropic 早期的 Managed Agents 架构就遇到过类似问题。当时Session、Harness 和 Sandbox 被放在同一个容器中由容器同时承担会话保存、Agent Loop 和代码执行。实际运行中容器失效连带导致 Session 丢失进程卡死后故障难以快速定位因为问题可能出在 Harness、事件流或底层容器。因此架构拆分的第一步是把 Agent Harness 从虚拟机中迁出。Agent 与执行环境的解耦Claude Code Harness 与 Linux 环境结合比较深因此需要重新构建一套 Harness。camelAI 新 Harness 的实现使用 Pi 提供的底层组件包括 Agent Loop 和状态管理并将这些组件运行在 Cloudflare Durable Object 中。Durable Object 是一种有状态计算实例。每个对话线程可以拥有独立的实例和持久状态需要处理请求时被唤醒空闲则进入休眠。Agent 因此可以保持稳定身份和会话状态同时避免长期占用计算资源。在这个阶段系统仍然保留虚拟机但 Agent 已经不再住在里面。只有要执行命令时Harness 才会远程调用对应的 VM。整个系统由此被拆成两个部分Agent 负责推理、规划、上下文和状态管理相当于系统的“大脑”虚拟机负责执行命令、安装依赖和操作项目相当于系统的“手”。完成拆分后Agent 不用等待 VM 启动就能开始响应当前任务不涉及命令执行时虚拟机可以继续休眠同一个 Agent 也可以同时控制多个执行环境。不过这一步主要是为了改善启动速度和请求延迟。只要每位用户仍然对应一台虚拟机机器和磁盘带来的成本压力就依然存在。Anthropic Managed Agents 后来也采用了类似思路。早期架构将 Session、Harness 和 Sandbox 放在同一个容器中后来将三者拆成独立接口Session 负责保存事件日志Harness 运行 Agent LoopSandbox 则提供代码执行和文件编辑能力。图 2Agent 的“脑手分离”。Session 负责保存历史Harness 负责推理循环Sandbox、工具和外部系统作为可替换的执行端经过架构拆分Harness 不再依赖某个固定容器。执行环境发生故障后可以单独替换新的 Harness 也能够读取外部保存的历史事件并恢复任务。Sandbox 则被封装为标准化的execute(name, input)接口只有任务确实需要执行代码时才会创建。这项改造还带来了明显的延迟收益。Anthropic 公布的数据显示首 Token 延迟的 p50 下降约 60%p95 下降超过 90%。模型推理无需再等待容器创建、仓库克隆和进程启动因此可以更早开始响应。文件系统的数据化移除常驻 VM 后下一步是处理项目文件。在传统架构中文件系统依附于虚拟机磁盘。机器与磁盘解绑后Agent 仍然需要一个能够长期保存文件、支持读写编辑并维持完整项目结构的工作区。一种实现方式是在 Durable Object 中提供虚拟文件系统小文件直接写入 SQLite较大的文件则存入 R2SQLite 只保留元数据和对象引用。文件超过约 1.5 MB 后会转入对象存储以避开单行数据的大小限制。对 Agent 来说这套系统仍然表现为普通文件系统可以照常读取、写入、编辑、搜索和比较文件无需关心数据实际存放在 SQLite 还是 R2 中。但底层的持久化方式已经发生了变化项目从长期挂载的磁盘迁移为数据库和对象存储中的持久数据。Git 历史则继续交给兼容 Git 的存储服务管理这样既能保留完整的版本记录也不用额外运行 Git 服务器。即使虚拟机关闭项目文件、目录结构和提交历史仍然可以完整保留。完成这一步后Agent 状态和文件系统都已离开虚拟机剩下的主要依赖来自 Bash。Bash 与受控代码执行一般来说Coding Agent 会频繁地调用 Bash用它去搜索文件、安装依赖、运行测试、执行脚本和调用部署工具。借助 BashAgent 可以自由组合系统命令、访问文件和调用外部服务因此需要运行在完整的 Linux 环境中。这种开放式执行方式也扩大了权限风险。当 Agent 通过 Bash 调用数据库、代码仓库、云平台等外部服务时执行环境还得获得相应的访问凭证。凭证进入沙箱后Agent 生成的代码也可能直接访问这些敏感信息。一种替代方案是移除通用 Bash让 Agent 生成 JavaScript 代码并通过 Code Mode 和 Dynamic Workers 在独立的 V8 Isolate 中执行。虽然每次代码执行都会创建一个新的 Isolate但其启动通常只需毫秒级时间。执行环境默认无法访问网络和外部资源平台只向沙箱提供经过明确授权的文件读写、数据连接和项目部署等能力。相关凭证不会进入沙箱身份验证统一由平台侧完成。Agent 日常通过 Bash 完成的大部分操作其实可以被少量显式工具覆盖read、write和edit负责文件读写与编辑grep和glob负责内容搜索与路径匹配deploy_project负责项目部署应用构建和 Notebook 运行则分别封装为独立方法。显式方法还能够提供更准确的执行信息。过去直接运行wrangler deploy时平台只能从代理流量中推测部署行为封装为deploy_project后系统可以明确记录部署时间、所属项目、执行状态和最终地址并在部署完成后自动打开在线预览。Bash 提供的是开放的通用执行环境显式方法则把常用操作收敛为边界清晰的平台能力。命令执行范围由此更加可控也更容易加入权限管理、审计记录、超时限制和错误处理。Linux 能力的按需回归一些任务仍然离不开完整的 Linux 环境。前端项目构建可能涉及 Vite、Tailwind、React Router以及通过bun install安装依赖Python Notebook 也可能需要系统包、原生库和更大的运行内存。这类任务很难全部交给资源有限的 Worker 或轻量 JavaScript Isolate。因此系统仍然保留短时容器。当 Agent 发起构建任务时平台会临时启动一个 Linux 容器将项目文件复制进去完成依赖安装和项目构建再把结果同步回来。任务结束后容器随即关闭。Notebook 运行也采用类似流程。这样既保留了完整 Linux 环境的兼容性又把容器的使用时间压缩到真正需要它的几秒或几分钟。Cloudflare 在 Project Think 中进一步将这套思路整理为一条“执行阶梯”Workspace通过 SQLite 和 R2 提供持久文件系统Dynamic Worker运行 Agent 生成的 JavaScriptnpm运行环境为代码补充所需依赖Browser处理网页访问与自动化操作Sandbox执行git clone、npm test、cargo build等需要完整 Linux 环境的任务。Agent 默认从更轻量的运行环境开始再根据任务复杂度逐级调用更完整的执行能力。图 3Coding Agent 的执行阶梯。文件工具 → JavaScript Isolate → npm / Browser → 短时 Linux Sandbox显式能力的边界与收益移除 Bash 有好处也有坏处。这个坏处就是平台需要提前定义 Agent 可以使用哪些能力。在开放式 Shell 中Agent 可以临时查找命令、安装工具并自由地组合执行步骤。而迁移到显式方法后一旦缺少某项能力就要为它补充对应的接口。这种约束会增加前期的工具搭建成本但也变相地推动高频操作的标准化工作。类似部署、构建、文件搜索和 Notebook 执行这样的任务可以采用固定的输入输出、权限范围和错误结构整个执行过程也变得更容易观测、排查和恢复。工具范围缩小后模型的选择难度也会下降。开放式 Bash 包含大量命令、参数和组合方式能力较弱或成本较低的模型容易选错工具、生成无效命令。显式方法让工具数量变少、边界变清晰小模型也更容易稳定地完成任务。类似的能力设计也出现在其他 Agent 运行时中。LangChain 的 Code Interpreter 会从一个默认无法访问文件、网络和依赖的小型运行时开始再由 Harness 明确注入所需能力完整容器仍然保留用于处理确实依赖完整计算环境的任务。由此形成了两种常见模式Agent 可以运行在 Sandbox 内部或是把 Sandbox 作为普通工具按需调用运行在外部。后者将 Agent 状态和凭证保留在执行环境之外即使沙箱发生故障也不会直接影响会话状态。Coding Agent 的分层运行时经过拆分一套 Coding Agent 运行时由下面这些相对独立的部分组成Harness 负责 Agent Loop 和会话状态管理运行在 Durable Object 中项目文件保存在 SQLite 和 R2Git 服务独立保存版本历史常见代码通过 JavaScript Isolate 执行外部操作通过显式方法和受控凭证完成构建、测试和 Notebook 等任务按需启动 Linux 容器。从用户角度看Agent 依然可以读取、编辑、搜索、构建和部署项目但底层已经不再依赖一台长期运行的完整机器。这也是“Coding Agent 不需要 VM”更值得讨论的地方。Coding Agent 真正需要的是状态、文件、工具和计算能力而这些能力可以分布在不同的基础设施中。VM 仍然可以承担重型计算和完整 Linux 任务只是不再承载全部能力。Agent 可以先在成本更低的持久运行时中完成推理和状态管理再根据任务需要临时调用更重的执行资源。当推理、存储和执行完成解耦后Harness、文件系统和沙箱都可以独立替换不同任务也能选择更合适的计算环境。这样既能减少空闲资源成本也能让权限边界、故障恢复和工具调用过程更加清晰。