Harness Handbook:改 Agent 的脚手架,先得找对地方
改 Agent 的脚手架,先得找对地方:腾讯混元 Harness Handbook 解读
论文原文:Harness Handbook: Making Evolving Agent Harnesses Readable, Navigable, and Editable
arXiv:https://arxiv.org/abs/2607.13285
发布日期:2026-07-14
作者:Ruhan Wang, Yucheng Shi, Zongxia Li et al.(腾讯混元)
你有没有让 Claude Code 或者 Codex 帮你改过一个大项目?
如果有,你大概见过这样的场景:你说"把重试逻辑加上退避策略",然后 agent 开始疯狂地 grep、读文件、再 grep,读了十几个文件之后,改了三处代码。你一看,其中两处改对了,但还有一处散落在另一个模块里的重试调用,它压根没找到。
这篇腾讯混元的论文研究的就是这个问题,只不过场景更极端:要改的代码,是 agent 自己的"脚手架"。
Harness(脚手架/挽具):包裹在大模型外面的那层工程系统,负责构建提示词、管理状态、调用工具、控制执行流程。你用的 Claude Code、Codex,本质上都是"模型 + harness"的组合体。
模型能力再强,落到实际系统里,行为是由 harness 决定的。模型升级了、API 变了、需求改了,harness 就得跟着改。而现在越来越多的团队,希望让 coding agent 自己来改 harness,甚至让 agent 改进自己运行所依赖的那套系统。前不久 Lilian Weng 那篇关于 harness engineering 的长文讨论的也是同一件事:递归自改进的第一步,往往不是改权重,而是改脚手架。
问题来了。
一个修改请求描述的是"行为要怎么变",但它不会告诉你"这个行为写在哪儿"。
真正的难题不是改代码,是找代码
论文给这个前置步骤起了个名字:behavior localization。
Behavior Localization(行为定位):给定一个用自然语言描述的修改请求,找出实现这个行为的所有代码位置。注意是"所有",漏掉一处,改出来的就是个半成品。
为什么这件事难?看一组论文里的真实数据。他们评估的两个开源 harness 里,Codex 是 Rust 写的大型单体仓库,有 2267 个源文件、34363 个内部函数节点、将近 16 万条调用边。一个行为,比如"上下文压缩",它的实现可能分散在提示词构建、状态管理、工具调用好几个执行阶段里,彼此在文件系统上离得很远。
人类工程师面对这种仓库,靠的是长年累月建立起来的心智模型。coding agent 没有这个奢侈条件,它有一个硬约束:
上下文窗口限制:agent 一次能"看见"的代码量是有限的,没办法把整个仓库装进脑子里,只能一轮一轮地探索。探索路径一偏,冷门的执行路径就漏掉了。
你可能会说,这不是有仓库地图、代码搜索、代码摘要这些工具吗?论文的回答是:这些工具都在帮你找"代码",但没有一个在帮你找"行为"。
repository map 按文件和模块组织信息,代码搜索按关键词命中片段。它们能帮你找到零散的相关代码,但拼不出"这些代码合在一起是怎么产生那个行为的",更没法告诉你"你已经找全了"。这中间缺的那一环,就是这篇论文要补的。
再往深一层想,为什么关键词搜索会系统性地失灵?因为修改请求里的词汇和代码里的词汇经常压根对不上。请求说"给会话增加超时保护",代码里可能叫 deadline、叫 abort_controller、甚至藏在一个通用的调度循环里,一个 timeout 都搜不到。论文后面专门设计了一类 Search-Hostile 请求来测这种场景,这不是刁难,这就是生产环境里的日常。
打个比方。你去一家大医院看头疼,医院大厅挂着一张详细的楼层平面图:三楼东侧是检验科,五楼西侧是影像科。这张图对你有用吗?有一点,但不多。因为你的问题是"我头疼",不是"我要去三楼东侧"。你真正需要的是导诊台:头疼可能是神经内科、也可能是耳鼻喉科、严重的要去急诊,导诊台把"症状"翻译成"要去的科室清单"。如果医院只给平面图不设导诊台,病人就得挨个科室问过去,问漏一个科室,病因就可能被漏诊。文件目录就是那张平面图,而 agent 拿着修改请求站在大厅里,需要的是导诊台。
把仓库按"行为"重新编目
Harness Handbook 做的事情,本质上就是给仓库配一个导诊台:不按文件组织知识,按"这个系统在运行时做了什么"来组织,再把每个行为链接回实现它的源代码。

看这张图,手册是一个三层的文档树,外加一个横向的状态索引。
L1 是系统级概览:整个 harness 的架构、执行模型、主要阶段、全局数据流。L2 是组件级概览:选定某个执行阶段后,它的职责、输入输出、依赖和局部状态。L3 是单元级深潜:把这个阶段直接链接到有源码坐标的实现条目上。
除了这棵树,还有一个独立的视图 Z,专门记录跨越阶段边界的状态关系。
State Register(状态寄存器):harness 里被多个执行阶段共享读写的状态。比如一个"当前会话历史",可能在提示词构建阶段被读、在响应处理阶段被写。这种跨阶段耦合正是行为分散的根源,所以手册专门给它建了索引。
这个三层结构背后有两条铁律。
第一条叫渐进披露:读者从 L1 往 L3 走,只有任务需要更多细节时才下钻。这就像你规划一次欧洲旅行,先看国家概览决定去西班牙,再看城市攻略选定塞维利亚,最后才查具体街区的餐厅地址。如果反过来,第一步就把全欧洲每家餐厅的地址倒给你,你不会获得更多信息,只会淹死在信息里。对 agent 来说这不是体验问题,是成本问题:上下文窗口就那么大,每个无关细节都在挤占真正有用的信息的位置。
第二条叫行为与实现对齐:每个活跃的 L3 条目必须能解析到当前仓库的真实位置。解析不了的条目会被冻结,从定位流程里排除,直到刷新为止。
手册永远不是权威,仓库才是。手册只负责告诉你去哪儿看,看到什么以代码为准。
这一条看似保守,其实是整个设计里最防御性的一步。带过期地址的地图比没有地图更危险。
手册是怎么自动造出来的
手动维护这样一本手册显然不现实,所以论文搭了一条自动构建流水线。

流水线分三个阶段,图里从左到右:静态分析提取源码事实,行为组织把源码单元映射到执行阶段,层级合成产出 L1 到 L3 的手册文档。
第一阶段是纯静态分析,不调用任何大模型。语言适配器解析仓库,提取函数、外部边界、源码位置、签名和调用边,构建程序图。这里有个细节我很喜欢:解析不了的调用不会被猜一个目标塞进去,而是老老实实写进审计日志。
程序图(Program Graph):以函数为节点、调用关系为边的图结构。论文只保留能确定解析到内部函数或已命名外部边界的边,宁缺毋滥。
第二阶段才轮到 LLM 出场,负责把源码单元组织进执行阶段骨架。这里有一个重要的设计分叉,叫 leaf mode。
Leaf Mode(叶子模式):L3 条目的粒度选择,二选一且终身不变。function-as-leaf 模式下每个 L3 条目对应一个函数(或函数内的连续区域);file-as-leaf 模式下每个条目对应一个文件。
为什么要分两种模式?还是看数据。Terminus-2 是个紧凑的 Python 终端 agent,只有 6 个源文件、103 个函数节点,而且有一份可信的阶段骨架做种子,所以用函数级粒度,最终构建出 20 个阶段、106 个 L3 条目、10 个状态寄存器。Codex 是 2267 个文件的 Rust 巨兽,函数级组织会直接把预算炸穿,所以用文件级粒度,从零推断出 140 个阶段、2267 个 L3 条目、62 个状态寄存器。
这就像给两个规模完全不同的图书馆编目录。社区图书馆几千本书,可以精确到每一本书编一张卡片;国家图书馆几千万册,只能先按书架编目,具体哪本书在架子上什么位置,到了架子前再找。如果不看规模硬上单一粒度,要么小馆的目录粗到没用,要么大馆的编目成本高到永远编不完。
第三阶段做层级合成和打包:把阶段骨架变成文档树和状态索引,每个 L3 条目挂上静态分析确认过的源码定位器,再对当前仓库做一遍验证。
BGPD:agent 拿着手册怎么导航
手册建好了,agent 怎么用?论文设计了一套叫 BGPD 的导航流程。
BGPD(Behavior-Guided Progressive Disclosure,行为引导的渐进披露):从粗到细的定位工作流。先用 L1、L2 圈定相关执行阶段,再沿状态索引把共享状态耦合的阶段拉进来,然后在这些阶段里选出 L3 条目、取出源码定位器,最后沿调用图扩展候选集。
注意第二步。光看文档层级,两个阶段可能八竿子打不着,但它们读写同一个状态寄存器,改了一个就必须检查另一个。状态索引就是干这个的:把结构上相距很远、行为上互相依赖的阶段串起来。这正是关键词搜索最容易漏的那类关联。
导航的最后一步是回到真实仓库:解析所有候选定位器,只保留和请求确实相关的位置,产出一组经过验证的、带源码摘录的证据。规划器再基于这些证据生成编辑计划。
那 agent 是怎么知道手册存在、又该怎么读的呢?答案在这张图里,熟悉 Claude Code 的读者会心一笑:

手册以一个 SKILL.md 清单的形式暴露给规划器:什么时候该查手册、参考文件都有什么、按什么顺序读。这份"如何使用本手册"的说明书写得非常具体,比如第 2 条明确警告"不要过早收窄到那个最显眼的阶段,一个修改经常横跨多个阶段",第 3 条要求"对你要动的每一个状态寄存器,查清所有读写位置"。
这些指令每一条都在对抗 agent 的某个已知坏习惯。
过早收敛、只改最先找到的那处、忽略共享状态的远端读写者,做过 agent 开发的人对这些失败模式都不陌生。
还有一处措辞我想单独指出来。清单的结尾写着:手册告诉你东西在哪儿、如何连接,但改成什么样由你决定,而且每个位置都要对照真实代码做验证。这和前面那条"仓库才是权威"的铁律是同一件事的两面:手册负责缩小搜索空间,不负责替代判断。这个边界划得越清楚,手册偶尔过期时造成的伤害就越小,因为 agent 被要求永远做最后一步核对。
代码改完了,手册怎么不变成过期地图
任何"给代码建外部文档"的方案都会撞上同一堵墙:代码一改,文档就开始腐烂。这也是很多团队 wiki 和架构图的宿命。
Harness Handbook 的做法是把重新同步做成流程里的强制环节:每次执行器产生非空 diff,就自动触发 resynchronization。
Resynchronization(重同步):改动落地后自动更新手册的过程。重新解析改动的源码,刷新程序图,用不依赖行号的指纹(函数模式)或文件集差异加内容哈希(文件模式)对齐新旧版本,识别增删改的单元。
同步分两档。如果阶段骨架还有效,只刷新受影响的条目和它们所在的结构;如果骨架本身失效了,才用同样的配置整体重建。解析不了、分类不了的内容一律保守处理:冻结,或者记入覆盖率记录,绝不靠猜。
而且模型调用被限制在四个语义步骤里:分类、文件归属、阶段内组织、描述修订。其余全部是确定性操作。
这就像图书馆的日常管理。每天闭馆后,管理员把当天被挪动过的书归位、更新卡片目录,而不是每个月把全馆推倒重编一次。碰到一本破损到看不清索书号的书,规矩是放进"待处理"箱,而不是凭感觉插回某个架子。如果允许凭感觉插架,目录很快就会积累一堆看起来正常、实际指向错误位置的卡片,而这种"自信的错误"比"明确的空白"破坏性大得多,因为没人会去怀疑它。
数据:更好的计划,更少的 token
实验设置值得先交代清楚。规划器是用 NexAU 框架搭的只读 agent,底座是 DeepSeek-V4-Pro。对比两个组:Baseline 直接探索仓库,Handbook-Assisted 按 BGPD 策略在手册引导下定位。除了手册,两组的请求、模型、仓库、工具权限、解码参数完全一致。
每个 harness 出 30 个修改请求,按类型分成三类:Query(改已有行为但不透露位置)、Cross-file(加一个横跨多文件的端到端能力)、Search-Hostile(相关实现藏在关键词搜索很难命中的地方)。计划质量由 GPT-5.5、Opus 4.8、DeepSeek-V4-Pro 三个模型独立评判。
评分方式也交代一下:每份计划在定位、范围控制、推理三个维度上打分,加权合成总分,其中定位占一半权重。两组的分差达到 3 分才算分出胜负,否则记为平局。
胜率(Win Rate):在所有有效的"评审 × 请求"对比里,某一组胜出的比例。因为存在平局,两组胜率相加不等于 100%。
这里有个容易忽略的细节:定位权重占 50%,是三个维度里最高的。这个权重设置本身就是论文的立场声明,作者认为编辑计划的生死线在于找没找对地方,理由也直白,位置错了,后面的方案写得再漂亮也是白搭。

结果的第一层:有手册的一组整体胜率在 Codex 上是 38.3% 对 28.3%,在 Terminus-2 上是 45.6% 对 26.7%。三个评审给出的方向完全一致,Codex 上每个评审的差距都是 10 个百分点,Terminus-2 上的差距从 13.3 到 26.7 个百分点不等。
同时,token 用量反而降了:Codex 上每个请求的平均规划 token 从 0.102M 降到 0.089M,省 12.7%;Terminus-2 上从 0.058M 降到 0.053M,省 8.6%。
胜率上升和 token 下降同时发生,说明质量提升不是靠烧更多预算换来的,而是探索路径本身变高效了。

按维度拆开看,定位、范围控制、推理三项全部是手册组占优。定位提升最大(Terminus-2 上平均高 12.2 个百分点),范围控制和推理分别提升 6.7 和 4.5 个百分点;Codex 上三项分别提升 2.2、1.1、3.3 个百分点。定位提升最大,这符合直觉,手册的核心价值就是定位。
范围控制的提升也说明了一个问题:手册没有让 agent 变得"什么都想改"。拿到更多候选位置的一个副作用可能是计划膨胀,把不该动的地方也圈进来,但数据显示范围控制反而更好了。定位准了,才敢收得紧。
第二层结果更耐人寻味:拿着手册的弱模型,能不能追上强模型的定位水平?论文把 DeepSeek-V4-Pro 的编辑计划和 Opus 4.8、GPT-5.5 独立生成的参考计划做比对,在文件和符号两个粒度上算查全、查准、F1。
24 组对比,手册组全胜,F1 提升从 5.0 到 18.8 个百分点。在 Terminus-2 上,弱规划器带手册后文件级 F1 达到 84.7% 和 89.3%,对 GPT-5.5 参考计划的查准率达到 93.3%。
还有一个指标叫 Wrong,指预测计划和参考计划零重叠的比例,也就是"完全找错了地方"的请求占比。手册最多把这个数字压低 25.9 个百分点。换句话说,手册消灭的不光是"找得不够全",还有"从头到尾全找错"这种最致命的失败。

第三层是分层分析。六组"harness × 请求类型"的对比全部是手册组赢,提升从 16.3 到 33.3 个百分点。Terminus-2 上提升最大的是 Search-Hostile 请求,33.3 个百分点。这个数字说服力很强:关键词搜索最无能为力的场景,恰好是行为组织的手册最能发挥的场景。反过来想,如果手册的提升集中在 Easy 和 Query 这种本来就好找的请求上,那它的价值就很可疑了。
按难度分层的六组对比也全部为正,从 3.7 到 33.3 个百分点不等。不过方向上有个小意外:Codex 在 Easy 请求上提升最大,Terminus-2 则是 Medium 最大,增益并不随标注难度单调变化。论文对此的解释很克制:难度标签本身解释不了增益的分布。换句话说,"人觉得难定位"和"agent 觉得难定位"可能根本不是同一件事,这本身就是个值得继续挖的现象。
写在后面
读这篇论文时我一直想到 Anthropic 的 Skills 机制。图 6 里那份 SKILL.md 清单说明这不是巧合:作者直接把手册包装成一个 agent skill,让"查手册"变成规划器工具箱里的一个标准动作。学术界和工业界在这里合流了,方向是同一个:把知识从模型的隐式记忆里搬出来,变成显式的、可校验的、可增量维护的外部结构。
最触动我的是那条"冻结而不是猜测"的设计。解析不了的定位器就冻结,分类不了的内容就记入覆盖记录。一个允许说"我不知道"的系统,比一个永远给出答案的系统更值得信任。这个原则对 RAG、对记忆系统、对一切给 LLM 喂外部知识的场景都成立,但真正执行它的系统很少。
论文结尾说下一步是 harness 自进化:agent 以手册为共享行为记忆,自主闭环定位、规划、执行、重同步。真到那一天,手册的准确性就不再是效率问题,而是安全问题了。一个还没被回答的问题是:重同步本身也依赖模型调用,当仓库连续演化几百轮之后,手册的误差会不会累积?论文没有给出长周期的退化曲线,这可能是它下一步最需要补的实验。
想象几个月后的某个深夜,一个 coding agent 接到请求,翻开自己系统的手册,定位、规划、修改、然后更新手册里描述自己的那几页。它合上的这本手册,下一次翻开时,读者还是它自己。我们给系统写文档写了几十年,第一次,文档的作者和读者是同一个非人类。这本手册该由谁来审?