规划与推理策略
ReAct 边想边做,Plan-and-Execute 先想后做,Tree of Thoughts 想多条路——三种规划范式怎么选?论文里的数字很漂亮(24 点 4%→74%,HumanEval 80%→91%),但规划本身烧 token、计划还赶不上变化。这一章把证据和反方都摆上桌。
开场:规划决定 Agent 的能力上限
上一章讲过,Agentic Loop 让模型「边开边看路况」。这对短任务没问题,但任务一复杂就会暴露一个硬伤:只看眼前一步的 Agent,走不出需要全局视野的迷宫。
类比一下:砌砖工人可以边干边看,但盖一栋楼不能没有图纸。没有图纸的施工队会盖到三楼才发现一楼承重墙位置错了——Agent 世界里对应的剧情是:写到第 15 步才发现第 3 步选的方案根本走不通,前面十几步的 token 全部白烧。
这就是规划(Planning)要解决的问题:在行动之前(或之中)显式地管理「接下来要做什么」这个状态。 它不改变模型的单步能力,但决定了这些能力能被组织成多长的链条。所以业内的共识是:模型的智力决定 Agent 能力的下限,规划策略决定能力的上限——同一个模型,配不同的规划策略,在复杂任务上的表现可以差出一个数量级(后面你会看到 4% 和 74% 这种夸张差距)。
但也要把丑话说在前面:规划不是免费的。 画图纸要花时间,图纸画错了要返工,环境变了图纸还会过期。这一章我们把主流的规划范式逐个拆开,既给论文里的硬证据,也给「过度规划」的反方观点——因为在工程实践里,选错规划策略的代价往往比不规划还大。
任务分解:规划的原材料
所有规划策略的底层动作都是同一个:把大任务拆成小任务。 为什么分解有效?三个原因,前两个上一章已经埋过伏笔:
- 缩短错误累积链。 单步决策准确率会随步数幂次衰减(0.95^n),把 30 步的任务拆成 3 个 10 步的子任务,每条链的全程无错概率从 21% 升到 60% 左右——而且子任务之间还可以插入验证点。
- 降低单步认知负荷。 让模型「一步只做一件事」,比「一口气想完所有事」的犯错率低得多。这也是 CoT(思维链)有效的根本原因。
- 让错误可定位。 一条 30 步的单线轨迹失败了,你很难说是哪步错了;拆成子任务后,失败被隔离在某一段里,重跑这一段就行。
分解手法里最值得一提的是 Least-to-Most Prompting(Google 2022,arXiv:2205.10625):不让模型边答边拆(CoT 的做法),而是先显式列出全部子问题,再按顺序逐个求解,后面的子问题可以利用前面的答案。在 SCAN 组合泛化基准上(考验「学会 jump 和 turn left,能不能推出 jump turn left」这类组合能力),普通提示只有约 6% 准确率,CoT 约 16%,Least-to-Most 直接干到 99% 以上。这个数字揭示了一个后来被所有 Planner 继承的思想:「拆」这个动作本身值得单独花一次模型调用,拆得好比执行得好更重要。
工程上的分解通常分两层:Planner 负责拆出步骤清单(语义层),Executor 负责把每一步变成具体的工具调用(动作层)。这个分层就是 Plan-and-Execute 的雏形。
三种范式一张表:边想边做、先想后做、想多条路
在深入细节前,先把三种主流范式的关系说清楚,它们不是替代关系,而是在「思考的时机和宽度」上的三个不同取点:
- ReAct:边想边做。 每走一步看一次路况再决定下一步。思考的时机是「每步」,宽度是「一条路」。灵活、省 token,但没有全局观。
- Plan-and-Execute:先想后做。 先把整条路线画出来,再照着走,走不通才停下来重画。思考的时机是「开局 + 必要时」,宽度仍是「一条路」。有全局观,但计划可能过期。
- Tree of Thoughts:想多条路。 每一步同时想好几个候选方向,评估打分后选最好的展开,走死了还能回溯。宽度是「一棵树」。探索能力最强,token 成本也爆炸。
一个生活类比:ReAct 是凭路感开车,Plan-and-Execute 是先用导航规划全程再出发,ToT 是把所有候选路线都模拟跑一遍再选最优。市区通勤用导航纯属浪费电,但穿越无人区不规划就是玩命——范式之争的答案是任务结构,不是信仰。
Plan-and-Execute:先画图纸再施工
机制:三个角色
Plan-and-Execute 的思想可以追溯到 BabyAGI 和 Plan-and-Solve Prompting(ACL 2023,arXiv:2305.04091),后来 LangChain 的 Plan-and-Execute agent 把它工程化。架构上是三个角色:
- Planner:通常用大模型,输入目标,输出一份完整的多步计划(一般是结构化的步骤列表)。Plan-and-Solve 论文的核心发现可以浓缩成一句提示词——「先理解问题、制定计划,再按计划逐步执行」,仅靠这个指令就让 Zero-shot 推理在 GSM8K 等算术基准上稳定超过 Zero-shot-CoT。显式的「先规划」本身就是免费的准确率。
- Executor:逐步执行计划。每一步内部可以是一个小的 ReAct 循环(因为单步执行时仍然需要根据工具结果现场反应)。Executor 可以用更便宜的小模型——计划已经给了,执行是局部决策。
- Replanner:每步执行完(或在检查点)对比「实际进展」和「原计划」,决定继续、调整还是推翻重来。
一个最小骨架(TypeScript):
type Step = { title: string; status: "todo" | "done" | "failed" };
// 1. Planner:一次性产出结构化计划
let plan: Step[] = await planner.makePlan(goal);
for (const step of plan) {
try {
await executor.run(step); // 2. Executor:步内是小 ReAct 循环
step.status = "done";
} catch (e) {
step.status = "failed";
// 3. Replanner:只在失败或检查点触发,不是每步都重排
plan = await replanner.revise(goal, plan, String(e));
}
}
看一个具体的计划长什么样。任务「给博客加暗色模式」,Planner 可能输出:
1. 读主题配置文件,确认当前颜色方案的组织方式
2. 新增 dark 配色变量,改造全局样式
3. 加一个切换按钮,状态存 localStorage
4. 跑构建和截图对比,验证两种模式都正常
注意好计划的两个特征:每一步都可执行、可验证(不是「优化一下样式」这种空话),且步骤之间传递了上下文假设(第 2 步依赖第 1 步的发现)。如果 Planner 输出的步骤含糊,别急着执行——让 Planner 重写计划,远比让 Executor 在执行中补救便宜。
何时重规划:规划与执行的节奏控制
这是 Plan-and-Execute 最核心的工程参数,没有之一。两个极端都是错的:
- 每步都重规划:等于退化成一个巨贵的 ReAct——每执行一步都要让大模型把全文重读一遍重出一份计划,token 成本翻好几倍,延迟翻倍,而且频繁重排会让 Agent 显得「朝令夕改」,上下游步骤的衔接反复被打断。
- 从不重规划:计划腐化。环境是非平稳的,第 8 步执行时,当初制定计划依据的信息可能已经过时(文件被改了、接口返回变了、用户的需求澄清了)。抱着过期地图走到黑,比没有地图更危险。
合理的节奏是事件驱动 + 里程碑检查点的混合:
- 失败触发:单步连续失败 N 次(经验值 2-3 次),说明计划对现实的假设错了,必须重规划;
- 偏差触发:工具返回与计划预期明显不符(预期搜到接口 A,实际发现接口已下线),立即重规划;
- 检查点触发:每完成一个里程碑(比如计划的 1/3 处)例行对照一次,低成本纠偏;
- 预算兜底:限制最大重规划次数(经验值 3-5 次),超过就升级给人类——反复重规划本身就是「这条路走不通」的信号。
一句话总结:重规划的频率应该和环境的「意外率」正相关。 静态环境(写纯函数、做数学题)一次规划走到底;高动态环境(操作真实系统、和外部 API 交互)多设检查点。
Tree of Thoughts:把推理变成搜索
ToT(Princeton + Google DeepMind,2023,arXiv:2305.10601)是把「想多条路」形式化的代表作。它把推理过程建模成一棵搜索树,四个组件缺一不可:
- 状态(State):当前的部分解,比如 24 点游戏里「已经算出的中间数字序列」;
- Thought 生成器:每一步让模型产生 k 个候选下一步(论文里 k=5);
- 状态评估器:让模型给每个状态打分——论文用了两种方式,独立打分(value:这个中间结果离答案还有多远)和跨状态投票(vote:几个候选里哪个最有戏);
- 搜索算法:BFS(逐层展开保留 b 个最优)或 DFS(深入一条路,评估低于阈值就回溯)。
24 点实验:数字值得细看
论文的招牌实验是 Game of 24:给 4 个数字,用加减乘除凑出 24。这个任务选得很刁钻——它需要「lookahead」(当前这一步算错,后面全盘皆输)和「回溯」(发现走死要能换路),恰好是单线推理的死穴。
实验设计:随机抽 100 道题(来自 4nums.com 的 1362 题中的索引 901-1000),同一批题、同一个 GPT-4,只改推理结构:
- 直接给答案(IO prompting):成功率 4%
- CoT(分步推理):4%——思维链在这个任务上几乎没用,因为一旦第一步算错,后面只是错得更有条理
- CoT-SC(采 100 条链取多数投票):约 9%
- ToT(宽度 b=5):成功率 74%
从 4% 到 74%,模型一个字都没改,改的只是 Harness 层的搜索结构——这是「规划决定能力上限」最震撼的实证。
状态评估器在 24 点里是这么干活的:每算一步,让模型判断剩余数字「确定 / 可能 / 不可能」凑出 24——剩 6 和 4 标「确定」优先展开,剩 10 和 13 标「不可能」直接剪枝。这个看似粗糙的三档评分就是整棵搜索树的导航系统。评估器比生成器更重要:候选想得再多,打分不靠谱,树搜索就只是在错误的方向上越走越远。
但成本的账必须算。 ToT 每道题要发起几十次模型调用(生成候选 × 评估 × 多层搜索),token 消耗是单线 CoT 的几十倍。论文的另一个实验(创意写作)里,ToT 让 GPT 自动评估的连贯性得分明显高于 CoT,但同样是靠百倍级的采样换来的。所以工程结论非常清晰:
- 值得用 ToT 的场景:单步价值极高、错了不可逆、且中间状态可被评估(数学证明、复杂规划、24 点这类「能算中间值」的任务)。「可评估性」是隐藏前提——24 点能检查中间数字是否可能凑出 24,代码能不能跑、单测过不过也是天然评估器。
- 不值得用的场景:对话、开放式写作、无法给中间状态打分的任务——树搜索退化成「花几十倍的钱随机游走」。
Reflexion:用错题本做「言语强化学习」
Reflexion(2023,arXiv:2303.11366)上一章提过一句,这里把机制拆透。它的全称思路是 verbal reinforcement learning(言语强化学习):传统 RL 用数值奖励更新权重,Reflexion 用自然语言的反思更新上下文。三个角色:
- Actor:干活的 Agent(通常是个 ReAct 循环);
- Evaluator:裁判,判断这一轮尝试成功还是失败。HumanEval 上用单元测试当裁判,ALFWorld 上用环境反馈;
- Self-Reflection 模型:失败后生成一段文字反思——「我错在哪、下次应该怎么改」,存进一个外部记忆(episodic memory),下一轮带着这段反思重跑。
最小实现(Python):
memory = [] # 错题本:历轮反思
for _ in range(3): # 熔断:最多试 3 轮
code = actor.solve(task, memory) # 带着历史反思作答
failed = run_tests(code) # Evaluator:单测当裁判
if not failed:
break
note = reflect(task, code, failed) # 生成文字版反思
memory.append(note[:500]) # 截断后进记忆,防上下文膨胀
HumanEval 实验:91% vs 80%
论文在代码生成基准 HumanEval 上,GPT-4 裸跑 pass@1 是 80%,加上 Reflexion 后达到 91%——靠的是失败后读单测报错、写反思、重写代码,最多重试若干轮。在 ALFWorld 决策任务上更夸张:Reflexion 把 ReAct 的成功率一路推到 97%(134 个任务只失败 4 个)。
机制上有两个细节决定了它好不好用:
- 反思的质量取决于报错的信息量。 单测失败信息(哪条断言、期望值实际值)是高质量的「梯度信号」;如果 Evaluator 只能给「成功/失败」一个 bit,反思就很容易变成瞎猜。这也是为什么 Reflexion 在「有自动验证器」的任务上效果拔群,在开放任务上大打折扣。
- 记忆要管理。 反思越积越多会挤爆上下文,工程上需要截断、压缩、甚至只保留「最近一次 + 最高频错误」。
同时要警惕它的边界:Reflexion 也可能把错误「合理化」——模型写出一篇逻辑自洽但方向全错的反思,带着它越跑越偏。而且 token 成本直接乘上重试轮数。它适合「有可验证标准答案」的任务,不适合「没有裁判」的任务。
过度规划:反方的声音
讲完了规划的收益,必须给反方同等篇幅,因为「过度规划」是 Agent 新手最常踩的坑。
反方论点一:规划本身烧 token、烧延迟。 Planner 是一次额外的大模型调用,Replanner 每次触发都要重读全文再出一份计划,ToT 更是几十倍的成本。如果一个任务本来 3 步 ReAct 就能搞定,套 Plan-and-Execute 等于为了点一份外卖先开了个项目立项会。Anthropic 在《Building Effective Agents》里的原话精神就是:找到能用的最简单的方案,只在证明有效的前提下增加复杂度。
反方论点二:计划赶不上变化。 军事上有句老话:「没有任何计划在遭遇敌人后还能幸存。」Agent 的环境是非平稳的——网页改版、接口超时、用户中途改需求。计划越长,它基于的信息越陈旧,腐化越严重。一份 20 步的精细计划,可能走到第 5 步就整体作废,前期制定计划的 token 全部沉没。环境变化越快,计划的保质期越短,越应该倾向 ReAct 式的现场决策。
反方论点三:简单任务上规划是负资产。 大量真实请求其实是「一问一答」级别的:查个天气、改一行代码、总结一段话。这类任务上规划不仅浪费,还引入新的失败模式——Planner 幻觉出不可执行的步骤、把简单任务拆碎后反而放大了累积错误率。社区在多个基准上观察到,Plan-and-Execute 相对纯 ReAct 的提升经常很有限,有时甚至下降,原因多是「计划的质量不如模型的现场判断」。
那么什么时候规划真的有正收益? 一张决策清单:
- 任务步骤可预先穷举 → 别用 Agent,用 Workflow 写死流程,最便宜最可控;
- 步骤不可预知、需要边看边走 → ReAct,不要规划;
- 有全局约束或长程依赖(预算、先后顺序、资源分配)→ Plan-and-Execute;
- 单步错了不可逆、中间状态可评估 → 才轮到 ToT;
- 有可自动验证的答案 → Reflexion 几乎总是划算的。
工程实践要点
把上面的理论落到代码里,有几条实战建议:
- 计划要存成结构化数据,不要只活在上下文里。 用 JSON 数组记录每个步骤的状态(todo/done/failed),而不是让计划以自然语言散落在对话历史里。结构化的计划才能被 Replanner 可靠地 diff 和修改,也方便打日志做可观测。
- Planner 和 Executor 可以用不同的模型。 规划是全局推理,值得用大模型;单步执行是局部决策,小模型往往够用。这个组合能把成本砍掉一半以上,效果几乎不掉。
- 给规划加预算。 最大计划步数、最大重规划次数、最大 token 预算,三层熔断缺一不可。重规划次数超限本身就是一个信号:任务定义有问题,该升级给人类了。
- Executor 内部保留 ReAct 的灵活性。 Plan-and-Execute 不是「先想后做就无脑执行」,每一步内部仍然要根据工具结果现场反应——全局靠计划,局部靠反应,两条腿走路。
- 评估优先。 想上 ToT 或 Reflexion 之前,先问自己:这个任务的中间状态/最终结果能不能自动评估?不能的话,先造评估器,否则搜索和反思都没有方向。
常见误区
- 上来就 ToT:树搜索是核武器不是常规武器,单线 ReAct 能解决的问题用它等于烧钱取暖
- 每步都重规划:退化成一个巨贵的 ReAct,还引入了「朝令夕改」的新问题
- 计划只写在 prompt 里:自然语言计划没法可靠更新,要存成结构化状态
- 把 Reflexion 当微调:它不改权重,「经验」只存在上下文里,换个会话就忘了
- 给简单任务套规划:一问一答的任务上 Planner 是纯纯的负资产——多一次调用、多一截延迟、多一个出错点
- 以为规划能弥补模型能力不足:规划是放大器不是发电机——它能把 60 分的模型组织出 80 分的效果,但组织不出 100 分
术语表
| 名词 | 定义 | 一句话直觉 | 常见混淆 |
|---|---|---|---|
| 任务分解 | 把复杂任务拆成可独立求解子问题的过程 | 把大象装冰箱分三步 | 与「分治算法」混淆:分解不要求子问题同构,关键是缩短错误累积链 |
| Least-to-Most | 先显式列出全部子问题、再按序逐个求解的提示技术(2022) | 先看完整张考卷,再从易到难答题 | 与 CoT 混淆:CoT 边答边拆,Least-to-Most 拆和答是两次独立动作 |
| Plan-and-Execute | 先由 Planner 出完整计划、Executor 逐步执行、必要时 Replanner 修订的范式 | 先画图纸再施工,图纸错了就地改 | 与 Workflow 混淆:Workflow 的流程是人预先写死的,Plan-and-Execute 的计划是模型现场生成的 |
| Planner / Executor / Replanner | Plan-and-Execute 的三个角色:制定计划、执行单步、修订计划 | 建筑师 / 施工队 / 驻场监理 | 以为必须三个独立模型——可以是同一个模型扮演不同角色,只是调用时机不同 |
| 重规划(Replanning) | 执行中发现计划与现实脱节时修订计划的动作 | 导航说「前方拥堵,已为你重新规划路线」 | 以为越频繁越好:每步重规划 = 昂贵的 ReAct,还有朝令夕改的副作用 |
| Tree of Thoughts | 把推理建模为搜索树:生成候选、评估打分、按 BFS/DFS 展开(2023) | 下棋时同时算多条变化再选最优 | 与 CoT-SC 混淆:CoT-SC 是「多条独立链投票」,链之间无交互;ToT 有中间状态评估和回溯 |
| 状态评估器 | ToT 中给部分解打分的组件(value 打分或 vote 投票) | 裁判在中盘判断这盘棋谁占优 | 以为可以省略:没有可评估的中间状态,ToT 退化成昂贵的随机搜索 |
| Reflexion | 失败后生成文字反思存入记忆、带着反思重试的方法(2023) | 错题本:下次考试前先翻一遍 | 与微调混淆:不改权重,「经验」只活在上下文/外部记忆里 |
| pass@1 | 代码生成指标:只生成一次答案就通过测试的概率 | 一锤子买卖的命中率 | 与 pass@k 混淆:pass@k 允许试 k 次取最好,数字天然更高,比较时别看混 |
| 言语强化学习 | Reflexion 的自称:用自然语言反思代替数值梯度来「更新」行为 | 不用改大脑,改错题本就行 | 与真 RL 混淆:没有梯度、没有权重更新,「学习成果」随会话结束而消失 |
| 计划腐化 | 长计划在执行中因环境变化而过时的现象 | 出门前查的路线,开了一半已经大堵车 | 以为重规划能完全解决:重规划本身有成本,且新计划基于的仍是旧认知 |
| 过度规划 | 给不需要规划的任务强加规划层,导致成本上升、效果反降 | 点一份外卖先开立项会 | 以为规划多多益善:简单任务上 Planner 是新的失败模式来源 |
参考材料
- Tree of Thoughts: Deliberate Problem Solving with Large Language Models — ToT 原始论文,24 点实验的设计和数字值得精读
- Reflexion: Language Agents with Verbal Reinforcement Learning — 错题本机制,HumanEval 91% 的完整实验
- Plan-and-Solve Prompting — Plan-and-Execute 思想的提示词版本,「先规划」是免费的准确率
- Least-to-Most Prompting — 「拆」这个动作值得单独花一次模型调用
- Building Effective Agents — 「找到能用的最简单的方案」,过度规划反方的权威出处
- LLM Powered Autonomous Agents — Lilian Weng 的综述,规划篇对任务分解的分类梳理
小结
记住三种范式的分工:ReAct 边想边做,Plan-and-Execute 先想后做,ToT 想多条路——它们不是竞争关系,是「思考的时机与宽度」上的三个取点。
再记住两组数字和一个原则。ToT 在 24 点上把 GPT-4 从 4% 拉到 74%,Reflexion 在 HumanEval 上把 pass@1 从 80% 推到 91%——规划确实决定能力上限。但规划本身烧 token,计划会腐化,简单任务上规划是负资产。那个原则是:范式之争的答案永远是任务结构——步骤可预知用 Workflow,边看边走用 ReAct,有全局约束用 Plan-and-Execute,错了不可逆且中间可评估才上 ToT。 从最简单的方案起步,痛了再加复杂度,这个顺序永远不会错。