Managed Agents 设计解读:如何让 Agent 系统不被模型迭代淘汰

12 分钟

本文基于 Anthropic 工程博客 Scaling Managed Agents: Decoupling the brain from the hands(作者 Lance Martin、Gabe Cemaj、Michael Cohen,发布于 2026-04)整理。

Anthropic 工程博客最近更新了一篇 Managed Agents,接续此前的 Harness 设计系列。这一篇讲的是:如何设计一个能适应模型能力持续提升的 Agent 系统?

核心答案来自一个熟悉的领域:操作系统。

背景:Harness 为什么会过时

文章开头抛出了一个值得深思的观察:

Claude Sonnet 4.5 会在感知到上下文快满时过早结束任务(Anthropic 称之为 "context anxiety",上下文焦虑),我们通过在 harness 中添加 context resets 来解决。但换到 Opus 4.5 之后,这个行为消失了,之前的修复变成了无用代码。

这就是 Harness 设计的核心困境:Harness 硬编码了"模型做不到什么"的假设,而这些假设会随着模型能力提升而失效。

作者进一步指出了这条规律的普遍性:

A common thread across this work is that harnesses encode assumptions about what Claude can't do on its own. However, those assumptions need to be frequently questioned because they can go stale as models improve.

每添加一个 Harness 组件,都是在为模型当前的某个弱点打补丁。如果模型三个月后补上了这个弱点,补丁就会变成技术债。

借鉴 OS 思想:虚拟化 Agent 组件

Anthropic 的解决思路来自一个古老的问题:如何为一个"尚未想到的程序"设计系统?

几十年前,操作系统给过一套答案:把硬件虚拟化为足够通用的抽象,processfile 就是典型例子。read() 系统调用则是这类抽象的极致代表,它不关心底层是 1970 年的磁带机还是现代 SSD,接口始终如一,而程序也不需要知道差别。

Managed Agents 走的是同一条路,把 Agent 的核心组件虚拟化为稳定接口:

组件职责类比
Sessionappend-only event log磁盘
Harness调用 Claude 并路由工具调用的循环进程
SandboxClaude 执行代码和编辑文件的环境外设

关键是接口稳定、实现可替换。Harness 不再假设沙箱里有什么,Session 也不再假设 Claude 能存多少上下文,这些"假设"全都被推到了接口背后。

具体的接口如下:

接口调用关系与作用
provision({resources})Harness → Sandbox
按标准配方初始化一个新容器(clone repo、启动进程等);容器失败后 Claude 决定重试时由 Harness 触发
execute(name, input) → stringHarness → Sandbox
把沙箱当成一个工具来调用,名字和参数进去、字符串出来;容器崩溃会以 tool-call error 的形式抛回 Claude 处理
emitEvent(id, event)Harness → Session
agent loop 每一步都通过它把事件写入 session 日志,为执行过程留下持久记录
getEvents()Harness → Session
按位置切片查询事件流,可以从当前位置继续、倒带几步看前因,或在某个具体操作前重读上下文
getSession(id)Harness → Session
取回整条事件日志,用于 wake 之后从上次中断处恢复
wake(sessionId)Orchestration 层 → Harness
harness 崩溃后启动一个新的无状态 harness 实例并绑定到指定 session

几个接口组合起来才看得出设计意图。provisionexecute 说明沙箱是被调用方,Harness 是调用方,这打破了"Claude 的工具长在容器里"的默认假设,沙箱从而变成可以按需插拔的外设。emitEventgetSession 把"状态"从 Harness 剥出去,交给外部 Session 管理。wake 则让 Harness 随时可以被重建:进程死了,外面的 Orchestration 层靠 session id 把它召回来,从日志里读回状态继续跑。

Managed Agents 架构图

从"宠物"到"牛":运维心智的转变

文章里用了一个基础设施圈熟悉的类比:pets vs cattle。pet 是需要精心照料、不能失去的个体,cattle 是可互换的,死了就换掉。

Managed Agents 团队最初的设计是"单容器模式":Session、Harness、Sandbox 全塞在一个容器里。好处是文件编辑就是直接的 syscall,没有跨服务边界的复杂性。但问题也随之而来:

  1. 容器挂了,Session 就丢了,典型的 pet,没了就是没了
  2. 容器卡住只能进去开 shell 调试,但容器里同时住着用户数据,调试意味着工程师要接触敏感信息
  3. Harness 和工具被绑在同一个容器里:当客户希望 Claude 访问自己 VPC 里的资源时,Anthropic 要么和客户做网络 peering,要么把整套 harness 搬到客户环境,没有第三条路
  4. 每次都要完整初始化:clone repo、boot process、fetch pending events,这些死时间直接推高了首 token 响应时延(TTFT)

把三个组件都变成 cattle 之后,画面就清爽了:

  • Sandbox 变成工具execute(name, input) → string。容器死了?Harness 捕获工具调用错误,Claude 决定重试,新容器通过 provision({resources}) 初始化
  • Harness 变成无状态进程:状态全在外部 Session 里。Harness 死了?wake(sessionId) + getSession(id) 就能恢复,继续从上次位置执行
  • Session 在外部持久化:容器轮换不再意味着对话作废

完美架构很少是一开始就设计出来的,往往要靠运维压力一步步倒逼,团队才能摸到"pet 不可守"这条道理。

安全边界:别让模型碰到密钥

单容器模式还有一个隐患是安全边界模糊

当 Claude 生成的代码和凭证在同一个环境里运行,prompt injection 只需要说服 Claude "看看自己的环境变量"就能拿到密钥。而模型正变得越来越擅长遵循指令,也就越来越难被 prompt injection 骗到。把安全建立在"模型不会被骗"之上,本身就是一个会过期的假设。

结构性修复是让凭证永远到不了沙箱

  1. Git 场景:沙箱初始化时把 repo access token 写进 git remote,后续的 push/pull 都不经过 Agent
  2. MCP 工具:OAuth token 存在外部 vault,Claude 通过专用 proxy 访问;proxy 持有 session 关联的令牌去 vault 取凭证,Harness 从头到尾不知道有凭证存在

两种方案都指向同一条原则:不依赖"模型做不到某事"的假设。模型能力会持续变强,安全必须结构性地实现。

Session ≠ Context Window

这是文章里最精妙的设计洞察之一。

长期任务迟早会超出上下文窗口,而常见解法都涉及不可逆的内容丢弃:把旧内容压缩为摘要(compaction)、把重要信息写入外部文件(memory tool)、裁掉"不重要"的事件(context trimming)。

问题在于:很难预测未来需要哪些上下文。 如果某个信息在第十轮才发挥作用,但第五轮就被压缩丢弃了,它就再也找不回来了,而这在长任务里几乎是必然的。

Managed Agents 的解法是把 Session 设计为存在于 Claude 上下文窗口之外的持久对象

Session 日志 (外部持久化)
        ↕ getEvents() / emitEvent()
Harness (上下文管理、压缩策略)

Claude 上下文窗口

Session 通过 getEvents() 允许大脑查询事件流的任意位置切片:从当前位置继续、从某事件前倒带看前因、在特定操作前重读上下文都可以。

Session 负责持久化,Harness 负责上下文工程,两个关注点被拆开了。未来模型需要什么样的上下文策略无法预测,但可以保证 Session 是持久的、可查询的。

这套架构还有一个实际好处:事件历史在服务端持久化,用户可以在执行中途发送新事件来引导或中断 agent,这也是 Managed Agents 支持异步工作模式的底层基础。

多脑多手:解耦之后的扩展空间

解耦之后,横向扩展顺理成章。

Many Brains

Many Brains 有两重好处。

第一重是解锁客户 VPC 场景。 这是 Anthropic 收到的最早一批客户投诉之一:Harness 还和沙箱绑在一起时,客户想让 Claude 访问自己 VPC 里的资源,只能做网络 peering。Harness 搬出容器后,这个假设随之消失,客户可以把自己的沙箱接到 Anthropic 的 brain 上,不再需要打通两边的网络。

第二重是 TTFT(Time To First Token) 大幅下降。 之前每个 brain 一个容器、每个容器都要完整初始化,哪怕 session 根本不需要沙箱,也要等容器启动才能开始推理。之后沙箱按需连接,不需要沙箱的 session 可以直接从 Session 日志拉取待处理事件开始推理,Harness 变成无状态的按需启动。文中给出的数据是 p50 TTFT 下降约 60%,p95 下降超过 90%。

p95 的改善幅度远大于 p50 是一个值得注意的信号。p50 代表一般情况,p95 代表最坏情况;在单容器模式下,最坏情况往往出现在需要初始化大型仓库或复杂环境时,而按需连接沙箱之后,这类极端场景被彻底绕过,改善自然是决定性的。

Many Hands

之前:单一容器里的 Claude 操作所有工具,容器死了所有工具的状态一起丢。文章特别强调,早期选择单容器并非粗心,而是因为当时的模型还不具备"在多个执行环境之间推理、决定把任务派到哪一只手"的能力,单容器是务实之选。等模型能力提升后,单容器反而成了上限。

之后:每只手都变成 execute(name, input) → string 的工具,Harness 不知道也不关心沙箱是容器、手机还是宝可梦模拟器。原文对此只有一句关键论断:

No hand is coupled to any brain, brains can pass hands to one another.

大脑之间可以互相传递手,这意味着"状态"必须有个对所有大脑都可见的地方,也就是 Session 日志。一只手刚才干了什么,只能通过 Session 转达给下一个大脑;日志里存的是事件序列,不是状态本身,所以接手的大脑要先重读日志、在自己这边重建状态。"手"变成工具正好为这类协作腾出了空间,而不是引入新的复杂性。

Meta-harness:设计一个设计系统

文章最后给出了一个有野心的愿景:

Managed Agents is a meta-harness, a system with general interfaces that allow many different harnesses. For example, Claude Code is an excellent harness that we use widely. We've also shown that task-specific agent harnesses excel in narrow domains. Managed Agents can accommodate any of these.

翻译过来:Anthropic 做的是"harness 的 harness",不预测未来需要什么样的具体 harness,只保证接口足够通用。

这和操作系统哲学一脉相承。1970 年代设计的 read() / write() 接口至今仍在服役,设计者当年没有预见到云计算和 AI,但接口足够抽象、适配性足够强,这套抽象就一直活到了今天。

启示

这篇有几个点可以仔细咂摸一下:

1. 每添加一个 Harness 组件,都在增加对当前模型能力的依赖。 这些依赖是必要的(没有它们任务跑不通),但也是短命的(模型更新后就会被淘汰)。值得定期做一次消融实验:移除某个组件,看看效果是否真的下降。

2. 安全不能建立在"模型做不到某事"之上。 昨天有效的指令过滤、范围限制,明天可能被更强的模型绕过。结构性防御(凭证隔离、最小权限)比行为限制可靠得多。

3. 把状态推到组件边界之外,是解耦的前提。 Session 活在 Claude 上下文窗口之外,才不会因模型重启或切换而丢失;这个思路可以迁移到很多场景。

目录