Learn Harness Engineering 课程全总结:12 讲核心要点

Learn Harness Engineering 课程全总结:12 讲核心要点

本文是 Learn Harness Engineering 课程全部 12 讲的系统总结。从理解 Harness 的本质到搭建完整的 Agent 运行环境,每一讲的核心论点、关键概念、实践方法和真实案例均已完整收录,无省略。


目录

  1. 第一讲:模型能力强,不等于执行可靠
  2. 第二讲:Harness 到底是什么
  3. 第三讲:让代码仓库成为唯一的事实来源
  4. 第四讲:把指令拆分到不同文件里
  5. 第五讲:让跨会话的任务保持上下文连续
  6. 第六讲:让 agent 每次工作前先初始化
  7. 第七讲:给 agent 划清每次任务的边界
  8. 第八讲:用功能清单约束 agent 该做什么
  9. 第九讲:防止 agent 提前宣告完成
  10. 第十讲:跑通完整流程才算真正验证
  11. 第十一讲:让 agent 的运行过程可观测
  12. 第十二讲:每次会话结束前都做好交接

第一讲:模型能力强,不等于执行可靠

核心论点:模型能力和执行可靠性是两回事。遇到失败,先检查 harness,后考虑换模型。同一个模型在空白环境里和在有完整 harness 的环境里,产出有本质差异。模型没变,变的是马具。

关键概念

  • 能力鸿沟(Capability Gap):模型在基准测试(如 SWE-bench Verified)上的表现和真实任务上的表现之间的巨大落差。SWE-bench Verified 通过率仅 50-60%,意味着近一半的真实 issue 解不了。
  • Harness 诱导失败:模型本身能力足够,但因为执行环境有结构性缺陷而失败。Anthropic 的对照实验证明:Opus 4.5 配完整 harness 6 小时 $200 做出可玩的游戏,裸跑 20 分钟 $9 游戏核心功能跑不起来。
  • 诊断循环:执行 → 观察失败 → 定位到 harness 的哪一层 → 修补那一层 → 重新执行。这是 harness 工程的核心方法论。
  • 完成定义(DoD,Definition of Done):一组可以用命令验证的条件——测试通过、lint 没报错、类型检查通过。没有显式的 DoD,agent 就会自己编一个。

五种 Agent 典型失败模式

  1. 需求描述模糊:agent 只能自己猜,猜错概率大
  2. 隐性约定没写下来:agent 无从遵守——它不知道"所有 API 必须走 OAuth 2.0"这条规矩
  3. 环境配置有缺口:agent 把上下文花在修环境上,真正该干的活反而没精力做
  4. 验证手段缺失:没有测试、没有 lint,agent 自己觉得做完了就算完成
  5. 跨会话状态丢失:每个新会话都要重新探索项目,超过 30 分钟的任务失败率急剧上升

核心要点

  • 模型能力和执行可靠性是两回事,千里马也得配上好马具。
  • 失败的时候先看 harness,再看模型。换模型是成本最高的选择。
  • 每次失败都是一个信号:你的 harness 有结构性缺陷。
  • 五层防御排查:任务规范、上下文供给、执行环境、验证反馈、状态管理。
  • 一个AGENTS.md文件可能比你换一个更贵的模型更有效。

第二讲:Harness 到底是什么?

核心论点:"harness"在 AI coding agent 圈子被用得越来越多,但大部分人说 harness 时指的只是一个 prompt 文件。一个 prompt 文件不是 harness。Harness 由五个子系统组成:指令、工具、环境、状态、反馈。不是模型权重的部分,全是 harness。

关键概念

  • 什么是 Harness:模型权重之外的一切工程基础设施。OpenAI 把工程师的核心工作概括为设计环境、表达意图、构建反馈循环。Anthropic 直接把 Claude Agent SDK 称为"通用 agent harness"。
  • 仓库是唯一事实来源:agent 看不到的东西对它来说就不存在。所有必要的上下文都必须在仓库里,通过结构化的文件和清晰的目录组织来呈现。
  • 给地图,不给说明书AGENTS.md应该是目录页,不是百科全书。100 行左右就够了,放不下就拆分到docs/目录里,让 agent 按需去读。
  • 约束而非微操:好的 harness 用可执行的规则约束 agent,而不是在指令里逐条叮嘱。OpenAI 说"执行不变量,不要微管实现";Anthropic 发现解决方案是把"干活的人"和"检查的人"分开。
  • "控制变量排除法"量化价值:保持模型不变,逐个移除五个子系统,看哪个移除后性能下降最多。下降最多的组件边际贡献最大。但要定位真正瓶颈,还需结合失败记录和归因分析,不能只靠拆除实验。

Harness 五子系统模型

子系统职责关键实践
指令让 agent 看懂项目规则创建 AGENTS.md / CLAUDE.md,含项目概览、技术栈、硬约束、文档链接
工具确保 agent 所需的工具可随时调取不要因为"安全考虑"禁掉 shell,按最小权限原则开放工具权限,确保环境状态自描述
环境运行环境可重现pyproject.toml/package.json锁定依赖,.nvmrc/.python-version指定运行时版本
状态跨会话连续性用 PROGRESS.md 记录进度,用 DECISIONS.md 记录决策原因
反馈验证结果反馈显式列出验证命令

核心要点

  • Harness = 指令 + 工具 + 环境 + 状态 + 反馈,五个子系统缺一不可。
  • 五个子系统中,反馈子系统投入最少、回报最高——先把验证命令写清楚。
  • 用"控制变量排除法"量化各子系统边际贡献;定位瓶颈需结合失败记录和原因归因。
  • Harness 和代码一样会腐化,需定期审计,像还技术债一样还 harness 债。

真实案例

一个 TypeScript + React 项目(约 20,000 行代码),四个阶段:

  • 阶段 1:只有 README,5 次运行成功 1 次(20%)
  • 阶段 2:添加 AGENTS.md(技术栈版本、命名约定、架构决策),成功率升到 60%
  • 阶段 3:添加验证命令yarn test && yarn lint && yarn build,成功率升到 80%
  • 阶段 4:引入进度文件模板,成功率稳定在 80-100%

模型一个字没改,成功率从 20% 到接近 100%。


第三讲:让代码仓库成为唯一的事实来源

核心论点:不在仓库里的知识对 agent 来说等于不存在。Agent 的输入只有三样——任务描述、仓库文件内容、工具执行的输出。不在仓库里的信息 agent 永远看不到。你必须给它一张足够好的地图。

关键概念

  • 知识可见性缺口:项目总知识中不在仓库里的比例。缺口越大,agent 失败概率越高。
  • 系统记录(System of Record):代码仓库是项目决策、架构约束、执行状态和验证标准的权威信息源。仓库说了算。
  • 全新会话测试:开全新 agent 会话,只让它看仓库,测试能否回答五个基本问题——这是什么系统?怎么组织的?怎么跑?怎么验证?现在进度如何?答不上来的问题越多,地图空白越大。
  • 发现成本:agent 为了在仓库里找到关键信息需要消耗的上下文。信息越隐蔽,发现成本越高。
  • 知识衰减率:仓库中单位时间内变得过时的知识条目比例。过时的文档比没有文档更危险——它会误导 agent 还以为自己是对的。

画好地图的四条原则

  1. 知识靠近代码:API 认证规则放在 API 代码旁,而不是藏在全局文档里
  2. 标准化入口文件:AGENTS.md 作为着陆页,50-100 行,快速回答三个问题
  3. 最小但完备:删掉不影响 agent 决策质量的规则,但全新会话测试的每个问题都必须有答案
  4. 和代码一起更新:把知识文档放在对应模块目录里,改代码时自然看到

ACID 类比管理 Agent 状态

  • 原子性(Atomicity):每个逻辑工作单元一个 git 提交,要么全做要么不做
  • 一致性(Consistency):定义"一致状态"的验证谓语——所有测试通过,lint 无报错。不一致的中间状态不要提交
  • 隔离性(Isolation):多 agent 并发时用独立进度文件或 git 分支隔离
  • 持久性(Durability):关键知识必须写进 git 跟踪的文件里。脑子里的不算

真实案例

一个约 30 个微服务的电商平台:架构决策散落在 Confluence(部分过时)、Slack(难以搜索)、资深工程师的脑子里(不可扩展)。引入 AI agent 后 70% 的任务需要人工干预——几乎每次失败都涉及 agent 违反"所有人都知道但从未写入仓库"的隐性约束。

改造:根目录创建 AGENTS.md → 每个微服务目录添加 ARCHITECTURE.md → 创建集中的 CONSTRAINTS.md → 每个服务目录添加 PROGRESS.md → 改造后同一 agent 能在冷启动时回答所有关键项目问题。


第四讲:把指令拆分到不同文件里

核心论点:"加条规则"是短期的止痛药、长期的毒药。入口文件是路由器,不是百科全书。50-200 行就够了。

巨型指令文件的问题

  • 上下文预算被吃掉:600 行 AGENTS.md 占用 10K-20K tokens,对 128K 窗口就是 8-15%
  • 中间迷失(Lost in the Middle):Liu 等人 2023 年研究表明,LLM 对长文本中间部分的信息利用效率显著低于两端
  • 分不清轻重:硬约束("不得使用 eval()")和软建议("优先使用函数式风格")以相同格式呈现,agent 无法区分
  • 维护衰减:指令只增不减,信噪比持续下降
  • 矛盾累积:不同时期加的指令出现矛盾,agent 每次随机选一条

指令信噪比(Instruction SNR)

  • 定义:入口文件中与当前任务相关的指令条数 ÷ 总指令条数
  • 现状:文件膨胀到 600 行时,SNR 常低于 0.3
  • 目标:理想 SNR 应为 0.7-1.0(大部分指令与当前任务相关)
  • 作用:SNR 是衡量入口文件质量的量化指标, SNR 越低,agent 上下文利用率越差

注意:SNR 不是一个绝对值标准,而是相对参考。它会受任务类型影响——做 bug 修复和做新功能的"相关指令"不同。

推荐的文件结构

  • 入口文件 AGENTS.md(50-200 行):项目概览 + 快速开始命令 + 全局硬约束(不超过 15 条)+ 指向专题文档的链接
  • 专题文档(50-150 行/每个):按主题放在 docs/ 目录下,agent 按需读取
  • 信息直接放在代码里:类型定义、接口注释等——agent 读代码时自然看到

维持指令健康的核心原则

  • 每条指令标明来源(为什么加这条?)、适用条件(什么时候需要?)、过期条件(什么时候删?)
  • 重要信息放顶部或底部,利用"中间迷失"效应
  • 定期审计,删掉必要的 vs 不必要的——像管理代码依赖一样管理(升级/降级/依赖管理)指令

关键数据:某 SaaS 团队的 AGENTS.md 从 50 行膨胀到 600 行,重构后(裁剪到 80 行 + 创建 3 个专题文档)成功率从 45% 升到 72%,安全约束遵循率从 60% 升到 95%。


第五讲:让跨会话的任务保持上下文连续

核心论点:上下文窗口是有限的资源。长任务一定会跨会话,跨会话一定会丢信息。解决方案不是更大的窗口,而是更好的状态持久化。

关键概念

  • 上下文焦虑:Anthropic 观察到,当 agent 感觉上下文快满了,它们会表现"赶工收尾"行为——匆忙结束、跳过验证、选简单方案而非最优方案
  • 重建成本:新会话恢复到可执行状态所需的时间。好的 harness 能把重建成本从 15 分钟压到 3 分钟
  • 漂移(Drift):agent 的理解跟代码仓库实际状态之间的偏差。每个会话边界都会引入漂移

两种上下文管理策略

  • 压缩(Compaction):同一会话内把早期对话摘要化。优点是保留连续性,缺点是"为什么"经常丢失,且上下文焦虑并未消除——agent 知道上下文曾经很大
  • 重置(Context Reset):全新会话从持久化工件重建。优点是干净的心理状态("我没赶时间"),缺点是依赖交接工件的完备性

四个工具

  1. 进度文件(PROGRESS.md):记录当前状态(commit hash + 测试状态 + lint 状态)+ 已完成 + 进行中 + 已知问题 + 下一步
  2. 决策日志(DECISIONS.md):记录"什么决策 + 为什么 + 什么时候"。让新会话理解设计意图
  3. git 检查点:每完成一个原子工作单元就 commit
  4. 标准化流程:每次"上班"读 PROGRESS.md + DECISIONS.md +make check;每次"下班"更新 PROGRESS.md +make check+ commit

混合策略

  • 短任务(30 分钟内):同一会话内完成
  • 长任务:用结构化工件维持连续性
  • 判断标准:任务需要的上下文超过窗口的 60% → 开始准备交接

关键数据

定量对比:一个含 12 功能点的博客系统,需要 5 个 agent 会话。没有状态持久化:12 点只完成 7 个(58%),隐含缺陷 43%,重建 15 分钟。有状态持久化:12 点全部完成(100%),隐含缺陷降到 8%,重建 3 分钟。重建时间减少约 78%


第六讲:让 agent 每次工作前先初始化

核心论点:初始化和实现的优化目标不同,混在一起只会互相拖后腿。Agent 在做功能前,必须先经历一个独立的初始化阶段。

初始化的五个产出

  1. 可运行的环境:项目能启动、依赖装好
  2. 可验证的测试框架:至少有一个示例测试通过
  3. 启动就绪清单:告诉后续会话"怎么跑 + 怎么测 + 做到哪了"
  4. 任务分解:把项目拆成有序的任务列表 + 每个任务有验收标准
  5. git 检查点:提交干净的 checkpoint

启动就绪清单四个条件

条件说明验收方式
能启动从零开始make setup成功全新环境验证
能测试make test至少一个测试通过验证测试框架
能看进度新 agent 只看仓库就能回答"怎么跑 + 怎么测"全新会话测试
能接手下一步任务分解文件存在 + 至少 3 个任务检查清单

热启动 vs 冷启动

  • 冷启动:从空目录开始,agent 需自行推断项目结构,效果差
  • 热启动:用项目模板(create-react-app / fastapi-template 等)预置标准目录结构和依赖配置
  • 做法:把通用初始化步骤预置到模板里,只留下项目特有的初始化工作

关键数据

Anthropic 实验:使用独立初始化阶段的项目,多会话场景中功能完成率比混合方式高 31%

React 项目对比
-混合:100 行功能代码 + 基础设施,重建 20 分钟
-独立初始化:20 分钟只做初始化,后续 3-4 个会话中把时间全部收回
-总重建时间:混合比独立初始化多约 60%


第七讲:给 agent 划清每次任务的边界

核心论点:Agent 天生就有"多做一点"的冲动——看到相关的事情就顺手一起做了。但注意力是有限的资源,同时做太多事情往往每件都做不好。WIP=1 是 agent harness 的默认安全设置。

两个共生问题

  • 过度延伸(Overreach):一次会话中激活的任务数超过最优值。量化:同时做 5 个功能但 0 个跑通
  • 不足完成(Under-finish):已启动的任务中通过端到端验证的比例低于阈值。仅"写了代码"不等于"做了"

两者互相加剧:overreach 导致注意力分散 → under-finish → 半成品代码增加系统复杂度 → 下一个任务的 overreach → 恶性循环

Little 法则的启示

L = lambda × W(在制品 = 交付率 × 前置时间)。如果 L 过大(同时做太多事),每个任务的 W 必然增加。对 agent 而言,这意味着每个功能从开始到验证通过的时间被拉长,失败概率被放大。

四个实施方法

  1. 强制执行 WIP=1:明确写进 CLAUDE.md——"每次只做一个功能点 + 当前功能点端到端验证通过后才能开始下一个 + 不要在实现功能 A 时'顺便'重构功能 B"

  2. 显式完成证据:每个功能任务都有可执行的验证命令

  3. 范围表面外部化:用可读写的文件(JSON/ Markdown)记录所有任务的状态——哪个在做 + 什么行为算完成 + 通过了什么验证

  4. 监控 VCR(Verified Completion Rate)= 已通过验证的任务数 / 已启动的任务数。VCR < 1.0 → 阻止新任务启动

关键数据

Anthropic 实验:使用"小下一步"策略(WIP=1)的 agent,任务完成率比使用宽泛提示的 agent 高 37%

REST API 项目(8 个功能点)对比
-无约束:第一个会话同时启动 5 个 → 3 个会话结束时完成 3 个(37.5%)
-WIP=1:每个会话只做 1 个 → 4 个会话结束时完成 7 个(87.5%)
-总代码:WIP=1 更少(800 vs 1200 行),但有效代码更多


第八讲:用功能清单约束 agent 该做什么

核心论点:功能清单不是备忘录——它是整个 harness 的基础数据结构。调度器靠它选任务,验证器靠它判完成,交接器靠它生成报告。没有它,所有组件就没有可以依赖的共识。

三元组结构

每个功能项包含三个要素 —— 缺一项就不完整:

  • behavior(行为描述):告诉 agent 做什么
  • verification(验证命令):告诉 agent 怎么算做完
  • state(当前状态):告诉 agent 现在到哪了

用 JSON 格式举例:
json { "id": "F03", "behavior": "POST /cart/items with {product_id, quantity} returns 201", "verification": "curl -X POST http://localhost:3000/api/cart/items ... | jq .status == 201", "state": "passing", "evidence": "commit abc123, test output log" }

状态机模型

状态含义可转移至
not_started未开始active
active进行中passing/blocked
blocked被阻塞active
passing已验证通过不可逆

"通过状态门控"activepassing的唯一方式是验证命令执行成功。agent 不能自己改状态——它只能提交验证请求,harness 执行验证并根据结果决定是否允许转移。这是最基本的约束——也是作为"原语"(primitive)的关键所在。

为什么功能清单必须是"原语"(primitive)

  • 文档可以被忽略——原语不能被绕过
  • 功能清单服务四个 harness 组件:调度器(读状态 → 选下一个not_started) +验证器(执行验证 → 判断状态转移) +交接报告(自动生成交接摘要) +进度追踪(统计状态分布 → 提供健康度指标)
  • 反向压力not_started项的数量 = harness 对 agent 的压力(压力归零 = 项目完成)

粒度校准

每个功能项应该是"一次性会话能完成"的范围:

  • 合适粒度:"用户可以添加商品到购物车"
  • 太粗:"实现购物车"(一次性会话完成不了)
  • 太细:"创建 Cart 模型的 name 字段"(管理开销大)

关键数据

电商平台 10 个功能项对比
-备忘录模式:3 个会话后笔记成了"购物车基本完成但还有 bug"——新会话花 20 分钟推断状态
-结构化模式:一次性读取功能清单 → 3 分钟内知道:F01-F05 是passing+ F06 是active+ F07-F10 是not_started→ 直接从 F06 继续
-完成率:结构化模式比自由形式高 45%,零重复实现


第九讲:防止 agent 提前宣告完成

核心论点:Agent 系统性地过度自信。Guo 等人 2017 年(ICML)经典论文证明——现代神经网络系统性地过度自信。Agent 也一样——它觉得做完了,但实际上差得远。解决方案:把"干活的人"(generator)和"检查的人"(evaluator)分开,且 evaluator 需要专门调校。

过早完成声明的常见套路

  1. 代码语法正确、逻辑看起来合理
  2. 静态检查,没有明显错误
  3. 跳过了实际运行(或只跑了部分测试)
  4. 单元测试全部通过(但集成测试/E2E 测试都没跑)
  5. 得出结论:"嗯,做完了"

三层终止检查

层级成本检查内容
第 1 层:静态分析最低语法正确 + 类型检查通过
第 2 层:运行时行为验证中等单元测试/集成测试通过 + 应用能正常启动
第 3 层:系统级确认最高E2E 测试通过 + 完整用户流程走通

完成优先级约束:第 1 层没通过 → 不许进第 2 层;第 2 层没通过 → 不许进第 3 层;核心功能没验证通过之前 → 不许做重构

Generator + Evaluator 分离的价值

Agent 在评估自己的工作时系统性地过度正面评价——同一个模型既生成又评估,内在地倾向于对自己慷慨。

Anthropic 实验数据(同一任务 + 同一模型 Opus 4.5):

架构成本时长核心功能
单一 agent 裸跑$920 分钟❌ 不可用
三 agent 架构(planner + generator + evaluator)$2006 小时✅ 可用

Evaluator 也需要调校

Evaluator不是一开始就那么强——早期版本的 evaluator 也会识别出合理的问题,然后说服自己这些问题"不过" ——最终也会"……,但……"

调校的关键信号:当 evaluator 使用"尽管/但是/虽然/…… 这种权衡" 的方式为代码变更辩护 → 这一面红旗就是"需要被校准"的信号

错误消息设计

OpenAI Codex 实践——面向 agent 的错误消息必须包含三种要素

  1. 什么出了问题(what)
  2. 为什么是问题(why)
  3. 该怎么改(fix)


"测试失败"
"测试失败:POST /api/reset-password 返回了 500。请在环境变量中检查邮件服务配置是否已正确设置。邮件模板文件应位于 templates/reset-email.html。"


第十讲:跑通完整流程才算真正验证

核心论点:单元测试对组件边界缺陷系统性盲视——隔离设计恰好使其无法检测交互问题。只有 E2E 测试能证明系统级缺陷不存在。

单元测试的五种盲区

缺陷类型描述单元测试E2E 测试
接口不匹配渲染进程传给 preload 的文件路径格式不一致
状态传播错误ORM 缓存层持有旧结构
资源生命周期问题文件句柄获取/释放跨越多个组件
环境依赖性在 mock 环境正确但在真实环境失败
错误传播服务层异常未能传到 UI 层

E2E 测试的两个效应

  1. 检测效应:E2E 测试捕获了 5 个跨组件边界缺陷(在一个 Electron 文件导出功能中,单元测试一个都没发现)

  2. 行为效应:当 agent 知道它的工作要过 E2E 测试时,它的编码行为也会改变:
    - 写代码时会考虑"这个接口和上游怎么对接"
    - 尊重架构边界(在有约束的系统里,E2E 测试迫使 agent 遵守边界规则)
    - 处理异常路径(E2E 测试包含故障场景,迫使 agent 考虑异常处理)

架构规则的"可执行"原则

  • 每条架构约束必须有对应的测试或 lint 规则来机械执行
  • "执行不变量,不微管实现"——OpenAI Codex 工程实践的核心原则
  • 每次提交自动检查——不能只写在文档里等人来看

"审查反馈提升"(Review Feedback Elevation)

流程:发现 agent 的新类型错误 → 转化为自动化检查规则

每个被捕获的缺陷类别都变成永久防线,harness 自动变强


第十一讲:让 agent 的运行过程可观察

核心论点:可观察性是 harness 的架构属性——设计时必须考虑的核心能力,不应仅作为"事后追加"的功能。

缺少可观察性导致的四类问题

问题描述
无法区分"正确"与"看似正确"代码审查看起来正确,但运行时因边界条件在特定输入下产生了错误结果;只有运行时追踪能揭示实际执行路径偏离了预期
评估变成"玄学"没有评分标准和验收条件,评估者只能依赖隐式假设;同一输出不同评估者可能给出截然不同的结论
重试变成"盲猜"agent 不知道失败原因,重试方向随机——可能在错误方向反复尝试,修复无关代码路径,忽略真正故障根源
会话交接信息断崖缺乏可观察性意味着新会话必须从零诊断系统状态;Anthropic 观察发现这占会话总时间的 30-50%

双层可观察性

运行时可观察性和过程可观察性——两者缺一不可,相互增强。

层级职责内容
运行时可观察性回答"系统做了什么"日志、追踪、进程事件、健康检查
过程可观察性回答"为什么这个变更应被接受"冲刺合同、评分标准、验收条件

冲刺合同(Sprint Contract)

在每个任务开始前,生成者和评估者协商一份合同,明确这次做什么、怎么做算通过:

要素内容
范围(Scope)修改哪些组件 + 每个组件的验证标准
验证标准(Verification Criteria)例如每个组件的 Lighthouse 评分 ≥ 80
排除项(Exclusions)例如"不处理打印样式" + "不处理第三方组件暗色模式"

没有冲刺合同:生成者和评估者的隐式预期不一致,循环 3-4 次,总耗时约 45 分钟。

有冲刺合同:一次迭代出高质量结果,总耗时约 15 分钟。

效率差 3 倍,区别只在可观察性。

评估评分标准

把"好不好"从主观判断变成基于证据的多维结构化评分:

维度ABCD
代码正确性所有测试通过主流程通过部分通过编译失败
架构合规完全合规轻微偏离明显偏离严重违反
测试覆盖主流程+边缘场景仅主流程仅有骨架无测试

第十二讲:每次会话结束前都做好交接

核心论点:OpenAI 和 Anthropic 一致指出——单次运行成功并不够,每个会话退出时的状态质量直接决定下一个会话的效率。清洁状态是"完成"的必要条件。

软件演化定律(Lehman's Law)

一个持续变更的系统,如果没有人主动管理,它的复杂性一定会增加。

OpenAI 在长达 5 个月的 Codex 实验中观察到一个清晰的现象:
- Agent 会复制仓库中已有的模式,即使那些模式是不一致或次优的
- 每个会话都会引入新的偏差
- 熵增是默认方向
- 只有主动的清洁操作才能对抗它

来源:Lehman,《Programs, Life Cycles, and Laws of Software Evolution》

清洁状态 ≠ "代码能编译"

清洁状态的要求远比"代码能编译"要多。构建通过是最基本的前提——下一个会话不应该一上来就先修别人的构建错误。所有测试也必须通过,包括会话开始前就存在的旧测试——你这次改动不能破坏已有的功能。

清洁状态五个维度——缺一不可:

维度要求验证方式
构建通过项目能够正常构建npm run build成功
测试全部通过所有测试通过(含先前的旧测试)npm test成功
进度已记录功能清单/进度文件已更新为机器可读的工件文件存在且内容最新
临时工件已清理无残留的调试日志、临时文件、注释掉的代码、过时的 TODO 标记显式扫描确认
启动路径可用新会话可不依赖人工干预直接开始工作环境初始化 + 代码加载 + 上下文获取 + 任务选择可达

双模式清理策略

模式时机任务原则
即时清理每个会话结束时清理本次会话的临时文件、更新功能清单、确保构建和测试全部通过谁产生的垃圾谁负责清掉,像引用计数一样
定期清理每周一次系统扫描,处理累积的结构性问题、更新质量文档、跑基准测试检测质量漂移定期全身体检,不让小问题拖成大病

质量文档

质量文档是一份持续更新的文件,对代码库中每个模块记录质量评分和评价。新会话一打开就能直接看到当前每个模块的状态。

评估项每模块评分
验证状态通过 ✓ / 部分通过 ✗
测试稳定性稳定 / 不稳定
架构边界合规 / 有违规 / 严重违反
代码规范遵循 / 部分遵循 / 不遵循
agent 可理解性容易 / 中等 / 困难(逻辑分散在多个文件)

Harness 简化

Harness 中每个组件的存在,都源于模型在某个方面尚无法独立完成。随着模型能力不断演进,这些前提会逐渐过时。

推荐做法

  • 每月挑选一个 harness 组件,暂时禁用它
  • 跑一遍基准任务集
  • 如果结果没有退化,就永久移除
  • 如果退化,恢复该组件,或换一个更轻量的替代方案

幂等清理

定义:一个操作无论执行一次还是一百次,结果都一样。

为什么需要:清理失败时你需要重跑一遍,重跑必须产生相同的结果。

幂等清理操作举例

rm -f /tmp/debug-*.log # -f 确保文件不存在时不报错 git checkout -- .env.local # 恢复到已知状态,多跑几次结果相同 npm run test # 验证清理没有破坏任何功能

清洁状态——实测数据对比

一个使用 agent 持续开发的 Electron 应用,12 周演化过程的实际对比:

指标无清洁策略(第12周)有清洁策略(第12周)
构建通过率68%97%
测试通过率61%95%
新会话启动时间60 分钟以上9 分钟
过时工件数量103 个11 个

到第 12 周的差距
- 构建通过率高 29 个百分点
- 测试通过率高 34 个百分点
- 新会话启动时间减少约 85%

每个会话只多花 5 分钟做清理,12 周下来却省了几十个小时的混乱时间。


课程总览——全表

讲次主题核心概念
01模型能力强≠执行可靠能力鸿沟、诊断循环、完成定义
02Harness 到底是什么五子系统:指令+工具+环境+状态+反馈
03仓库作为唯一事实来源知识可见性缺口、全新会话测试、ACID 类比
04把指令拆分到不同文件巨型文件陷阱、中间迷失效应、信噪比 SNR
05跨会话上下文连续上下文焦虑、重建成本、漂移
06独立初始化阶段启动就绪清单、热启动策略
07给 agent 划清边界过度延伸 Overreach、不足完成 Under-finish、WIP=1、VCR
08功能清单是 harness 原语三元组结构、状态机模型、通过状态门控
09防止提前宣告完成三层终止检查、校准偏差、Generator+Evaluator 分离
10E2E 测试组件边界缺陷、架构约束可执行、审查反馈提升
11可观察性双层可观察性、冲刺合同、评估评分标准
12会话结束做好交接清洁状态五维度、质量文档、幂等清理、Harness 简化

一句话总结课程

Harness = 指令 + 工具 + 环境 + 状态 + 反馈。失败的时候先检查 harness,再检查模型。让 agent 真正可靠的唯一途径,是显式、可验证、持久化的工程基础设施,而不是"一个更强的模型"。


来源:本文内容总结自 Learn Harness Engineering 全部 12 讲(中文版),完整内容及引用来源请参见原文。