太长摘要版:
Anthropic 把 Agent 的"大脑"(harness)、"手"(sandbox)、"会话"(session)从一个容器里拆开来分别管理。
这件事的起因是两个痛点:一是每次模型升级,针对旧模型打的补丁就可能会失效,Agent框架要推倒重来;二是客户要接入自己的私有云,但旧架构因“大脑和手”耦合部署的假设被硬编码了,根本做不到。
拆开之后,容器挂了换一个、大脑挂了接着跑、凭据从物理上就不会出现在代码执行环境里。性能也跟着提升:任务启动延迟中位数降了 60%,最差情况降了 90%。
其中的设计是Anthropic 只锁定了三个组件的接口,对接口背后跑什么实现不做任何假设。就像操作系统的 read() 命令,七十年代读磁盘、今天读 SSD,上层程序一行代码不用改。
01
—
先说一个工程师的尴尬处境
去年Anthropic的工程团队发现了一个有意思的问题。他们给Claude Sonnet 4.5 配了一套"agent框架"(现在流行叫“harness”,可以理解为了让AI自动干活的一套脚手架),其中有个设计:当Claude的上下文窗口快撑满的时候,系统会自动帮它"清空重来"一次,避免它因为记忆太满而慌乱收工。
这个设计是有效的。Sonnet在快撑满的时候确实会有上下文焦虑,会提前结束任务,加了这个机制之后好多了。
后来他们把同一套框架套在Claude Opus 4.5 上,发现……Opus 4.5 基本没有这个毛病。那个"清空重来"的机制成了多余的负担——每次都在做一件根本不需要做的事。
图:同一个harness设计在不同模型中效果说明
这事听起来是个好事,模型进化了嘛。但工程师的感受完全不同:为Sonnet 4.5专门打的补丁,就这么白费了。而且下一代模型出来,又得重新审视一遍框架里哪些假设已经过时了。
这就是Anthropic做 Claude Managed Agents 之前面临的真实困境,也是他们把整个架构推倒重来的直接原因。
02
—
别让容器变成要精心照料的“宠物”
在Managed Agents之前,Anthropic内部的agent是怎么跑的?简单说:把所有东西塞进一个容器里,AI的"大脑"(调用模型、决策逻辑)、AI的"手"(执行代码、操作文件)、AI做过什么的"会话"(会话事件日志),全在一起。
这个方案的好处是简单,文件操作是直接的系统调用,没有什么服务之间互相等待的问题。
问题是,这台容器活下去就成了整个系统的命根子。容器挂了,任务就没了。或者容器卡住了,工程师想进去排查,却发现容器里还存着用户数据——不能随便进,进了就是安全问题。
Anthropic 把这个由来已久的基础设施问题比喻叫"宠物问题"——你养了一只猫,它生病了你得守着它喂药;而不是养了一群牛,一头牛病了你直接换一头。
图:旧架构中容器组成与管理说明
当你的容器变成了宠物,整个系统的稳定性就得靠精心照料来维持,这在规模化的时候是不可持续的。
但真正让他们决心动手的,不只是因为稳定性问题,还因为一个客户提了个看似简单的需求。
03
—
一个需求捅穿了整个架构
有客户需求希望把Claude接入自己公司的私有云网络(VPC)使用其中的资源。
问题来了:因为旧架构中agent框架(harness)和执行容器(sandbox)在一起,"你的资源得跑在我容器旁边"这个部署方式的假设被硬编码了。在旧架构上要实现需求,客户要么把自己的网络跟Anthropic的网络打通(成本高、安全风险大),要么自己把Anthropic的框架部署到自己的环境里(又变成客户的运维负担)。
图:旧架构中两个方法都无法合理满足客户需求
一个原本只是"部署方式"的内部假设,变成了锁死扩展性的障碍。所以他们做了一个决定:把harness和sandbox分离开。
04
—
把Agent各组件拆开来跑
新的架构里,agent被拆成了几个分开的组件。
图:Agent拆分
“大脑"(harness,调用Claude决策的框架)不再住在容器里。它通过一个极其简单的接口调用"手":execute(name, input) → string 。大脑不关心手是什么,是容器、是手机、是某个模拟器,都一样。
“手”(sandbox容器)变成了牲畜,不是宠物了。容器挂了?大脑收到一个工具调用错误,把情况告诉Claude,Claude决定要不要重试,不重试则重开一个容器就好。没有什么需要精心照料的对象了。
“会话”(session log)搬到了两者之外,单独持久化存储。大脑挂了也不要紧,重启一个新的大脑,把session ID丢给它,它找回事件日志接着干。
图:新Harness通过会话Id获取任务执行记录后继续执行刚才中断的任务
这个拆解,完美解决了前面提到的客户需求。 既然大脑不再和容器绑定,当客户要求"让Claude在我的私有云里干活"时,Anthropic只需要把作为"手"的沙箱容器部署在客户的VPC里,或者直接通过接口调用客户自己的工具。作为"大脑"的harness依然留在Anthropic的云端,通过标准的工具调用接口远程指挥这双"手"。客户不需要打通对等网络,也不需要自己运维复杂的agent框架,安全和扩展性同时得到了满足。
图:新架构满足客户接入自己VPC资源的需求
不仅如此,光是这一个架构调整,还让一个关键性能指标大幅改善:从接受任务到开始输出第一个字的等待时间(TTFT),中位数降了约60%,最差情况(p95)降了90%以上。换句话说,原本可能要等十几秒才能开始出活,现在可能只需要一两秒——这是用户感知最直接的那种快。
原因很简单:以前每个任务都得先把容器启好才能开始,哪怕这个任务根本用不到容器。现在容器按需开,大脑一启动就能直接出活。
但这只是性能层面的收益。真正有意思的,是"会话"这个东西本身被重新定义了,以及解耦之后才能解决的那个更深的问题。
05
—
凭据不能和代码住在一起
在耦合的旧设计里,Claude生成的代码和系统凭据(各种token、密钥)住在同一个容器里。这意味着什么?一旦发生提示词注入攻击(prompt injection),攻击者只需要让Claude读一下自己的环境变量,就能拿走所有凭据。拿到凭据之后,攻击者可以用这些token开启新的、不受限制的agent会话,让它去干任何事。
有人会说:那就收窄权限,限制Claude能做什么。但这个思路有个根本缺陷——它假设了Claude的能力是有上限的。而Claude正在变得越来越聪明,你今天认为"Claude用有限token做不到"的事,明天它可能就做到了。
Anthropic的解法是结构性的:让凭据从物理上就不可能出现在代码执行的沙箱里。
具体怎么做的?两种模式。一种是"初始化时注入":比如Git仓库的访问token,只在容器初始化时用来克隆仓库、写进本地git配置,之后容器内的代码执行push和pull,但永远接触不到token本身。
另一种是"vault代理":自定义工具的OAuth token存在容器外的安全保险库里,Claude调用工具时走一个专用代理,代理去保险库取凭据、完成调用,整个过程Claude和harness都不知道凭据长什么样。
图:凭据与沙箱隔离的两种模式
这不是在限制Claude能做什么,而是从架构上保证了某些东西Claude根本就看不见。
06
—
会话日志不是聊天记录
还有一个容易被忽略的细节,值得单独讲。AI的记忆有上限。任务跑得够长,早晚会撑满。传统处理方式无非是压缩、裁剪、让AI自己写个总结然后清掉原文——都是不可逆的操作,删了就找不回来了。而且没人知道后续的步骤到底需要哪些上下文,删错了就出错。
Managed Agents的session log不一样。它是一条持久化的事件流,存在大脑和容器之外的独立地方。大脑可以随时调用getEvents()来"查档案"——想从哪里开始读就从哪里开始读,想重看某个关键步骤之前发生了什么,直接定位过去。
这相当于把AI的"记忆"从脑子里挪到了档案室。脑子里装的是当前工作的内容,档案室保存的是完整历史,两者分开管理。
图:会话处理方式对比
更关键的是:怎么把档案室里的内容整理后送进AI脑子,这个逻辑完全交给harness来决定。Anthropic不对这部分做任何假设,因为他们也不知道未来的模型需要什么样的上下文整理方式。
这就引出了整套设计里最难被看见的那层东西。
07
—
为一个还不存在的程序写代码
操作系统为什么能活几十年?因为它虚拟化的是接口,不是具体的实现。read()这个命令,在七十年代读的是磁盘包,今天读的是SSD,但上层的程序不需要改一行代码。抽象活得比硬件更长。
Managed Agents做的是同一件事,只不过虚拟化的对象变成了agent的组件:会话(session)、执行框架(harness)、沙箱(sandbox)。
Anthropic对这三个接口的抽象有明确的立场——大脑需要能操作状态,需要能调用计算资源,需要能扩展到多个大脑和多只手——但对接口背后跑的具体实现,没有任何固执。
所以Claude Code可以是一种harness,专门针对某类任务的定制框架也可以是一种harness,未来出现的某种今天完全没法想象的执行方式,只要接口对得上,也能插进来。
图:新架构设计与OS设计中read()命令类比
回头看最开始那个Sonnet的"焦虑补丁":在这套架构下,补丁过时了很简单,换harness就行,不影响session,不影响sandbox,更不影响下一个接进来的模型。
这不是在解决今天的问题,而是在给 Agent 还不知道长什么样的未来留门。
—
结语
回头想想,这套架构解决的其实是一个挺朴素的问题:怎么让今天写的东西,明天还能用。
大多数工程问题的解法都是加逻辑、打补丁、往框架里塞假设。Anthropic这次的思路反过来——把假设从框架里拆出去,只留接口。结果是每次模型升级,不再是一次推倒重来,而是换个harness插进来接着跑。
这个思路对正在构建Agent的我们同样适用:今天你为模型局限性写的每一行补丁代码,都是有可能过时的。与其把对当前模型能力的假设硬编码进系统,不如想清楚哪些是接口、哪些是实现——把假设关进实现里,让接口保持干净。
参考资料
[1] Anthropic Engineering:Managed Agents
https://www.anthropic.com/engineering/managed-agents
[2] Claude Blog:Introducing Claude managed agents
https://claude.com/blog/claude-managed-agents
[3] Claude Platform Docs:Managed Agents Overview
https://platform.claude.com/docs/en/managed-agents/overview