reins 的『回合(turn)』是什么 图片: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方向性上下文(手册 + 示例)如果说反馈是校正信号,手册与示例就是方向信号——两者互不可替代“瓶颈不是智能,而是上下文”
4Ratchet Pattern(契约锁定)通过的条目不可变,剩余工作量只减不增——完工由结构保证remaining(t+1) ≤ remaining(t)
5进度持久化进度活在进程之外(磁盘上)——就算 AI 死了,进展仍在“Agents are disposable; progress is cumulative.”
6cheese 防御(领域门)即便是机器检验,只看外壳也会被投机取巧攻破——门必须重新验证其领域的真实事实“门有自己的领域”

表里的术语还觉得陌生也没关系。回合是这六者在一个周期之内相会的最小单位,所以把一个回合从头跟到尾,六个要素就会各就各位地全部登场。先把地图画好:回合的第一步 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。

相关文章

延伸阅读(外部)

参考文献

变更历史

  • 2026-07-07: 初版