AI渐进编程之二:什么时候该给 AI 编程加一层 Harness?
上一章我们先把最轻的情况说清楚了:
如果任务很小,直接 prompt 就够了。
但一旦任务开始变复杂,问题就不再只是“模型会不会写”,而是“模型能不能在边界内持续做对”。
这时候,才需要给 AI 加一层 Harness。
在这本书里,Harness 不是一个花哨的概念,它就是放在模型外面的控制层。
它负责把任务范围、允许动作、验收条件和失败反馈组织起来,让 AI 不只是“能输出”,而是“能在约束下完成任务”。
更重要的是,Harness 不是永远加厚的控制层。
它先是为了救场,等任务稳定、模型能力增强、测试和工具链变强之后,它应该逐步收缩到最小必要控制。
也就是说,本书讲的不是“控制越多越好”,而是“什么时候该加,什么时候该收”。
1. 以修改程序为例
程序项目的常见结构:
- 主代码(Main Code):负责核心业务逻辑,比如结算、登录、路由或数据处理。
- 测试(Tests):验证修改后行为是否仍然正确。
- 配置(Config):控制运行参数、环境和依赖。
- 日志(Logs):记录修改过程和验证结果。
- 问题记录(Open Issues):保存暂时不能解决,但不能忘掉的问题。
比如一个空购物车结算问题,通常会涉及:
checkout/service.py:结算逻辑tests/test_checkout.py:回归测试revision_log.md:修改日志open_issues.md:开放问题current_task.md:当前任务
这类任务一开始看起来像一个小修补,
但只要开始涉及多文件、验证、回写和后续跟进,它就已经不再只是“改一行代码”了。
2. Harness 解决的不是写代码能力,而是控制问题
如果只靠 prompt,AI 可以开始做事,但它不一定知道:
- 当前任务到底限定在哪个文件
- 哪些内容可以改,哪些不能改
- 改完以后怎么判断通过
- 失败以后该不该继续
这就是为什么本书强调:
Prompt解决“怎么说”,Harness解决“能不能做,做完怎么验收”。
这两者不是同一层问题。
在轻量任务里,prompt 足够。
但当任务涉及多轮修改、跨文件影响、失败恢复和结果验收时,只靠 prompt 就不够了。
另外,当前阶段的 AI 编程,很多时候并不能像人类在 IDE 里那样单步调试、看变量、设断点、反复观察。
所以我们只能通过日志、Hook、状态文件和验收,把执行过程“照亮”。
这看起来有点像回到最原始的 printf 调试,
但本质上不是倒退,
而是在为黑盒建立可观测性。
也就是说,Harness 不只是控制边界和验收,
它还负责把黑盒打开一点:
- 在关键点插入观测
- 在失败时留下轨迹
- 在下一轮继续时保留事实
没有这些观测点,AI 往往只能继续猜;
有了这些观测点,项目才有机会慢慢收敛。
3. 什么时候该引入 Harness?
判断标准不是看任务本身永远有多复杂,而是看当前模型 + 当前工具链 + 当前流程能不能稳住这个任务。
3.1 任务开始跨文件
如果一轮修改只改一个局部,还能直接处理。
但如果任务开始影响多个文件,或者修改可能波及正文、状态、日志和问题记录,那就需要 Harness。
因为这时,AI 很容易:
- 顺手改到授权范围外
- 忘记任务只允许改某个文件
- 把局部任务扩大成全局改动
3.2 任务开始有风险
当修改会影响:
- 代码库的稳定性
- 测试结果
- 接口兼容性
- 状态文件的正确性
这类任务就不能让模型自由扩散。
必须先定义边界,再让它动。
3.3 任务需要持续推进
如果一次修改就能结束,直接 prompt 就行。
但如果任务需要反复检查、调整和继续,那就不能只停留在一次性输出。
这时 Harness 的作用,就是让每一步都在可检查的范围内推进。
4. Harness 在本书里到底管什么?
这本书里的 Harness,至少管四件事:
4.1 当前任务
当前任务写在 current_task.md 里。
它不是聊天记录,而是当前这一轮真正要做什么。
例如:
- 只修改结算逻辑
- 不改认证模块
- 修改后更新
revision_log.md - 发现范围外问题就写入
open_issues.md
4.2 允许范围
Harness 要知道这轮能动哪些文件,不能动哪些文件。
这不是形式主义,而是为了防止模型把局部任务做成扩散修改。
4.3 结果检查
做完以后要检查:
- 有没有越界修改
- 行为是否符合预期
- 回归测试是否通过
- 状态文件有没有同步更新
4.4 失败记录
如果这一轮失败了,不能只停在“没做对”。
还要把失败轨迹留下来,供下一轮继续用。
这就是为什么书里会有:
project_map.mdcurrent_task.mdrevision_log.mdopen_issues.md
它们不是额外负担,而是让下一轮继续推进的基础。
不过这里也要注意:
这些控制并不是永远都要一样重。
随着模型能力增强、测试更成熟、工具链更稳定,Harness 里的一部分职责会逐步被测试框架、静态规则或模型本身吸收。
所以 Harness 要保持最小必要控制,而不是无限加厚。
5. 贯穿全书的例子:修复空购物车结算问题
这本书一直用一个例子:
修复空购物车结算报错,避免影响已有下单流程。
这个例子很适合说明为什么要加 Harness。
任务输入
“修复空购物车结算报错,但不能影响已有下单流程。”
真正风险
模型很容易为了“修好”顺手去改:
- 结算服务
- 订单状态
- 支付流程
- 相关测试
- 甚至配置和文档
如果没有 Harness,这种扩散很难被及时拦住。
有 Harness 以后
Harness 会先告诉模型:
- 只允许改结算相关文件
- 其他模块不能动
- 修改后必须检查 diff
- 结果要写回状态
这样,模型不是在整个代码库里自由游走,而是在一个明确边界里完成任务。
6. 为什么 Harness 会让系统更容易收敛?
因为它把“无边界试错”变成了“有边界循环”。
没有 Harness 的时候,模型可能这样跑:
- 改一点
- 看起来不对
- 再换个说法
- 再改一点
- 继续扩大范围
最后系统虽然还在动,但不一定是在收敛。
有 Harness 之后,流程会变成:
- 读取
current_task.md - 只在允许范围内动作
- 修改后检查结果
- 把结果写回
revision_log.md - 如果发现范围外问题,写入
open_issues.md - 下一轮基于新状态继续
这时,循环不是空转,而是在把任务往前推。
7. 一个最小 Harness 可以长什么样?
本书不主张一上来就把系统做得很重。
一个最小 Harness,最关键的是把职责分开。
context:
- current_task.md
- project_map.md
- relevant files
permissions:
allow:
- checkout/service.py
- tests/test_checkout.py
- revision_log.md
- open_issues.md
deny:
- auth/*
- payment_gateway/*
- docs/*
- unrelated modules
checks:
- diff scope
- regression test
- behavior preservation
- state update
这个结构的重点不是 YAML,
而是它表达了本书的核心思想:
- 任务要明确
- 边界要明确
- 验收要明确
- 会影响下一轮的事实要回写
同时也要记住:
这类控制不是永远固定不变的。
有些检查最后会被测试吸收,有些边界会被规则固化,有些临时状态会被清理掉。
Harness 的目标不是把系统锁死,
而是先把项目救回来,再慢慢收缩到最小必要控制。
8. 什么时候该收缩控制层?
这里要讲严谨一点。
本书不是说任务结束后就“回到什么都不管的轻量模式”,
而是说:
- 临时状态要清理
- 已验证的长期状态要保留
- 控制层要根据后续任务风险降级
- 只保留当前任务真正需要的最小约束
也就是说,收缩的不是“知识”,而是“临时负担”。
可以清理的部分
- 一次性的草稿
- 中间产物
- 已经过期的试错轨迹
- 当前轮不再需要的临时缓存
应该保留的部分
- 已验证的项目地图
- 已确认的任务边界
- 需要长期追踪的
open_issues - 对后续任务仍然有效的验收规则
所以,更准确的说法是:
任务完成后,清理临时状态,保留已验证的长期状态;控制层按任务风险降级,但不丢掉已经确认的规则和事实。
这样就不会让人误解成“系统又回到混沌状态”。
9. 本章小结
这一章想讲清楚的,其实就是一句话:
Harness 不是为了让 AI 更复杂,而是为了让 AI 在复杂任务里不乱跑。
它把任务范围、允许动作、结果检查和失败记录组织起来,让模型可以在边界内继续推进。
而当任务结束后,应该清理临时状态,保留已经验证过的长期状态,再按风险决定是否降级控制层。
这也就是本书从 prompt 走向 Harness,再走向 state 的原因。
下一章,我会继续讲:什么时候需要引入状态,以及为什么状态会让循环更容易收敛。
更多推荐


所有评论(0)