
实用技巧 — 知道这些就能指挥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 → 全部完成。停止。
只有三条规则:
- 一次只展示一个项目。 智能体不能选择跳过。
- 通过才能继续。 不能跳过。
- 全部通过就停止。 “全部完成"由机器说。
应用这三条规则,之前停在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测试 | “整体看起来还行” |
验证器的四个条件:
- 相同输入总是相同结果(确定性)
- 不需要人看(机器可检查)
- 中断后能续接(可恢复)
- 告诉你在哪里为什么失败(局部化反馈)
不满足这四个条件,棘轮的齿就咬不上。
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。做四件事:
- 函数索引 — 找到项目的所有函数
- 测试检测 — 检查每个函数是否有测试
- 覆盖率测量 — 测量测试覆盖到函数的哪些部分
- 反馈生成 — 用行号告知未覆盖的分支
智能体需要知道的命令只有一个:
$ 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%分支覆盖率) | 246 | 46.7% |
| DONE(尽力而为,结构限制) | 281 | 53.3% |
| TODO(未处理) | 0 | 0.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为例:
tsma next指定下一个函数(机器定方向)- LLM生成测试(概率性生成)
go test判定pass/fail(确定性反馈)- 失败时返回"line 41未覆盖"这个事实(梯度信号)
- LLM修改 → 回到3
- 通过时棘轮锁定 → 回到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 --test | API端点验证 |
棘轮 + yongol validate | SSOT规范一致性 |
| 棘轮 + 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的生成能力保持不变,但方向和终点由机器强制。
很多人在造火车。铺铁轨的人几乎没有。
核心总结
- LLM擅长生成但判断不了完成。 在40时说"完成了"。
- 把完成判定交给机器就能完成527。 这就是Ratchet Pattern。
- 不要指示方法,指示契约。 不是"做TDD"而是"这个测试必须通过"。
- 反馈的精度决定修正的准确度。 “line 41未覆盖"比"失败"有效10倍。
- 智能体会死但进度被保存。 session.json就是检查点。
- 换验证器就成了不同的工具。 模式只有一个,验证器决定领域。
下一课第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课 | 数据的法则 |
参考资料来源
- TDAD,ACM AIWare 2026 — “做TDD"过程指示(6.08%→9.94%)恶化回归,提供具体测试文件作为上下文(6.08%→1.82%)减少70%回归。