【免费下载链接】learn-harness-engineering
Harness engineering beginner tutorial, from 0 to 1
导读:本篇文章聚焦 learn-harness-engineering 课程中第十二讲《为什么每次会话都必须留下干净状态》的核心技术主题。你将学会如何把"清洁状态(clean state)"从一句口号变成可执行、可检查、可度量的 Harness 机制——包括五维退出检查清单、双模式清理策略、质量文档、幂等清理脚本,以及由 benchmark-runner.ts 与 cleanup-scanner.ts 构成的可运行参考实现,并结合 Project 06 完整工作环境 中的真实配置逐项落地。
问题:一个不干净的会话交接,会吃掉下一个会话的前 30 分钟
Agent 跑了一整个下午,改了 20 个文件,提交了代码,然后会话结束。下一个会话启动时立刻发现:构建坏了、测试红了、临时调试文件散落各处、功能清单和进度记录没有更新、进度完全不可见。新会话的前 30 分钟全部耗在"搞清楚上一个会话到底做了什么"上。
OpenAI 与 Anthropic 都明确表达了同一结论:长期可靠性取决于操作纪律,而不是单次运行的成功。每次会话结束时的状态质量,直接决定下一次会话的效率。这一讲要回答的问题就是:如何让每个会话在退出时留下干净状态,让下一个会话可以立刻开始干活。
为什么熵增是默认状态
Lehman 的软件演化定律指出:一个持续变更的系统,如果没有人主动管理,复杂性必然增加。对 AI 编码 agent 来说这尤其成立——每次会话都会引入变更,如果不在退出时清理,技术债务会指数级累积。
OpenAI 在 5 个月的 Codex 实验中观察到两个关键现象:
- 模式复制导致漂移:agent 会复制仓库中已有的模式,哪怕那些模式本身不一致或次优。第一个人放了一个杯子在公共区,第二个人心想"反正已经乱了"也放一个,一周后桌上堆满杯子——代码库的退化完全同构。
- 人工清理不可扩展:OpenAI 团队最初每周五花 20% 的工作时间手动清理 "AI slop",显然不可持续。
他们最终沉淀出三管齐下的系统性方案:
- 把"黄金规则"写进仓库:例如"优先使用共享工具包,不要手写 ad-hoc 辅助函数""不要瞎猜数据结构,查类型定义或使用类型安全的 SDK"。这些规则必须是具体的、机械的、可自动检查的。
- 建立周期性清理工作流:一组后台 Codex 任务定期扫描偏离规则的代码、更新质量评分、自动开定向重构 PR,大多数 PR 在一分钟内可审查并自动合并。
- 把人类品味捕获一次,持续执行:评审意见、重构 PR、用户报告的 bug,全部转化为文档更新,或直接编码进检查工具;文档不够用时,把规则提升为可自动检查的代码。
一句话总结:技术债是高息贷款,持续小额还款几乎总是好过攒成一次性爆雷。
清洁状态:远不止"代码能编译"
构建通过只是底线。完整的清洁状态由五个维度组成,缺一不可:
| 维度 | 要求 |
|---|---|
| 构建 | npm run build通过,下一个会话不必先修别人的构建错误 |
| 测试 | 所有测试通过,包括会话开始前就存在的旧测试;验证必须发生在 CI,不是"在我机器上能过" |
| 进度 | 以机器可读工件记录三类信息:已完成的子任务及通过标准、进行中但未完成的子任务及当前卡点、尚未开始的子任务 |
| 工件 | 调试日志、临时文件、注释掉的代码、TODO 标记全部清理干净 |
| 启动 | 标准启动路径可用:环境初始化、代码库加载、上下文获取、任务选择,任何一条断了,新会话都无法自行启动 |
原文档给出了两条互为镜像的流程图,值得原样保留作为会话内审阅的检查标准:
干净交接的检查流(功能工作完成 → 构建通过?→ 测试通过?→ 更新功能清单与进度 → 清理临时工件/调试代码 → 标准启动路径可用?→ 干净交接;任一环节失败则"先修好再退出"并回到构建):
正反两种会话结局的反馈回路(脏退出 → 下个会话先诊断 → 在乱仓库上继续改 → 更乱 → 更脏;干净退出 → 下个会话直接开写 → 无需救火 → 更稳定):
在五个维度里,进度记录与临时工件这两条最容易偷懒,也最伤下一个会话:好的进度记录可以减少 60%~80% 的会话启动诊断时间;而一堆console.log('debug')和// 临时方案,回头改会显著增加下一个会话的认知负担。
六个核心概念
- 清洁状态(Clean state):会话退出时必须同时满足五条件——构建通过、测试通过、进度已记录、无过时工件、启动路径可用。缺一个都不算"做完"。
- 会话完整性(Session integrity):类比数据库事务——要么全部完成并留下清洁状态,要么回滚到上一个一致状态,不存在"做了一半但还行"的中间地带。
- 质量文档(Quality document):持续记录每个模块质量评分的活动工件,是追踪代码库在变强还是变弱的仪表盘,而非一次性评估。
- 清理循环(Cleanup loop):定期执行的维护会话,系统性降低代码库熵。属于常规保养(像定期换机油),不属于紧急修复。
- Harness 简化(Harness simplification):随着模型能力提升,定期移除不再必要的组件——今天必须的约束,三个月后可能只是开销。
- 幂等清理(Idempotent cleanup):清理操作无论执行多少次结果都一样,保证失败重试时依然安全。
"以后再清理"等于永远不清理
最常见的心理陷阱是"这次来不及了,下次再弄"。但下次的 agent 不知道你留下了什么,它必须花大量时间推断"哪些代码是有意的、哪些是临时的"。更糟的是,新会话有自己的任务目标,它不会清理旧账,而是直接在混乱之上开始新工作,再引入更多混乱——这是熵增的正反馈循环。
原文档给出的 12 周实测对比(使用 agent 持续开发的项目,两组配置完全相同,唯一变量是有无清理策略):
无清洁策略:
| 时间 | 构建通过率 | 测试通过率 | 新会话启动时间 |
|---|---|---|---|
| 第 1 周 | 100% | 100% | 5 分钟 |
| 第 4 周 | 95% | 92% | 15 分钟 |
| 第 8 周 | 82% | 78% | 35 分钟 |
| 第 12 周 | 68% | 61% | 60+ 分钟 |
有清洁策略:
| 时间 | 构建通过率 | 测试通过率 | 新会话启动时间 |
|---|---|---|---|
| 第 1 周 | 100% | 100% | 5 分钟 |
| 第 12 周 | 97% | 95% | 9 分钟 |
12 周后两组构建通过率相差 29 个百分点,测试通过率相差 34 个百分点,新会话启动时间相差 85%。这些数字来自原文档所述的实际观察,并非理论推演。
怎么做:六步落地清洁状态
1. 把清洁状态写进"完成"的定义
在 Harness 里明确定义:会话完成 = 任务通过验证 AND 清洁状态检查通过。在 CLAUDE.md 或 AGENTS.md 中写下退出检查清单:
## Session Exit Checklist - [ ] Build passes (npm run build) - [ ] All tests pass (npm test) - [ ] Feature list updated - [ ] No debug code remaining (console.log, debugger, TODO) - [ ] Standard startup path available (npm run dev)仓库给出了一个远超五行的生产级范例:projects/project-06/solution/clean-state-checklist.md 把检查项展开为八个板块——Build、Architecture、Runtime、Logging、Data Integrity、Performance、Repository、Scripts——总计约 40 个可勾选项,例如:
- Build 板块要求
npm run check无类型错误、npm run build成功、无未使用变量/导入告警; - Architecture 板块要求 renderer 代码(
src/renderer/)不得导入fs/path、服务代码不得出现 Electron IPC、所有 IPC channel 定义在src/shared/types.ts; - Repository 板块要求
feature_list.json反映真实功能状态、session-handoff.md在会话结束时更新、claude-progress.md记录当前状态; - Scripts 板块要求
cleanup-scanner.sh报告无过时工件、benchmark.sh跑完全部任务套件、init.sh通过全部验证。
为什么必须有功能清单(feature list):功能清单是一份机器可读文件,记录每个功能项的三列信息——这个功能做什么、用什么命令验证、当前状态(未开始/进行中/已阻塞/已通过)。调度器靠它选下一个工作,验证器靠它判断做完没有,交接器靠它生成进度报告。没有清单,agent 会用自己那套(几乎必然更低)的标准判断"完成"。仓库中的真实样例见 projects/project-06/solution/feature_list.json:每个条目包含id、name、description、status(pass/in-progress/blocked/not-started)、evidence与testedAt时间戳,例如window-launch的 evidence 写明"main.ts 创建 1200x800 BrowserWindow,contextIsolation=true、nodeIntegration=false",让下个会话无需重新考古。
2. 双模式清理策略
把清理拆成两种模式配合使用:
- 即时清理(每个会话结束时):清掉本次会话创建的临时文件、更新功能清单状态、确保构建和测试全绿。原则是"用完就清",像引用计数一样,谁产生的垃圾谁负责。
- 定期清理(每周一次):全面系统扫描,处理累积的结构性问题、更新质量文档、跑基准测试检测漂移。原则是定期全身体检,不让小问题拖成大病。
原文档的 cleanup-loop.md 给出了清理循环的任务清单:扫描过时文档、扫描结构违规、更新质量评分、开定向清理 PR、清理后重跑固定基准切片。这五步正是"定期清理"的落地骨架。
3. 维护质量文档
质量文档是持续更新的评分文件,新会话一打开就知道每个模块的健康状况,并优先处理评分最低的模块。模板:
# Quality Document ## User Authentication Module (Quality: A) - Verification passing: Yes - Agent understandable: Yes - Test stability: Stable - Architecture boundaries: Compliant - Code conventions: Followed ## Payment Module (Quality: C) - Verification passing: Partial (payment callback untested) - Agent understandable: Difficult (logic spread across 3 files) - Test stability: Unstable (2 flaky tests) - Architecture boundaries: Violations present - Code conventions: Partially followed质量文档本质上是 Harness 可观测性的一部分——它把 agent 的运行结果在代码库层面变得可见(对应第十一讲的主题)。
4. 定期简化 Harness
Harness 里每个组件的存在都源于模型在某个方面还无法独立完成;模型能力演进后,这些前提会过时。Anthropic 的实验是直接证据:最初为了 Sonnet 4.5 而引入的 sprint 拆分机制,在 Opus 4.6 能自主做工作分解后就成了多余开销,移除后 builder agent 反而能连续工作两小时以上不跑偏。但 evaluator 是反例——即便 Opus 4.6 能力更强,当任务逼近模型能力边界时,evaluator 仍能抓住缺失功能和 stub 实现。结论是:要不要保留某组件,取决于任务难度与模型能力的相对位置,而不是一刀切。
推荐做法:每月挑一个 Harness 组件,暂时禁用,跑基准任务。结果不退化就永久移除;退化就恢复或换更轻量的替代。更深层的原则是:模型变强,Harness 中有趣的组合没有减少,而是在位移——旧问题被模型吸收,新能力边界又打开新的设计空间。
5. 清理操作必须幂等
清理失败时你会重跑一遍,因此清理脚本必须幂等:执行一次与执行一百次结果相同。
# Idempotent cleanup operations rm -f /tmp/debug-*.log # -f ensures no error when files don't exist git checkout -- .env.local # Restore to known state npm run test # Verify cleanup didn't break anything6. 高吞吐量下调整合并哲学
当 agent 每天开出 3.5 个甚至更多 PR 时,减少阻塞型合并门禁是正确选择:PR 应当短命,测试 flake 用后续运行修正,而不是无限期卡住进度。判断标准是修 bug 的平均成本 vs 等待人工审查的平均成本——当前者低于后者时,快合并 + 快修复优于慢确认。注意前提:这条规则只在高产出环境成立,低吞吐环境里快速合并没有意义。
参考实现一:benchmark-runner.ts —— 用固定基准切片检测漂移
原文档配套代码 benchmark-runner.ts 提供了一个可直接运行的基准执行器,用于支撑"清理后重跑固定基准切片"与练习 2 的对照实验。它模拟执行一组基准任务并输出对比报告,核心结构如下:
- 任务定义:
BenchmarkTask接口包含id、name、category、passCriteria(通过标准数组)、expectedDurationMs(期望耗时)与模拟的actualDurationMs/actualPass。内置 8 条任务,覆盖四类场景:文档导入管道(markdown/PDF 导入)、Q&A 管道(含"无相关文档时的优雅降级")、安全(并发用户隔离、API 限流)与可靠性(重启后会话连续性)。 - 执行模拟:
executeBenchmark()把每条任务映射为BenchmarkResult,统计criteriaPassed/criteriaTotal、计算durationDelta(实际-期望耗时差)。 - 报告输出:表格列出每条任务的 ID/名称/类别/通过与否/标准达成数/期望与真实耗时/偏差;对失败任务单独输出
failureReason(例如 "PDF text extraction failed on page 3 -- encoding issue"、"Model hallucinated a citation instead of saying 'no results'"、跨用户数据泄露 + 超 SLA);最后按类别聚合通过率并给出总体通过率。
运行方式(仓库内相对路径):
npx tsx docs/en/lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/benchmark-runner.ts这套切片的用法契合第十二讲的核心实践:把关键路径编码为带通过标准与期望耗时的固定任务集,每次清理循环后重跑,任何actualPass: false或耗时漂移都是"代码库在退化"的早期信号。配套的 benchmark-comparison-template.md 给出了两种 Harness 配置的对照模板(completion rate、average retries、bugs caught before human review),并提示回答两个问题:哪个 Harness 改变了结果?哪个 Harness 改变了获得结果的成本?
参考实现二:cleanup-scanner.ts —— 过期工件与违规扫描器
配套的 cleanup-scanner.ts 是"即时清理"与"定期清理"共用的扫描器,用 Node 原生fs/path实现,无需第三方依赖。它把扫描项组织为八类检查,每项带严重级别(critical/warning/info)与描述:
| 类别 | 检查项 | 严重级 |
|---|---|---|
| Stale Artifacts | *.tmp/*.bak/*.swp/~临时文件 | warning |
| Stale Artifacts | 源码目录(src/、lib/、app/)中的.log调试文件 | warning |
| Dead Code | src/lib/app中.ts/.tsx/.js文件前 50 行内的TODO:/FIXME:/HACK:/XXX:标记 | info |
| Structural Violations | 缺少.gitignore | warning |
| Structural Violations | src/dist、src/build等编译产物混入源码 | critical |
| Structural Violations | src/lib/app/test下的嵌套node_modules | critical |
| Session Cleanliness | WIP.md/IN_PROGRESS.md/scratch.ts/debug.ts/temp.ts等未完成会话痕迹 | info |
| Session Cleanliness | 空的src/lib/app/test/docs目录 | info |
| Configuration | 源码中的.env/.env.local/.env.production/.env.staging(可能含密钥) | critical |
扫描器实现要点:findFiles()递归遍历时限制深度(depth > 4即停止)并跳过node_modules/.git/dist/build/.next/coverage;scanForPatterns()只读 TS/TSX/JS 文件且只看前 50 行,避免把"正文里提到 TODO"误报。最终输出表格报告与汇总(Critical/Warnings/Info/Clean 计数),若存在 critical 问题会打印 ACTION REQUIRED;全部干净则输出 "Project is in a clean state."。
# 默认扫描当前目录 npx tsx docs/en/lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/cleanup-scanner.ts # 或指定目录 npx tsx docs/en/lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/cleanup-scanner.ts /path/to/project注意:这是仓库为第十二讲提供的教学参考实现(模拟执行 + 启发式扫描),实际项目落地时建议把同样逻辑写入 CI 或项目脚本。
生产级对照:Project 06 的完整 Harness 面
第十二讲不是孤立的理论——它直接支撑了 Project 06(搭建一套完整的 agent 工作环境,Capstone 项目)。该项目的 solution 目录把本讲所有概念都变成了真实文件:
- clean-state-checklist.md:上文已拆解的生产级退出检查清单;
- feature_list.json:机器可读功能清单,每个功能带 status/evidence/testedAt;
- cleanup-scanner.sh:面向应用数据目录的真实一致性扫描器,检查五类问题——孤儿内容文件(有 content 无 metadata)、悬空 chunk 文件(有 chunks 无 index 条目)、缺失内容文件(有 metadata 无 content)、不一致元数据(status=indexed 但无 chunk 文件)、过期 Q&A 引用(历史记录引用已删除文档)。脚本输出 CLEAN 或 ISSUES FOUND,后者给出推荐动作(用应用内 Reset 清空数据 → 从
data/sample-documents/重新导入 → 重跑扫描验证); - 另有 benchmark.sh、check-architecture.sh 支撑构建/架构/性能维度,以及 session-handoff.md 承载交接报告。
与之对照,starter 目录刻意只保留基础 AGENTS.md,没有feature_list.json、没有session-handoff.md、没有清洁状态清单、也没有基准脚本——这正是第十二讲要展示的"弱 Harness"基线。你可以用两个脚本bash scripts/benchmark.sh与bash scripts/cleanup-scanner.sh跑出证据,对比质量文档里的评分差异。
核心要点
- 清洁状态是会话完成的必要条件——它是"完成"定义的一部分,不是可选的额外家务。
- 五个维度缺一不可:构建、测试、进度、工件、启动,每一条都要在退出时显式检查,不能靠"感觉应该没问题"。
- 功能清单让 agent 知道"做完"的标准——没有清单,agent 用自己的标准判断完成,那个标准几乎一定更低。
- 质量文档让代码库健康可追踪——知道哪里在退化才能主动修复;不知道问题在哪,就只能等它爆发。
- 定期简化 Harness:每月挑一个组件禁用后跑基准,结果不退化就永久移除。
- "以后再清理"等于永远不清理:熵增是默认方向,只有主动清理能对抗它。每次多花五分钟,是长期回报最高的投资。
练习建议
- 设计清洁状态检查表:为你的代码库设计涵盖五个维度的会话退出检查表,连续 5 个会话坚持执行,记录每个维度的违反次数。
- 基准对比实验:用固定任务集分别跑"要求清洁状态"与"不要求"两种 Harness,比较完成率、重试次数与漏网 bug 数(可直接复用 benchmark-runner.ts 和 benchmark-comparison-template.md)。
- Harness 简化实践:禁用某个 Harness 组件跑基准,决定保留、移除还是替换。
- 质量文档入门:为 3~5 个核心模块打分(A/B/C/D)并标注扣分原因,连续 4 周每周更新,观察质量走势。
【免费下载链接】learn-harness-engineering
Harness engineering beginner tutorial, from 0 to 1
相关推荐
learn-harness-engineering 实战:构建会话级清理循环(Cleanup Loop),让每个 Agent 会话都从干净状态开始
learn harness engineering 实战:构建会话级清理循环(Cleanup Loop),让每个 Agent 会话都从干净状态开始 本篇文章以
绝区零一条龙自动化工具:智能游戏辅助的完整解决方案
绝区零一条龙自动化工具:智能游戏辅助的完整解决方案 绝区零一条龙(ZenlessZoneZero OneDragon)是一款专为《绝区零》游戏设计的全自动辅助工
构建 Harness 清理循环(Cleanup Loop):让每次 Agent 会话都从干净状态起步
构建 Harness 清理循环(Cleanup Loop):让每次 Agent 会话都从干净状态起步 导读 本篇文章基于 learn harness engin
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考