返回 文章 build CMS 文章

Anthropic 托管代理架构:将大脑与手解耦,实现长周期智能体扩展

Anthropic 通过虚拟化代理组件(会话、harness、沙箱),构建可扩展、安全且高性能的托管代理系统。

Anthropic托管代理架构设计解耦
成长分 / 100 83 综合收获、行动、留存与影响

Anthropic 托管代理架构:将大脑与手解耦,实现长周期智能体扩展
为什么值得读了解 Anthropic 如何设计托管代理以支持长周期任务,并解决上下文焦虑等模型行为问题。

学习如何通过解耦架构提升系统扩展性、安全性和性能,如 TTFT 降低 60% 以上。

关键洞察
  1. 托管代理将代理组件虚拟化为会话、harness 和沙箱三个接口,使各部分可独立替换和失败。
  2. 解耦后,harness 不再位于容器内,容器成为可替换的“牲畜”,故障可恢复,且支持多大脑和多手。
  3. 安全边界通过将凭证存储在沙箱外部的保险库中,确保 Claude 生成的代码无法触及令牌。
转成行动

深入阅读

正文与原文对照

原文保真覆盖:全文原文字符:12749

获取开发者通讯

产品更新、操作指南、社区聚焦等更多内容。每月发送至您的收件箱。

请参阅我们的文档,开始使用 Claude 托管代理。

仅举一例,在先前的工作中我们发现,Claude Sonnet 4.5 会在感知到上下文限制临近时过早结束任务——这种行为有时被称为“上下文焦虑”。我们通过在 harness 中添加上下文重置来解决这个问题。但当我们对 Claude Opus 4.5 使用相同的 harness 时,发现该行为已不复存在。重置成了累赘。

我们预计 harness 会持续演进。因此我们构建了托管代理:Claude 平台中的一项托管服务,通过一小组旨在比任何特定实现(包括我们今天运行的实现)更持久的接口,代表您运行长周期代理。

构建托管代理意味着解决计算领域的一个老问题:如何为“尚未想到的程序”设计系统。几十年前,操作系统通过将硬件虚拟化为抽象——进程、文件——来解决这个问题,这些抽象足够通用,能容纳尚不存在的程序。抽象比硬件更持久。read()

命令无论访问的是 1970 年代的磁盘组还是现代 SSD,都一视同仁。上层的抽象保持稳定,而下层的实现可以自由变化。

托管代理遵循同样的模式。我们将代理的组件虚拟化:会话(所有已发生事件的仅追加日志)、harness(调用 Claude 并将 Claude 的工具调用路由到相关基础设施的循环)和沙箱(Claude 可以运行代码和编辑文件的执行环境)。这使得每个组件的实现都可以在不干扰其他组件的情况下进行替换。我们对这些接口的形态有明确主张,但对它们背后运行什么则不然。

我们最初将所有代理组件放入单个容器,这意味着会话、代理 harness 和沙箱共享同一环境。这种方法有好处,包括文件编辑是直接的系统调用,且无需设计服务边界。

但将所有内容耦合到一个容器中,我们遇到了一个老的基础设施问题:我们收养了一只宠物。在宠物与牲畜的类比中,宠物是有名字、需亲手照料、不能失去的个体,而牲畜是可互换的。在我们的案例中,服务器成了那只宠物;如果容器故障,会话就会丢失。如果容器无响应,我们必须将其护理恢复健康。

护理容器意味着调试无响应的卡住会话。我们唯一的窗口是 WebSocket 事件流,但这无法告诉我们故障在哪里发生,这意味着 harness 中的错误、事件流中的数据包丢失或容器离线都表现相同。要弄清楚出了什么问题,工程师必须在容器内打开 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 上下文窗口的长度,而解决这一问题的标准方法都涉及关于保留哪些内容的不可逆决策。我们在关于上下文工程的先前工作中探讨过这些技术。例如,压缩(compaction)让 Claude 保存其上下文窗口的摘要,记忆工具则让 Claude 将上下文写入文件,从而实现跨会话的学习。这可以与上下文裁剪(context trimming)配合使用,后者会选择性地移除某些 token,例如旧的工具结果或思考块。

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

在 Managed Agents 中,会话(session)提供了同样的好处,充当一个存在于 Claude 上下文窗口之外的上下文对象。但上下文并非存储在沙箱或 REPL 中,而是持久地存储在会话日志中。接口 getEvents(),

允许大脑(brain)通过选择事件流的位置切片来查询上下文。该接口可以灵活使用,让大脑从上次停止读取的位置继续读取、回退到特定时刻之前的几个事件以查看前因,或在特定操作之前重新读取上下文。

任何获取到的事件也可以在 harness 中先进行转换,然后再传入 Claude 的上下文窗口。这些转换可以是 harness 所编码的任何内容,包括为实现高提示缓存命中率而进行的上下文组织,以及上下文工程。我们将可恢复的上下文存储(在会话中)与任意的上下文管理(在 harness 中)这两个关注点分离,因为我们无法预测未来的模型会需要什么样的具体上下文工程。这些接口将上下文管理推给 harness,只保证会话是持久的且可供查询。

多个大脑。将大脑与手解耦解决了我们最早的客户投诉之一。当团队希望 Claude 针对他们自己 VPC 中的资源工作时,唯一的途径是将他们的网络与我们的网络对等互联,因为承载 harness 的容器假定每个资源都紧邻其旁。一旦 harness 不再位于容器中,这一假定就不复存在了。同样的改变还带来了性能上的回报。当我们最初把大脑放进容器时,这意味着多个大脑需要同样多的容器。对于每个大脑,在该容器被配置完成之前都无法进行任何推理;每个会话都要预先支付完整的容器设置成本。每个会话,即使是永远不会接触沙箱的会话,都必须克隆仓库、启动进程、从我们的服务器获取待处理事件。

这段停滞时间体现在首 token 时间(time-to-first-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 将需要的大脑或手的数量或位置做任何假设。

由 Lance Martin、Gabe Cemaj 和 Michael Cohen 撰写。感谢 Nodir Turakulov 和 Jeremy Fox 就这些主题进行的有益对话。特别感谢 Agents API 团队和 Jake Eaton 的贡献。

产品更新、操作指南、社区聚焦等。每月发送到您的收件箱。