访问我们的文档,开始使用 Claude 托管智能体(Managed Agents)。
在工程博客中,我们持续探讨的一个主题是:如何构建有效的智能体,以及如何为长时运行任务设计编排框架(harness)。贯穿这些工作的一条主线是:编排框架本质上编码了对 Claude 能力边界的假设。但这些假设需要反复检验,因为随着模型的进步,它们很容易失效。
举一个具体的例子。在此前的工作中,我们发现 Claude Sonnet 4.5 会在感知到上下文窗口(context window)即将耗尽时提前结束任务——这种行为有时被称为”上下文焦虑”(context anxiety,即模型因感知到可用上下文空间不足而急于收尾的倾向)。我们通过在编排框架中添加上下文重置来应对。但当我们在 Claude Opus 4.5 上使用同一套编排框架时,这种行为已经消失了。那些重置逻辑沦为了累赘。
我们预期编排框架会持续演进,于是构建了托管智能体(Managed Agents):Claude 平台上的一项托管服务,通过一组精简的接口代你运行长周期智能体——这些接口的设计初衷是比任何特定实现都更持久,包括我们今天正在运行的实现。
核心思想
将”大脑”(Claude 及其编排框架)与”双手”(沙箱和工具)、“会话”(事件日志)解耦。每个组件只暴露一组通用接口,彼此尽量少做假设——这样任何一部分都可以独立失败或被替换,系统得以容纳尚未被构想出的编排框架。
构建托管智能体意味着要解决计算领域一个由来已久的问题:如何为”尚未被构想出的程序”(出自 Eric Raymond《Unix 编程艺术》)设计系统。几十年前,操作系统通过将硬件虚拟化为抽象概念——进程、文件——解决了这个问题,这些抽象足够通用,能够服务于当时尚不存在的程序。抽象比硬件更持久。read() 系统调用并不关心它访问的是 1970 年代的磁盘组还是现代 SSD。上层抽象保持稳定,底层实现自由更替。
托管智能体遵循了同样的模式。我们将智能体的各个组件虚拟化:会话(session,记录所有事件的仅追加日志)、编排框架(harness,调用 Claude 并将其工具调用路由到相应基础设施的循环)、以及沙箱(sandbox,Claude 运行代码和编辑文件的执行环境)。每个组件的实现都可以在不干扰其他组件的情况下被替换。我们对接口的形态有明确的主张,但对接口背后运行什么不做预设。

别养”宠物”
我们最初将所有智能体组件放在一个容器中,会话、编排框架和沙箱共享同一个环境。这种方案有其好处——文件编辑就是直接的系统调用,也不需要设计服务边界。
但将一切耦合在一个容器中,我们撞上了基础设施领域的一个经典问题:我们养了一只宠物。在”宠物与牲畜”(pets vs. cattle,云基础设施经典类比:宠物是命名的、精心照料的个体,失去不起;牲畜则是可互换的)这个类比中,我们的服务器变成了那只宠物——容器一旦崩溃,会话就丢失了;容器一旦无响应,就得想办法把它救活。
“救活”容器意味着调试那些卡死的会话。我们唯一的排查窗口是 WebSocket 事件流,但它无法告诉我们故障究竟发生在哪里——编排框架的 bug、事件流的丢包、还是容器本身下线,呈现出来的症状完全一样。为了定位问题,工程师不得不打开容器内部的 shell,但由于容器中往往还存有用户数据,这条路实际上意味着我们丧失了调试能力。
第二个问题是,编排框架假定 Claude 的所有工作内容都在容器内。当客户需要将 Claude 连接到自有 VPC(虚拟私有云)中的资源时,要么将他们的网络与我们对等互联,要么在他们自己的环境中运行我们的编排框架。一个写死在编排框架中的假设,在需要对接不同基础设施时就变成了障碍。
将大脑与双手分离
我们最终的解决方案是将”大脑”(Claude 及其编排框架)从”双手”(沙箱和执行操作的工具)和”会话”(会话事件日志)中分离出来。每个组件都成为一个对其他组件几乎不做假设的接口,可以独立地失败或被替换。
编排框架离开容器。 将大脑与双手分离意味着编排框架不再驻留在容器内部。它调用容器的方式与调用其他任何工具一样:execute(name, input) → string。容器变成了牲畜。容器崩溃时,编排框架将失败捕获为工具调用错误并传回给 Claude。如果 Claude 决定重试,新容器可以通过标准配方重新初始化:provision({resources})。我们不再需要费力把失败的容器救活。
从编排框架故障中恢复。 编排框架本身也变成了牲畜。会话日志存放在编排框架之外,框架内部不需要在崩溃中留存任何状态。框架崩溃时,新实例通过 wake(sessionId) 启动,用 getSession(id) 取回事件日志,然后从最后一个事件继续。在智能体循环运行期间,编排框架通过 emitEvent(id, event) 向会话写入数据,保持事件记录的持久性。

安全边界。 在耦合设计中,Claude 生成的所有不可信代码都在与凭据相同的容器中运行——提示注入(prompt injection)攻击只需要说服 Claude 读取自身的环境变量就能得手。攻击者一旦拿到这些令牌,就能创建全新的、不受限制的会话并将工作委托给它们。收紧令牌权限是显而易见的缓解措施,但这暗含了一个假设:Claude 用有限令牌做不了什么坏事——而 Claude 正变得越来越聪明。真正的结构性修复是:确保这些令牌在沙箱中——也就是 Claude 生成的代码实际运行的环境中——根本不可达。
我们采用了两种模式来实现这一点。认证信息可以与资源绑定,也可以存放在沙箱之外的保险库中。对于 Git,我们在沙箱初始化阶段使用仓库的访问令牌来克隆仓库,并将其配置到本地 git remote 中。沙箱内的 push 和 pull 操作正常工作,而智能体本身从未接触过令牌。对于自定义工具,我们支持 MCP 并将 OAuth 令牌存储在安全保险库中。Claude 通过专用代理调用 MCP 工具;代理接收与会话关联的令牌,从保险库中取出相应凭据,然后向外部服务发起调用。编排框架自始至终不接触任何凭据。
会话不等于 Claude 的上下文窗口
长周期任务的持续时间往往超出 Claude 上下文窗口的容量,而解决这个问题的标准方法都涉及不可逆的取舍——保留什么、丢弃什么。我们在此前关于上下文工程的工作中探讨过这些技术。例如,压缩(compaction)让 Claude 保存上下文窗口的摘要,记忆工具让 Claude 将上下文写入文件从而实现跨会话学习。这些方法可以与上下文裁剪(context trimming)配合使用,后者有选择地移除旧的工具返回结果或思考块等 token。
然而,不可逆地选择性保留或丢弃上下文可能导致故障。很难预知未来的对话轮次需要哪些 token。一旦消息经过压缩步骤被转换,编排框架就会将已压缩的消息从 Claude 的上下文窗口中移除——除非事先另行存储,否则无法恢复。此前的研究已经探索过一些应对方法,比如将上下文作为存在于上下文窗口之外的对象来存储。例如,上下文可以是 REPL 中的一个对象,LLM 通过编写代码对其进行过滤或切片,以编程方式访问。

在托管智能体中,会话提供了同样的能力——它是一个存在于 Claude 上下文窗口之外的上下文对象。不同于存储在沙箱或 REPL 中,这里的上下文被持久化存储在会话日志中。getEvents() 接口允许大脑通过选取事件流的位置切片来查询上下文。这个接口使用灵活:大脑可以从上次停止阅读的位置继续、在某个特定时刻之前回退几个事件查看前因、或者在执行某个操作前重新阅读上下文。
获取到的事件还可以在编排框架中先行转换,然后再传入 Claude 的上下文窗口。这些转换可以是编排框架编码的任何逻辑,包括为实现高提示缓存命中率(prompt cache hit rate)而进行的上下文组织,以及各种上下文工程(Context Engineering)策略。我们将可恢复的上下文存储(会话的职责)与任意的上下文管理(编排框架的职责)分离开来,因为我们无法预测未来模型需要什么样的上下文工程。接口将上下文管理推入编排框架,只保证会话本身是持久且可查询的。
多个大脑,多双手
多个大脑。 将大脑与双手分离解决了我们最早收到的客户投诉之一。当团队需要让 Claude 访问自有 VPC 中的资源时,唯一的路径是将他们的网络与我们对等互联——因为承载编排框架的容器假定所有资源都在它旁边。编排框架从容器中独立出来后,这个假设就不复存在了。同样的改变也带来了性能收益。最初把大脑放在容器中时,多个大脑就需要同等数量的容器。每个大脑在容器配置完成之前都无法开始推理,每个会话都要预先支付完整的容器启动成本。每个会话——即使是永远不会用到沙箱的会话——都必须克隆仓库、启动进程、从服务器拉取待处理事件。
这些等待时间体现为首 token 延迟(TTFT,Time-to-First-Token),即会话从接受任务到产生第一个响应 token 之间的等待时长。这是用户感受最为强烈的延迟。
将大脑与双手分离意味着容器只在需要时才由大脑通过工具调用 (execute(name, input) → string) 来创建。不需要容器的会话无需等待。编排层从会话日志中拉取待处理事件后,推理即可立即开始。采用这一架构后,我们的 p50 首 token 延迟下降了约 60%,p95 下降超过 90%。扩展到多个大脑只需启动多个无状态的编排框架,并在需要时将它们连接到双手即可。
多双手。 我们还希望每个大脑能连接多双手。在实践中,这意味着 Claude 必须对多个执行环境进行推理,并决定将工作发送到哪里——这是一项比在单个 shell 中操作更困难的认知任务。我们最初将大脑放在单个容器中,是因为早期模型还不具备这种能力。随着智能水平的提升,单容器反而变成了瓶颈:一旦那个容器失败,大脑正在操控的所有双手的状态都会丢失。
将大脑与双手分离后,每只手都是一个工具 execute(name, input) → string:输入名称和参数,返回一个字符串。这个接口支持任何自定义工具、任何 MCP 服务器,以及我们自己的工具。编排框架不关心沙箱是一个容器、一部手机、还是一个宝可梦模拟器。而且由于没有任何手与特定大脑绑定,不同大脑之间可以将双手交接给彼此。

结论
我们面对的挑战由来已久:如何为”尚未被构想出的程序”设计系统。操作系统之所以能延续数十年,正是因为它将硬件虚拟化为足够通用的抽象,使得尚不存在的程序也能在其上运行。托管智能体的目标与此一脉相承——设计一个能够容纳未来编排框架、沙箱或其他围绕 Claude 的组件的系统。
托管智能体是同一精神下的元编排框架(meta-harness),不预设 Claude 未来需要什么具体的编排框架,而是提供通用接口来容纳多种不同的框架。例如,Claude Code 就是一个优秀的编排框架,我们在各类任务中广泛使用。我们也已证明,针对特定任务的智能体编排框架在垂直领域表现出色。托管智能体可以容纳其中任何一种,随着 Claude 智能水平的提升而匹配进化。
元编排框架的设计意味着对 Claude 周围的接口持有明确主张:我们预期 Claude 需要操纵状态(会话)和执行计算(沙箱)的能力,也需要扩展到多个大脑和多双手的能力。我们设计的接口使这些能力可以在长期内可靠、安全地运行。但我们不对 Claude 需要的大脑或双手的数量和位置做任何假设。
致谢
本文由 Lance Martin、Gabe Cemaj 和 Michael Cohen 撰写。特别感谢 Agents API 团队和 Jake Eaton 的贡献。