循环原语:ReAct、五个构件、以及什么时候停

推理和行动交错着来,比只推理不行动强 34 个百分点。但循环真正难的不是转起来,是停下来——而停不下来的账单是按轮数乘上去的。

位置
第 02 篇 / 共 5 篇
预计
6 分钟

上一篇画了四层栈的地图。这一篇进到循环内部。

ReAct:推理、行动、观察、重复

这个原语的出处是 2022 年那篇 ReAct(副标题 Synergizing Reasoning and Acting in Language Models)。

它的主意很简单:让模型交错地产出「推理痕迹」和「具体动作」,而不是只做其中一样。

两边互相帮忙:

  • 推理帮行动 —— 推理痕迹让模型能归纳、追踪、更新行动计划,还能处理异常
  • 行动帮推理 —— 动作让它接触外部世界(知识库、环境),把新信息取回来

这个组合解掉的是纯思维链的老毛病:只推理不行动的模型会一路幻觉下去,而且错误会沿着推理链传播 —— 因为它没有任何机会去核对现实。

数字上:在两个交互式决策基准(ALFWorld 和 WebShop)上,ReAct 比模仿学习和强化学习方法的成功率分别高出 34 和 10 个百分点,而它只用了一两个上下文示例。

「观察」这一步是这个原语的重心。 没有它,模型只是在自己脑子里推演;有了它,每一轮都被现实校正一次。

每个 agent 循环的五个构件

ReAct 是内核。而一个能自己转起来的循环,一圈里要做五件事。少一件,圈要么转不起来,要么原地打转。

构件 干什么 少了会怎样
发现 自己找出这一轮该干什么 你每天早上还得告诉它干什么
交接 把任务交给干活的 agent,彼此隔离 几个 agent 改同一个目录,撞成一团
验证 换一个 agent 来说「不行」 它自己夸自己,一轮轮往下滑
持久化 把状态写到对话之外 每天早上都从同一个地方重新开始
调度 让它一轮接一轮转下去 那只是「跑过一次」,不是循环

发现这一格决定了整个循环的天花板。 如果它捞上来的活本身没价值,后面四格做得再漂亮也是在为一件没意义的事服务。

这五格里最容易被偷工减料、也最不能省的是验证。它是那个「能说不行」的东西 —— 一个没有真正检查的循环,只是一个对着自己点头的 agent。这一点在多份材料里被反复证明:被改的对象和验证的对象必须分开。

停止条件:循环真正难的地方

「循环」这个词容易让人以为难点在转起来。真正难的是停下来。

停止条件有三类,成本完全不同:

一、固定轮数。 最简单,也最钝。跑三轮就停 —— 但三轮可能没干完,也可能第一轮就该停了。

二、模型自己说完成了。 最危险。它会说完成的,几乎总是说。让干活的那个来判断干完没有,是让它给自己判卷。

三、独立的判据。 交给一个新的、没参与干活的模型或者一段确定性的检查去判断条件成立没有。

Claude Code 把第三类做成了一个原语 /goal:给一个条件,让它跑到条件成立为止。

/goal all tests in test/auth pass and the lint step is clean

关键在于每一轮之后,是一个小而快的新模型去检查条件成不成立 —— 不成立就再跑一轮,而不是把控制权交回来。完成与否由一个新模型判定,不是由干活的那个判定。

这是银行业里几十年的双人复核原则(maker-checker):录入大额转账的人和复核的人必须是两个人。搬到 agent 上就是 —— 写代码的和判断写完没有的,不能是同一个。

顺带澄清一个容易混的地方:/goal(跑到条件成立)和 /loop(按间隔重跑)不是一回事。后者只是定时重复,它不判断任何东西。

循环经济学:为什么停不下来这么贵

单次运行跑飞了,代价是一次调用。循环跑飞了,代价要乘以轮数 —— 而且是在你睡觉的时候乘

三笔账值得在动手之前就算:

一、派生的帮手会翻倍。 一个循环分出两个子 agent,每个子 agent 又可能重试三次 —— 一轮的实际调用数是你写下的那个数的好几倍。

二、重试是复利。 一个卡住的 bug 配上「失败就重试」,能空转整整一夜。它不会报警,因为从系统的角度看它一直在正常工作。

三、上下文越长越贵。 循环把自己的产出喂回去,于是每轮的输入都比上一轮长。成本不是线性的,是随轮数累加的。

第一条我自己量到过一个具体的数。我那套东西接执行引擎跑一条四步的用例,日志显示每次请求 prompt 都在 9000 token 上下,而其中 6144 已经命中前缀缓存 —— 也就是说贵的不是文本,是每一步都要重新编码一张截图。一条四步的用例十六分钟。把这个数乘进「几十轮」,循环经济学就不是一句空话了。

所以那篇实践笔记给的建议很直接:在第一次让它无人值守跑之前,就把硬上限设好 —— 单次运行预算、每日预算、最大重试次数。

这些数字主要不是为了省钱,是断路器。 它们把一个开放式的风险变成一个有界的风险。一个没有上限的循环,等于把花钱的权力交给了自己的 bug。

边界与代价

ReAct 那 34 个百分点是 2022 年、在特定基准上的数。 今天的模型基线早就不同了,别拿它去论证「现在用 ReAct 还能涨这么多」。它证明的是方向:让模型有机会观察现实,比让它闷头推理强。

五个构件不是每个循环都要全上。 一个只在你眼前跑几轮的小循环,不需要持久化和调度。全上是过度工程;而少了验证那一格,任何规模都不该上线。

停止条件用独立模型判,也有它的代价。 每轮多一次调用,而且那个判官本身也会错。它换来的是「判官至少没有被写代码的过程说服过」—— 这是结构上的独立,不是能力上的更强。

下一篇

这一篇讲的是循环内部的骨架。下一篇往下挖一层,看单次运行本身是怎么被武装起来的:

harness 的解剖(骨架、错误处理、护栏)、上下文腐烂为什么会让 agent 跑着跑着忘了自己在干嘛,以及那个整个循环转动所依赖的铰链 —— 验证。