DeepSeek总结的 规模化托管代理:将大脑与双手解耦

张开发
2026/4/16 1:32:44 15 分钟阅读

分享文章

DeepSeek总结的 规模化托管代理:将大脑与双手解耦
来源https://www.anthropic.com/engineering/managed-agents规模化托管代理将大脑与双手解耦随着模型能力的提升那些编码了“模型不能做什么”这一假设的“套件”Harnesses会逐渐过时。托管代理Managed Agents——我们用于处理长周期代理工作的托管服务——正是围绕那些即使在套件发生变化时也能保持稳定的接口而构建的。请参阅我们的文档以开始使用 Claude 托管代理。工程博客上一个持续讨论的话题是如何构建有效的代理并为长时间运行的工作设计套件。这些工作的一个共同点是套件编码了关于 Claude 自身无法完成哪些事情的假设。然而这些假设需要经常被质疑因为随着模型的改进它们可能会变得过时。仅举一例在我们之前的工作中我们发现 Claude Sonnet 4.5 在感知到其上下文窗口接近上限时会过早地结束任务——这种行为有时被称为“上下文焦虑”。我们通过在套件中添加上下文重置来解决这个问题。但是当我们在 Claude Opus 4.5 上使用相同的套件时我们发现这种行为消失了。重置变成了无用的负担。我们预计套件将继续发展。因此我们构建了托管代理这是 Claude 平台中的一项托管服务通过一组旨在超越任何特定实现包括我们今天运行的实现的接口代表您运行长周期代理。构建托管代理意味着要解决计算领域的一个老问题如何为“尚未想到的程序”设计系统。几十年前操作系统通过将硬件虚拟化为抽象概念如进程、文件来解决这个问题这些抽象概念具有足够的通用性可以服务于尚未存在的程序。这些抽象概念比硬件更持久。read()命令无论访问的是 1970 年代的磁盘包还是现代 SSD都是无差别的。顶层的抽象保持稳定而底层的实现则可以自由更换。托管代理遵循相同的模式。我们将代理的组件虚拟化会话Session所有发生事件的仅追加日志、套件Harness调用 Claude 并将其工具调用路由到相关基础设施的循环和沙箱SandboxClaude 可以运行代码和编辑文件的执行环境。这使得每个组件的实现都可以被替换而不会影响其他组件。我们对这些接口的形态有明确的看法但对它们背后运行什么则没有。不要养宠物我们最初将所有的代理组件都放入一个单一的容器中这意味着会话、代理套件和沙箱都共享一个环境。这种方法有其好处包括文件编辑是直接的系统调用并且没有服务边界需要设计。但是通过将所有内容耦合到一个容器中我们遇到了一个老的基础设施问题我们养了一只“宠物”。在“宠物 vs. 牲畜”的类比中“宠物”是一个有名字的、需要手工照料的个体你承受不起失去它的代价而“牲畜”则是可互换的。在我们的案例中服务器变成了那只宠物如果一个容器发生故障会话就丢失了。如果一个容器没有响应我们必须费心使其恢复健康。费心照料容器意味着要调试那些无响应的、卡住的会话。我们唯一的观察窗口是 WebSocket 事件流但这无法告诉我们故障发生在哪里这意味着套件中的 bug、事件流中的数据包丢失或容器离线都呈现出相同的现象。为了弄清楚哪里出了问题工程师必须打开容器内的 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和git pull可以从沙箱内部工作而代理本身从未处理过令牌。对于自定义工具我们支持 MCP模型上下文协议并将 OAuth 令牌存储在一个安全的保险库中。Claude 通过专用的代理调用 MCP 工具这个代理接收与会话关联的令牌。然后代理可以从保险库中获取相应的凭证并向外部服务发出调用。套件永远不会意识到任何凭证的存在。会话不是 Claude 的上下文窗口长周期任务往往会超过 Claude 上下文窗口的长度而解决这个问题的标准方法都涉及关于保留哪些内容的不可逆的决定。我们在之前关于上下文工程的工作中已经探讨了这些技术。例如压缩允许 Claude 保存其上下文窗口的摘要而记忆工具允许 Claude 将上下文写入文件从而实现跨会话的学习。这可以与上下文裁剪相结合后者选择性地移除某些令牌例如旧的工具结果或思考块。但是选择性地保留或丢弃上下文的不可逆决定可能导致失败。很难知道未来的轮次需要哪些令牌。如果消息经过压缩步骤转换套件会将压缩后的消息从 Claude 的上下文窗口中移除并且这些消息只有在被存储的情况下才能恢复。先前的工作已经探索了通过将上下文存储为存在于上下文窗口之外的对象来解决这个问题的方法。例如上下文可以是 REPL读取-求值-打印循环中的一个对象LLM 通过编写代码来过滤或切片它以编程方式访问该对象。在托管代理中会话提供了同样的好处充当存在于 Claude 上下文窗口之外的上下文对象。但上下文并非存储在沙箱或 REPL 中而是持久地存储在会话日志中。getEvents()接口允许大脑通过选择事件流的位置切片来查询上下文。该接口可以灵活使用允许大脑从它上次停止阅读的地方继续在特定时刻之前回退几个事件以查看前因后果或者在特定操作之前重新阅读上下文。任何获取到的事件也可以在传递给 Claude 的上下文窗口之前在套件中进行转换。这些转换可以是套件编码的任何内容包括为实现高提示缓存命中率而进行的上下文组织以及上下文工程。我们将可恢复的上下文存储在会话中和任意的上下文管理在套件中的关注点分离开来因为我们无法预测未来的模型需要什么样的特定上下文工程。这些接口将上下文管理推送到套件中并且仅保证会话是持久的并且可以被查询。多大脑多双手多大脑。将大脑与双手解耦解决了我们最早的一批客户投诉。当团队希望 Claude 在他们自己的 VPC 内处理资源时唯一的途径是将他们的网络与我们的网络对等因为容纳套件的容器假设每个资源都位于它旁边。一旦套件不再位于容器中这个假设就消失了。同样的改变也带来了性能上的回报。当我们最初将大脑放在容器中时这意味着许多大脑需要同样多的容器。对于每个大脑在该容器被配置好之前无法进行任何推理每个会话都预先支付了完整的容器设置成本。每个会话即使是那些永远不会接触沙箱的会话也必须克隆仓库、启动进程、从我们的服务器获取待处理事件。这个空闲时间体现在首字耗时TTFT上它衡量一个会话在接受工作到产生第一个响应令牌之间等待了多长时间。TTFT 是用户最直接感受到的延迟。将大脑与双手解耦意味着容器仅在需要时才由大脑通过工具调用execute(name, input) - string来配置。因此一个不需要立即使用容器的会话不会等待容器。一旦编排层从会话日志中拉取了待处理事件推理就可以立即开始。使用这种架构我们的 p50 TTFT 下降了大约 60%p95 TTFT 下降了超过 90%。扩展到许多大脑仅仅意味着启动许多无状态的套件并仅在需要时才将它们连接到双手。多双手。我们还希望能够将每个大脑连接到许多双手。在实践中这意味着 Claude 必须推理多个执行环境并决定将工作发送到哪里——这比在单个 shell 中操作更困难的认知任务。我们最初将大脑放在单个容器中是因为早期的模型没有能力做到这一点。随着智能水平的提升单个容器反而成为了限制当该容器发生故障时大脑正在触及的每双手的状态都会丢失。将大脑与双手解耦使得每双手成为一个工具execute(name, input) - string传入一个名称和输入返回一个字符串。该接口支持任何自定义工具、任何 MCP 服务器以及我们自己的工具。套件不知道沙箱是一个容器、一部手机还是一个宝可梦模拟器。并且由于没有哪双手与某个大脑耦合大脑们可以互相传递双手。结论我们面临的挑战是一个老问题如何为“尚未想到的程序”设计系统。操作系统通过将硬件虚拟化为对尚未存在的程序足够通用的抽象已经持续了几十年。通过托管代理我们旨在设计一个能够适应围绕 Claude 的未来套件、沙箱或其他组件的系统。托管代理是一个秉承相同精神的“元套件”它对 Claude 将来需要的具体套件没有固定的看法。相反它是一个拥有通用接口的系统允许多种不同的套件。例如Claude Code 就是一个优秀的套件我们在各种任务中广泛使用它。我们也已经证明针对特定任务的代理套件在狭窄领域表现出色。托管代理可以容纳任何一种套件与 Claude 随时间推移而增长的智能相匹配。元套件设计意味着对围绕 Claude 的接口有明确的看法我们预计 Claude 将需要操纵状态会话和执行计算沙箱的能力。我们还预计 Claude 将需要扩展到许多大脑和许多双手的能力。我们设计了这些接口以便它们能够在长时间跨度内可靠且安全地运行。但是我们对 Claude 将需要的大脑或双手的数量或位置不做任何假设。致谢本文由 Lance Martin、Gabe Cemaj 和 Michael Cohen 撰写。感谢 Nodir Turakulov 和 Jeremy Fox 就这些主题进行了有益的对话。特别感谢 Agents API 团队和 Jake Eaton 的贡献。

更多文章