2026 年 4 月 8 日,Anthropic 发布了 Scaling Managed Agents: Decoupling the brain from the hands。这是目前公开资料中,对生产级 Agent 基础设施描述最详细的一篇。
这篇文章不打算复述原文。我们想做的是拆解它的设计决策——为什么这么做,代价是什么,以及哪些点是真正反直觉的。
起点:单容器的三个死穴
Anthropic 最初把所有东西塞在一个容器里——Session 状态、Agent 编排循环(Harness)、代码执行沙箱(Sandbox)共享同一个环境。
这个方案的问题:
- 容器挂了,状态全丢。Session 跟进程走,没有独立持久化
- 安全隔离不存在。Claude 生成的不可信代码和 credentials 在同一个环境里——prompt injection 只需要说服 Claude 读一下环境变量
- 无法调试。排查问题要进容器 shell,但容器里有用户数据,工程师不该碰
- 部署耦合。客户想让 Claude 连自己的 VPC,必须做网络 peering,因为 Harness 假设所有资源都在同一个容器里
解法:三层虚拟化
Anthropic 的核心类比是操作系统——OS 把硬件虚拟化成 process、file 这些抽象,read() 不关心底下是 70 年代的磁盘还是现代 SSD。接口稳定,实现随便换。
Managed Agents 做了同样的事:把 Agent 虚拟化成三个独立组件。
Session — 持久事件日志
- Append-only event log,是整个系统唯一的 source of truth
- 存在于 Claude 的 context window 之外
- API:
emitEvent(id, event)写入,getEvents()读取,支持 rewind、slice、位置访问
Session 就是个持久化的事件流。所有发生过的事情(用户消息、Claude 输出、Tool 调用结果)都追加进去,不删不改。
Harness — 无状态编排器
- 经典 Agent Loop:调 Claude API → 解析 tool calls → 路由到执行环境 → 结果写回 Session → 循环
- 完全无状态:crash 后通过
wake(sessionId)+getSession(id)从 event log 恢复,从最后一个事件继续 - 负责 context engineering:从 Session 取事件 → 裁剪/转换 → 塞进 Claude 的 context window
Sandbox — 一次性执行环境
- 容器隔离,通过
provision({resources})按需创建 - Lazy init:只有 Claude 发出 tool call 需要执行代码时才启动
- 容器挂了,Harness 把失败当普通 tool error 传给 Claude,Claude 决定是否 retry,新容器用标准配方重建
两个真正反直觉的设计
三层架构本身不稀奇。关键是两个解耦的具体做法。
1. Session ≠ Context Window
很多 Agent 框架把「上下文管理」和「状态存储」混在一起。典型做法是 context 满了就压缩(compaction),压缩后的内容既是存储也是上下文——信息丢了就是真的丢了。
Anthropic 明确拆开了这两件事:
- Session 只负责持久存储,append-only,完整不压缩
- Context engineering 是 Harness 的事——从 Session 取什么、怎么裁剪、怎么塞进 context window,全部是 Harness 的实现细节
原文的表述很精准:
We separated the concerns of recoverable context storage in the session and arbitrary context management in the harness because we can’t predict what specific context engineering will be required in future models.
这意味着 context engineering 策略可以随模型能力演进而变化(他们举的例子:Sonnet 4.5 有 context anxiety 需要加 reset,Opus 4.5 这个行为消失了,reset 变成死重),但 Session 里的原始数据永远在。你随时可以回去用新策略重新裁剪。
2. Tool 执行不在 Agent 身边
传统心智模型里,Agent 就像你开了个终端——推理和执行在同一个环境里。Anthropic 的做法是把「想」和「做」物理隔离:
Brain = Claude + Harness(推理,长活,无状态)
Hands = Sandbox + Tools(执行,按需拉起,隔离)
通信接口:execute(name, input) → string
Brain 和 Hands 之间就这一个接口。Harness 不知道 Sandbox 是容器、VPC、手机还是——用原文的话——“一个宝可梦模拟器”。任何实现 execute(name, input) → string 的东西都是合法的 Hand。
这个设计的直接好处:
- 安全是架构的结果,不是策略的产物。Sandbox 里的代码物理上接触不到任何 credential
- Git token:init 时注入到 local git remote URL,Claude 用 git push/pull 但碰不到 token 本身
- OAuth:token 在外部 vault,Claude 通过 MCP proxy 调用,proxy 拿 session token 去 vault 取真实凭证
- 成本:大量 session 不需要执行环境(纯对话/推理),不起 sandbox 就不花钱
- 故障域:sandbox 挂了只是个 tool error,Brain 还活着
TTFT 优化的真相
原文报告了 TTFT(Time To First Token)p50 降 ~60%,p95 降 >90%。
这个数字看起来很吓人,但原因其实很朴素:推理启动不再等容器了。
旧架构:Session 开始 → 起容器(clone repo + boot)→ 容器就绪 → 开始推理
新架构:Session 开始 → Harness 从 Session 拉事件 → 直接开始推理 → Claude 说”我要跑代码” → 这时候才 provision() sandbox
也就是说 TTFT 优化不是什么黑科技,就是把容器启动从关键路径上移走了。大量 session 的第一个 turn 根本不需要执行代码。
Sandbox 是 cattle,但不是一次性的
这里有个容易误读的地方。原文反复说 “cattle, not pets”,容易理解成”每次 tool call 起一个新容器”。但仔细看实际模型:
Session 开始
→ Harness 启动(无状态,立即可推理)
→ Claude 第一次需要跑代码
→ provision() 拉起 Sandbox
→ 后续 tool calls 复用同一个 Sandbox
→ Sandbox 挂了 → provision() 新的 → 从 repo 恢复
Session 结束或超时
→ Sandbox 销毁
“Cattle” 的意思不是”用完就扔”,而是”挂了不心疼,重建一个就行”。一个 long-running task 里的多次 tool call 共享同一个 sandbox 的文件系统状态,否则 coding 场景(读文件 → 改代码 → 跑测试 → 看结果)根本没法做。
Many Brains, Many Hands
解耦之后拿到了拓扑自由度:
- Many Brains:无状态 Harness 水平扩展,不再一个 session 绑一个容器
- Many Hands:一个 Brain 可以操作多个执行环境——你的 VPC、我的容器、他的数据库
- Brain 互传 Hands:因为 Hand 不耦合到任何特定 Brain,Brain 之间可以传递 Hands
这最后一点暗示了 multi-agent 协作的可能性——agent A 在某个 sandbox 里做了一半工作,可以把这个 sandbox 的 handle 交给 agent B 继续。
同一问题,不同刀法:GCP Agent Engine
Anthropic 不是唯一在解这个问题的。Google Cloud 的 Vertex AI Agent Engine 也在做生产级 Agent 托管,但设计哲学差异很大。
GCP 的思路是 PaaS:我帮你管 Session 和 Memory,你专注写 Agent 逻辑。
VertexAiSessionService— 托管的会话持久化VertexAiMemoryBankService— 托管的长期记忆- Agent 代码跑在 Cloud Run 或 Agent Engine 托管的运行时上
- 开放生态:Agent2Agent (A2A) 协议 + MCP 集成
Anthropic 的思路是 OS:我定义抽象层和接口,具体实现可替换。
关键差异在 执行隔离。GCP Agent Engine 解决了状态持久化(Session 不跟进程走),但 Agent 代码和 Tool 执行仍然在同一个 Cloud Run 服务里——没有 Brain-Hands 分离。execute(name, input) → string 这个把推理和执行物理隔开的接口,在 GCP 那边没有对应物。
换个角度看,这也反映了两家的立场差异:
- Google 卖的是云基础设施,Agent Engine 是让你用更多 GCP 服务的入口。开放性(A2A、MCP)是竞争策略
- Anthropic 卖的是模型能力,Managed Agents 是让 Claude 在更复杂的场景里跑起来的基础设施。封闭但深度优化
两个方案不矛盾,甚至可以互补——用 GCP 的基础设施跑 Anthropic 的 Brain-Hands 拓扑,理论上是可行的。
没说的东西
原文有几个明显的留白:
- 没有讨论 tool call 延迟。每次
execute()都走网络 roundtrip,对高频 tool call 场景(比如 Claude Code 疯狂读文件改代码)的影响是什么?是不是有 warm pool 或 co-location 优化? - 有客户案例但没有展开场景差异。Notion、Rakuten、Asana、Sentry 已经在生产环境跑 Managed Agents(Notion 的场景是 Claude 从 team board 认领任务,在 workspace 里执行)。原文也提到 Claude Code 和 task-specific harnesses 都能跑在这套架构上。但不同场景对 Brain-Hands 拓扑的需求显然不同——高频 tool call 的 coding agent 和低频异步的 task agent 是否用同一套配置?这里没有展开
- Session 的具体存储实现。Append-only event log 用什么存?有多大的 retention?rewind 的粒度是什么?
- Context engineering 的具体策略。说了 Harness 负责 context engineering,但没有展开具体怎么做——全量塞入?滑动窗口?压缩摘要?只给了 context anxiety/reset 一个例子
这些留白是合理的——这是一篇架构理念文章,不是实现文档。但如果你要基于这个思路构建自己的系统,这些空白都需要自己填。
结论
Managed Agents 的核心贡献不是”Agent 要分层”这个结论——这个大家都知道。它的贡献是明确了怎么切:
- 存储(Session)和上下文工程(Harness)必须分离。你的 context engineering 策略会随模型迭代而变,但原始数据不该丢
- 推理(Brain)和执行(Hands)必须物理隔离。不是为了架构优雅,是因为安全边界只有物理隔离才可靠
- 接口要比实现更持久。
execute(name, input) → string这个接口够简单、够通用,可以 outlast 具体实现
引用原文的收尾:
The challenge we faced is an old one: how to design a system for “programs as yet unthought of.”
这话放到 Agent 基础设施上就是:不要为今天的模型能力设计系统,要为你还不知道模型能做什么的那一天设计系统。
原文链接:Scaling Managed Agents: Decoupling the brain from the hands