Plan-and-Solve 与动态重规划
难度:中级 分类:Planning & Reasoning
简短回答
Plan-and-Solve (PS) 是 Wang et al. (2023, ACL) 提出的零样本 Prompting 策略,核心思想是将任务执行分为"先制定计划、再逐步执行"两个阶段,解决了 Zero-shot CoT 的计算错误、遗漏步骤和语义理解错误三大问题。增强版 PS+ 加入了"提取变量"、"计算中间结果"、"检查计算"等指令,在多个数学推理基准上接近 Few-shot CoT——而无需提供任何示例。在 Agent 系统中,PS 演化为 Plan-and-Execute 架构:Planner Agent 生成全局计划,Executor Agent 逐步执行。然而初始计划不可能完美,执行中必然遇到意外(工具失败、信息偏离、环境变化),因此需要**动态重规划(Replanning)**能力。重规划包含三大机制:触发条件检测(何时重规划)、计划修正策略(如何修改)、上下文保持(保留已完成进度)。前沿框架 DuSAR 结合子目标导向的全局规划与经验驱动的局部适应,ALAS 引入事务性计划执行实现步骤级回滚与重试。从静态规划到动态调整,形成了完整的 Agent 规划闭环。
详细解析
一、从 Zero-shot CoT 到 Plan-and-Solve
代码块
Plain Text
Zero-shot CoT:
Prompt: "问题... Let's think step by step."
问题:
1. 可能遗漏关键步骤
2. 可能出现计算错误
3. 模型自由发挥,推理质量不稳定
Plan-and-Solve (PS):
Prompt: "问题... Let's first understand the problem and
devise a plan to solve it. Then, let's carry out
the plan and solve the problem step by step."
改进:
1. 明确要求先"理解问题"
2. 明确要求"制定计划"
3. 然后按计划执行
二、PS vs PS+ 的 Prompt 模板
代码块
Python
# 基础 PS Prompt
ps_prompt = """
{question}
Let's first understand the problem and devise a plan to solve it.
Then, let's carry out the plan and solve the problem step by step.
"""
# 增强版 PS+ Prompt(加入更详细的指令)
ps_plus_prompt = """
{question}
Let's first understand the problem, extract relevant variables
and their corresponding numerals, and devise a plan to solve it.
Then, let's carry out the plan, calculate intermediate results
三、基准测试结果
数学推理基准(text-davinci-003,PS 原论文 Table 4):
#guqTUMbXlqoe text { white-space: pre; }#guqTUMbXlqoe .fb0 { stroke: var(--N900-FG, 0.15); }#guqTUMbXlqoe .fb0 {stroke: rgba(31,35,41, 0.15)}#guqTUMbXlqoe .fx0 { stroke-miterlimit: 10; }#guqTUMbXlqoe .fx0 {stroke-miterlimit: 10}#guqTUMbXlqoe .fa1 { fill: rgb(187, 191, 196); }#guqTUMbXlqoe .fa1 {fill: rgb(187, 191, 196)}#guqTUMbXlqoe .fx1 { font: 400 12px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#guqTUMbXlqoe .fx1 {font-style: normal}#guqTUMbXlqoe .fx2 { text-anchor: middle; }#guqTUMbXlqoe .fx2 {text-anchor: middle}#guqTUMbXlqoe .fx3 { dominant-baseline: central; }#guqTUMbXlqoe .fx3 {dominant-baseline: central}#guqTUMbXlqoe .fx4 { stroke: none; }#guqTUMbXlqoe .fx4 {stroke: none}#guqTUMbXlqoe .fc0 { fill: var(--text-caption); }#guqTUMbXlqoe .fc0 {fill: #646a73}#guqTUMbXlqoe .fa2 { fill: var(--text-link-disabled); }#guqTUMbXlqoe .fa2 {fill: rgb(187, 191, 196)}#guqTUMbXlqoe .fx5 { font: 400 13px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#guqTUMbXlqoe .fx5 {font-style: normal}#guqTUMbXlqoe .fx6 { text-anchor: start; }#guqTUMbXlqoe .fx6 {text-anchor: start}#guqTUMbXlqoe .fx7 { dominant-baseline: alphabetic; }#guqTUMbXlqoe .fx7 {dominant-baseline: alphabetic}#guqTUMbXlqoe .fc1 { fill: rgb(0, 0, 0); }#guqTUMbXlqoe .fc1 {fill: rgb(0, 0, 0)}#guqTUMbXlqoe .fb1 { fill: var(--N900-FG, 0.15); }#guqTUMbXlqoe .fb1 {fill: rgba(31,35,41, 0.15)}#guqTUMbXlqoe .fb2 { fill: rgb(209, 217, 224); }#guqTUMbXlqoe .fb2 {fill: rgb(209, 217, 224)}#guqTUMbXlqoe .fa3 { fill: var(--bg-body); }#guqTUMbXlqoe .fa3 {fill: #fff}ABCD123456方法Zero-shotZero-shot CoTPlan-and-SolvePS+Few-shot CoTGSM8K17.756.458.259.358.4SVAMP65.474.377.879.279.4MultiArith22.778.787.291.893.6
注意:
•
数字以 Wang et al. 2023 PS Prompting 原论文 Table 4 为准(text-davinci-003 / Zero-shot CoT 对照)。
•
不同复现/不同 base model 数字会有抖动,但 Few-shot CoT 在 MultiArith 上保持 ~93%,PS+ 接近 92%,远高于早期勘误中常见的"83.8%"。
•
PS+ 几乎追平 Few-shot CoT,但不需要提供任何示例!
四、Plan-and-Execute Agent 架构
Plan-and-Solve 在 Agent 系统中演化为 Plan-and-Execute 架构,将规划与执行分离为独立模块:
代码块
Python
class PlanAndExecuteAgent:
"""Plan-and-Solve 在 Agent 系统中的扩展"""
def __init__(self, planner_llm, executor_llm, tools):
self.planner = planner_llm # 规划用的 LLM(可用更强模型)
五、与 ReAct 的对比
代码块
Plain Text
ReAct(思考 → 行动 → 观察 循环):
✓ 灵活,根据每步结果动态决策
✗ 没有全局视角,容易陷入局部循环
✗ 短视——只看下一步,不看全局
Plan-and-Execute:
✓ 先有全局计划,再逐步执行
✓ 计划明确了总步数和依赖关系
✓ 支持对计划的提前审核
✗ 初始计划可能不完美
✗ 需要重规划机制应对意外
混合方案(LangGraph 推荐):
六、LangGraph 中的 Plan-and-Execute
代码块
Python
七、为什么需要动态重规划?
静态计划无法应对执行中的意外,当步骤失败或前提假设被推翻时,Agent 需要动态调整:
代码块
Plain Text
初始计划:
Step 1: 搜索竞品A的数据 ✅ 完成
Step 2: 搜索竞品B的数据 ❌ API 超时,未获取到
Step 3: 对比分析 A 和 B → 依赖 Step 2,无法执行
Step 4: 生成报告
不重规划 → Agent 卡死或跳过关键步骤
重规划后:
Step 2': 换用备用数据源搜索竞品B
Step 3: 对比分析(保持不变)
Step 4: 生成报告(保持不变)
八、重规划的触发条件
代码块
Python
class ReplanTrigger:
"""检测何时需要重规划"""
def should_replan(self, state) -> bool:
# 触发条件 1:步骤执行失败
if state.last_step_failed:
return True
# 触发条件 2:结果与预期严重偏离
if state.deviation_score > self.threshold:
return True
# 触发条件 3:发现新信息改变了前提假设
if state.assumptions_invalidated:
return True
九、重规划策略
策略 1:反应式重规划
步骤失败时立即触发,保留已完成进度,重新规划剩余部分:
代码块
Python
class ReactiveReplanner:
"""步骤失败时立即重规划"""
策略 2:周期性重规划
每执行 N 步后主动评估计划有效性,无需等待失败:
代码块
Python
class PeriodicReplanner:
"""每 N 步重新评估和调整计划"""
async def execute_with_checkpoints(self, plan, task):
results = []
checkpoint_interval = 3 # 每 3 步检查一次
for i, step in enumerate(plan.steps):
result = await self.execute_step(step)
results.append(result)
# 每 N 步检查是否需要调整计划
策略 3:ALAS 事务性规划
每个步骤作为原子事务执行,失败可回滚和重试:
代码块
Python
class TransactionalPlanner:
"""ALAS: 每个步骤作为原子事务执行"""
async def execute_step_transactional(self, step, context):
"""事务性执行:成功提交,失败回滚"""
checkpoint = self.save_state() # 保存当前状态
try:
十、DuSAR 双策略框架
DuSAR 结合全局规划与局部适应,在长时域任务上表现优异:
代码块
Python
class DuSAR:
"""双策略自适应推理框架"""
async def solve(self, task):
# 策略 1:子目标导向(全局规划)
subgoals = await self.decompose_to_subgoals(task)
for subgoal in subgoals:
# 策略 2:经验驱动(局部适应)
# 从历史执行中学习类似子目标的最佳策略
strategy = self.experience_bank.get_best_strategy(subgoal)
if strategy:
result = await self.execute_with_strategy(subgoal, strategy)
else:
result = await self.explore_new_strategy(subgoal)
# 动态调整:根据结果更新后续子目标
if result.changes_context:
十一、重规划的关键设计原则
代码块
JSON
十二、实际系统中的重规划架构
Plan-and-Execute 闭环:Executor 被 Monitor 盯梢,偏差触发 Replanner 生成新计划回灌执行。
适用场景总结
常见误区 / 面试追问
误区:"Plan-and-Solve 就是 Chain-of-Thought 的变体" — PS 不仅是让模型"逐步思考",而是明确将过程分为"规划"和"执行"两个独立阶段。CoT 是一次性生成推理链,PS 是先生成计划再按计划执行。
误区:"计划一旦制定就不应该改变" — 好的 Plan-and-Execute 系统必须支持重规划(Replanning)。执行过程中可能遇到意外情况(工具失败、信息不符合预期),需要动态调整计划。
误区:"每次失败都应该重规划" — 不是所有失败都需要重规划。瞬时错误(网络超时)用重试就行,只有结构性问题(方案不可行、前提假设变化)才需要重规划。过于频繁的重规划浪费计算资源且可能引入新问题。
误区:"重规划 = 重新从头开始规划" — 好的重规划是增量修改——保留已完成的进度和仍然有效的步骤,只修改必须改变的部分。全部推翻重来是最后手段。
追问:"PS+ 为什么不需要 Few-shot 示例就能接近 Few-shot CoT?" — 因为 PS+ 的详细指令(提取变量、计算中间结果、注意计算正确性)本质上将 Few-shot 示例中隐含的推理策略显式化了。指令替代了示例的作用。
追问:"Plan-and-Execute 架构中,Planner 和 Executor 应该用同一个模型吗?" — 不一定。常见做法是 Planner 用更强的模型(如 Claude Opus)保证计划质量,Executor 用更快更便宜的模型(如 Claude Haiku)降低成本。这种异构模型配置是生产中的最佳实践。
追问:"如何防止重规划陷入循环?" — 三层防御:(1) 记录失败的计划,新计划不能重复;(2) 设置最大重规划次数上限;(3) 每次重规划必须与前次不同——可以用 LLM 自评判断新计划是否实质性不同。
追问:"重规划的成本如何控制?" — 只在必要时重规划(而非每步都重规划);重规划只传递摘要而非完整历史(控制 token 用量);Planner 可以用较小模型做快速重规划,只在关键决策点用大模型。