AI Agent 长任务中断、状态丢失、context 超限怎么办?拆解 Anthropic Managed Agents 的架构设计
Anthropic 最近发布了一篇工程博客,讲他们怎么重新设计 Agent 的底层架构。表面上是一篇基础设施文章,但背后的设计思路值得仔细看。

给模型打的补丁,会随着模型进化变成废代码
做 Agent 开发的人都遇到过这种情况:模型有某个行为问题,于是在框架层面加一段逻辑来绕过它。问题解决了,但这段逻辑就永远留在代码里了。
Anthropic 自己也遇到了这件事。他们发现 Claude Sonnet 4.5 在 context 快满的时候会提前放弃任务,表现得像是"时间不多了,赶紧收尾"——他们把这个现象叫做 context anxiety(上下文焦虑)。解决方案是在 harness 里加入 context reset 的逻辑,每隔一段就重置一次。
后来他们把同一套 harness 用在 Claude Opus 4.5 上,发现这个行为消失了。模型能力提升之后,context anxiety 不再出现,而那段 reset 逻辑就变成了没有意义的死代码。
这个例子说明一个更普遍的问题:架构里的每一个设计决定,本质上都是一个关于"模型不能做什么"的假设。模型在进化,假设会过期,但代码不会自动失效。
Anthropic 的应对思路是:与其不断打补丁,不如重新设计架构,让接口足够稳定,能撑过任意一代模型的变化。这套架构就是他们现在推出的 Managed Agents。
把所有东西塞进一个容器,是个迟早要还的债
Anthropic 最初的实现很直接:把 Agent 运行需要的一切——调度逻辑、执行环境、会话记录——全部放进一个容器里。好处是简单,文件读写就是系统调用,不需要跨服务通信。
问题在于,这个容器承担了太多职责,变成了一个"动不了的个体"。一旦容器崩溃,整个会话就丢了,没有办法恢复。如果容器卡死,工程师只能进去手动排查,但容器里同时还跑着用户数据,这让调试变成一件既繁琐又有安全风险的事。
更深层的问题是,这个设计把"Claude 的执行环境必须和 harness 在一起"这个假设硬编码进了架构。当企业客户希望把 Claude 接到自己私有云里的资源时,唯一的选择是把自己的网络和 Anthropic 的网络打通,或者自己部署整套 harness。一个隐含假设,变成了扩展性的障碍。
把大脑和手分开
解决方案是把三个部分拆开:
- Brain(大脑):Claude 本身加上调度它的 harness
- Hands(手):具体执行操作的沙盒环境,比如运行代码、操作文件
- Session(会话):完整的事件日志,记录这个 Agent 会话里发生过的一切
三者之间只通过简单的接口通信。Hands 对外暴露的接口就是 execute(name, input) → string,大脑不需要知道手是一个容器、一台手机还是别的什么,只需要传入指令和参数,拿回结果。
这个拆分带来了两个直接好处。
第一个是可靠性。 沙盒容器挂了,harness 只是收到一个工具调用失败的错误,可以决定是否重试,重新起一个新容器继续执行。Session 日志放在外部,harness 自己崩了也无所谓——重启一个新的 harness,读取 session 日志,从上次停的地方继续,没有任何状态丢失。每个组件都可以独立失败、独立重启。
第二个是性能。 原来的设计里,每个 Agent 会话启动时必须先把容器跑起来,才能开始推理。现在容器是按需启动的——如果一个会话暂时不需要执行代码,就不用等容器。推理可以在调度层拿到 session 日志之后立刻开始。这一个改动让首 token 延迟的 p50 降了约 60%,p95 降了 90% 以上。
凭证不能和代码跑在同一个地方
这部分稍微解释得细一点,因为涉及的安全逻辑不是一眼就能看明白的。
在原来耦合的设计里,Claude 生成的代码和各种 API token、访问凭证都在同一个容器里。这意味着如果 Claude 被 prompt injection 攻击——比如被恶意内容诱导执行了一段读取环境变量的代码——攻击者就能拿到容器里的所有 token,然后用这些 token 发起新的、不受控制的请求。
新架构的结构性解法是:让沙盒里运行的代码从物理上就拿不到任何凭证。
以 Git 为例。Claude 需要能够 push 和 pull 代码,但不需要"知道"用什么 token 在做这件事。Anthropic 的做法是:在沙盒初始化阶段,用仓库的 access token 完成 clone,并把 token 配置进本地 git 的 remote 设置里。之后 Claude 在沙盒里执行 git push 或 git pull,git 工具自己处理认证,Claude 生成的代码全程接触不到那个 token 本身。这就是"把 token wire 进去"的意思——token 在初始化环节就被嵌入工具配置,而不是作为一个变量暴露在运行环境里。
对于其他外部服务,Anthropic 用了 MCP proxy 的方式:OAuth token 存在 harness 外部的安全 vault 里,Claude 调用外部工具时请求先到 proxy,proxy 凭 session 标识从 vault 取出对应凭证,再转发到外部服务。Claude 的沙盒环境和 harness 都不持有这些凭证。
结果就是,即便沙盒里的代码被劫持,攻击者也没有任何凭证可以拿走。安全保证不依赖"相信模型不会被骗",而是靠结构隔离实现的。
Session 是事件日志,不是 context window 的副本
Agent 处理长任务时,很快会遇到 context 长度的上限。常见的处理方式是 compaction——让模型把当前 context 总结成一段摘要,用摘要替换原始内容,释放空间。问题在于这是一个不可逆的操作,原始信息一旦压缩就找不回来了,而且很难提前判断哪些细节在后续步骤里还会用到。
Managed Agents 的 session 设计从根本上解决了这个问题。Session 是一个完整保存在外部的事件流,而 context window 只是这个事件流的一个视图。
具体来说,harness 可以调用 getEvents() 从 session 里取任意位置的事件片段,然后决定把哪些内容放进 Claude 的 context window。可以只取最近的 N 条事件,可以重新读取某个关键决策之前的上下文,也可以在某个特定动作之前往前多看几条做参照。
这和传统 compaction 的本质区别在于:对 context window 里内容的操作是可逆的。压缩、裁剪、重组,都是 harness 在"视图"层面做的选择,原始数据始终完整地保存在 session 里。出了问题可以回溯,未来换了新的 context 管理策略也不需要迁移数据。
接口稳定,实现可以随时换
Anthropic 用了一个操作系统的类比来说明这套设计的目标。Unix 的 read() 系统调用,从 1970 年代的磁盘时代用到今天的 NVMe,接口从来没变过,变的只是底层实现。应用程序不需要关心存储介质是什么。
Managed Agents 想做的是同样的事情。Session、harness、sandbox 三个抽象定义好接口,背后跑什么实现是可以随时替换的。Claude Code 是一种 harness,任务特化的 harness 也能接进来,将来还没出现的 harness 同样可以。架构不对任何特定的实现下注,只对接口的形状下注。
对做 Agent 应用的人来说,这个思路有一个很直接的启示:不要把对当前模型能力的 workaround 写死进架构,而是定期问自己,哪些设计决定本质上是对模型局限性的假设,这些假设现在还成立吗。
Anthropic原文:https://www.anthropic.com/engineering/managed-agents
