真题拆解 05:ReAct 还是 Plan-and-Execute------规划范式怎么选
这是「真题拆解」系列的第五篇。前四篇拆的都是"怎么把 Agent 跑稳",这篇问的是架构层面的一题 :你的 Agent 用的是什么规划范式,为什么?正片第 2 篇手写过一个最小 ReAct,第 8 篇提过 Plan-Execute------这篇把它们单独拎出来正面比较。这是 Agent 架构里最高频的概念对比题,2026 年大厂校招几乎必问:因为它考的不是"背两个概念",是"你会不会在真实场景里做权衡"。
问题还原
你讲完自己的 Agent 方案,有人问了一句:
"你用的是 ReAct 还是 Plan-and-Execute?为什么用这个不用另一个?"
很多人第一反应是"ReAct 啊,最经典"。但如果追问一句"你这个场景用 ReAct 真的合适吗?换成 Plan-and-Execute 会不会更好?",答不上来了------因为从没想过"什么时候该换"。
为什么难答
难在这是对比题 :不是问"ReAct 是什么"(背定义就能过),而是问"为什么是这个不是那个"(要讲权衡逻辑)。而且两个概念不是非此即彼------生产里大量 Agent 是两者混用的。只背定义、不讲判断标准,一问就露馅。
浅答案 vs 深答案的差距:
| 浅答案:ReAct 最经典 | 深答案:按任务性质选范式 | |
|---|---|---|
| ReAct 是什么 | 背定义 | 知道它的强弱项(局部最优、绕圈、贵) |
| Plan 是什么 | 只知道名字 | 知道它强在全局规划、弱在计划可能错 |
| 判断标准 | 无 | 路径可枚举性 + 中间反馈依赖 |
| 生产形态 | 二选一 | 混合:粗规划 + 局部 ReAct |
知识点拆解:这题背后是 3 个知识点
- ReAct 的机制与代价------边想边做的优点和三个软肋
- Plan-and-Execute 的机制与代价------先规划后执行的优点和致命弱点
- 选型判断标准------什么任务用哪种,以及为什么生产主流是混合
逐个拆开。
深度答案:按"路径能不能预先枚举"来选
先看清两种范式的机制
ReAct(Reason + Act):循环地"思考 → 行动 → 观察 → 再思考",每一步根据当前结果决定下一步。
python
# ReAct:每一步都重新决策
while not done:
thought = model.think(context) # 思考:根据当前观察决定下一步
action = execute(thought.action) # 行动:调工具
context += observation(action) # 观察:把结果拼回上下文
Plan-and-Execute:先让模型一次性输出完整计划(步骤列表),再逐步执行,执行中发现问题才重新规划(replan)。
python
# Plan-and-Execute:先出计划,再执行
plan = model.plan(task) # 先整体规划:第1步查航班,第2步订票,第3步确认
for step in plan:
result = execute(step)
if not step_ok(result):
plan = model.plan(task, feedback) # 只有失败才重新规划
再对比它们的代价
| 维度 | ReAct | Plan-and-Execute |
|---|---|---|
| 决策时机 | 每步都决策 | 计划阶段决策一次 |
| 路径可枚举 | 不需要 | 需要(计划才有意义) |
| 强依赖中间反馈 | 天生适应 | 弱(计划超前于反馈) |
| 调用次数 | 多(每步一次推理) | 少(计划一次 + 执行) |
| 延迟 | 高(多轮往返) | 低 |
| token 成本 | 高(每步都带全量上下文) | 相对低 |
| 失败恢复 | 天然灵活(随时改道) | 靠 replan(晚了半步) |
| 致命弱点 | 局部最优、绕圈子、贵 | 计划错则全错,且察觉晚 |
判断标准:一句话
任务路径能不能预先枚举?强依赖中间反馈 → ReAct;路径基本确定 → Plan-and-Execute。
- 查资料类 ("对比三款大模型的 API 价格"):下一步取决于上一步查到什么 → ReAct
- 流程固定类 ("订机票:查航班→选座→支付→出票"):步骤早就知道 → Plan-and-Execute(更省更稳)
- 边界模糊类 ("帮我安排周末行程"):路径未知、反馈强依赖 → ReAct
但生产主流其实是混合
真实系统很少纯用一种。最实用的形态是**"粗粒度规划 + 局部 ReAct"**:
- 外层用 Plan-and-Execute:模型先把大目标拆成几个阶段("先查资料,再定方案,最后写报告")
- 每个阶段内部用 ReAct:阶段内部细节未知,让 Agent 边做边探索
#mermaid-svg-ZkCOrCKXHVRLIe7z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZkCOrCKXHVRLIe7z .error-icon{fill:#552222;}#mermaid-svg-ZkCOrCKXHVRLIe7z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZkCOrCKXHVRLIe7z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .marker.cross{stroke:#333333;}#mermaid-svg-ZkCOrCKXHVRLIe7z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZkCOrCKXHVRLIe7z p{margin:0;}#mermaid-svg-ZkCOrCKXHVRLIe7z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster-label text{fill:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster-label span{color:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster-label span p{background-color:transparent;}#mermaid-svg-ZkCOrCKXHVRLIe7z .label text,#mermaid-svg-ZkCOrCKXHVRLIe7z span{fill:#333;color:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .node rect,#mermaid-svg-ZkCOrCKXHVRLIe7z .node circle,#mermaid-svg-ZkCOrCKXHVRLIe7z .node ellipse,#mermaid-svg-ZkCOrCKXHVRLIe7z .node polygon,#mermaid-svg-ZkCOrCKXHVRLIe7z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .rough-node .label text,#mermaid-svg-ZkCOrCKXHVRLIe7z .node .label text,#mermaid-svg-ZkCOrCKXHVRLIe7z .image-shape .label,#mermaid-svg-ZkCOrCKXHVRLIe7z .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZkCOrCKXHVRLIe7z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .rough-node .label,#mermaid-svg-ZkCOrCKXHVRLIe7z .node .label,#mermaid-svg-ZkCOrCKXHVRLIe7z .image-shape .label,#mermaid-svg-ZkCOrCKXHVRLIe7z .icon-shape .label{text-align:center;}#mermaid-svg-ZkCOrCKXHVRLIe7z .node.clickable{cursor:pointer;}#mermaid-svg-ZkCOrCKXHVRLIe7z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .arrowheadPath{fill:#333333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZkCOrCKXHVRLIe7z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZkCOrCKXHVRLIe7z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZkCOrCKXHVRLIe7z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster text{fill:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z .cluster span{color:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZkCOrCKXHVRLIe7z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZkCOrCKXHVRLIe7z rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZkCOrCKXHVRLIe7z .icon-shape,#mermaid-svg-ZkCOrCKXHVRLIe7z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZkCOrCKXHVRLIe7z .icon-shape p,#mermaid-svg-ZkCOrCKXHVRLIe7z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZkCOrCKXHVRLIe7z .icon-shape .label rect,#mermaid-svg-ZkCOrCKXHVRLIe7z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZkCOrCKXHVRLIe7z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZkCOrCKXHVRLIe7z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZkCOrCKXHVRLIe7z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
否
是
大任务
Plan: 拆成阶段
阶段1 内部 ReAct 探索
阶段1 完成
阶段2 内部 ReAct
全部完成
计划需要修正
replan 重新规划
完成
为什么混用?因为纯 Plan 怕"计划外的意外",纯 ReAct 怕"没有全局目标的乱撞"------混合让计划提供方向、ReAct 处理细节,两边的软肋互相补掉。这就是生产里最常看到的 Agent 形态。
知识联动:这道题串起了整个系列
| 知识点 | 串起的系列篇目 | 关联 |
|---|---|---|
| ReAct 循环 | 第 2 篇 手写 ReAct | 那 50 行就是最朴素的 ReAct |
| 多 Agent 编排 | 第 8 篇 编排与多 Agent | 任务分解 = Plan,执行细节 = ReAct |
| 死循环防护 | 真题 01 | ReAct 的绕圈子是死循环根因之一,靠熔断兜底 |
| 上下文成本 | 第 4 篇 上下文管理 | ReAct 每步带全量上下文,是 token 大户 |
这道题之所以高频,是因为它把架构选择、成本、延迟、容错全串在了一个判断里------答的时候能一路延伸到"为什么生产用混合",说明你是真做过权衡,不是背概念。
追问链:更进一步的提问
追问 1:"Plan 的计划错了怎么办?"
→ 靠 replan:执行中发现步骤失败或结果不符合预期,就带着反馈重新规划。但要承认 replan 是"事后补救"------计划错得越晚,浪费越多。所以 Plan 适合"大方向稳定、细节允许偏差"的任务,方向都可能错的场景不要用 Plan。
追问 2:"ReAct 为什么 token 消耗大?"
→ 每步思考都要把"原始任务 + 全部历史观察"重新发给模型,轮数越多上下文越长,成本随轮数二次增长。Plan-and-Execute 执行阶段步骤独立,上下文可以裁剪。这也是为什么"省成本"常常是选 Plan 的理由。
追问 3:"什么时候 Plan 反而不省?"
→ 路径太动态时,计划很快失效,反复 replan 比直接 ReAct 还贵------"计划了个寂寞"。判断标准回到原点:路径能枚举才值得规划。
追问 4:"混合范式里 replan 的触发条件是什么?"
→ 常见三种:步骤执行失败 (工具报错)、结果偏离预期 (校验不通过)、进度停滞(连续 N 步无推进,联动真题 01 的无进展检测)。触发后重新规划整个阶段,而不是只改下一步------不然会陷入局部打补丁。
总结:一句话记住它
路径能枚举用 Plan(省、稳),路径未知强依赖反馈用 ReAct(活、贵);而生产主流是"粗规划 + 局部 ReAct"------计划给方向,ReAct 处理细节,两边的软肋互相补掉。