第9章:规划与推理(Planning & Reasoning)
规划是 Agent 区别于简单 LLM 调用的核心能力之一。给模型一个复杂任务,它需要把任务拆开,判断先做什么后做什么,执行过程中发现跑偏了要怎么纠正——这一整套认知过程,统称为规划。
但"规划"这个词用得很滥。有人把 Chain of Thought 叫规划,有人把 Plan-and-Execute 叫规划,有人把推理模型的内部 thinking 也叫规划。这一章会把这些概念梳理清楚,讲清楚每种机制背后的原理、适用场景和代价,以及推理模型的出现如何改变了这张图谱。
9.1 任务分解策略
核心直觉
把大任务拆成小任务,是所有规划的基础。问题在于怎么拆,以及谁来拆。
三种分解结构
线性链(Linear Chain):步骤 1 完成后交给步骤 2,步骤 2 完成后交给步骤 3,严格顺序执行。实现最简单,也最脆弱——任何一步失败,后续全部中断。适合任务步骤之间有强依赖、顺序不可换的场景。
DAG(有向无环图)结构:步骤之间有依赖关系,但没有依赖的步骤可以并行执行。比如"收集三个数据源的信息,然后合并分析"——三个数据源的收集互相独立,可以并行;合并分析依赖三个收集结果,必须等待。DAG 结构能利用并行提升效率,但需要更复杂的编排逻辑来管理依赖和等待。
动态分解(Dynamic Decomposition):规划本身是运行时生成的,不是写死的。Anthropic 描述的 Orchestrator-Workers 模式 [1] 就是这类:一个 Orchestrator Agent 接到任务后,动态决定需要哪些子任务、分配给哪些 Worker,根据 Worker 的返回结果决定下一步。这是灵活性最高、也最复杂的分解方式。
怎么选
任务步骤固定、依赖明确:线性链或 DAG,写死结构,别让模型动态决策。LLM 做运行时规划的开销(延迟 + 成本 + 可能出错)不值得,除非任务真的无法预先枚举步骤。
任务开放、步骤数不可预测:动态分解。这类任务的定义特征是:你事先不知道需要几步,需要几次工具调用,中间会遇到什么分支。代码 Debug(不知道要改多少个地方)、Web Research(不知道要查几个网页)都属于这类。
Anthropic 的建议 [1] 很直接:从最简单的解决方案开始,只在必要时增加复杂度。不要一上来就设计动态分解系统——先试试线性链够不够用。
9.2 Chain of Thought(CoT)在 Agent 中的应用
核心直觉
让模型在给出答案之前写出推理步骤,准确率会显著提升——这就是 Chain of Thought(CoT)的全部。
原理
Wei et al. (2022) 在 "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models" [2] 中发现:给模型提供少量"写出推理过程再回答"的示例,模型在算术、常识推理、符号推理等任务上的准确率显著提升。540B 参数模型用 8 个 CoT 示例,在 GSM8K 数学题基准上达到了当时的最优表现。
为什么有效?最可信的解释是:逐步写出推理步骤,相当于把一个"一步到位"的困难问题分解成了多个"一步"的简单问题,让模型的下一个 token 预测任务难度下降。另一个角度:写出中间步骤增加了上下文中的"工作记忆",让模型可以依赖这些中间结果继续推理。
重要限制:CoT 不是万能药。研究显示它在需要多步推理的任务上效果明显,在需要直接判断的任务上帮助有限,在纯粹检索事实的任务上几乎没用。另外,CoT 提示下的推理过程不一定"真实"反映了模型内部的计算——输出的推理链可能是事后合理化,不一定是因果链路。
Zero-shot CoT
不需要 few-shot 示例,只需要在 prompt 里加上 "Let's think step by step",也能激活类似效果。Wang et al. (2023) 的 Plan-and-Solve 工作 [3] 把这进一步扩展:先让模型生成解题计划("Let's first understand the problem and devise a plan to solve the problem"),再按计划执行("Let's carry out the plan")。这比单纯 "Let's think step by step" 减少了缺步错误(missing-step errors)。
CoT 在 Agent 里的用法
在 Agent 架构里,CoT 通常通过 system prompt 或 user message 里的指令来触发——要求模型在采取行动前先输出推理过程。这个推理过程有两个用途:
- 提高决策质量:让模型在调用工具前明确说出"我要做什么、为什么这样做",减少错误工具调用。
- 可追溯性:开发者可以观察模型的"思考",判断它是不是走在正确的方向上,是否触发了重规划条件。
# 让 Agent 在每次工具调用前输出推理的 system prompt 片段
SYSTEM_PROMPT = """
在每次调用工具前,先用以下格式输出你的推理:
<思考>
当前状态:...
我要做什么:...
为什么这样做:...
预期结果:...
</思考>
然后再调用工具。
"""ReAct:CoT 进入外部环境后的闭环版本
核心直觉:
ReAct(Reasoning + Acting)不是在行动之前想清楚再行动,而是把推理和行动交替进行——想一步,做一步,看结果,再想,再做。
原理:
Yao et al. (2022) 在 ReAct [4] 中提出:让模型在一个轨迹里交替生成"Thought"(推理)、"Action"(行动)、"Observation"(观察结果)三种内容。
Thought: 我需要查询苹果公司的市值
Action: search("Apple Inc market cap 2024")
Observation: Apple 市值约为 3.37 万亿美元(截至 2024 年)
Thought: 找到了市值,现在需要对比竞争对手
Action: search("Microsoft market cap 2024")
Observation: Microsoft 市值约为 3.1 万亿美元
Thought: 现在有足够信息来比较了
Action: finish("苹果市值约为微软的 1.08 倍")ReAct 相比纯 CoT 的优势:每一步 Action 都是和外部环境(工具、数据库、API)的真实交互,Observation 是真实的外部反馈。这打破了纯 CoT 的"闭环推理"——如果模型推断错了某个事实,外部 Observation 会纠正它。原始论文报告,在 HotpotQA(多跳问答)和 FEVER(事实核验)任务上,ReAct 显著减少了幻觉和错误传播。
ReAct 的失败模式:
思考-行动脱节:模型的 Thought 里说要做 X,但 Action 实际做了 Y。这在工具很多时更常见——模型"想"的时候参考一套逻辑,"选工具"的时候被另一套逻辑带走了。
Observation 被错误解读:工具返回了异常结果(比如空数组、错误码),模型把它当成正常结果继续推进,而不是触发错误处理。
循环推理:模型陷入"我需要信息 A → 查询 A → 觉得还需要信息 B → 查询 B → 觉得需要回去确认 A"的循环,无法收敛。这是 ReAct 系统必须设置最大轮次的原因。
工程上更常见的退化是:工具一多,Thought 里推出来的"下一步"和实际 Action 之间更容易脱节。解决方法通常不是继续加 prompt,而是减少当轮可见的工具子集,或者要求模型在行动前明确写出"我要调用的工具名称和参数"。
9.3 Plan-and-Execute:先规划后执行
核心直觉
把任务分成两个阶段:先生成完整计划,再逐步执行并在偏差时校验。和 ReAct 的区别是"先想好整个方案,再动手",而不是"走一步看一步"。
为什么需要两阶段
ReAct 的走一步看一步适合短任务和不确定性高的任务,但有个固有问题:近视偏差(Myopic Bias)。每次 Action 只基于最近的 Observation 做决策,容易陷入局部最优,忘记全局目标。典型症状:3 步之后还在处理"怎么把数据取出来",忘记了最初的目标是"分析数据并生成报告"。
Plan-and-Execute 的逻辑是:
- 规划阶段(Plan):给模型完整任务,让它生成一个明确的执行计划,包括每个步骤的预期输入输出和成功条件。
- 执行阶段(Execute):按计划执行每个步骤,每步结束后检验结果是否符合预期。如果偏差超过阈值,触发重规划。
什么时候选 Plan-and-Execute
适合:任务步骤可以提前枚举,有明确的终止条件,需要保证全局一致性(比如软件开发任务,先设计架构再写代码,不能边写边改架构)。
不适合:任务高度动态(步骤依赖运行时发现的信息),或者任务非常短(一两步能搞定,根本不需要"规划"阶段的额外开销)。
一个容易踩的坑:Plan 阶段生成的计划越详细越好吗?不是。过度详细的计划意味着更高的"规划-执行脱节"风险——现实执行中遇到的情况总是和计划里预设的不一样。好的计划应该详细到"步骤清晰、目标明确",但保留执行层的自主性来处理细节。
9.4 自我反思与纠错
Reflexion:用语言反馈替代梯度更新
核心直觉:
传统强化学习通过梯度更新让模型从错误中学习,但 Agent 在推理时改不了权重。Reflexion 的做法是:把"从错误中学习"的信号转换成自然语言,存进 Agent 的记忆里,下一次执行时参考这些语言反馈来改进决策。
机制:
Shinn et al. (2023) 在 Reflexion [5] 中提出:
第一次尝试 → 失败 → 生成语言反思("我犯了什么错误,下次应该怎么做")
→ 把反思存入 episodic memory buffer
→ 第二次尝试时,把历史反思注入 context
→ Agent 参考历史教训,改进决策原始论文报告,在 HumanEval 编程基准上,Reflexion 让 GPT-4 的 pass@1 准确率从 80% 提升到 91%,这是当时的最优结果。
实现关键:需要一个评估信号来判断尝试是否成功。这个信号可以是:外部环境的二进制反馈(代码跑通了/没跑通)、人类评分、另一个 LLM 的评判。没有可靠的评估信号,Reflexion 就无法工作——模型不知道自己"错在哪里"。
Evaluator-Optimizer:把评估角色显式拆出来
Anthropic 在《Building effective agents》里把 Evaluator-Optimizer 描述成一种很实用的工作流 [1]:一个模型先产出草稿,另一个模型按明确标准评估并给出反馈,再把反馈送回去迭代。这比让同一个模型"自己想想哪里不对"更适合一次性任务里的质量打磨,比如改写文案、重构代码、补测试、审查输出格式。
它和 Reflexion 容易混淆,但关注点不同:Evaluator-Optimizer 主要解决当前这一次任务的质量提升;Reflexion 主要解决跨多次尝试的经验积累。
Reflexion 和 Anthropic 提出的 Evaluator-Optimizer 模式 [1] 容易混淆,但有本质区别:
| 维度 | Reflexion | Evaluator-Optimizer |
|---|---|---|
| 学习作用域 | 跨 episode,反思积累 | 单次 session 内迭代 |
| 反馈存储 | 写入 episodic memory,未来 episode 可用 | 只在当前对话内传递 |
| 典型用途 | Agent 需要在多次失败中积累经验的长期任务 | 一次性任务的输出质量迭代优化 |
| 角色分离 | 同一个 Agent 自我反思 | 一个 LLM 生成,另一个 LLM 评估 |
Evaluator-Optimizer 更像代码 review——一个写了一版代码,另一个给出具体修改意见,循环直到通过。Reflexion 更像工程师的个人成长记录——把每次失败的原因记下来,下次遇到类似问题时不重蹈覆辙。
Reflexion 的实用限制
Reflexion 有一个不明显的前提:任务可以多次尝试。代码生成、游戏、搜索任务——都满足。但很多现实任务只有一次机会(给用户发了邮件就发出去了,不能撤回重来),Reflexion 在这类场景下没有用武之地。
另一个现实限制是:反思质量高度依赖模型能力。能力弱的模型生成出的"教训"可能本身就是错的,甚至会把错误经验写进记忆里,导致后续行为越来越偏。
Self-Refine:迭代打磨输出
核心直觉:
输出不满意?让模型自己给自己的输出打反馈,然后按反馈改——迭代,直到质量达标或者达到最大轮次。
机制:
Madaan et al. (2023) 的 Self-Refine [6] 使用同一个 LLM 担任三个角色:生成器(Generator)、反馈者(Feedback Provider)、精炼器(Refiner)。
def self_refine(task: str, max_iterations: int = 3) -> str:
output = generate(task)
for _ in range(max_iterations):
feedback = generate_feedback(task, output)
if is_satisfactory(feedback):
break
output = refine(task, output, feedback)
return output原始论文在 7 个多样化任务上(对话、代码优化、数学等)评估,Self-Refine 的输出平均被人类评估者偏好超过基线约 20%。
和 Reflexion 的核心区别:Self-Refine 是单次 session 内的质量提升,不涉及跨 episode 的记忆积累。它更适合生成类任务(写作、代码审查、分析报告),不适合需要与外部环境交互的决策任务。
Self-Refine 的常见误区
很多人认为 Self-Refine 就是"让模型多想一会",从而用它替代所有形式的改进。实际上 Self-Refine 的有效性依赖两个条件:模型本身有能力识别自己输出的问题,且模型有能力根据反馈生成更好的版本。如果模型的能力上限就在那里,Self-Refine 只是在同一个质量上限附近打转,不会突破。
补充:搜索式规划(LATS)
核心直觉:
与其线性地走一条规划路径,不如像棋手一样同时考虑多条路径,挑最好的那条走——LATS 把蒙特卡洛树搜索引入了 Agent 规划。
原理:
LATS(Language Agent Tree Search)由 Zhou et al. (2023) [7] 提出,把蒙特卡洛树搜索(MCTS)和 LLM 推理结合。每个树节点是一个状态(当前的推理步骤或行动),树的扩展通过让 LLM 生成多个候选下一步,Value Function 也由 LLM 扮演(评估当前状态距目标有多远)。
LATS 达到了当时在 HumanEval 上的最优 pass@1 准确率(92.7%,使用 GPT-4),在 WebShop 网购任务上的表现也达到了接近梯度微调方法的水平。
但 LATS 有明显的工程代价:每次树扩展需要多次 LLM 调用,实际部署的计算成本是 ReAct 的数倍。它更适合"高价值、低频率"的复杂决策场景,不适合需要快速响应的日常任务。
实用性评估
LATS 目前更多停留在学术评估阶段。截至写作时,没有找到可靠公开资料显示它已经被大规模生产部署。一个更谨慎的判断是:在很多原本会考虑显式树搜索的场景里,推理模型已经吸收了其中一部分收益,因此 LATS 更像高成本的专项武器,而不是默认架构。
9.5 动态重规划:执行偏差时怎么办
核心直觉
计划是在信息不完整时做的决定,执行中发现计划不对,必须能修正。问题在于:什么时候触发重规划,怎么做,以及怎么防止无限循环。
偏差检测
重规划需要一个触发条件。几种常见的检测方式:
基于规则的检测:工具调用返回错误码、任务步骤超时、重复执行相同工具超过 N 次、轮次超过阈值。这些是最可靠的信号,不依赖模型判断。
基于 LLM 的检测:在每个步骤后让 Evaluator 判断"当前进展是否符合预期目标",返回布尔值或置信分数。灵活但有误判风险——Evaluator 本身也会出错。
混合策略:规则检测处理明显的失败状态(超时、错误码),LLM 检测处理"方向偏移"(还在执行,但做的事情越来越偏离原始目标)。
重规划策略
检测到偏差后,有几种不同粒度的重规划选项:
- 局部重规划:只修改当前失败的步骤,后续计划不变。代价最小,但只适合局部问题。
- 从当前状态重规划:保留已完成的步骤结果,基于当前状态重新生成后续计划。最常用的选项。
- 全局重规划:丢弃当前计划,从头根据新信息重新规划。代价最高,但有时不可避免(比如发现初始目标被误解了)。
一个实践建议:把重规划历史记录下来,作为 Agent 的"工作笔记"的一部分。多次在同一个地方触发重规划,说明这个步骤有系统性问题,可能需要修改工具或任务分解逻辑,而不只是简单重试。
防止无限循环
无限循环是动态重规划最常见的灾难性失败模式。几种必要的防护:
- 最大重规划次数:全局限制重规划触发次数(比如 3 次),超过后强制升级到 Human-in-the-Loop 或返回失败。
- 检测重复状态:如果重规划后的新计划和上一个计划高度相似(比如语义相似度 > 0.9),很可能陷入循环,直接报错。
- 超时兜底:整个任务设置全局超时,不管内部状态如何,时间到了就停。
9.6 规划的失败模式
过度规划(Analysis Paralysis)
给模型一个开放性任务,它生成了一个详细的 20 步计划,然后花在规划和重规划上的时间比实际执行还多。或者更常见的:Plan 阶段输出一堆细节,但这些细节大量是假设而非事实,执行到第 3 步就发现前 20 步的计划全部作废。
识别信号:Plan 阶段的输出占整个任务 token 消耗的比例过高(超过 30%),或者频繁触发重规划。
缓解策略:限制 Plan 阶段的 max_tokens,强制模型生成高层计划而非详细步骤;或者直接跳过显式 Plan 阶段,用 ReAct 代替。
规划-执行脱节
Planner 生成了计划,Executor 实际执行时忽视或曲解了计划。这在 Planner 和 Executor 是同一个 LLM 时尤其容易发生——模型在 Executor 角色时容易被当前上下文的信息"带偏",忘记 Plan 阶段定下的方向。
缓解策略:每个执行步骤前,强制 Executor 引用计划中对应的步骤("根据计划第 N 步,我现在要...");或者将 Plan 放在 system prompt 的醒目位置,而不是 user message 里容易被"淡忘"的地方。
目标漂移(Goal Drift)
Agent 执行了很多步之后,实际在优化的目标偏离了原始用户目标。经典案例:用户要求"帮我优化这段代码的性能",Agent 在第 10 轮开始优化代码的可读性和注释,因为之前某个 Observation 里提到了"这段代码可读性差"。
根本原因是 Agent 的注意力被中间出现的信息带走了,失去了对原始目标的锚定。
缓解策略:在每次 LLM 调用的 system prompt 里重复原始目标(Goal Anchoring);在 Evaluator 的评分逻辑里,把"是否在推进原始目标"作为一个独立维度而不是只看当前步骤的质量。
9.7 推理模型如何改变 Agent 规划
核心直觉
推理模型在生成答案之前会消耗更多计算在内部推理上。这改变了 Agent 规划架构的某些假设——有些原本要靠外部脚手架才能获得的规划质量,现在模型本身就能提供一部分。
具体模型名称、thinking / reasoning 的暴露方式、计费方式和工具调用交互能力变化很快。写作或选型时不要背某个固定名单,而要回到官方文档确认:它是否支持工具调用、是否能在工具调用之间继续推理、是否暴露推理摘要、推理 token 如何计费。
推理模型 vs. 传统 CoT
传统 CoT 的推理过程出现在 LLM 的"输出"里,作为上下文的一部分被用户看到,也被后续步骤参考。推理模型的内部推理是隐藏的(或以摘要形式返回),发生在模型生成最终输出之前。
Anthropic 的扩展思考文档说明,thinking 的可见形式会随模型版本而变化:有的版本返回完整 thinking block,有的版本返回摘要化内容;文档也强调了它和工具调用可以交错工作(interleaved thinking)[8]。OpenAI 在推理模型相关说明里也明确强调,原始 Chain of Thought 不会直接暴露给用户,应用通常只能看到摘要或最终输出 [9]。这意味着:推理模型确实更会"先想再答",但这些思考不再像传统 CoT 那样稳定、完整地出现在上下文里供你复用。
对 Agent 架构的具体影响
Plan-and-Execute 的 Plan 阶段更可靠:推理模型在生成计划时能自主发现逻辑缺陷并修正,减少了"计划听起来合理但执行时处处碰壁"的情况。这对需要长序列规划的任务(代码重构、多步骤数据处理)尤其明显。
显式 CoT 提示的重要性下降:不再需要在 prompt 里反复强调"请一步步思考"——推理模型内部已经在做了,重复提示反而可能干扰。但这不意味着任务分解、检查点设置和外部验证可以省略,这些仍然必要。
Evaluator-Optimizer 循环部分简化:推理模型在生成输出时已经做了一定程度的自我校验,简单任务上可以少跑一轮 Evaluator。但对于需要外部验证(跑单元测试、查数据库)或高精度要求的场景,外部 Evaluator 仍然不可少。
新兴混合架构:工程上很自然会出现"推理模型规划 + 快速模型执行"的组合——用推理模型(慢、贵、准)负责规划和复杂判断,用轻量模型(快、便宜)负责简单的工具调用和数据处理。截至写作时,这个模式是否有系统性的公开对比优势,我没有找到足够强的一手数据,但它符合"按能力匹配任务"的工程直觉。
推理模型的实际代价
别被"推理更强"的叙事带偏。推理模型在高复杂度任务(数学竞赛、代码调试、系统设计)上表现优秀,但在简单任务上会带来额外延迟和成本。很多不需要复杂推理的自然语言生成、轻量分类、简单抽取任务,用快速通用模型或小模型反而更合适。
在 Agent 系统设计中,推理模型适合放在:高价值决策节点(选择哪个策略)、复杂计划生成、错误诊断和根因分析。不适合放在:高频率的简单路由、日志分析、格式化输出这类任务。
面试高频题
Q1:如何让 Agent 在任务执行失败时自动纠错而不陷入无限循环?
参考答案框架:
- 检测层:区分"可重试的失败"(工具超时、临时网络错误)和"需要重规划的失败"(工具返回了意外结果、步骤前提假设被推翻)。前者重试,后者触发重规划。
- 限制层:设置三重保护——单步最大重试次数(防止单点死循环)、全局最大重规划次数(防止整体死循环)、任务全局超时(兜底)。
- 逃逸层:超出重规划次数后,不能静默失败,要明确返回失败状态(包含已执行步骤、失败原因)并升级到 Human-in-the-Loop 或上游错误处理逻辑。
加分点:说出"检测重复状态"(新计划和旧计划相似度过高时直接报错而非再次执行);说出在重规划历史里记录"什么在哪里失败了",用于后续系统优化而非只是即时纠错。
Q2:推理模型如何改变传统的 ReAct 和 Plan-and-Execute 模式?
参考答案框架:
- 对 ReAct 的影响:推理模型的内部推理过程部分替代了显式 Thought 步骤的作用——模型在生成 Action 前已经内部推理过了。但 ReAct 的"行动-观察-行动"循环本身仍然有价值,因为它让 Agent 能从外部环境获取反馈,这是推理模型内部推理做不到的。两者是互补而非替代关系。
- 对 Plan-and-Execute 的影响:推理模型让 Plan 阶段的质量更高(能自主发现和修正逻辑缺陷),减少了"计划听起来好但执行时一塌糊涂"的情况。同时,因为推理模型内部已经在做部分 Evaluator 的工作,显式 Evaluator-Optimizer 循环的必要性在简单场景下降低了。
- 新的考量:推理模型不适合所有步骤——在高频、简单的执行任务上用推理模型是浪费。"推理模型规划 + 轻量模型执行"的混合架构是一个合理的工程方向。
加分点:提到不同供应商在推理摘要、原始推理链可见性、reasoning token 计费、工具调用交错推理上的 API 差异;提到推理模型和工具调用结合时的 Interleaved Thinking 特性,让模型能在每次工具调用结果返回后重新推理。
参考资料
[1] Building Effective Agents - Anthropic Engineering Blog (https://www.anthropic.com/engineering/building-effective-agents)
[2] Chain-of-Thought Prompting Elicits Reasoning in Large Language Models - Wei et al., 2022 (https://arxiv.org/abs/2201.11903)
[3] Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models - Wang et al., ACL 2023 (https://arxiv.org/abs/2305.04091)
[4] ReAct: Synergizing Reasoning and Acting in Language Models - Yao et al., ICLR 2023 (https://arxiv.org/abs/2210.03629)
[5] Reflexion: Language Agents with Verbal Reinforcement Learning - Shinn et al., NeurIPS 2023 (https://arxiv.org/abs/2303.11366)
[6] Self-Refine: Iterative Refinement with Self-Feedback - Madaan et al., NeurIPS 2023 (https://arxiv.org/abs/2303.17651)
[7] Language Agent Tree Search Unifies Reasoning Acting and Planning in Language Models - Zhou et al., 2023 (https://arxiv.org/abs/2310.04406)
[8] Building with Extended Thinking - Anthropic Platform Documentation, 截至 2026.04 (https://platform.claude.com/docs/en/build-with-claude/extended-thinking)
[9] Learning to Reason with LLMs - OpenAI, 2024.09 (https://openai.com/index/learning-to-reason-with-llms/)