Plan & Execute

先规划再执行的两阶段架构、Replanning 机制、与 ReAct 的对比,以及 LangGraph 等实现方式

17 min read Part of Agent · Ch. 4
← 上一层级:学习路径 · Part 03 · Agent 设计与工程

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。

它把原本混在同一个循环里的两件事拆开了:

  1. Plan 阶段:先回答“整体上应该怎么做”
  2. Execute 阶段:再回答“现在具体做哪一步、怎么做”

这个拆分看起来简单,但它带来了很重要的变化:

  • 任务被显式结构化;
  • 执行不再完全依赖即时灵感;
  • 可以更容易表达依赖、阶段、并行和检查点;
  • 用户和系统都更容易理解“接下来要做什么”。

从系统设计上说,这也是上一篇提到的 Planner / Executor 职责分离的一种更明确实现。

两阶段架构:先规划,再执行

最基本的 Plan & Execute 架构可以写成:

阶段负责角色输入输出
PlanPlanner用户目标、约束、可用工具、当前状态一个计划:步骤列表、依赖关系、阶段划分
ExecuteExecutor当前步骤、上下文、执行历史、工具返回步骤结果、状态更新、是否继续/是否需要重规划

如果写成更直观的流程,大致是:

User Goal
  -> Planner 生成计划
  -> Executor 执行步骤 1
  -> Executor 执行步骤 2
  -> ...
  -> 若偏离预期,则触发 Replanning
  -> 最终输出

它和 ReAct 的最大区别,不在于“有没有循环”,而在于:

循环前面多了一个“先做结构化理解”的阶段。

这意味着,Plan & Execute 并不意味着完全没有动态调整;它只是把动态调整放在“有初始计划”的前提下发生。

计划到底是什么:不是漂亮清单,而是任务结构

很多人第一次接触 Plan & Execute,会把“计划”理解成一串自然语言待办项,比如:

  1. 搜索资料
  2. 阅读资料
  3. 整理结论
  4. 输出报告

这种表示当然可以作为最简版本,但从工程角度看,它常常不够。

一个真正有用的计划,至少应该表达其中的一部分信息:

  • 步骤是什么;
  • 每一步的目标是什么;
  • 哪些步骤必须先做;
  • 哪些步骤可以并行;
  • 哪些步骤需要用户确认;
  • 什么条件下任务算完成;
  • 哪些失败可以重试,哪些失败应触发改计划。

所以,计划的价值不在于“列了几条”,而在于它是否把任务的结构表达出来。

计划可以有不同粒度

计划粒度特点适用情况
粗粒度阶段先定义 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 更像一种先建立任务结构、再组织执行的方式。

它们并不互斥,甚至在很多真实系统里会组合出现。

一个清晰的对比

维度ReActPlan & Execute
规划时机每一步即时决定先整体规划,再执行
全局视野
适应变化强,天然逐步调整依赖 Replanning
表达依赖关系较弱较强
并行潜力低到中更容易表达并行
实现复杂度较低中等到较高
可向用户展示计划一般很适合
适用任务开放探索、局部搜索、排查多阶段任务、可拆解流程、依赖明确任务

先看定义:ReAct 擅长“现在先做哪一步”,Plan & Execute 擅长“整件事应该怎么分段推进”。

一个很实用的判断标准

如果任务满足下面这些特征,Plan & Execute 通常更值得考虑:

  • 你大致知道任务可以拆成哪些阶段;
  • 子目标之间存在明显依赖;
  • 任务较长,走偏代价较高;
  • 用户或系统需要看到执行计划;
  • 存在并行空间;
  • 某些阶段值得单独检查和确认。

如果任务更像下面这样,ReAct 往往就够了:

  • 信息不完整,路径高度不确定;
  • 每一步都要靠最新观察决定下一步;
  • 很难在开始时写出可靠全局计划;
  • 任务更像探索,而不是流水线。

不要把 Plan & Execute 理解成“规划一次就够了”

这是最常见的误解之一。

很多人会把 Plan & Execute 想成:

  1. 先规划一次;
  2. 后面完全按计划执行到底。

这样的系统在真实环境里通常很脆。 因为初始计划几乎一定是基于不完整信息做出的。 一旦执行暴露新的约束,原计划就会部分失效。

所以,Plan & Execute 的更现实版本通常是:

粗规划
 -> 按阶段执行
 -> 在关键节点检查
 -> 必要时局部重规划
 -> 继续执行

这意味着,它更像“先搭骨架,再在运行中修骨架”,而不是“一次性把所有细节计划死”。

一个例子:研究型任务中的 Plan & Execute

假设用户要求:

“帮我对比三家向量数据库方案,给出适合中型团队的建议,并说明各自的适用边界。”

如果使用 ReAct,系统可能会这样工作:

  • 先查一家;
  • 再查第二家;
  • 再查第三家;
  • 再意识到还需要比较维度;
  • 再去补维度;
  • 再回头找价格;
  • 再补部署方式;
  • 最后整理。

这条路径不一定错,但容易反复回头补信息。

而一个更像 Plan & Execute 的系统,会先形成一个计划:

  1. 明确比较维度:部署方式、扩展性、过滤能力、运维复杂度、成本;
  2. 分别收集三家产品在这些维度上的信息;
  3. 统一整理为结构化比较;
  4. 基于“中型团队”约束给出推荐;
  5. 补充适用边界和不适用场景。

这个计划的价值不在于“更像咨询顾问 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 ReActReAct 偏局部决策,Plan & Execute 偏整体组织

小结

Plan & Execute 解决的,不是“模型会不会思考”,而是“复杂任务到底该怎么组织”。 当任务较长、依赖明显、走偏代价高时,仅靠 ReAct 的逐步试探往往不够;这时,把任务先结构化,再组织执行,会更稳定、更易解释,也更容易插入检查点、审批流和用户确认。

但要注意,Plan & Execute 并不意味着“规划一次就万事大吉”。真正让它在现实中可用的,是 Replanning:承认初始计划只是暂时假设,并允许系统在执行中基于新信息改写剩余路径。

下一篇要讲的 Reflection,会继续补上另一块重要能力: 即使有了计划和执行,Agent 仍然可能做错。那么,它该如何在运行中检查自己,并在错误扩散前及时修正?