💡 核心摘要 :Planning 是 Agent 面对任务时,决定"怎么做""先做什么后做什么""用什么工具做"的核心过程。本文系统梳理 8 种纯 LLM 规划范式与 8 种混合规划模式,每种均配有直观流程图、适用场景与工程实现要点,助你根据实际需求选择最合适的方案。
上一篇文章讲解了 Agent 的四大核心组件,感兴趣可以在专栏中查看,今天专门深入聊聊组件之一的 Planning(规划) 。
Planning 的本质,就是让 Agent "会规划任务"。它的实现方式多样,从纯 LLM 自主规划到代码与 LLM 协同的混合规划,各有其适用边界。别一上来就追求最复杂的方案,够用、有效才是最优解。
一、LLM-based Planning:纯大模型规划
这种方式的核心思想是:任务分解、步骤生成、工具选择,全部由 LLM 自主完成 。代码仅负责执行 LLM 输出的指令,不参与规划逻辑本身。
1. CoT(Chain-of-Thought):让 LLM 展示推理过程
CoT 是最基础的规划方式,核心是通过 Prompt 引导 LLM 显式输出中间推理步骤,而非直接给出答案。
案例 :数学题"小明有 15 个苹果,给出去 7 个,又买了 5 个,还剩几个?"
- 不用 CoT:LLM 可能直接输出"13 个"(易出错)
- 用 CoT:LLM 输出"15 - 7 = 8;8 + 5 = 13",再给出答案"13 个"
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt
"请一步步思考:小明有15个苹果,给出去7个,
又买了5个,还剩几个?展示你的推理过程。"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
推理:15 - 7 = 8,8 + 5 = 13
答案:13
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 直接输出结果,结束
(无循环,单次调用)
└─────────────────────────────────────────┘
| 维度 | 说明 |
|---|---|
| 适用场景 | 数学、逻辑、常识推理等需要显式推理的任务 |
| 优点 | 简单直接,Token 成本低 |
| 缺点 | 单次调用,无迭代改进空间 |
2. ReAct(Reasoning + Acting):思考-行动-观察循环
ReAct 是目前最主流 的规划方式,核心是让 LLM 交替进行 Thought → Action → Observation 循环,直到生成 Final Answer。
案例 :"查北京今天天气,然后建议穿衣"
- LLM Thought:"需要先查天气" → Action:
search('北京天气') - 代码执行搜索,返回 Observation:"北京 25 度,晴天"
- LLM Thought:"天气晴朗温暖" → Final Answer:"建议穿短袖,带件薄外套"
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(第1轮)
"你可以使用工具:search(query)
任务:查北京今天天气,然后建议穿衣。
请按以下格式回答:
Thought: [你的思考,分析需要什么信息]
Action: 工具名
Observation: [等待系统返回结果,不要编造]
开始:"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
Thought: 我需要先查天气
Action: search('北京天气')
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 解析 Action,调用搜索工具
代码 → 获取 Observation:晴天 25°C
代码 → 拼接回 Prompt
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(第2轮)
Thought: 我需要先查天气
Action: search('北京天气')
Observation: 晴天 25°C
(继续生成)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
Thought: 天气晴朗温暖
Final Answer: 建议穿短袖,带件薄外套
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 检测到 "Final Answer",终止循环
代码 → 输出最终答案
└─────────────────────────────────────────┘
工程实现要点 :
- 循环控制器 :解析 LLM 输出的 Action,判断是否继续
- 工具执行器 :调用真实工具,获取 Observation
- 状态管理器 :拼接 Thought+Action+Observation 到对话历史
- 终止判断器 :检测到
Final Answer或达最大步数时停止
| 维度 | 说明 |
|---|---|
| 适用场景 | 工具调用、实时查询、多步交互任务 |
| 优点 | 灵活,能基于观察结果纠正错误 |
| 缺点 | 需要代码实现循环控制,Token 消耗随轮次增加 |
3. ToT(Tree of Thoughts):生成多个思路,评估后选择最优
ToT 的核心是生成多个候选思路 → 评估打分 → 选择最优路径继续探索 ,类似树搜索算法。
案例 :用 4、5、6、7 四个数字得到 26
- 生成 3 个候选算式:A=(7-5)4=8;B=65=30;C=(6+4)*5=50
- 评估离 26 的距离:A=6分,B=8分,C=3分
- 选择最高分 B(30),继续从该节点扩展:30-4=26 ✓
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(扩展,调3次)
"当前可用数字:4,5,6,7
请生成一个算式尝试得到26,
只输出一个具体的算式尝试,不要解释,不要评估
例如:(7-5) * 6 + 4 = 16"
(temperature=0.7,独立调用3次)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回3个候选
候选A: (7-5)*4 = 8
候选B: 6*5 = 30
候选C: (6+4)*5 = 50
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(评估)
"请评估以下算式离26的距离(1-10分):
A=8, B=30, C=50"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
A:6分, B:8分, C:3分
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 选最高分B(30),作为当前节点
代码 → 检测是否等于26?否,继续循环
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(从B扩展,调3次)
"当前已有30,剩余数字可用4,7
请生成新算式:"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
候选D: 30-4 = 26 ✓
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 检测到26,终止
代码 → 输出路径:6*5-4 = 26
└─────────────────────────────────────────┘
工程实现要点 :
- 候选生成器 :调 LLM 多次生成(temperature>0),获取多样思路
- 评估函数 :可以是规则(如"含数字 26 得 10 分")或另一个 LLM
- 树搜索算法 :BFS/DFS/Beam Search,决定扩展哪个节点、何时回溯
- 选择器 :基于评估分数,选择最优路径继续或输出
| 维度 | 说明 |
|---|---|
| 适用场景 | 谜题、创意生成、多方案决策 |
| 优点 | 能探索多种可能性,避免陷入局部最优 |
| 缺点 | 需要评估函数,Token 成本高 |
4. GoT(Graph of Thoughts):图结构推理
GoT 是 ToT 的进阶版,核心是多源信息聚合、精炼、循环改进 ,支持节点间的合并、拆分、回溯等图操作。
案例 :分析 AI 对教育的影响
- 生成三个观点:A(技术)、B(社会)、C(伦理)
- 判断可聚合性:发现 A 与 B 矛盾,先生成调和观点 E
- 将 E、B、C 聚合成综合结论 D
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(扩展)
"请从技术、社会、伦理3个角度
分析AI对教育的影响"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
观点A(技术):AI实现个性化学习
观点B(社会):加剧教育资源不平等
观点C(伦理):数据隐私风险
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 创建节点A、B、C,存入图结构
代码 → 发送 Prompt(判断)
"这3个观点能聚合吗?有矛盾吗?
输出JSON:{'可聚合':true/false,
'矛盾':['']}"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
{'可聚合':true, '矛盾':['A与B']}
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 解析JSON,决策:先调和再聚合
代码 → 发送 Prompt(调和)
"观点A说AI降本,观点B说加剧不平等,请调和这个矛盾"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
调和观点E:AI降本但需政策保障公平分配
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 创建节点E,画边 A→E, B→E
代码 → 发送 Prompt(聚合)
"请将E、B、C聚合成综合结论"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
综合观点D:AI教育需技术创新+政策调控+隐私保护
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 创建节点D,画边 E→D, B→D, C→D
代码 → 检测D的质量分 > 8?是 → 终止
否 → 回到精炼步骤
└─────────────────────────────────────────┘
工程实现要点 :
- 图结构管理 :维护节点和边的关系(可聚合、可循环)
- 聚合操作器 :将多个节点输入 LLM,要求合并共同之处
- 精炼循环器 :检测需要改进的节点,触发 LLM 重新生成
- 遍历控制器 :决定扩展、聚合还是精炼
| 维度 | 说明 |
|---|---|
| 适用场景 | 复杂信息整合、多维度分析、报告生成 |
| 优点 | 比 ToT 更灵活,支持信息融合与迭代优化 |
| 缺点 | 实现复杂,调试困难,Token 成本高 |
5. Reflexion:执行后评估,迭代改进
Reflexion 的核心是生成 → 外部评估 → 反思改进 → 再生成 的闭环,强调从失败中学习。
案例 :写一段快速排序代码
- 生成代码版本 1,运行测试:3 通过 / 2 失败
- LLM 反思:"边界条件处理不当" → 改进方案:"增加空列表判断"
- 生成代码版本 2,运行测试:5 全部通过 ✓
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(生成)
"请写一段快速排序代码"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
[代码版本1]
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 执行测试用例
代码 → 获取结果:3个通过,2个失败
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 检测全部通过?否,发送Prompt(反思)
"测试失败了,请分析问题并给出改进方案"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
问题:边界条件处理不当
改进:增加空列表判断
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(改进)
"请按改进方案重写代码"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
[代码版本2]
│
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 执行测试用例
代码 → 获取结果:5个全部通过 ✓
代码 → 检测通过?是 → 终止,输出版本2
否 → 继续循环(最多5轮)
└─────────────────────────────────────────┘
工程实现要点 :
- 外部评估器 :执行测试、规则检查或调 LLM 打分
- 记忆存储器 :保存历史尝试和失败经验
- 迭代控制器 :设置最大反思次数,防止无限循环
- 结果比较器 :对比多版输出,选择最优
| 维度 | 说明 |
|---|---|
| 适用场景 | 代码生成、高精度任务、可验证输出 |
| 优点 | 能持续改进质量,从失败中学习 |
| 缺点 | 依赖外部反馈信号,迭代成本高 |
6. ReWOO(Reasoning w/o Observation):先规划所有步骤,再批量执行
ReWOO 的核心是一次性规划所有工具调用 → 批量并行执行 → 最后总结 ,避免 ReAct 的多轮交互开销。
案例 :查 5 个城市的天气
- LLM 生成完整计划:
["search('北京')", "search('上海')", ...] - 代码并行执行 5 个搜索,获取所有结果
- LLM 基于所有结果生成对比分析
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(规划)
"请一次性规划查5个城市天气需要的所有工具调用"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
["search('北京')",
"search('上海')",
"search('广州')",
"search('深圳')",
"search('杭州')"]
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 解析工具列表
代码 → 批量并行执行5个搜索
代码 → 获取所有结果
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 拼接结果到 Prompt(总结)
"北京25°C,上海28°C,广州32°C,
深圳30°C,杭州26°C,
请给出对比分析"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
最热的城市是广州32°C,建议...
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 输出最终结果
(无循环,只调2次LLM:规划+总结)
└─────────────────────────────────────────┘
工程实现要点 :
- 计划解析器 :从 LLM 输出中提取工具调用列表
- 批量执行器 :并行或串行执行所有工具调用
- 结果注入器 :将工具返回替换到 Prompt 的 Observation 位置
- 最终生成器 :调 LLM 一次,基于所有结果生成答案
| 维度 | 说明 |
|---|---|
| 适用场景 | 低成本、确定性高、可并行的任务 |
| 优点 | Token 消耗低,执行效率高 |
| 缺点 | 无中途纠正能力,依赖规划准确性 |
7. Plan-and-Execute:先全局规划,再分步执行
Plan-and-Execute 的核心是先生成全局计划 → 逐步执行 → 异常时触发重规划 ,兼顾全局视野与局部适应性。
案例 :制定从北京到上海出差的完整计划
- LLM 生成全局计划:订机票 → 订酒店 → 参加会议
- 执行步骤 1(订机票)→ 成功
- 执行步骤 2(订酒店)→ 失败(满房)
- 触发重规划:换酒店 → 调整会议时间
- 继续执行至完成
bash
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(规划)
"请制定从北京到上海出差的完整计划"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
步骤1:订机票
步骤2:订酒店
步骤3:参加会议
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 解析步骤列表
代码 → 执行步骤1:订机票 → 成功
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 执行步骤2:订酒店 → 失败(满房)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 检测异常?是,触发重规划
代码 → 发送 Prompt(重规划)
"酒店满了,请重新规划剩余步骤"
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回
新步骤2:换另一家酒店
步骤3:调整会议时间
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 执行新步骤2 → 成功
代码 → 执行步骤3 → 成功
代码 → 全部完成,输出最终行程
└─────────────────────────────────────────┘
工程实现要点 :
- 计划解析器 :将自然语言计划解析为结构化步骤列表
- 步骤执行器 :按顺序执行每一步,监控执行状态
- 异常检测器 :判断执行结果是否偏离预期
- 重规划触发器 :异常时,将状态+目标传给 LLM 重新制定计划
- 状态同步器 :更新已完成步骤、当前资源、剩余任务
| 维度 | 说明 |
|---|---|
| 适用场景 | 复杂多步骤任务、长流程自动化 |
| 优点 | 全局视野 + 局部调整,适应性强 |
| 缺点 | 实现复杂,重规划增加 Token 成本 |
8. LATS(Language Agent Tree Search):蒙特卡洛树搜索决策
LATS 的核心是将 MCTS(蒙特卡洛树搜索) 应用于 LLM 决策,通过模拟、评估、回溯选择最优动作序列。
案例 :围棋对弈
- UCB 公式选择节点,生成 3 个候选动作
- 对每个动作快速模拟(rollout)5 步,评估终局得分
- 回溯更新树节点统计值,选择 UCB 最高的节点继续扩展
- 循环直至选出最优动作
bash
┌─────────────────────────────────────────┐
代码 → UCB公式选择节点(初始只有根节点)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 发送 Prompt(扩展,调3次)
"当前局面:围棋第50手,黑棋优势
请生成3个可能的下一手:"
(temperature=0.7,独立调用3次)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
LLM 返回3个候选动作
动作A:占角(胜率预估55%)
动作B:守边(胜率预估52%)
动作C:打入(胜率预估48%)
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 对每个动作快速模拟(rollout)
代码 → 随机走5步,评估终局结果
代码 → 获取评分:A=60, B=55, C=50
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 回溯更新树:A访问+1,累计分+60
代码 → UCB计算,A得分最高
代码 → 选择A作为下一轮扩展节点
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
代码 → 检测A是否达到目标胜率(如>90%)?
否 → 回到扩展步骤,继续循环
是 → 终止,输出A为最优动作
└─────────────────────────────────────────┘
工程实现要点 :
- UCB 计算器 :实现公式平衡探索/利用
- 节点管理器 :维护树结构,记录访问次数、得分、父子关系
- 模拟 rollout :快速执行评估终局结果
- 回溯更新器 :反向传播更新路径上所有节点统计值
- 选择执行器 :多轮迭代后选择得分最高的动作
| 维度 | 说明 |
|---|---|
| 适用场景 | 复杂工具调用、博弈、多步决策 |
| 优点 | 决策质量高,能探索长期最优策略 |
| 缺点 | Token 成本极高,实现复杂度最高 |
纯 LLM 规划选型速查表
| 任务特征 | 推荐范式 | 核心理由 |
|---|---|---|
| 简单推理、低成本 | CoT / ReWOO | 单次或两次调用,Token 消耗最低 |
| 工具调用、实时交互 | ReAct | 业界标准,灵活可靠 |
| 多方案探索、创意 | ToT / GoT | 支持多路径搜索与信息融合 |
| 可验证输出、高精度 | Reflexion | 从失败中迭代改进 |
| 复杂多步骤、长流程 | Plan-and-Execute | 全局规划 + 动态重规划 |
| 博弈、长期决策 | LATS | MCTS 保证决策质量 |
⚠️ 选型原则 :没有银弹,优先从简单方案开始,仅在简单方案无法满足需求时才升级复杂度。
下一篇讲继续讲 Planning 的Hybrid Planning:混合规划 内容。
我刚开源的 ThinkLoop 工具就是采用了 Reflexion 的设计思路,让各大厂商的 web 端大模型问答更加精准,降低 web 端单模型的幻觉问题,感兴趣可以看一下这篇文章。