第6课

实用技巧 — 知道这些就能指挥AI

棘轮的核心是一句话:每次添加功能都必须通过hurl –test才能继续。 这就是棘轮。就像齿轮不会倒转一样,通过一次的测试不会坏。

“不要相信’全部完成’。“AI是乐观的。527个函数只做了40个就宣布"完成”。用数字来确认——TODO为0才算结束。在那之前都不算。

给智能体布置批量任务时:

对智能体说:“运行tsma next,给TODO函数写测试。测试通过就用tsma next进入下一个函数。重复直到出现All functions complete!”

这个循环就是全部。tsma next决定下一个任务,验证器(go test、hurl –test等)判定是否通过,机器宣布"结束”。AI只负责生成。

不要指示方法,要指示契约。不是"做TDD"而是"这个测试必须通过"。试图教方法论反而造成混乱。给出必须达成的条件就行。

智能体在会话中途崩溃也没关系。再运行tsma next就从最后处理的函数之后继续。进度被保存。

快速体验

用Claude Code打开第1课应用,这样指挥:

对智能体说:“按顺序添加3个功能。每添加一个功能都要运行hurl –test tests/,所有现有测试全部通过后才能进入下一个功能。失败就修好再继续。”

智能体工作时观察:

  • 第2个功能会不会打破第1个的测试?——打破了就修好才能继续
  • 第3个会不会打破第1、第2个?——同样修好才继续
  • 完成标准不是"完成了"的宣言而是测试通过

这就是棘轮。第3课的Hurl已经在充当棘轮的验证器了。


为什么要这样指挥

前5课总结

第5课学了Reins Engineering的三根支柱。用确定性契约定方向,用棘轮锁定,分离决策和实现。今天深入挖掘三根支柱中最核心的棘轮。

棘轮是Reins Engineering的技术心脏。理解了这个,其余全部跟着来。

“全部完成了”

还记得第5课的40 vs 527案例吗。同一个模型、同一个项目、同样527个函数,自主智能体停在40个(7.6%),应用棘轮就完成527个。

第5课解释了为什么会有这种差异。这节课分解棘轮如何强制做到这一点的结构。

LLM擅长生成。但完成判定不可信赖。

那怎么办?

棘轮扳手

工具箱里有棘轮扳手。拧螺栓用的工具。齿只能单向咬合。转就往前走,松手就停住但不会倒转。

这个机制是关键。

项目1:机械验证 → PASS → 锁定。下一个。
项目2:机械验证 → FAIL → 反馈。重试。
项目2:机械验证 → PASS → 锁定。下一个。
...
项目N:PASS → 全部完成。停止。

只有三条规则:

  1. 一次只展示一个项目。 智能体不能选择跳过。
  2. 通过才能继续。 不能跳过。
  3. 全部通过就停止。 “全部完成"由机器说。

应用这三条规则,之前停在40的智能体就跑到了527。

棘轮强制的是什么 — 完成判定的移交

第5课的核心是"区别不在模型性能,而在谁判定’结束’"。这节课把"机器判定的结构"分解到零件层面。

把完成判定从智能体手中夺走,交给机器。

这是贯穿本课全部内容的核心。

棘轮的一句话定义

把每次产出不同结果的AI,放进始终按相同规则运作的清单中。

展开来说:

角色谁来担当
生成(写代码、写测试)LLM
判定(通过还是失败)验证器(go test、validate等)
进度管理(下一个是什么、结束了没)棘轮(CLI)

氛围编程中这三个角色全交给了LLM。代码LLM写,做得好不好LLM判断,下一步做什么LLM决定。

Ratchet Pattern把这三者分离。LLM只做生成。其余机器来。

五个原则

Ratchet Pattern有五个原则。缺一个就不是棘轮。

原则1. 终止条件是机械的

pass/fail。不是"looks good”。

  • go test通过就是PASS。
  • 覆盖率达标就是PASS。
  • validate错误为0就是PASS。

没有主观判断的余地。“还不错吧?“不是判定。要么0要么1。

原则2. PASS不可变

通过的项目不会重新打开。不会倒退。剩余工作绝不会增加。

今天做的明天不会被拆。只能前进。

这里有个重要区别。跑过"24小时智能体"吗?没有终止条件运行的智能体今天加的抽象明天删掉后天又加回来。棘轮不允许这种震荡。

原则3. LLM只做生成

生成代码、编写测试、提出修改方案——这是LLM的角色。

修什么?机器决定。 通过没有?机器判定。 下一个是什么?机器告知。 结束了没?机器宣布。

AI不是定方向的,而是只按指示做东西的。

原则4. 剥夺智能体的终止判断权

LLM说"完成了"就停在40。 机器说"完成了"就停在527。

棘轮存在的意义用这一行就能概括。

原则5. 验证器必须是确定性的

不是什么都能当验证器。

能当验证器不能当验证器
go test“looks cleaner”
覆盖率测量“seems better”
AST验证“more scalable”
schema diff“clean architecture”
Hurl测试“整体看起来还行”

验证器的四个条件:

  1. 相同输入总是相同结果(确定性)
  2. 不需要人看(机器可检查)
  3. 中断后能续接(可恢复)
  4. 告诉你在哪里为什么失败(局部化反馈)

不满足这四个条件,棘轮的齿就咬不上。

TDAD研究 — “做TDD"指示适得其反

还记得第5课介绍的TDAD研究吗。这里更深入地探讨它与棘轮的关系。

软件工程教科书写着"TDD(测试驱动开发)是好的”。先写测试,后写代码。

但对AI智能体说"做TDD"会怎样?

TDAD(Test-Driven AI Development)研究实测了这个。结果令人震惊。

指示回归率
“做TDD”(方法论指示)比基准恶化
“这个测试必须通过”(契约指示)回归减少70%

“做TDD"指示的是方法。LLM模仿TDD形式反而更混乱。先写测试又写不了代码,写代码又覆盖测试。

“这个测试必须通过"指示的是契约。LLM知道该做什么很明确。让这个测试通过就行。

教训是:

不要指示方法,指示契约。

不是"先写Hurl测试再写代码”。而是"这个Hurl测试必须通过”。不要试图教LLM方法论。给出必须达成的条件就行。

棘轮正是按这个原理运作。不是"做TDD"而是"这个项目必须PASS”。

tsma — 棘轮的实战工具

理论理解了,来看实战工具。

tsma是把Ratchet Pattern应用到项目的CLI工具。支持Go、TypeScript、Python。做四件事:

  1. 函数索引 — 找到项目的所有函数
  2. 测试检测 — 检查每个函数是否有测试
  3. 覆盖率测量 — 测量测试覆盖到函数的哪些部分
  4. 反馈生成 — 用行号告知未覆盖的分支

智能体需要知道的命令只有一个

$ tsma next

这一条命令驱动整个循环:

$ tsma next          # 显示下一个没有测试的函数
  → 智能体编写测试
$ tsma next          # 检测新测试,运行,测量覆盖率
  → 100%?PASS。下一个函数。
  → <100%?用行号告知未覆盖的分支。
$ tsma next          # 重新测量修改后的测试
  → PASS或标记DONE,进入下一个。

重复直到"All functions complete!“出现。

给智能体的指示只需6行:

1. 运行tsma next
2. 如果是TODO — 读函数并写测试
3. 如果测试失败 — 读错误并修改测试
4. 如果显示未覆盖分支 — 添加覆盖那些分支的测试
5. 如果是PASS/DONE — 下一个函数自动显示
6. 重复直到"All functions complete!"

6行就是全部。其余CLI强制执行。

527个函数的实测结果

在实际项目(527个函数)上应用tsma的结果:

结果数量比例
PASS(100%分支覆盖率)24646.7%
DONE(尽力而为,结构限制)28153.3%
TODO(未处理)00.0%

TODO为0。 527个函数全部处理完毕。

246个函数达到了100%分支覆盖率。其余281个为什么没到100%?

这不是LLM的局限,而是代码可测试性问题。有些函数由于代码结构物理上无法测试。直接依赖外部服务(短信发送、支付接口等)的函数在测试环境中无法替代那些服务。

tsma对这种情况再尝试一次后接受为DONE。这很现实。

重要的是TODO为0这个事实。棘轮推着智能体跑到底,强制达到"一个不漏全部尝试了"的状态。

反馈是梯度信号

棘轮的真正力量不仅在于判定"通过/失败”。失败时告诉什么才是决定性的。

弱反馈:    "测试失败"               → LLM无方向地修
中等反馈:  "覆盖率65%"              → LLM大致加强
强反馈:    "line 41, 44, 70未覆盖"  → LLM精确覆盖那些分支

实际项目中验证的数字:

没有反馈:  停在60~70%覆盖率
有反馈:    达到100%(可达函数范围内)

同一个模型。“line 41 not covered"这一行充当了梯度信号。

用深度学习来类比:训练神经网络时,如果损失函数只说"错了"学不到东西。需要用梯度告诉"在哪里错了多少"权重才能精确调整。

LLM修改代码也一样:

  • “测试失败” = 只告诉了loss。没有方向。
  • “line 41未覆盖” = 告诉了梯度。精确修正成为可能。

反馈精度越高,LLM修正准确率越高,循环迭代次数越少,token成本越低。

Symbolic Feedback Loop — 棘轮的心脏

第5课学的Symbolic Feedback Loop是棘轮的心脏。LLM生成,确定性工具判定,结果反馈给LLM。

在棘轮中这个循环具体怎么运作。以tsma为例:

  1. tsma next指定下一个函数(机器定方向)
  2. LLM生成测试(概率性生成)
  3. go test判定pass/fail(确定性反馈)
  4. 失败时返回"line 41未覆盖"这个事实(梯度信号)
  5. LLM修改 → 回到3
  6. 通过时棘轮锁定 → 回到1

第5课说"反馈拓扑比模型IQ重要”。棘轮是在项目级别强制执行这个拓扑的物理装置。

智能体会死。进度会活。

说说现实。智能体必然会崩溃。

  • 碰到token限制。
  • 网络错误。
  • 会话断开。
  • 上下文填满。

527个函数不可能在一个会话中全部处理。那怎么办?

棘轮把进度状态持久化存储。tsma记录在.tsma/session.json中。

智能体A:处理1~200号函数 → token限制死亡
智能体B:tsma next → 从201号继续
智能体C:tsma next → 从401号继续

智能体是一次性的。进度是累积的。

你用Claude Code时会话断了,在新会话中运行tsma next就从最后处理的函数之后继续。session.json就是检查点。

这是"跑24小时智能体"的根本区别。24小时智能体会话断了要从头来。棘轮从断的地方继续。

换验证器就成了不同的工具

棘轮不依赖特定验证器。只换验证器就变成完全不同的用途。

棘轮 + 验证器用途
棘轮 + go test + coverage函数级测试生成
棘轮 + hurl --testAPI端点验证
棘轮 + yongol validateSSOT规范一致性
棘轮 + filefunc validate代码结构规则强制
棘轮 + schema diff数据库迁移

模式只有一个。验证器决定领域。

第4课学的yongol validate也能当棘轮的验证器。第3课学的Hurl也能当棘轮的验证器。不是工具变了,而是同一个模式插入不同的验证器。

从40到527的三步

整理理论是三步:

第1步:列出项目

让智能体"修整个项目"就成了广泛探索。LLM迷失方向。换成列出项目。“527个函数。从1号开始。”

tsma自动做这个工作。索引项目的所有函数并生成列表。

第2步:一次一个,验证着前进

“给这个项目写测试”——这是广泛探索。 “给calculateTax函数写测试”——这是局部修正。

LLM局部修正比广泛探索更强。棘轮按LLM的强项分解工作。

第3步:机器宣布"结束”

智能体说"全部完成"也忽略。tsma status显示"TODO: 0"才算结束。在那之前都不算。

$ tsma status

527 functions
PASS:  246 (46.7%)
DONE:  281 (53.3%)
TODO:    0 (0.0%)

为什么对氛围编程者重要

你不读代码。不读代码就没法确认AI是不是真的全做完了。

但用棘轮就不需要确认。

  • “TODO是0?” — 完了。
  • “TODO是37?” — 没完。

只看一个数字就行。不需要读代码。不需要理解测试。机器判定、机器报告。

这就是棘轮对氛围编程者特别强大的原因。越不懂代码,越需要依赖机械验证。棘轮让这种依赖变得安全。

类比:火车和铁轨

氛围编程是火车。快。一句"做"代码就涌出来。

但没有铁轨就脱轨。

AI编程工具全都在集中精力让火车更快。更大的模型、更聪明的智能体、更好的提示。但火车越快脱轨的损害越大。

棘轮是铁轨。LLM生成代码(火车),CLI定义"到这里为止,下一个是那里"(铁轨)。LLM的生成能力保持不变,但方向和终点由机器强制。

很多人在造火车。铺铁轨的人几乎没有。

核心总结

  1. LLM擅长生成但判断不了完成。 在40时说"完成了"。
  2. 把完成判定交给机器就能完成527。 这就是Ratchet Pattern。
  3. 不要指示方法,指示契约。 不是"做TDD"而是"这个测试必须通过"。
  4. 反馈的精度决定修正的准确度。 “line 41未覆盖"比"失败"有效10倍。
  5. 智能体会死但进度被保存。 session.json就是检查点。
  6. 换验证器就成了不同的工具。 模式只有一个,验证器决定领域。

下一课第7课深入挖掘为什么棘轮有效的原理。LLM的谄媚偏差如何成为棘轮的动力,以及提示和验证器应该按什么比例设计。

实操:用棘轮完成20个测试(tsma)

目标: 从现有项目选择20个函数,用tsma应用棘轮完成20/20。

准备物: 安装tsma,项目(Go、TypeScript、Python任一)

安装: 告诉智能体"帮我装tsma”。tsma --help有输出就安装完成。

tsma支持Go、TypeScript、Python项目。第1课的应用用什么语言都行。

步骤1:索引

$ cd your-project
$ tsma next

首次运行时tsma索引项目的所有函数。显示当前状态。

TODO: calculateTax (handler/tax.go:15)
No test file found.

步骤2:给智能体棘轮指示

在Claude Code中这样指示:

运行tsma next,给TODO函数写测试。
测试通过就用tsma next进入下一个函数。
如果显示未覆盖分支就添加覆盖那些分支的测试。
重复直到"All functions complete!"出现。

步骤3:观察

智能体工作时观察:

  • 智能体试图跳过吗? → 棘轮强制它停在当前函数
  • 有反馈和没反馈时覆盖率差多少? → 行号反馈后急升
  • 几次就转为PASS了? → 大多1-2次

步骤4:确认结果

$ tsma status

TODO为0就完成了。20个函数全有测试。

对比实验(可选):

对同样20个函数,不用tsma只对智能体说"给这20个函数写测试"。看它停在几个。


相关文章

Reins Engineering 全部课程

课程标题
第1课如何指挥AI
第2课如何不信任AI
第3课不会崩溃的应用
第4课将决策移出代码
第5课有缰绳的AI
第6课通过就锁定
第7课翻转谄媚
第8课智能体的工厂
第9课代码之外的自动化
第10课数据的法则

参考资料来源

  1. TDAD,ACM AIWare 2026 — “做TDD"过程指示(6.08%→9.94%)恶化回归,提供具体测试文件作为上下文(6.08%→1.82%)减少70%回归。