图片:AI 生成
把大活交给过 AI 智能体的人都知道。循环崩塌的地方永远是同一个:模型自己宣布"我做完了"的那一刻——而实际上并没有完。
reins 是一个把这份完成宣告权从 AI 手里夺走、交给机器的Quest CLI 框架。它把工作清单像游戏里的任务一样拆成一个个条目,一次交给 AI 一条,而"做完了没有"不听 AI 的话,由机器检验来裁决。在它的心脏,坐着一个叫**回合(turn)**的小单位。
有两个词会反复出现,先把它们备好。
- 门(gate) —— 机械地检验提交物、裁定 PASS 或 FAIL 的检查器。不是人的印象分,也不是 AI 的自我评价。
- 棘轮(ratchet) —— 只朝一个方向转的齿轮。我们用它来表示:一旦通过而被锁定的条目,永远不会再被打开。
这篇文章从头到尾跟随一个回合,看它究竟经历了什么。回合看起来很小,但拆开来看,它是 reins 的全息缩影。
Reins Engineering 的六大核心要素
把 reins 立足的工程压缩成一句话,就是:**把完成宣告权从 AI 移交给确定性机器门的工程。这里的"确定性"不是什么难词,它的意思是相同的输入永远产生相同的结果。**测试要么通过要么失败,昨天和今天的裁决不会随心情而不同。
在提示词工程(挑选词句)→ 上下文工程(供给语境)→ 挽具工程(筑起围栏)的谱系里,Reins 是那根定方向的缰绳。这门工程由六个要素装配而成。
| # | 要素 | 一句话 | 正典句 |
|---|---|---|---|
| 1 | 机器裁定的完成 | 完成条件必须能让机器以 yes/no 作答,裁定也由机器执行——剥夺 AI 宣布自己完工的权力 | “完成由门裁定,而不是由谁声称” |
| 2 | 确定性反馈 | 给事实,不给意见——“哪里、本应是什么、实际是什么"成为指向修正的信号 | “给它意见它就谄媚,给它事实它就修正” |
| 3 | 方向性上下文(手册 + 示例) | 如果说反馈是校正信号,手册与示例就是方向信号——两者互不可替代 | “瓶颈不是智能,而是上下文” |
| 4 | Ratchet Pattern(契约锁定) | 通过的条目不可变,剩余工作量只减不增——完工由结构保证 | remaining(t+1) ≤ remaining(t) |
| 5 | 进度持久化 | 进度活在进程之外(磁盘上)——就算 AI 死了,进展仍在 | “Agents are disposable; progress is cumulative.” |
| 6 | cheese 防御(领域门) | 即便是机器检验,只看外壳也会被投机取巧攻破——门必须重新验证其领域的真实事实 | “门有自己的领域” |
表里的术语还觉得陌生也没关系。回合是这六者在一个周期之内相会的最小单位,所以把一个回合从头跟到尾,六个要素就会各就各位地全部登场。先把地图画好:回合的第一步 compose 装配方向性上下文与确定性反馈;judge 给出机器裁决(cheese 防御正是这道门的设计品质);record 锁上棘轮并把进度持久化。
什么是 Reins Turn?
Reins Turn 是**对一个任务条目的一次尝试,以生成 → 裁定 → 记录收束的、reins 的最小执行单位。**循环不过是回合的重复,任务的进度不过是回合的累积。所以定义一行就够了。
Turn N = 第 N 条被记录的 Attempt。未被记录的就不是回合。
Attempt 是"一次尝试的一条记录”。这里有一个微妙之处——回合不等于"调用了一次 LLM"。回合的存在条件不是调用,而是记录。即使调用了 LLM,只要结果没有记录到棘轮上,那个回合就不曾发生。反过来,哪怕是人手工提交的结果,一经记录就是一个回合。没有 LLM 也一样。数回合的不是模型,而是棘轮。
这一条定义是后面所有性质——驱动器无关性、重启韧性、可审计性——的根。现在先让这些名字掠过去,我们会在各自的位置再次遇到它们。
一个回合恰好是四步
一个回合依次经过四步。步骤名是英文,但做的事很简单——装配(compose)、生成(generate)、裁定(judge)、记录(record)。
| 步骤 | 做什么 | 性质 |
|---|---|---|
| ① compose | 读取此前所有回合的记录(Log),装配交给 LLM 的提示词 | 纯函数 |
| ② generate | 调用一次 LLM 产出结果 | 唯一的概率步骤 |
| ③ judge | 门对产出物作出裁定(PASS / REVIEW / FAIL) | 确定性 |
| ④ record | 把裁定施加到棘轮并写入磁盘 | 唯一的不可逆步骤 |
“纯函数"指相同输入永远得到相同输出、没有其他副作用;“不可逆"指一旦执行便无法撤销。于是这张表的核心浮现出来——**四步之中,概率性的只有②,不可逆的只有④。**生成不能裁定,裁定不能生成。AI 的不确定性被囚在一格里,无法撤销的决定被囚在另一格里。
有一处奇特的设计值得一记。这条四步级联并不是用两套 Go 代码实现的。它定义在一份名为 pkg/cli/turn.md 的人类可读文档(一份 TANGEUL 文档)里,嵌入二进制(go:embed)并在运行时被解释执行。“回合怎么转"的正典不是代码,而是一份读得懂的文档——这个选择的理由会在文末回来。
① compose —— 上下文只来自 Log
Log 是保存在磁盘上、记录了迄今为止每一个回合的账本。而装配第 N 回合提示词的输入只有一样:**这份 Log。**那种藏在程序内存某处、进程一死就烟消云散的状态——不存在。
从 Log 装配出的提示词有三层。
- 要做的事 —— 这个条目必须产出什么(写作指令与验证上下文)
- 手册 —— 全局系统提示词,若上一回合是 FAIL,再加上导致失败的那条规则对应的教练指导(按规则的手册)
- 反馈尾巴 —— 上一次 FAIL 的事实。“哪里、本应是什么、实际是什么”
用前面的六要素来说,手册是方向性上下文,反馈尾巴是确定性反馈。这两者每个回合都从 Log 中机械地装配出来。
有一条微妙却重要的规则。compose 参照的不是最后一条 Attempt,而是最后一条**完成了裁定(judged)**的 Attempt。即使中间夹着 LLM 服务器宕机之类的生成错误,重试看到的也不是基础设施的报错信息,而是上一次 FAIL 的事实反馈。运维故障不会污染工作的上下文。
② generate —— LLM 只管生成
装配好的提示词以一次调用发往 LLM 后端。后端是 HTTP API(ollama/xai/gemini)还是命令行工具(claude/grok/codex/geminicli)都无所谓。无论哪种,它的角色都固定为生成器。框架根本不暴露任何可以授予 LLM PASS 权限的 API。不是"选择了不授予"裁定权——而是**没有授予的途径。**这就是六要素之 1(机器裁定的完成)成为结构的方式。
连用哪个后端,都在每个回合从 Log 里重新算出。在默认模型上屡屡失败的条目会被送往更强的模型(升级),而这个决定同样是每回合从 Log 读出的——“过往 FAIL 的成因规则里,有没有升级对象?“没有哪里留着一个开着的开关,也没有循环里的局部变量。同一个程序、同一份 Log——就选出同一个后端。把进程杀掉再重启也表现完全一致的性质——重启韧性——白送上门。
③ judge —— 只有门在裁定
给产出物下裁决的是门。门是**一组违规检测规则。**每条规则发现自己负责的问题就触发(fire),并留下一条事实——哪里(Where)、本应是什么(Expected)、实际是什么(Actual)。
汇总是确定性的。只要有一条 Fail 规则触发,就是 FAIL。否则若有 Review 规则触发,就是 REVIEW(留给人核对的灰色地带)。什么都没触发,就是 PASS。同样的提交物、同样的规则——永远同样的裁决。这里没有那种每问一次答案就变一次的检查员。
在规则彼此纠缠的复杂领域——一处违规会使另一项检查失去意义的情形——裁决可以升到论证图(toulmin)之上,裁定逻辑本身也可以移入一份可审计的文档(gate.md)。无论何种形态,有一件事不变:裁定者是机器。
④ record —— 唯一的不可逆步骤
把裁定施加到棘轮,写入磁盘,并导出(export)已收束的条目。这是回合中唯一无法回头的地方。
- PASS / REVIEW / SKIPPED / BLOCKED → 锁定。棘轮是单向的,不会倒转。
- FAIL → 尝试次数(
Tries)加 1,条目仍留为 TODO。达到最大尝试次数(默认 3 次)后锁定为 DONE。“这个条目这条路走不通"也是收束的一种形式——不允许一个卡死的条目永远劫持整个循环。 - 生成错误 → 会作为 Attempt 记入 Log(保留发生了什么的痕迹),但**不消耗尝试次数。**LLM 服务器宕机不是条目的错,而是运维故障。如果故障持续,另有一道保险装置停下循环(连续 N 次生成失败即中止——熔断器)。
有了这一步,下一回合的 compose 才有 Log 可读。record 是回合的收尾,也是下一回合的生成者。
失败是事实,不是意见
FAIL 以什么样貌返回——这是回合能否收敛(每次重试都更接近正确答案)的钥匙。不是"质量略有欠缺"这样的意见,而是这样的东西:
FAIL. root cause = who-anchor-present
Fact: where=who.anchors expected="source substring" actual="陈浩副经理"
读法很简单。哪个字段(where)、本应是什么(expected——原文中真实存在的字符串)、实际是什么(actual)。**位置 + 期望值 + 实际值。**对 LLM 来说,这是一种无人可谄媚的反馈——数字和位置没有情绪。把谄媚的模型引向的不是争辩而是收敛的,正是这种结构化的事实。
再附赠一条。喂给模型的 FAIL 文本,与人敲下 submit 命令时屏幕上打印的字符串是完全相同的渲染(feedback parity)。人看到的反馈与模型看到的反馈绝不背离。“到底给 AI 发了什么,它才改成这样?“这种谜团在结构上不存在。
三个入口,一个回合
把驱动回合的角色称为驱动器(driver)。reins 有三个:人直接接收提示词的 next、人提交结果的 submit,以及无人值守的自动 loop。但这三者不是三份独立的实现,而是**通向同一份回合文档的三个入口。**区分手动与自动的,只是文档里的一条规则。
这带来的实战性质是:**任务中途更换驱动器,提示词也逐字节相同。**昨天跑自动 loop,今天换成人用 next 接手——只要 Log 状态相同,出来的就是同一份提示词。这之所以可能,是因为上下文只来自 Log(我们在①步已经见过),而且它是被证明的性质,不是期望——一项对比不同驱动器输出的驱动器互换黄金测试(driver-swap golden test)验证了字节级同一性。
把一个回合从头跟到尾
理论讲完了。来看一个真实回合的全程。它是一个从文档中提取邮箱地址的任务里的一个条目,上一回合以"不是有效的邮箱格式"FAIL,这是第二次尝试。
[回合入场判定] 条目是 TODO 吗?还剩尝试次数吗?→ 继续
① compose 在 Log 中找到最后一条 judged Attempt → FAIL,原因 = email-format
手册 = 全局提示词 + email-format 规则的教练指导
提示词 = 要做的事 + "FAIL. Fact: where=email
expected='valid email format' actual='kim at example'"
② generate 调用 LLM → {"email":"kim@example.com", ...}
③ judge 规则巡检:email-format 通过,source-lacks-email 通过,freemail 通过
→ 无 Fail 规则触发 → PASS
④ record 棘轮锁定(不可逆)→ 记录 Attempt #2 → 保存 → export
模型拿到上次失败的事实(“kim at example 不是有效的邮箱格式”),恰好修正了那个位置;门确认通过;棘轮锁定。这个条目从此永远是 PASS。下一回合会跳过它,剩余工作量只减不增。当所有条目都到达收束状态(PASS、REVIEW,或达到最大尝试次数),循环结束。不是"AI 觉得做完了的时候”,而是**剩余条目归零的时候。**收敛由结构保证。
Loop Engineering —— 业界给同一个问题起了名字
2026 年 6 月,处理智能体方式的一场转变有了名字。Peter Steinberger 写道,“You shouldn’t be prompting coding agents anymore. You should be designing loops that prompt your agents”(你不该再给编码智能体写提示词了。你该设计那些去提示你的智能体的循环),同月早些时候,打造了 Claude Code 的 Anthropic 的 Boris Cherny 在一场活动上说,“I don’t prompt Claude anymore. I have loops running… My job is to write loops”(我不再给 Claude 写提示词了。我有循环在跑着……我的工作是写循环)。几天后,Google 的 Addy Osmani 给这股潮流命名为 Loop Engineering——从给智能体写提示词的人,变成设计那些提示智能体的系统的人。
这场讨论描绘出一条迁移叙事。提示词工程(挑选词句)→ 上下文工程(挑选展示什么信息)→ 挽具工程(搭建执行环境)→ 循环工程(设计观察·行动·验证·恢复这一周期本身)。杠杆一层层向外移动:从词句到信息,从信息到环境,从环境到周期。
Osmani 给出的好循环解剖图,对读到这里的读者应该并不陌生。把状态外部化到磁盘或看板,而不是对话里。把构建的智能体与验证的智能体分开。让终止由独立的裁决者确认,而不是编码智能体的自我宣告。把它与回合并排放在一起,对应关系一目了然。
| Loop Engineering 的建议 | reins 回合的结构化 |
|---|---|
| 把状态外部化到磁盘·看板(模型会忘) | Log 不是记忆辅助,而是回合的唯一输入——compose 是 Log 的纯函数 |
| 把构建者与验证者分开(子智能体) | 验证者不是另一个 LLM,而是确定性门——根本不存在授予 PASS 的 API |
| 定义可测试的终止条件 | 棘轮的单调性把收敛保证为不变式——是结构,不是条件 |
| 区分可恢复的失败与致命的失败 | 内建于 record 规则——FAIL 消耗尝试次数,生成错误归熔断器管 |
差异的核心是**建议与结构之间的距离。**循环工程的文献自己也承认验证的层级——把裁决托付给 AI 的 LLM-as-judge"可能被骗,或与行动者串通”(can be gamed or can collude with the actor),因此凡是能放确定性检查的地方就放确定性检查。但那仍停留在最佳实践——一条托付给设计者善意的建议。如果验证者子智能体归根结底也是 LLM,串通之门就还开着。reins 用设计关上这扇门。裁定只由门执行,框架不暴露任何给 LLM 授予 PASS 的途径。
而且,当循环工程谈论整个循环时,reins 把那个循环的一圈做成了契约。要在 Cherny 的"我的工作是写循环"之上再迈一步,就必须先定义清楚循环转一圈到底在做什么——什么是概率的、什么是确定的、什么是不可逆的。这个定义的名字,就是回合。
为什么是这个单位
把回合拧紧到这个程度,就得到三样东西。前面掠过的那些名字在这里各归其位。
- 可审计性 —— “自动 loop 和手动 next 有什么不同?“的答案不是比对两套代码库的苦活,而是文档里的一条规则。你可以亲眼确认:文档中能锁定 PASS 的路径恰好只有一条。这就是回合的正典是可读文档而非代码的原因。
- 重启韧性 —— 回合的所有输入都派生自磁盘上的 Log,所以即使进程死掉,同一份 Log 也能复现同一个回合。
- 智能体可弃性 —— 换掉智能体(LLM、驱动器),进度依然累积、绝不回退。“Agents are disposable; progress is cumulative.”
反过来说,一个回合模糊不清的系统——上下文藏在会话内存里、完成由模型自我宣告、重试倚赖对话历史——这三样会全部失去。
回合看起来很小。但作为在一个周期之内把生成(概率)、裁定(确定性)、记录(不可逆)分离并串行化的最小单位,理解了回合,就理解了整个 reins。
相关文章
- reins —— Quest CLI 只留下领域,ratchet 交给框架 —— 本文的主角框架正篇。
- Ratchet Pattern — 让 Agent 做到底的方法 —— 契约锁定(六要素之 4)的完整论述。
- 如何制作 Quest CLI —— 亲手打造让机器判定完成的工具 —— 实战蓝图:任务五部件、门的设计、cheese 防御。
- 反向利用IFEval的棘轮代码 —— 确定性反馈 + 方向性上下文产生收敛的实验。
- Reins Engineering — 给AI装上缰绳 —— 提示词→上下文→挽具→Reins 谱系的宣言。
- TANGEUL —— 用 Markdown 书写、由人类审核的规则 —— 回合的正典为何是一份文档。
延伸阅读(外部)
- Building Effective Agents — Anthropic —— 智能体循环设计的经典。其"工作流(确定性编排)与智能体(模型驱动)“之分,与本文的生成/裁定分离相互共鸣。
- Agentic Loops: From ReAct to Loop Engineering — Data Science Dojo —— 从 ReAct 到循环工程,智能体循环谱系的综述。
- The Anthropic leader who built Claude Code says he ditched prompting — now he just writes loops — The New Stack —— 报道 Boris Cherny 之转变的业界文章。
参考文献
- Loop Engineering — Addy Osmani —— 2026-06。术语的命名与好循环的解剖(自动化·工作树·技能·子智能体·独立裁决者·状态外部化)。
- What Is Loop Engineering? A Complete Guide from Prompt to Harness Engineering — Tosea.ai —— 提示词→上下文→挽具→循环的四阶段迁移、确定性优先的验证层级,以及 LLM-as-judge 的串通风险。
- Claude Code’s Creators Explain Agent Loops — The Neuron —— Boris Cherny 与 Cat Wu 详解循环运用:
/loop与/goal、把状态外部化到磁盘与 Linear、构建者与验证者的分离。
变更历史
- 2026-07-07: 初版