为什么能力强的 Agent 仍然会失败

失败多半不在模型权重,而在权重之外那层叫 harness 的工程基础设施。

Module C · 第 0 讲

立靶:把一个能拿满分的模型,丢进真实任务里

先看一组让人不舒服的数字。

当下最强的编码 Agent,在公开 benchmark 上的任务通过率大约只有 50%–60%。这已经是被精心清洗过的题目——需求明确、环境干净、验收标准写死。可一旦换到真实工程现场,通过率往往更低。原因不在模型变笨了,而在真实世界多了三样 benchmark 里没有的东西:

  • 需求是模糊的:用户说「帮我把登录修好」,没说「修好」指什么。
  • 规则是隐性的:这个仓库的提交必须过 lint、必须配 fixture、生产分支只读——这些没人写在任务里。
  • 环境是有缺陷的:依赖装不上、外部服务超时、上一轮的半成品还堆在那里。

于是我们很容易得出一个错误结论:「模型还不够强,等下一代模型吧。」

这一讲要拆掉这个结论。核心命题只有一句:

让 Agent 失败的,多数时候不是模型权重,而是模型权重之外那层工程基础设施——我们把它叫 harness。

框架:五层失败归因

「Agent 失败了」是一句没有信息量的话,就像说「程序崩了」。要修,得先把失败归到具体某一层。walkinglabs 的 Harness Engineering 把一次 Agent 任务拆成五层,任何一次失败都应该能落到其中一格:

这层负责什么失败长什么样典型修法(改 harness,不换模型)
1. 任务规范把模糊意图翻译成 Agent 能执行的明确目标跑偏、答非所问、做一半就宣布完成写 PRD/SPEC,把验收标准、反模式、约束显式化
2. 上下文供给在恰当时机把恰当信息喂给模型重复造轮子、违反仓库隐性规则、忘了上一步持久化文件(CLAUDE.md/STATUS.md)+ 上下文隔离
3. 执行环境提供可复现、能跑起来的运行环境装不上依赖、服务连不上、本地能跑线上不能init.sh 自检 + fixtures + 环境固化
4. 验证反馈让 Agent 知道自己对没对、能自我纠错输出看着对其实错、没有信号就停每个任务挂可执行的 verify(fixture/metric/log)
5. 状态管理跨步骤、跨会话保住进度与决策长任务越跑越乱、新会话接不上单一事实源 + 切片推进 + session 收尾落盘

这张表的价值不在于记住五个名词,而在于它逼你做一件事:遇到失败,先问「这是哪一层的问题」,而不是笼统地怪模型。 模型权重在这五层里只占一小块——它负责「想」,其余四层都是工程在负责「让它想得对、看得见、记得住、跑得起来」。

数据与 case:同一个模型,0 到 1 的距离

最能说明问题的是一类对照实验:模型权重一行不动,只在外面那层 harness 上做文章。

  • 裸跑:把一个真实任务直接丢给最强模型,不给规范、不给环境、不给验证。结果是失败——它可能跑偏,可能改一半就声称完成,可能在一个装不上的依赖前空转。
  • 加完整 harness 后:同一个模型、同一个任务,先补齐任务规范、把环境固化成可一键自检、给每一步挂上可执行的验证。结果是成功。

在 walkinglabs 给出的案例里,这类改造能把某任务的成功率从约 20% 一路爬到接近 100%——模型一个参数都没换。 涨上去的那几十个百分点,全部来自权重之外的工程。

这件事的方法论含义极强:当你看到 Agent 失败,第一反应不该是「换个更强的模型」,而是「我的 harness 哪一层漏了」。 换模型是最贵、见效最慢、而且经常无效的动作——因为如果失败在第 3 层(环境装不上),再强的模型也装不上那个依赖。

把框架落到真实做法

抽象的五层,落到一个真实项目里是什么样?下面用一套在多个长周期 Agent 项目里反复跑出来的方法论来印证——它本质上就是给这五层每一层都配了确定性的工程兜底,整理成「四层防御体系」,和上面的五层失败归因几乎一一对应。

先讲一个反直觉的纪律:文档先行,没写完不许写代码。 听起来像形式主义,其实它精确对应第 1 层(任务规范)和第 2 层(上下文供给)。做法是:任何新项目——哪怕只是个小 CLI、一次技术验证——动手前先落五份文件:项目指令、状态文件、需求、技术规范、架构。这五份文件就是把「模糊意图」和「隐性规则」从 Agent 不可靠的记忆里,搬到确定性的磁盘上。

这里有个真实踩过的坑:曾把一个模块从大项目里「抽离成独立项目」,当时判断为「只是搬文件」,于是只搬代码加了个 README,跳过文档先行。结果被反复追问三次才暴露问题——根因是场景识别失败:「抽离」措辞像搬运,实质是新建项目,必须走完整规范。教训固化成一条判据:只要会产生一个新的顶层目录,就是新建项目,文档先行不可跳。 这正是第 1 层失守的典型样本——不是模型不行,是没人把「这是新建」这个规范喂清楚。

第二条纪律:单一事实源 + 可执行验证。 对应第 4 层和第 5 层。维护一个 features.json,把任务拆成原子 feature,每条带状态字段 pending / in_progress / failing / passing。铁律是:

verify 真正跑通,才能把状态改成 passing。

这条规矩直接消灭 Agent 最常见的失败——「过早宣布胜利」。模型很擅长说「我完成了」,但它说完成不算数,verify 跑通才算数。而且每条 feature 的 verify 字段若为空,就不准开工——这是一道开工闸门,强制你动手前先想清楚「怎么算对」。

把它和这门课自己的配置对照看更具体:这门课给「每讲讲义」定义的成功信号是一串确定性检查——build 无报错、产出对应 HTML、关键标题出现在 HTML、grep 确认全文无 emoji、从导航可点达。五条全过,这一讲才允许从 in_progress 改成 passing。没有一条是「我觉得写得不错」。

第三条纪律:环境可复现 + fixture 先于代码。 对应第 3 层。每个里程碑配一个 init.sh 做六段自检(依赖、env、外部服务、schema、fixtures、端到端),故意不用 set -e——走完全部六段再统一报告。配套 fixture 先于代码:验证要用的 fixture 不存在就先造,不许 mock、不许「等真数据」。在这门课里,第一讲的 markdown 本身就是 build 脚本的 fixture——先写讲义,再写脚本。

第四条纪律:上下文隔离,把脏活外包给子 Agent。 对应第 2 层。长任务最隐蔽的失败是上下文被噪声污染。修法是把「吃大量 context 的脏活」派给独立子 Agent,让它在自己的 context 里跑完,只回结论,主线保持干净。这门课里:批量读知识库笔记重写讲义时,派子 Agent 去读原始笔记,只回提炼后的讲义草稿,主 Agent 绝不把整篇原文 Read 进主 context。

把四条纪律对回五层:

失败归因层工程兜底这门课里的落地
1 任务规范文档先行五件套CLAUDE.md + PRD + SPEC + architecture
2 上下文供给持久化 + 上下文隔离子 AgentSTATUS.md + 派子 Agent 读笔记只回草稿
3 执行环境init.sh 六段自检 + fixture 先于代码bash M1/init.sh 全绿才开工
4 验证反馈可执行 verify + 开工闸门每讲五条机器可判定检查
5 状态管理单一事实源 + 切片 + 收尾落盘features.json 四态 + STATUS 每次收尾更新

收口

回到开头那组数字。50%–60% 的 benchmark 通过率,不是模型能力的天花板,而是「裸模型」的天花板。剩下那几十个百分点,藏在权重之外那层你能亲手搭建、调试、加固的工程基础设施里。

遇到 Agent 失败,先把失败归到五层中的某一层,然后修那一层的 harness——换模型是最后一步,不是第一步。