第八章 规划与反思¶
导读¶
ReAct 是"边想边做"——每一步都重新推理,每步决策依赖上一步结果,适合工具调用密集但路径明确的任务。但有些任务这种"局部最优"策略不够:一是任务结构清晰(如多步报告生成),可以一次性规划再分步执行;二是任务难度高,单次推理经常失败,要靠"失败-反思-重试"循环;三是任务有多种可能路径,要靠树搜索找最优解;四是任务有随机性,要靠多次采样投票降低方差。本章讲四种高级范式:Plan-and-Execute(先规划后执行)、Reflexion(失败反思重试)、Tree of Thoughts(多路径树搜索)、Self-Consistency(多次采样投票)。它们都是在 ReAct 之上的扩展,分别解决"全局规划"、"鲁棒性"、"路径探索"、"随机性"四个问题。读完本章你能按任务特征选对范式。
8.1 Plan-and-Execute¶
ReAct 是"边想边做"——每一步都重新推理决策下一步。但很多任务(多步报告生成、多阶段数据处理、复杂业务流程)其实可以先一次性规划出完整步骤列表再分步执行——这就是 Plan-and-Execute 范式。
Plan-and-Execute 核心思路¶
Plan-and-Execute 把"规划"与"执行"分离:先用 Planner LLM 一次性生成完整步骤列表(如"1. 查数据 2. 算统计 3. 生成图表 4. 写报告"),再用 Executor LLM 逐步执行每一步。Planner 输出的是结构化计划(JSON 列表或自然语言编号步骤),Executor 拿到每一步作为子任务执行——可能调工具、可能再 ReAct、可能直接生成文本。
Plan-and-Solve 论文¶
Plan-and-Execute 思路来自 Plan-and-Solve prompting(Wang et al., 2023, arXiv:2305.04091)——让 LLM 在 CoT 推理前先输出"计划"再分步执行。论文发现:单纯 CoT 让模型"想到哪写到哪",复杂推理经常跳步或漏步;Plan-and-Solve 先输出完整计划再按计划执行,准确率提升 5-10 个百分点(GSM8K 数学题上)。后续 LangChain 把这个思路做成 Agent 框架(Plan-and-Execute Agent)——Planner 与 Executor 分别是两个 LLM 调用。
为什么 Planner 用小模型,Executor 用大模型¶
Plan-and-Execute 工程上的一个关键取舍:Planner 用小模型(便宜快),Executor 用大模型(强)。原因:规划任务("这个任务该分几步、每步做什么")的难度低于执行任务("具体怎么算、怎么调 API")——前者只要语义理解,后者要细粒度推理与工具调用。GPT-3.5 / Llama 8B 做规划够用且便宜,GPT-4 / Claude 3.5 做执行更稳。这种"小模型规划 + 大模型执行"可以把单任务成本降到 1/3-1/5,是生产 Plan-and-Execute 的常见架构。
Plan-and-Execute vs ReAct¶
Plan-and-Execute 与 ReAct 是两种正交策略。ReAct 每步重新推理,决策动态——适合"下一步要看上一步结果"的探索性任务(如查到 A 后基于 A 决定查 B 还是 C)。Plan-and-Execute 一次性规划,决策静态——适合"任务结构清晰、子步骤解耦"的执行性任务(如多步报告生成,每步独立可并行)。两者可以混用:Planner 出计划,Executor 用 ReAct 做每一步——这是 LangChain Plan-and-Execute Agent 的实际实现。
Plan-and-Execute 的几个工程细节¶
Plan-and-Execute 工程实现几个细节。第一,计划可重规划:执行过程中发现某一步做不到(工具失败、数据缺失),Executor 反馈给 Planner,让 Planner 重新规划——这是"动态规划"。第二,步骤粒度:太粗(3 步)每步太复杂,太细(30 步)规划本身烧 token——5-15 步是甜点。第三,计划格式:用结构化 JSON(如 [{"step": 1, "action": "search", "args": ...}])比自然语言编号更稳定——Executor 解析 JSON 不漂移。第四,并行执行:计划里独立的步骤可以并行(如"查北京天气"与"查上海天气"独立),Executor 用并行 Function Calling 加速。
Plan-and-Execute 的失败模式¶
Plan-and-Execute 有几个失败模式。第一,规划错则全错:Planner 输出的计划第一步就错了,后面 Executor 再努力也是错的——解法是 Executor 执行时发现不对劲主动反馈 Planner 重规划。第二,计划太理想化:Planner 不知道某些步骤做不到(如调用了不存在的工具),Executor 执行时才发现——解法是 Planner 拿到 tools schema,规划时只引用真实工具。第三,计划与执行不一致:Planner 说"3 步",Executor 实际跑了 5 步——解法是 Executor 每步 append 到计划 JSON,最后对比。第四,长计划漂移:计划 20 步时 Planner 容易在第 10 步后"飘"——解法是分段规划(先规划前 5 步,执行到第 4 步时再规划下 5 步)。
Plan-and-Execute 的工程价值¶
Plan-and-Execute 在生产中的价值是让"长程任务"可控。第一,可观测:计划是结构化 JSON,工程师看 trace 就知道 Agent 准备做什么、做到哪步——比 ReAct 的"边想边做"trace 清晰。第二,可重试:某步失败只重试这一步,不用整个任务重来——ReAct 失败要回到起点重新推理。第三,可并行:计划里独立的步骤可以并行执行,整体延迟降低。第四,可分模型层:Planner 用便宜模型、Executor 用强模型,成本可降到 1/3-1/5。第五,可暂停恢复:计划可以序列化存盘,长任务可以中途暂停恢复——ReAct 的 Thought/Action 状态难序列化。这些工程价值让 Plan-and-Execute 在生产代码 Agent(如 Devin)与长程任务 Agent 里成为主流选择。
8.2 Reflexion¶
ReAct 与 Plan-and-Execute 都是"尝试一次"——失败就返回错误。但很多任务(代码生成、数学题、复杂工具调用)失败后反思再重试能显著提升成功率——这就是 Reflexion。
Reflexion 核心思路¶
Reflexion 让 Agent 在失败后做三件事:1. Evaluator 评分:评估这次尝试失败在哪(不对 / 部分对 / 全错);2. Self-Reflection 反思:让 LLM 自己分析"为什么失败、下一步该怎么改";3. Memory Update 更新记忆:把反思结论存到 memory(自然语言文本),下次重试时把 memory 塞进 prompt 避免重蹈覆辙。这个循环让 Agent 从失败中学习——成功率随尝试次数上升。
Reflexion 论文¶
Reflexion 来自 Shinn et al. 2023 论文 "Reflexion: Language Agents with Verbal Reinforcement Learning"(arXiv:2303.11366)。论文在 HotpotQA、ALFWorld、HumanEval(代码生成)等基准上验证:Reflexion 让 Agent 多次尝试后成功率提升 10-20 个百分点。关键发现:用"自然语言反思"作为 memory 比用"参数更新"(fine-tune)更便宜且更可解释——这就是论文标题里的 "verbal reinforcement learning"(语言强化学习)。
Reflexion 的几个工程细节¶
Reflexion 工程实现几个细节。第一,Evaluator 不可少:必须有客观评估器(如代码任务的 unit test、数学任务的最终数值校验)告诉 Agent 成功还是失败——靠 LLM 自己评"我做对了吗"不可靠(模型自信地说"对了"但其实错了)。第二,反思要具体:反思文本要写"具体哪步错、为什么错、下次该怎么做"——泛泛说"我没做好"对下次没帮助。第三,memory 不无限增长:每次失败都加一条反思 memory 会让 prompt 爆炸——只保留最近 3-5 条反思,旧的总结成一句话。第四,重试次数上限:3-5 次重试后还失败就放弃——再多也不会成。
Reflexion vs ReAct¶
ReAct 是"单次尝试"——一次 ReAct 循环要么成功要么失败。Reflexion 是"多次尝试 + 反思"——失败后反思再重试,让 Agent 从错误中学习。两者关系:Reflexion 是 ReAct 的"外层循环"——内层用 ReAct 做单次尝试,外层用 Reflexion 反思重试。生产场景里 Reflexion 适合"高失败率 + 有客观评估器"的任务(代码生成有 unit test、数学题有标准答案);ReAct 适合"低失败率 + 无客观评估器"的任务(聊天、信息查询)。
Reflexion 的适用场景¶
Reflexion 适合几类任务。第一,代码生成:HumanEval / SWE-Bench 这类代码任务有 unit test 评估,Reflexion 让 Agent 看到 test 失败信息后修改代码再试,成功率提升 15-20 个百分点。第二,数学推理:GSM8K / MATH 这类数学题有标准答案,Agent 反思"哪步推理错了"再重试。第三,长程任务:ALFWorld 这种长步骤家庭场景,Agent 失败后反思"哪个 action 错了"再重试。第四,任务成功率可量化:任何有客观评估器的任务都适合——评估器告诉 Agent 成功失败,Agent 反思再试。
不适合的场景:聊天 / 信息查询这种"无客观对错"的任务——Reflexion 没有 Evaluator 就瞎反思,反而越试越偏。也不适合延迟敏感场景——重试 3-5 次意味着 3-5 倍延迟。
Reflexion 与强化学习的关系¶
Reflexion 论文标题里的 "verbal reinforcement learning"(语言强化学习)暗示它与传统 RL(强化学习)的关系。传统 RL(如 PPO / DPO)让模型从失败中学习是靠**参数更新**——失败后改模型权重,下次推理输出更准。Reflexion 让模型从失败中学习是靠**记忆更新**——失败后把反思写进 memory,下次推理时把 memory 塞进 prompt 引导模型避错。两者本质都是"从失败中学习",但 Reflexion 不改模型权重(即时生效)而传统 RL 改模型权重(要重训)。Reflexion 的优势是便宜(不 fine-tune)、可解释(memory 文本可读)、即时(不用训练循环);劣势是不能持久(每次会话 memory 重置)且受 context window 限制(memory 太长会爆)。生产 Agent 大多用 Reflexion 做即时记忆 + RL 做长期优化——两层学习。
8.3 Tree of Thoughts¶
ReAct 与 Plan-and-Execute 都是"线性推理"——一条路径走到底。但有些任务(数学难题、24 点游戏、创意写作)需要"探索多条路径选最优"——这就是 Tree of Thoughts (ToT)。
ToT 核心思路¶
ToT 把推理建模为树搜索:从一个状态出发,生成 K 个候选"下一步思考"(thought),评估每个 thought 的优劣(用 LLM-as-Judge 或环境反馈),选 top-M 个继续展开,形成一棵搜索树。搜索到深度 D 或找到目标状态后回溯选最优路径。本质是把 CoT 的"线性推理"升级为"树搜索"——能跳出局部最优,找到全局更优解。
ToT 论文¶
ToT 来自 Yao et al. 2023 论文 "Tree of Thoughts: Deliberate Problem Solving with Large Language Models"(arXiv:2305.10601)。论文在 24 点游戏(用 4 个数算 24)、Creative Writing(创意写作)、Crosswords(填字游戏)三个基准上验证:ToT 把 24 点游戏成功率从 CoT 的 4% 拉到 74%。关键发现:CoT 让模型"一条道走到黑",复杂推理任务经常走错路;ToT 让模型"探索多条路 + 评估 + 选最优",成功率大幅提升。
ToT 的搜索算法¶
ToT 搜索算法有四种。第一,BFS(广度优先):每层保留 top-M 个 thought,逐层展开——适合"深度浅、宽度大"的任务。第二,DFS(深度优先):选最优 thought 一路深入,失败回溯——适合"深度大、宽度小"的任务。第三,beam search:BFS 变种,每层只保留 top-K 个最优——介于 BFS 与 DFS 之间。第四,MCTS(蒙特卡洛树搜索):用随机模拟评估节点价值——更复杂但效果更好,是 AlphaGo 同款算法。ToT 论文主用 BFS 与 DFS。
ToT 的代价¶
ToT 的代价是 LLM 调用次数指数增长。CoT 是 1 次 LLM 调用;ToT 树宽 K、深度 D,最多 K^D 次 LLM 调用。K=5、D=3 时是 125 次调用,比 CoT 贵 100 倍。生产 ToT 必设深度上限(一般 D ≤ 4)与宽度上限(K ≤ 5),且用便宜模型做 thought 生成、用强模型做评估——把成本压到可承受范围。
ToT 的几个工程细节¶
ToT 工程实现几个细节。第一,thought 评估器:用 LLM-as-Judge 评估每个 thought 的"前景"——给 1-10 分或"likely/impossible"。评估器要稳定(多次评分一致),否则搜索方向乱。第二,剪枝:低分 thought 早期剪掉不展开——避免计算爆炸。第三,回溯:搜索失败时回溯到上一层选次优 thought——这是树搜索的基本能力。第四,终止条件:找到目标状态(如 24 点算出 24)或达到深度上限——不要无限搜索。第五,结果选择:搜索结束后从所有叶子节点选分数最高的路径作为答案——不是直接用最后状态。
ToT 的适用场景¶
ToT 适合几类任务。第一,有明确目标状态的任务:24 点游戏(目标 24)、填字游戏(填满且符合规则)、迷宫(找到出口)——目标状态可判定,搜索有方向。第二,需要探索不同思路的任务:创意写作(多个开头选最优)、数学难题(多种解法选最简)——线性 CoT 容易陷入局部最优。第三,评估器可靠的任务:ToT 靠评估器选 thought,评估器准才能搜对。不适合"无明确目标"的开放任务(如聊天、信息查询),也不适合"评估器不可靠"的任务——评估器瞎指挥搜索方向乱飘。
ToT 与 MCTS 的关系¶
ToT 与 AlphaGo 用的 MCTS(蒙特卡洛树搜索)思想相通——都是"采样 + 评估 + 选优 + 展开"的树搜索。差异:MCTS 在游戏环境里采样N次随机模拟评估节点价值(如 AlphaGo 自我对弈评估棋局胜率),评估器是"环境反馈";ToT 在 LLM 里用 LLM-as-Judge 评估节点价值,评估器是"另一个 LLM 调用"。MCTS 在固定规则环境(围棋、国际象棋)效果极佳——评估器客观精确;ToT 在开放任务(创意写作、数学推理)效果有限——LLM-as-Judge 评估主观且不稳定。近年有研究把 MCTS 思路用在 LLM 推理(如 AlphaCode 用 MCTS 在代码空间搜索),但成本极高(一次任务几十万次 LLM 调用),生产难用。ToT 是 MCTS 思路在 LLM 的简化版——保留树搜索核心思想但简化到 K^D 次调用可承受。
8.4 Self-Consistency¶
CoT 让模型输出一条推理链。但单次采样有随机性——同一问题采样 5 次可能得到 5 个不同答案。Self-Consistency 思路:多次采样投票选多数,降低方差。
Self-Consistency 核心思路¶
Self-Consistency 让 LLM 对同一问题采样 N 次(temperature > 0 触发多样性),得到 N 个答案,用多数投票(majority vote)选最终答案。直觉:如果模型真的"懂"问题,多次采样应该多数答案一致;如果模型"瞎猜",多次采样答案分散——多数投票能放大真懂的部分,抑制瞎猜的部分。
Self-Consistency 论文¶
Self-Consistency 来自 Wang et al. 2022 论文 "Self-Consistency Improves Chain of Thought Reasoning in Language Models"(arXiv:2203.11171)。论文在 GSM8K 数学题上验证:单次 CoT 准确率 17.7%,Self-Consistency(40 次采样投票)拉到 56.9%(LaMDA-137B)。在 PaLM-540B 上从 56.9% 单次拉到 74.4%(多采样)。关键发现:Self-Consistency 的提升与模型规模正相关——大模型多次采样更易"互相对齐",小模型多次采样还是各答各的。
Self-Consistency 的工程细节¶
Self-Consistency 工程实现几个细节。第一,采样数 N:5-10 次够用,太多收益递减且贵——论文 40 次是为了论文数据漂亮,生产 5-10 次性价比高。第二,temperature:用 temperature=0.7-1.0 触发多样性,temperature=0 退化为单次采样(每次答案相同)。第三,投票方式:多数投票(majority vote)最简单;加权投票(按模型 confidence 加权)略好但复杂;文本相似度投票(用 LLM 评"这两个答案是否等价")适合开放式答案(不是数值)。第四,何时停止:可以提前结束——如 5 次采样里 4 次一致,第 6 次不用采样。
Self-Consistency vs ToT¶
Self-Consistency 与 ToT 都是"多采样"但思路不同。Self-Consistency 是"独立采样 N 次投票"——N 次采样相互独立,无搜索无评估,靠数量投票。ToT 是"树搜索"——采样有方向(评估器选优),有结构(树形展开),靠搜索找最优。Self-Consistency 更简单更便宜(N 次独立调用),ToT 更复杂更贵(指数级调用)但能解决更难问题。Self-Consistency 适合"任务难度中等、采样能覆盖解空间"的场景;ToT 适合"任务难度高、需要主动搜索"的场景。
Self-Consistency 的适用场景¶
Self-Consistency 适合几类任务。第一,数学推理:GSM8K / MATH 这类有唯一正确答案的数学题,多次采样投票能放大正确答案。第二,多选题:考试题有固定选项,多次采样投票选多数。第三,分类任务:情感分类、意图识别这类离散标签任务,多次采样投票稳定。不适合"开放式生成"任务(写诗、写小说)——多次采样得到 5 首不同的诗,投票没意义。也不适合"延迟敏感"场景——5 次采样 5 倍延迟。
Self-Consistency 的成本与延迟¶
Self-Consistency 的成本是 N 倍 LLM 调用——5 次采样 = 5 倍 token 成本与 5 倍延迟。但 N 次采样可以并行(用 ThreadPoolExecutor 同时发 5 个请求),所以延迟不是 5 倍而是约等于单次延迟 + 调度开销。生产 Self-Consistency 应该并行采样,且要监控成本——5 倍 token 在百万 QPS 下是显著成本。成本控制技巧:用便宜模型采样(GPT-4o-mini / Llama 8B),用强模型只在分歧时仲裁——把 N 次采样成本降到接近单次。
Self-Consistency 的几个变种¶
Self-Consistency 有几个变种。第一,简单多数投票:N 次采样直接选多数答案——最简单稳定。第二,加权投票:按模型 confidence(logprob)加权——更准但复杂。第三,分级投票:先按答案分组,每组选一个代表再投——适合答案文本相似度高的场景。第四,条件 Self-Consistency:模型第一次就高 confidence(如 logprob > 0.9)则不采样多次——省成本。第五,Deep Self-Consistency:N 次采样后让 LLM 自己评估"哪个答案最可信"——比简单投票略好但贵。生产大多用简单多数投票——5-10 次采样足够,再复杂的变种 ROI 递减。
范式选型的成本预算视角¶
工程师选范式除了看任务特征,还要看成本预算。ReAct 单次任务 5 步 = 5× 单次 LLM 调用,假设单次 0.01 美元则单任务 0.05 美元。Plan-and-Execute 单任务 1 次 Planner(0.005 美元,便宜模型)+ 5 次 Executor(0.05 美元)= 0.055 美元,比纯 ReAct 略贵但更稳定。Reflexion 单任务 3 次重试 × ReAct 单任务成本 = 0.15 美元,比单次 ReAct 贵 3 倍但成功率从 50% 拉到 80%。ToT 单任务 K=5、D=3 = 125 次 LLM 调用 = 1.25 美元,比 ReAct 贵 25 倍——只在难题场景用。Self-Consistency 5 次采样 = 5× 单次 = 0.05 美元,与 ReAct 相当但只适合有唯一答案的任务。生产 Agent 成本预算要按"单任务成本 × 预期 QPS × 时间"算——百万 QPS 下 0.05 美元/任务 = 每天 50 万美元,范式选错成本差几倍。
8.5 适用场景决策¶
四种范式各有所长,要按任务特征选。
决策树¶
工程师选范式时按几个维度决策。第一,任务是否有多步且结构清晰?是 → Plan-and-Execute(先规划再执行);否 → 看 ReAct 或更高级。第二,任务是否有客观评估器?是 → 看是否高失败率。高失败率 → Reflexion(失败反思重试);低失败率 → ReAct 直接做。第三,任务是否需要探索多路径?是 → ToT(树搜索);否 → Self-Consistency 或单次 ReAct。第四,任务是否有唯一正确答案且采样能覆盖?是 → Self-Consistency;否 → 单次 ReAct 或 Plan-and-Execute。
任务特征矩阵¶
| 任务类型 | 推荐范式 | 原因 |
|---|---|---|
| 简单工具调用 | Function Calling / ReAct | 单步即解,复杂范式徒增成本 |
| 多步结构清晰任务 | Plan-and-Execute | 一次性规划比边想边做更稳 |
| 高失败率 + 有评估器 | Reflexion | 失败反思重试提升成功率 |
| 数学难题 / 多路径探索 | ToT | 树搜索跳出局部最优 |
| 数学题 / 多选题 | Self-Consistency | 多次采样投票放大正确答案 |
| 开放式创意 | 单次 CoT 或 Plan-and-Execute | 无评估器,多采样投票无意义 |
哪种范式最适合代码生成¶
代码生成是 Reflexion 的典型场景。原因:第一,代码任务有客观评估器(unit test / 编译错误 / lint);第二,代码任务失败率高(一次写对的概率 30-50%);第三,失败信息可读(test failure 错误堆栈),LLM 反思"哪里错了"准确率高;第四,重试能利用前次失败信息(如"上次是 import 缺了"),重试有方向。所以生产代码 Agent(如 Cursor / GitHub Copilot Workspace / Devin)大多用 Reflexion 范式——内部循环是 ReAct 或 Function Calling,外部循环是 Reflexion 反思重试。SWE-Bench 评测也基于这种范式。
范式组合¶
实际生产 Agent 经常组合多种范式。如代码 Agent:外层 Reflexion(失败反思重试)+ 中层 Plan-and-Execute(规划"先理解需求 → 改代码 → 跑 test → 修 bug")+ 内层 ReAct 或 Function Calling(具体每一步调工具)。这种"分层范式"是复杂 Agent 的常态——上层范式负责战略决策,下层范式负责战术执行。第八章建立的"按任务特征选范式"心智模型,是后续章节(第 9 章记忆、第 11 章多 Agent、第 13 章评测)的基础。
范式选择的文化差异¶
工程师 vs 研究者对范式选择有不同偏好。研究者喜欢复杂范式——ToT / Reflexion 在论文基准上提升 10-20 个百分点,是发 paper 的好故事;工程师偏好简单范式——ReAct + Function Calling 在 80% 生产场景够用,复杂范式带来的稳定性 / 延迟 / 成本问题在生产里更突出。生产 Agent 的范式选择应该"先简单后复杂"——先用 ReAct 或 Function Calling 验证业务可行,再按需引入 Plan-and-Execute / Reflexion / ToT / Self-Consistency。这是工程纪律——不要一上来就 ToT,先用最简单的范式跑通流程,再针对具体瓶颈引入对应高级范式。
范式选择的常见错误¶
工程师选范式时常犯几个错。第一,为复杂而复杂:新项目一上来就 ToT / Reflexion / Self-Consistency 三件套——结果生产环境成本爆炸、稳定性差、调试困难。正确做法是先用 ReAct 或 Function Calling 跑 80% 场景,再针对具体瓶颈引入高级范式。第二,无视评估器可靠性:Reflexion 要 Evaluator,靠 LLM 自评"做对了吗"不可靠——结果 Agent 越试越偏。正确做法是优先用客观评估器(unit test / 标准答案),LLM-as-Judge 仅作辅助。第三,忽略成本预算:ToT K=5、D=3 = 125 次调用,生产百万 QPS 下成本不可承受。正确做法是先算成本预算再选范式。第四,范式与任务错配:把 Self-Consistency 用在开放生成(写诗)上——多次采样得到 5 首不同的诗投票没意义。正确做法是按任务特征选——有唯一答案用 Self-Consistency,结构多步用 Plan-and-Execute,高失败率用 Reflexion,多路径用 ToT。第五,范式不组合:单范式硬刚所有任务——结果某类任务该用 ToT 但用了 ReAct 准确率低。正确做法是按场景组合——外层 Reflexion + 中层 Plan-and-Execute + 内层 Function Calling。
代码片段:Plan-and-Execute 骨架¶
下面给出 Plan-and-Execute 的最小骨架代码(约 25 行),演示 Planner + Executor 分离 + 步骤循环。
from openai import OpenAI
import json
client = OpenAI()
def plan_and_execute(question, tools, max_steps=10):
# 1. Planner:一次性生成完整计划
plan_prompt = f"任务:{question}\n可用工具:{list(tools.keys())}\n输出 JSON 步骤列表,每步 {{action, args}}。"
plan_resp = client.chat.completions.create(
model="gpt-4o-mini", # 规划用小模型省钱
messages=[{"role": "user", "content": plan_prompt}],
response_format={"type": "json_object"},
)
plan = json.loads(plan_resp.choices[0].message.content)["steps"]
print(f"Planner 输出 {len(plan)} 步计划")
# 2. Executor:逐步执行
results = []
for i, step in enumerate(plan):
# 每步用大模型执行
exec_prompt = f"执行步骤 {i+1}/{len(plan)}: {step}\n之前结果: {results}"
resp = client.chat.completions.create(
model="gpt-4o", # 执行用大模型
messages=[{"role": "user", "content": exec_prompt}],
tools=tools_schema(tools),
)
msg = resp.choices[0].message
if msg.tool_calls:
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = tools[call.function.name](**args)
results.append({"step": i+1, "tool": call.function.name, "result": result})
else:
results.append({"step": i+1, "result": msg.content})
return results
# tools_schema 把 Python dict 转 OpenAI tools 参数
def tools_schema(tools_dict):
return [{"type": "function", "function": {"name": n, "parameters": {"type":"object","properties":{}}}} for n in tools_dict]
这段代码示范了 Plan-and-Execute 的两层循环:Planner 一次性规划(用小模型省钱),Executor 逐步执行(用大模型保稳)。生产系统还要加:执行失败时反馈 Planner 重规划、独立步骤并行执行、计划与执行结果对比、Reflexion 外层循环。
工程实战要点¶
- 规划要分模型层:Planner 用小模型(GPT-4o-mini / Llama 8B)规划,Executor 用大模型(GPT-4 / Claude 3.5)执行——规划难度低于执行,分模型层能把成本降到 1/3-1/5。
- 反思要避免无限循环:Reflexion 重试 3-5 次必停——再多也不易成且烧钱;反思 memory 只保留最近 3-5 条,旧的总结成一句话避免 prompt 爆炸。
- ToT 成本爆炸要设深度上限:树宽 K、深度 D 时最多 K^D 次 LLM 调用;K ≤ 5、D ≤ 4 是生产上限;用便宜模型做 thought 生成、强模型做评估降成本。
- Self-Consistency 投票数 5-10 够:再多收益递减且贵;temperature=0.7-1.0 触发多样性;如 5 次里 4 次一致可提前结束省一次。
- 选范式看任务不确定性:低不确定性 → ReAct/FC 直接做;中不确定性 + 有评估器 → Reflexion;中不确定性 + 多路径 → ToT;高不确定性 + 有唯一答案 → Self-Consistency;结构清晰多步 → Plan-and-Execute。
小结¶
- Plan-and-Execute:先 Planner 一次性规划再 Executor 逐步执行;适合结构清晰多步任务;Planner 用小模型、Executor 用大模型是工程标配;arXiv:2305.04091。
- Reflexion:失败 → Evaluator 评分 → Self-Reflection 反思 → Memory Update → 重试;适合高失败率 + 有客观评估器的任务(代码生成有 unit test);arXiv:2303.11366。
- Tree of Thoughts:树搜索 K^D 次 LLM 调用,BFS / DFS / beam search / MCTS;适合多路径探索任务(24 点、迷宫);成本爆炸要设深度上限;arXiv:2305.10601。
- Self-Consistency:多次采样投票选多数,降低方差;适合有唯一正确答案的数学题 / 多选题;5-10 次采样够;arXiv:2203.11171。
- 选范式看任务:简单 → FC/ReAct;结构多步 → Plan-and-Execute;高失败率+评估器 → Reflexion;多路径探索 → ToT;唯一答案+采样覆盖 → Self-Consistency。
- 实际生产常组合:外层 Reflexion + 中层 Plan-and-Execute + 内层 ReAct/FC;代码生成 Agent 是典型组合案例。
练习题¶
- Plan-and-Execute 与 ReAct 的核心差异?
- Reflexion 解决了什么问题?
- ToT 的代价是什么?
- Self-Consistency 适合什么任务?
- 为什么"规划用小模型、执行用大模型"是常见工程取舍?
- 哪种规划范式最适合代码生成任务?为什么?
参考答案¶
第 1 题答案
Plan-and-Execute 是"先规划后执行"——Planner 一次性生成完整步骤列表(如"1. 查数据 2. 算统计 3. 生成图表 4. 写报告"),Executor 拿到每一步作为子任务执行;计划是静态的,决策在执行前完成。ReAct 是"边想边做"——每一步都重新推理决策下一步,下一步依赖上一步结果;决策是动态的,每步重新决策。本质差异:Plan-and-Execute 适合"任务结构清晰、子步骤解耦"的执行性任务(多步报告生成),子步骤可并行;ReAct 适合"下一步要看上一步结果"的探索性任务(查到 A 后基于 A 决定查 B 还是 C),子步骤必须串行。两者可以混用:Planner 出计划,Executor 用 ReAct 做每一步——这是 LangChain Plan-and-Execute Agent 的实际实现。第 2 题答案
Reflexion 解决了"Agent 单次尝试失败就放弃"的问题——很多任务(代码生成、数学推理、长程任务)单次成功率低(30-50%),但失败后反思再重试能显著提升成功率。Reflexion 让 Agent 在失败后做三件事:1. Evaluator 客观评估失败原因(用 unit test / 标准答案);2. Self-Reflection 让 LLM 自己分析"为什么失败、下次该改什么";3. Memory Update 把反思结论存到 memory,下次重试时塞进 prompt 避免重蹈覆辙。论文 arXiv:2303.11366 验证:Reflexion 在代码生成(HumanEval)上提升 15-20 个百分点成功率。本质是用"自然语言反思"作为 memory 替代 fine-tune——便宜、可解释、即时生效,论文称为 "verbal reinforcement learning"(语言强化学习)。第 3 题答案
ToT 的代价是 **LLM 调用次数指数增长**。CoT 是 1 次 LLM 调用;ToT 树宽 K、深度 D,最多 K^D 次 LLM 调用。K=5、D=3 时是 125 次调用,比 CoT 贵 100 倍。生产 ToT 必设深度上限(D ≤ 4)与宽度上限(K ≤ 5),且用便宜模型做 thought 生成、用强模型做评估——把成本压到可承受范围。ToT 还需要稳定的 thought 评估器(LLM-as-Judge 给 1-10 分),评估器不准搜索方向乱飘。ToT 还要剪枝(低分 thought 早期剪掉不展开避免计算爆炸)、回溯(搜索失败回溯到上一层选次优)、终止条件(找到目标或达深度上限)、结果选择(搜索完从叶子节点选分数最高路径)。ToT 论文 arXiv:2305.10601 在 24 点游戏上把成功率从 CoT 的 4% 拉到 74%,但调用次数也贵了几十倍。第 4 题答案
Self-Consistency 适合几类任务。第一,**数学推理**:GSM8K / MATH 这类有唯一正确答案的数学题,多次采样投票能放大正确答案——单次 CoT 准确率 17.7%,Self-Consistency 40 次采样拉到 56.9%(论文 arXiv:2203.11171 数据)。第二,**多选题**:考试题有固定选项,多次采样投票选多数稳定。第三,**分类任务**:情感分类、意图识别这类离散标签任务,多次采样投票稳定。Self-Consistency 的核心条件是"任务有唯一正确答案且采样能覆盖"——多次采样得到一致结果说明模型真的"懂",分散则说明在瞎猜。不适合"开放式生成"任务(写诗、写小说)——多次采样得到 5 首不同的诗,投票没意义。也不适合"延迟敏感"场景——5 次采样 5 倍延迟。生产实际 5-10 次采样够用,temperature=0.7-1.0 触发多样性。第 5 题答案
"规划用小模型、执行用大模型"是 Plan-and-Execute 的常见工程取舍,原因有三。第一,**规划难度低于执行**:规划任务("这个任务该分几步、每步做什么")只要语义理解,能列出步骤列表就行;执行任务("具体怎么算、怎么调 API、参数填什么")要细粒度推理与工具调用——前者用 GPT-4o-mini / Llama 8B 够用且便宜,后者要 GPT-4 / Claude 3.5 才稳。第二,**成本可降 3-5 倍**:单任务总成本主要看 Executor 的多次大模型调用,Planner 一次性规划只调一次小模型,成本占比小——但用大模型做 Planner 反而贵且无收益。第三,**Planner 与 Executor 可独立优化**:Planner 可以 fine-tune 让它在特定业务域规划更准,Executor 用通用大模型即可——分层优化比单模型优化更可控。这是 LangChain Plan-and-Execute Agent 的默认架构。第 6 题答案
代码生成任务最适合 **Reflexion** 范式。原因有四。第一,**有客观评估器**:代码任务有 unit test / 编译错误 / lint——Evaluator 不需要 LLM 自评(不可靠),直接跑 test 看通过率。第二,**失败率高**:单次代码生成成功率 30-50%,需要重试——Reflexion 重试 3-5 次能拉到 70-80%。第三,**失败信息可读**:test failure 错误堆栈、编译错误信息都是结构化文本,LLM 反思"哪里错了、为什么错、下次该改什么"准确率高。第四,**重试有方向**:反思 memory 把"上次 import 缺了"、"上次 off-by-one 错"记下来,下次重试时塞进 prompt 避免重蹈覆辙——比单纯"再来一次"无信息重试成功率高。生产代码 Agent(Cursor / GitHub Copilot Workspace / Devin)与 SWE-Bench 评测大多基于 Reflexion 范式——外层 Reflexion 反思重试,内层 ReAct 或 Function Calling 调具体工具(读代码 / 改代码 / 跑 test)。下一章:第九章 记忆与上下文工程