Plan & Execute
flowchart TD
A[用户目标] --> B[Planner 生成整体计划]
B --> C[Executor 执行步骤 1]
C --> D[Executor 执行步骤 2]
D --> E{结果偏离预期?}
E -->|否| F[继续后续步骤]
F --> G[最终输出]
E -->|是| H[Replanning]
H --> B
ReAct 的优势,在于它足够灵活:先走一步,看结果,再决定下一步怎么走。上一篇已经讲过,这种模式很适合开放式探索、调试、检索和代码定位。但一旦任务变长、依赖关系变多、执行成本变高,单纯“边走边看”就会开始暴露问题。
比如:
- 任务明明可以先拆成几个阶段,却一直在局部反复试错;
- 某些步骤本可并行,却被串行推进;
- 前面几步已经决定了后面路径,系统却迟迟不做整体安排;
- 执行失败时,只会在原地重试,而不是回头改策略。
这时,更合适的模式往往不是继续把 ReAct 拉长,而是引入一个更明确的结构:先规划,再执行。
这就是 Plan & Execute 的核心思想。它不是否定 ReAct,而是在更复杂任务中,给 Agent 增加一个“先站高一点看全局”的阶段。OpenAI 和 Anthropic 在近两年的 Agent 工程资料里都反复强调一个相近原则:并不是所有任务都需要最强的动态自主性,很多任务更适合先用简单、可解释、可约束的工作流组织起来,再把模型放到合适的位置上。(developers.openai.com) (anthropic.com)
为什么 ReAct 在复杂任务里会开始吃力
先看定义:ReAct 的问题不是不够聪明,而是它天然偏向局部决策。
上一篇说过,ReAct 的本质是:
观察 -> 思考 -> 行动 -> 再观察
每一步都合理,但它并不保证整体上最合理。 这在短任务里通常没问题,在复杂任务里则会出现典型代价。
1. 它容易“局部正确,整体低效”
一个十步任务中,第 3 步的局部最优,可能会把系统带到一条后面越来越贵、越来越绕的路上。 ReAct 往往直到走出几步之后,才意识到最初的方向不值得。
2. 它天然倾向串行
ReAct 通常是一轮轮推进。 如果任务里有两个彼此独立的子问题,本来可以并行处理,ReAct 也经常会先做一个,再做另一个,因为它每次只聚焦当前下一步。
3. 它不擅长表达依赖关系
复杂任务里常常有这样的结构:
- A 和 B 都做完后,才能开始 C;
- 如果 D 失败,E 和 F 都不该继续;
- 用户确认通过后,才允许进入下一个阶段。
这些结构并不是“多走几步 ReAct”就能自然表达出来的。 它们更像计划问题,而不是单步决策问题。
4. 它失败时经常先重试,而不是重构路线
如果当前步骤失败,ReAct 很容易做的第一反应是:
- 再试一次;
- 换个相似 query;
- 再读一个相似文件;
- 再调一次同类工具。
这在某些情况下有用,但在很多情况下真正需要的是:
不是重复当前动作,而是重新思考整体策略。
这就是 Plan & Execute 产生的背景: 不是因为 ReAct 错了,而是因为有些任务需要更强的全局组织能力。
Plan & Execute 是什么
先看定义:Plan & Execute 是一种两阶段 Agent 架构:先由 Planner 生成整体计划,再由 Executor 按计划逐步执行;必要时根据执行结果触发 Replanning。
它把原本混在同一个循环里的两件事拆开了:
- Plan 阶段:先回答“整体上应该怎么做”
- Execute 阶段:再回答“现在具体做哪一步、怎么做”
这个拆分看起来简单,但它带来了很重要的变化:
- 任务被显式结构化;
- 执行不再完全依赖即时灵感;
- 可以更容易表达依赖、阶段、并行和检查点;
- 用户和系统都更容易理解“接下来要做什么”。
从系统设计上说,这也是上一篇提到的 Planner / Executor 职责分离的一种更明确实现。
两阶段架构:先规划,再执行
最基本的 Plan & Execute 架构可以写成:
| 阶段 | 负责角色 | 输入 | 输出 |
|---|---|---|---|
| Plan | Planner | 用户目标、约束、可用工具、当前状态 | 一个计划:步骤列表、依赖关系、阶段划分 |
| Execute | Executor | 当前步骤、上下文、执行历史、工具返回 | 步骤结果、状态更新、是否继续/是否需要重规划 |
如果写成更直观的流程,大致是:
User Goal
-> Planner 生成计划
-> Executor 执行步骤 1
-> Executor 执行步骤 2
-> ...
-> 若偏离预期,则触发 Replanning
-> 最终输出
它和 ReAct 的最大区别,不在于“有没有循环”,而在于:
循环前面多了一个“先做结构化理解”的阶段。
这意味着,Plan & Execute 并不意味着完全没有动态调整;它只是把动态调整放在“有初始计划”的前提下发生。
计划到底是什么:不是漂亮清单,而是任务结构
很多人第一次接触 Plan & Execute,会把“计划”理解成一串自然语言待办项,比如:
- 搜索资料
- 阅读资料
- 整理结论
- 输出报告
这种表示当然可以作为最简版本,但从工程角度看,它常常不够。
一个真正有用的计划,至少应该表达其中的一部分信息:
- 步骤是什么;
- 每一步的目标是什么;
- 哪些步骤必须先做;
- 哪些步骤可以并行;
- 哪些步骤需要用户确认;
- 什么条件下任务算完成;
- 哪些失败可以重试,哪些失败应触发改计划。
所以,计划的价值不在于“列了几条”,而在于它是否把任务的结构表达出来。
计划可以有不同粒度
| 计划粒度 | 特点 | 适用情况 |
|---|---|---|
| 粗粒度阶段 | 先定义 2–5 个阶段 | 长任务、需要全局方向 |
| 中粒度步骤 | 每步是一个可执行子任务 | 最常见、实用性最好 |
| 细粒度动作 | 每步几乎等于一次工具调用 | 可控但昂贵,容易过碎 |
这里最容易踩的坑有两个:
计划过细
如果每一步都细到接近一次工具调用,Planner 虽然“看起来很严谨”,但执行时会出现:
- 计划过长;
- token 成本高;
- 稍有偏差就大量失效;
- Executor 更像机械跑脚本,而不是做任务。
计划过粗
如果一条步骤大到需要 Executor 自己再想很多层,计划就失去了大部分价值。 这时你只是把复杂度从 Planner 挪回了 Executor。
所以,一个好的计划粒度通常满足:
每一步都足够明确,能独立完成;但又不细碎到等于把 runtime 行为写死。
Replanning:Plan & Execute 真正成立的关键
如果只有“先规划,再执行”,没有重规划机制,那 Plan & Execute 只是一张脆弱的蓝图。
现实任务里,计划几乎一定会遇到变化:
- 某一步工具失败;
- 新信息推翻原假设;
- 数据源不可用;
- 用户中途修改目标;
- 某个阶段成本超预算;
- 某一步结果表明后面步骤已经没必要做。
所以,真正让 Plan & Execute 可用的,不只是 plan,而是 replan。
先看定义:Replanning 是在执行过程中,根据已完成步骤、当前状态和新约束,重新生成剩余计划。
注意这里有个很重要的细节:
Replanning 不是“从头重来”,而是“基于当前已知情况重写后半程”。
这意味着 Planner 需要知道:
- 当前已经完成了哪些步骤;
- 哪些结果可以复用;
- 哪些步骤失败了;
- 剩余目标是什么;
- 当前约束是否变化;
- 上一版计划为什么失效。
如果这些状态没有被清楚保留,所谓 Replanning 很容易退化成“重新胡思乱想一遍”。
常见的 Replanning 触发条件
| 触发条件 | 更合理的处理方式 |
|---|---|
| 工具调用失败,且无法简单重试 | 请求替代步骤或新路径 |
| 结果与预期显著不符 | 评估是否需要改计划 |
| 用户追加新目标或约束 | 将新目标并入剩余计划 |
| 某一步提前解决多个子问题 | 压缩后续计划,避免重复工作 |
| 已达到预算/时间边界 | 缩减计划,优先完成核心目标 |
Replanning 的两个常见误区
一是太不愿意重规划
计划已经明显失效,系统却继续机械执行。 这通常来自“过度信任初始计划”。
二是太容易重规划
稍微有一点偏差就整张计划重写。 这会导致:
- 运行成本飙升;
- 执行不稳定;
- 用户感知到系统一直在“改主意”。
一个更成熟的系统通常会区分:
- 可局部修补的问题
- 必须重构路径的问题
不是所有失败都值得触发 Replanning。
Plan & Execute 和 ReAct,不是替代关系,而是两种组织方式
很多文章喜欢把这两种模式写成“谁更高级”。 这其实不太准确。
更好的理解是:
- ReAct 更像一种局部决策驱动的执行方式;
- Plan & Execute 更像一种先建立任务结构、再组织执行的方式。
它们并不互斥,甚至在很多真实系统里会组合出现。
一个清晰的对比
| 维度 | ReAct | Plan & Execute |
|---|---|---|
| 规划时机 | 每一步即时决定 | 先整体规划,再执行 |
| 全局视野 | 弱 | 强 |
| 适应变化 | 强,天然逐步调整 | 依赖 Replanning |
| 表达依赖关系 | 较弱 | 较强 |
| 并行潜力 | 低到中 | 更容易表达并行 |
| 实现复杂度 | 较低 | 中等到较高 |
| 可向用户展示计划 | 一般 | 很适合 |
| 适用任务 | 开放探索、局部搜索、排查 | 多阶段任务、可拆解流程、依赖明确任务 |
先看定义:ReAct 擅长“现在先做哪一步”,Plan & Execute 擅长“整件事应该怎么分段推进”。
一个很实用的判断标准
如果任务满足下面这些特征,Plan & Execute 通常更值得考虑:
- 你大致知道任务可以拆成哪些阶段;
- 子目标之间存在明显依赖;
- 任务较长,走偏代价较高;
- 用户或系统需要看到执行计划;
- 存在并行空间;
- 某些阶段值得单独检查和确认。
如果任务更像下面这样,ReAct 往往就够了:
- 信息不完整,路径高度不确定;
- 每一步都要靠最新观察决定下一步;
- 很难在开始时写出可靠全局计划;
- 任务更像探索,而不是流水线。
不要把 Plan & Execute 理解成“规划一次就够了”
这是最常见的误解之一。
很多人会把 Plan & Execute 想成:
- 先规划一次;
- 后面完全按计划执行到底。
这样的系统在真实环境里通常很脆。 因为初始计划几乎一定是基于不完整信息做出的。 一旦执行暴露新的约束,原计划就会部分失效。
所以,Plan & Execute 的更现实版本通常是:
粗规划
-> 按阶段执行
-> 在关键节点检查
-> 必要时局部重规划
-> 继续执行
这意味着,它更像“先搭骨架,再在运行中修骨架”,而不是“一次性把所有细节计划死”。
一个例子:研究型任务中的 Plan & Execute
假设用户要求:
“帮我对比三家向量数据库方案,给出适合中型团队的建议,并说明各自的适用边界。”
如果使用 ReAct,系统可能会这样工作:
- 先查一家;
- 再查第二家;
- 再查第三家;
- 再意识到还需要比较维度;
- 再去补维度;
- 再回头找价格;
- 再补部署方式;
- 最后整理。
这条路径不一定错,但容易反复回头补信息。
而一个更像 Plan & Execute 的系统,会先形成一个计划:
- 明确比较维度:部署方式、扩展性、过滤能力、运维复杂度、成本;
- 分别收集三家产品在这些维度上的信息;
- 统一整理为结构化比较;
- 基于“中型团队”约束给出推荐;
- 补充适用边界和不适用场景。
这个计划的价值不在于“更像咨询顾问 PPT”,而在于它让执行阶段更少偏航。 后续如果发现某一家资料不足,就可以只对“信息收集阶段”局部修补,而不是整条链路来回跳。
BabyAGI 为什么值得提,但不要把它当成熟范式
原文提到 BabyAGI,这个位置是合理的,但需要稍微收紧表述。
BabyAGI 在 2023 年之所以影响大,是因为它让很多人第一次直观看到: 一个系统可以围绕任务列表循环运行,执行任务、生成新任务、重新排序任务,再继续推进。
它的重要性主要在于启发意义:
- 把任务拆解当成一等公民;
- 让执行结果反过来影响后续任务列表;
- 把“计划”理解成一种动态可更新状态。
但从今天回看,BabyAGI 更像是早期探索,而不是成熟生产模式。 它的问题包括:
- 任务生成容易发散;
- 优先级机制较粗;
- 缺少更明确的状态治理;
- 执行边界和终止条件不够强;
- 很容易看起来很忙,但不一定真的更接近目标。
所以更准确地说,BabyAGI 是动态任务规划思想的一个早期流行原型,而不是今天落地系统的默认最佳实践。
计划的表示形式:从线性列表到 DAG
如果只是最简单的任务,计划可以是自然语言列表。 但一旦涉及依赖、分支或并行,计划的表示形式就开始变得重要。
1. 线性步骤
这是最简单的形式:
Step 1 -> Step 2 -> Step 3
优点是简单,易解释。 缺点是表达能力有限,只适合严格顺序任务。
2. 带依赖的步骤列表
例如:
[
{ "id": 1, "task": "收集 A 产品信息", "depends_on": [] },
{ "id": 2, "task": "收集 B 产品信息", "depends_on": [] },
{ "id": 3, "task": "收集 C 产品信息", "depends_on": [] },
{ "id": 4, "task": "统一对比并总结", "depends_on": [1, 2, 3] }
]
这种表示已经可以支持并行执行 1、2、3,再执行 4。 对于很多中等复杂度任务来说,这就已经足够有用了。
3. 条件分支或 DAG
更复杂时,计划可能包含:
- 条件边;
- 分支路径;
- 回退节点;
- 阶段性检查点。
这时它更像一个 DAG 或工作流图,而不再只是列表。
先看定义:计划的表达能力,决定了 Agent 能处理多复杂的任务结构;但表达能力越强,实现和维护成本也越高。
所以不必一开始就上 DAG。 多数系统真正需要的,往往只是“中粒度步骤 + 基本依赖关系”。
LangGraph 为什么适合实现 Plan & Execute
LangGraph 近年的定位越来越明确:它是一个面向长流程、状态化、可控 Agent 的低层编排框架,重点是 agent orchestration、state、human-in-the-loop 和 long-running workflow。(docs.langchain.com)
这使它很适合承载 Plan & Execute 这种模式,因为这种模式天然需要:
- 显式状态;
- 清晰节点;
- 条件分支;
- 可以插入检查点;
- 执行中可能回到 Planner 节点重规划。
用图来理解它会更自然
一个典型的 Plan & Execute 图,通常包含:
- Planner Node:生成计划
- Executor Node:执行当前步骤
- State:记录计划、当前索引、执行结果、错误、预算等
- Conditional Edge:判断继续执行、完成,还是触发 Replanning
LangGraph 的 runtime 文档本身也强调其执行模型分为计划、执行和更新这类阶段,并支持按状态变化驱动后续节点。(docs.langchain.com)
这并不意味着“Plan & Execute 必须用 LangGraph 实现”,而是说:
像 LangGraph 这种把状态和控制流显式化的框架,会比单纯链式 prompt 更适合承载这类模式。
Planner 和 Executor 是否应该用不同模型
原文提到“Planner 用强模型,Executor 用便宜模型”,这个方向是对的,但可以再讲清楚一点。
同一个模型的好处
- 实现简单;
- 调试路径短;
- 不需要处理跨模型风格差异;
- 适合早期验证。
分模型的好处
- Planner 可以使用更强、更贵、推理能力更好的模型;
- Executor 可以用更快、更便宜、更偏工具调用的模型;
- 长任务里总体成本更可控。
OpenAI 的 Agent 指南也强调,模型选择应该和任务阶段匹配,不是每一步都值得使用最强模型。(developers.openai.com)
但也要看到分模型的代价:
- 计划表达可能和执行理解不一致;
- 需要更清晰的中间表示;
- 调试成本更高;
- 上下文传递更复杂。
所以,逻辑上分 Planner / Executor 很有价值;实现上是否分成两个模型,要看复杂度是否真的值得。
最佳实践:让计划“够用”,而不是“看起来很聪明”
1. 计划要服务执行,而不是服务展示
一个看起来很漂亮、层次分明的计划,如果 Executor 难以据此行动,那它只是文案,不是计划。
好的计划应该能回答:
- 当前该做哪一步?
- 完成的判据是什么?
- 失败后怎么处理?
- 哪些结果会影响后续步骤?
2. 计划粒度要可执行
经验上,计划里的每一步最好满足:
- 可以独立完成;
- 有明确输入和输出;
- 不依赖模型额外发挥太多“隐性推理”才能落地。
3. Replanning 要克制
不是所有错误都值得重规划。 很多问题只需要:
- 重试一次;
- 换一个相近工具;
- 跳过一个低优先级步骤;
- 记录为部分失败继续执行。
真正应该 Replan 的,通常是那些改变后续路径的问题。
4. 给长任务加检查点
如果任务会持续很久,或者中间动作昂贵,就应该在阶段边界保留检查点:
- 当前计划版本;
- 已完成步骤;
- 中间结果;
- 错误信息;
- 剩余目标。
这不仅有助于恢复,也有助于人工接管。
5. 让用户看到计划,尤其是在高风险场景里
Plan & Execute 的一个天然优势是: 计划可以成为用户沟通界面。
在一些高风险动作中,先把计划展示给用户,再进入执行,会比黑箱式自动推进更容易建立信任。Anthropic 关于 Agent 实践的建议里也一再强调,系统的复杂度和自主性要与风险匹配,不要为了“自动化更多”牺牲可控性。(anthropic.com)
实践中的常见坑
1. 计划过细,导致执行成本爆炸
把一个本可一次完成的动作拆成很多微步骤,结果是:
- Planner 成本高;
- Executor 步数多;
- 状态维护复杂;
- 任何偏差都会引发大面积失效。
2. 计划过粗,导致 Executor 无从下手
比如“分析问题并提出最佳方案”这种步骤,听起来像计划,实际上仍然太大。 Executor 还是得自己再做二次规划。
3. 把 Replanning 当默认动作
系统一遇到偏差就整张计划重写,最后用户会感觉它一直在推翻自己。 更好的做法是建立分层处理:
- 可修补的小错误;
- 需要局部改计划的问题;
- 必须大改路线的问题。
4. 没有显式终止条件
Plan & Execute 比 ReAct 更容易让人误以为“有计划就会自然结束”。 事实不是这样。 你仍然需要定义:
- 什么时候算完成;
- 什么时候算失败;
- 什么时候交还给用户;
- 什么时候因为预算/时间停止。
5. 把计划当真理,而不是假设
计划只是基于当前信息做出的最好猜测,不是不可动摇的真理。 如果系统过度坚持初始计划,就会丧失这种模式最该具备的韧性。
何时用 Plan & Execute
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 长任务、多阶段任务 | 很适合 | 需要更强的整体结构 |
| 明确存在依赖关系 | 很适合 | 计划能表达依赖与顺序 |
| 用户希望先看行动方案 | 很适合 | 计划本身可作为沟通界面 |
| 高风险任务 | 适合,但需加确认 | 有利于插入审批和检查点 |
| 开放式探索任务 | 未必最优 | 初始计划可能很快失效 |
| 非常短的简单任务 | 通常没必要 | 额外规划成本可能不值 |
一个很实用的经验判断是:
如果任务可以被稳定拆成几个阶段,而且走错一步的代价不低,就值得考虑 Plan & Execute。
核心概念速查
| 概念 | 一句话 |
|---|---|
| Plan & Execute | 先生成整体计划,再按计划逐步执行的 Agent 模式 |
| Planner | 负责理解目标、输出阶段或步骤结构 |
| Executor | 负责根据计划执行当前步骤并更新状态 |
| Replanning | 执行过程中基于新状态改写剩余计划 |
| 依赖关系 | 决定哪些步骤可并行、哪些必须顺序执行 |
| 检查点 | 在长任务中保存中间状态,便于恢复和人工介入 |
| vs ReAct | ReAct 偏局部决策,Plan & Execute 偏整体组织 |
小结
Plan & Execute 解决的,不是“模型会不会思考”,而是“复杂任务到底该怎么组织”。 当任务较长、依赖明显、走偏代价高时,仅靠 ReAct 的逐步试探往往不够;这时,把任务先结构化,再组织执行,会更稳定、更易解释,也更容易插入检查点、审批流和用户确认。
但要注意,Plan & Execute 并不意味着“规划一次就万事大吉”。真正让它在现实中可用的,是 Replanning:承认初始计划只是暂时假设,并允许系统在执行中基于新信息改写剩余路径。
下一篇要讲的 Reflection,会继续补上另一块重要能力: 即使有了计划和执行,Agent 仍然可能做错。那么,它该如何在运行中检查自己,并在错误扩散前及时修正?