Harness 设计笔记:审查门
agent harness 最不被重视的一层是提交流程。不是模型,不是工具,不是记忆:一项改动要活过什么,才会成为现实?我的默认做法是提案先行。在提案通过门禁之前,任何东西都不得变更共享状态:草稿、diff、人工提交。批准一个动作是被动的,逐帧进行。批准一个 diff,是对整个变更做出的一次决定,在一切落地之前做出。
这是我对Harness 设计笔记:沙箱化 agent 变更的姊妹篇。沙箱决定一个候选计划是否可行;审查门决定它是否被需要。
门禁光谱
门禁是一个变更可以被拦下的位置。设计空间是一个光谱:
- 没有门禁。 agent 在每次工具调用时都直接变更。通往价值的路径最快,爆炸半径也最大。玩具可以,但想从中吸取教训就贵了。
- 结构门禁。 不变量、类型、schema、约束检查。微秒级运行,精确捕获你能编码的一切,永不疲倦。
- eval 门禁。 测试、回放、沙箱空跑、裁判模型。捕获你无法编码的行为,成本更高,且质量上限是它的 oracle。
- 人工门禁。 审查与批准。最通用的裁判,也是最慢的。它无法规模化,所以必须留作后用。
这门技艺的关键是按成本顺序把它们叠起来:结构、eval、人工,把人工时间留给爆炸半径大的表面。目标不是门禁最多,而是用最便宜的门禁捕获你承担不起的那类失败。门禁有两个性质值得内化。第一,每道门禁都是一个可以在失败变成变更之前捕获它的位置。第二,任何门禁都能在压力下被绕过,而被绕过的门禁比没有门禁更糟,因为之后你仍然信任它。
失败模式分类作为门禁检查清单:MAST
Why Do Multi-Agent LLM Systems Fail?(Cemri 等人,arXiv 2503.13657,2025)构建了 MAST,即多 agent 系统失败模式分类:系统设计问题、agent 间失调与任务验证,全部从大规模带标注的 trace 语料库中提炼而来。语料库数字与完整分类体系,我在多 agent 系统为何失败,以及监督应该是什么样中做过精读;这里我想要的是门禁视角的解读。
第三类,任务验证,字面上就是「缺失门禁」这一类:输出验证不足、质量检查缺失、错误不断传播,因为没有人重新检查中间结果。而论文的核心结论——基础模型的改进覆盖不了这套分类体系——正是 harness 工作的实证依据:失败是结构性的,所以修复也是结构性的。审查门是能一次性捕获全部三个类别的最小结构性修复——在提交时。提案与意图不符时,它捕获规格漂移;diff 动了不该动的东西时,它捕获失调;diff 通不过检查时,它捕获验证失败。但「捕获」就是它全部的主张:门禁在设计阶段阻止不了其中任何一类,而把门禁当预防措施来读的团队,会继续写出同样的规格 bug,并继续支付审查成本去拦下它们。一个机制,捕获三类失败,没有一类在设计阶段被排除。
harness 就是数据 pipeline
这两篇 harness 笔记都围绕一篇论文:The Interplay of Harness Design and Post-Training in LLM Agents(Kim、Choi、Lee、Jun、Kim、Park,arXiv 2606.25447,June 2026)。它把 harness 定义为决定暴露哪些工具、如何描述它们、以及每次观察伴随什么辅助信息的脚手架,并指出这套脚手架被当作一个固定的工程细节,而后训练假设的却是一个静态环境。作者扩展了 ALFWorld,让 harness 成为一个可控维度,并在任务与工具环境迁移下评测。他们的结果:harness 感知的后训练提升了分布内性能,让 agent 在分布外依然稳健;而 harness 设计投入极少时,工具环境一旦迁移,性能便大幅下滑。
我同意这个方向,并且想把机制说得更锋利。论文把 harness 当作后训练的上下文;我的经验是,harness 就是后训练的数据 pipeline。事件日志兼作训练数据轨迹:门禁决定了哪些轨迹根本存在。拦截坏变更的审查门,同时也是训练分布上的过滤器,而每一条拒绝理由都是监督信号。由此得出两个推论。
第一,harness 感知的后训练不只是暴露更好的工具。它首先关乎生成正确的轨迹,还关乎在错误轨迹被拒绝的那一刻——趁理由还容易记录——给它们打上标签。
第二,他们的分布外发现,与我担心的一个生产失败模式吻合。廉价的 harness 会产生退化的轨迹:分布内看起来正常,环境一迁移就散架,因为从来没有任何东西对捷径踩过刹车。门禁正是让轨迹分布保持诚实的东西。这是我对他们结果的解读;作者没有这样主张,但这就是为什么审查门不是安全特性——它是数据质量特性。
人作为执行前门禁:InferAct
InferAct(Fang 等人,arXiv 2407.11843,2024)论证了把人工门禁放在动作之前、而不是之后。InferAct 使用基于心智理论的信念推理,在执行前检测与用户意图不一致的动作,并提醒用户及时纠正,防止诸如网页购物中意外点下「立即购买」之类的后果。作者报告,失调动作检测相比基线最多提升 20%。
两个教训。执行前检测胜过事后修复:动作一旦在现实世界中执行,事后修复可能就不再是选项。人是门禁的一部分,但「每个动作一次告警」无法规模化。提案先行审查,就是把人类监督变得可行的压缩:agent 提案,人审阅一个 diff,而不是两百次工具调用的记录文本。
门禁需要裁判:Agent-as-a-Judge
以 eval 驱动的迭代,只有在 eval 付得起的时候才成立。Agent-as-a-Judge(Zhuge 等人,arXiv 2410.10934,2024)是这一论点最强有力的版本:它是 LLM-as-a-Judge 的有机延伸,用 agentic 系统评测 agentic 系统,其 agentic 特性让整个任务求解过程都能得到中间反馈,而不只是一个最终评分。在他们的 DevAI benchmark 上——55 个真实的 AI 开发任务、365 条层级化需求——裁判的可靠性远超 LLM-as-a-Judge,并与人工基线相当;作者将其定位为动态、可扩展的自我改进所需的奖励信号。
门禁的教训:跑不起的门禁等于不存在的门禁。裁判 agent 让逐提案评测便宜到可以对每一条提案都跑,这正是 eval 驱动迭代的前提。
提案 pipeline
我一直在构建的形状:
draft agent proposes a mutation (plan node, config, code)
diff machine-readable delta against current state
gate 1 structural: invariants, types, constraints
gate 2 eval: dry-run in the sandbox + judge verdict
gate 3 human: approve or reject, with one-click rollback
commit append-only event-log entry (doubles as training data)
设计规则:
- 每次变更都是提案。 没有旁路通道,没有后台写入。一项改动如果不能以 diff 的形式存在,就无法被审查;如果无法被审查,它就不该发生。
- 门禁按成本排序。 结构检查对每条提案执行,eval 对每条通过的提案执行,人工只在爆炸半径大或 eval 置信度低时介入。人工这条线画在哪里是个设计决定,我想把它明确为设计决定,而不是一个结论:我没有生产环境的误路线数据来证明这个阈值是校准过的。错误阈值的失败模式有两个方向——太松,坏变更未经审查就落地;太紧,审查者变成橡皮图章,那等于带多余步骤的绕过门禁——所以诚实的做法是从保守开始,再根据事件日志显示的内容调整;事先断言一个阈值就是在猜。
- 人审阅的是 diff,不是记录文本。 人擅长判断「这符合意图吗」,不擅长读日志。类型化计划图让这一点名副其实:一个计划的 diff 是一个真实的对象。
- 事件日志记录每一条判定及其理由。 那条日志就是你正在成型的失败模式分类。MAST 给出起点词汇:规格、失调、验证;从自己的拒绝中收获的分类体系,胜过事先猜出来的分类体系。
- 重新规划也是一条提案。 现实会变,关键路径会移动,新计划与最初那份要过同样的门禁。门禁不是一次性的仪式;它是常态。
- 负面判定是一等公民。 一条被拒的提案是带标签的样本,也是一条免费的监督信号;这一轮没有任何东西被浪费。
这些规则从何而来:PiPlan.ai 与 SafeRoutes
上面两条规则都来自我构建过的系统。
在 PiPlan.ai,目标变成类型化图,harness 约束每一次变更:提案先行审查,每次变更都以 diff 的形式到达、由一个人签署;候选计划有一个模拟沙箱;还有一份完整的、兼作训练数据轨迹的事件日志。自适应重新规划在现实变化时重新推导关键路径,因此每一次修订都会触发门禁。对话式规划器–执行器 agent 尚在进行中;将来约束它的 harness,正是这篇文章描述的模式。
SafeRoutes 把门禁推向它的逻辑极限:正确性是数据面的属性,而不是提示词的属性。每一次状态写入都受不变量检查约束:途经点自洽性、路径连续性、续航区间。检查失败会把状态回滚,并返回一个错误,其内容就是如何继续的指引。途经点变更是一等操作:agent 可以提议修改途经点,由门禁决定它是否落地。模型想说什么都可以;数据面按自己的节奏表示异议。循环笔记我写在训练一个 Safe-Routes 技能:来自循环的笔记。
第 4 条里那个「成型中的失败模式分类」,在那里并不是假设;拒绝本身就是产物。每一个覆盖缺口错误都会携带一个 caller_guidance 字符串,其构造目标就是通过工具自身的返回值触达模型:「覆盖缺口:不要用网上搜到或猜出来的加油站代替(未经验证 = 编造的燃油安全),也不要调低或调高 --safe-range 来强行通过。加载走廊数据(先 run doctor,再 ingest),或让用户指定一个该技能可以验证的真实停靠点。」不变量违例以结构化的 code、detail 和 recovery 返回:一条被截断的路线返回 INV-7、「已提交的路线未到达目的地」,恢复指引为「重新规划;被截断的路线不得持久化」;超续航区间的分段则返回恢复指引「加载走廊燃油数据(doctor → ingest),或让用户指定一个经验证的停靠点;绝不调低/调高 --safe-range 来强行通过」。每一次拒绝都已经是一个带标签的样本:哪条不变量、在行程的哪个位置、以及应该改做什么。
审查门就是把 agent 从「会说话的东西」变成「你允许它写入的东西」的那一步:模型起草,门禁过滤,由一个人签署提交。
本文中链接的来源均已抓取并核实。