跳到正文
Anthropic Engineering·· 2026-04-08精选AI 评分73

Claude Managed Agents 如何通过解耦“大脑”与“双手”实现扩展

Scaling Managed Agents: Decoupling the brain from the hands

AI 导读

Anthropic 详解 Claude Managed Agents 的架构,将 Claude 及其运行框架、执行沙箱和会话日志解耦,使各组件能独立替换与故障恢复。持久化会话日志支持按需检索历史上下文,凭据隔离与代理机制避免沙箱中的代码直接接触认证凭据。沙箱改为按需配置后,无需立即使用沙箱的会话可直接开始推理,p50 首 token 延迟(TTFT)降低约 60%,p95 降低超过 90%。

推荐理由

将运行循环、执行环境与事件日志拆成独立接口,为长时运行智能体提供了可迁移的故障恢复设计,也让上下文管理能随模型演进。

正文 · AI 翻译

按照我们的文档开始使用 Claude Managed Agents。

工程博客上一个持续讨论的话题是如何构建高效的智能体,以及如何为长时间运行的工作设计运行框架。这些工作有一个共同点:运行框架中包含了对 Claude 无法独立完成哪些事情的假设。然而,这些假设需要经常受到审视,因为随着模型改进,它们可能会过时。

举一个例子,在此前的工作中,我们发现,Claude Sonnet 4.5 在察觉到即将达到上下文上限时,会提前结束任务——这种行为有时被称为“上下文焦虑”。我们通过在运行框架中加入上下文重置来解决这个问题。但当我们将同一套运行框架用于 Claude Opus 4.5 时,发现这种行为已经消失了。重置反而成了累赘。

我们预计运行框架会继续演进。因此,我们构建了 Managed Agents:这是 Claude Platform 中的一项托管服务,通过一组精简的接口,代表你运行执行长期任务的智能体。这些接口旨在比任何特定实现都更长久,包括我们目前运行的实现。

构建 Managed Agents 意味着要解决计算领域的一个老问题:如何为“尚未被构想出来的程序”设计系统。几十年前,操作系统通过将硬件虚拟化为足够通用的抽象——进程、文件——解决了这个问题,使其能够适用于尚不存在的程序。这些抽象比硬件更长寿。read() 命令并不关心自己访问的是 1970s 的磁盘组,还是现代 SSD。上层抽象保持稳定,底层实现则可以自由变化。

Managed Agents 遵循同样的模式。我们将智能体的各个组件虚拟化:会话(记录所有已发生事件的仅追加日志)、运行框架(调用 Claude 并将 Claude 的工具调用路由到相关基础设施的循环),以及沙箱(Claude 可以在其中运行代码和编辑文件的执行环境)。这样就可以替换任一组件的实现,而不影响其他组件。我们对这些接口的形式有明确主张,但不限定其背后运行的具体实现。

不要养宠物

我们最初将所有智能体组件都放进一个容器,这意味着会话、智能体运行框架和沙箱共享同一个环境。这种方法有一些好处,包括文件编辑可以直接通过系统调用完成,也无需设计服务边界。

但将所有东西耦合在一个容器中,让我们遇到了一个老牌基础设施问题:我们养了一只宠物。在“宠物与牲畜”的比喻中,宠物是有名字、需要悉心照料且无法承受失去的个体,而牲畜则可以相互替换。在我们的场景中,服务器成了那只宠物;如果容器发生故障,会话就会丢失。如果容器失去响应,我们就得悉心照料,让它恢复正常。

照料容器意味着要调试那些卡住、失去响应的会话。我们唯一的观察窗口是 WebSocket 事件流,但它无法告诉我们故障发生在哪里,这意味着运行框架中的缺陷、事件流中的丢包或容器离线,表现出来都一样。要查明出了什么问题,工程师必须在容器内打开 shell,但由于该容器往往也存放着用户数据,这种方式实际上意味着我们不具备调试能力。

第二个问题是,运行框架假定 Claude 处理的所有内容都与它处在同一个容器中。当客户要求我们将 Claude 连接到他们的虚拟私有云时,他们要么必须将自己的网络与我们的网络建立对等连接,要么在自己的环境中运行我们的运行框架。当我们想将运行框架连接到不同的基础设施时,这个内置假设就成了问题。

我们最终采用的解决方案是,将我们所认为的“大脑”(Claude 及其运行框架)与“双手”(执行操作的沙箱和工具)以及“会话”(会话事件日志)解耦。三者各自成为一个接口,对彼此的假设很少,而且都可以独立发生故障或被替换。

运行框架移出容器。 将大脑与双手解耦,意味着运行框架不再位于容器内部。它像调用其他任何工具一样调用容器:execute(name, input) → string。容器成了可随时替换的资源。如果容器崩溃,运行框架会将故障作为工具调用错误捕获,并传回给 Claude。如果 Claude 决定重试,就可以按照标准流程重新初始化一个新容器:provision({resources})。我们不再需要费心修复发生故障的容器。

从运行框架故障中恢复。 运行框架也成了可随时替换的资源。由于会话日志位于运行框架之外,运行框架中没有任何内容需要在崩溃后保留下来。当一个运行框架发生故障时,可以用 wake(sessionId) 重新启动一个新的运行框架,用 getSession(id) 取回事件日志,并从最后一个事件继续执行。在智能体循环期间,运行框架通过 emitEvent(id, event) 向会话写入内容,以持久保存事件记录。

安全边界。 在耦合设计中,Claude 生成的任何不可信代码都在存有凭据的同一个容器中运行,因此,提示注入只需说服 Claude 读取它自己的环境即可。一旦攻击者获得这些令牌,就可以创建新的、不受限制的会话,并将工作委派给这些会话。缩小权限范围是一种显而易见的缓解措施,但这隐含了一个假设,即 Claude 无法利用权限受限的令牌做某些事,而 Claude 正变得越来越聪明。从结构上解决问题的方法,是确保这些令牌永远无法从运行 Claude 所生成代码的沙箱中访问。

我们采用了两种模式来确保这一点。身份验证可以与资源绑定,也可以存放在沙箱外部的保险库中。对于 Git,我们在沙箱初始化期间使用每个代码仓库的访问令牌克隆仓库,并将其配置到本地 git 远程仓库连接中。Git push 和 pull 可以在沙箱内部使用,而智能体始终无需处理令牌本身。对于自定义工具,我们支持 MCP,并将 OAuth 令牌存储在安全的保险库中。Claude 通过专用代理调用 MCP 工具;该代理接收一个与会话关联的令牌。随后,代理可以从保险库中获取相应凭据,并调用外部服务。运行框架始终不会获知任何凭据。

会话并不等于 Claude 的上下文窗口

长周期任务往往会超出 Claude 上下文窗口的长度,而解决这一问题的常规方法都需要就保留哪些内容做出不可逆的决定。我们在关于上下文工程的先前工作中探索过这些技术。例如,压缩让 Claude 可以保存上下文窗口的摘要,而记忆工具让 Claude 可以将上下文写入文件,从而实现跨会话学习。这可以与上下文裁剪结合使用,后者会选择性地移除旧工具结果或思考块等内容中的词元。

但选择性地保留或丢弃上下文的不可逆决策可能导致失败。很难预知后续轮次会需要哪些 token。如果消息经过压缩步骤转换,运行框架就会将已压缩的消息从 Claude 的上下文窗口中移除,而这些消息只有在已被存储的情况下才能恢复。此前的工作探索过一些解决方法:将上下文存储为一个存在于上下文窗口之外的对象。例如,上下文可以是 REPL 中的一个对象,LLM 通过编写代码对其进行筛选或切片,以编程方式访问它。

在 Managed Agents 中,会话提供了同样的好处,充当存在于 Claude 上下文窗口之外的上下文对象。但上下文并非存储在沙箱或 REPL 中,而是持久存储在会话日志中。接口 getEvents(), 允许大脑通过按位置选取事件流切片来查询上下文。该接口可以灵活使用,让大脑从上次停止读取的位置继续读取,回退到某个特定时刻之前的几个事件以了解事情的来龙去脉,或重新读取某个特定操作之前的上下文。

任何获取到的事件也可以先在运行框架中进行转换,再传入 Claude 的上下文窗口。这些转换可以是运行框架所编码的任何操作,包括为实现较高的提示词缓存命中率而进行的上下文组织,以及上下文工程。我们将会话中可恢复的上下文存储与运行框架中任意形式的上下文管理这两项职责分离,因为我们无法预测未来的模型将需要哪些具体的上下文工程。这些接口将上下文管理交由运行框架处理,仅保证会话持久存储且可供查询。

多个大脑,多双手

多个大脑。将大脑与双手解耦,解决了客户最早提出的抱怨之一。当团队希望 Claude 使用其自有 VPC 中的资源开展工作时,唯一的途径是将他们的网络与我们的网络建立对等连接,因为承载运行框架的容器假定所有资源都位于它旁边。一旦运行框架不再位于容器中,这一假设也就不复存在。同样的变化还带来了性能收益。最初将大脑放入容器时,就意味着有多少个大脑,就需要多少个容器。对每个大脑而言,只有在对应容器配置就绪后才能进行推理;每个会话都要预先承担完整的容器设置开销。每个会话,即使那些永远不会使用沙箱的会话,也必须克隆代码仓库、启动进程,并从我们的服务器获取待处理事件。

这段空等时间体现在首 token 时间(TTFT)上,该指标衡量会话从接受任务到生成首个响应 token 之间的等待时长。TTFT 是用户感受最为强烈的延迟。

将大脑与双手解耦,意味着只有在需要时,大脑才会通过工具调用 (execute(name, input) → string) 来配置容器。因此,不需要立即使用容器的会话就不必等待容器就绪。编排层一从会话日志中拉取待处理事件,推理就可以开始。采用这种架构后,我们的 p50 TTFT 下降了约 60%,p95 下降了超过 90%。扩展到多个大脑,只需启动多个无状态运行框架,并仅在需要时将它们连接到双手。

多只手。我们还希望能够让每个大脑连接多只手。在实践中,这意味着 Claude 必须对多个执行环境进行推理,并决定将工作分派到哪里——这比在单个 shell 中操作需要更强的认知能力。我们最初将大脑放在单个容器中,因为早期模型还不具备这种能力。随着智能水平的提升,单个容器反而成了限制:一旦该容器发生故障,大脑所触及的每只手的状态都会丢失。

将大脑与手解耦后,每只手都成为一个工具,execute(name, input) → string:输入名称和参数,返回一个字符串。这个接口支持任何自定义工具、任何 MCP 服务器以及我们自己的工具。运行框架并不知道沙箱是容器、手机,还是 Pokémon 模拟器。而且,由于任何一只手都不与任何一个大脑绑定,大脑之间可以相互移交手。

结论

我们面临的是一个由来已久的挑战:如何为“尚未被构想出来的程序”设计系统。操作系统通过将硬件虚拟化为足够通用的抽象,支持尚未出现的程序,从而延续了数十年。对于 Managed Agents,我们的目标是设计一个系统,能够容纳未来围绕 Claude 构建的运行框架、沙箱或其他组件。

Managed Agents 是秉持同样理念的元运行框架,不对 Claude 未来需要的具体运行框架作预设。相反,它通过通用接口支持多种不同的运行框架。例如,Claude Code 是一个出色的运行框架,我们将其广泛用于各种任务。我们也已证明,面向特定任务的智能体运行框架在狭窄领域表现出色。Managed Agents 可以容纳其中任何一种,随着时间推移与 Claude 的智能水平相匹配。

元运行框架的设计意味着,要对 Claude 周边的接口作出明确取舍:我们预计 Claude 将需要操纵状态(会话)和执行计算(沙箱)的能力。我们还预计,Claude 将需要扩展到多个大脑和多只手的能力。我们设计了相应接口,使它们能够长期可靠、安全地运行。但我们不对 Claude 所需的大脑或手的数量及位置作任何假设。

来源:Anthropic Engineering · anthropic.com