智能体的两种灵魂:ReAct 与 Plan-and-Solve 深度对决
从实际运行数据出发,深入剖析两种经典智能体模式的本质差异
前言
AI Agent(智能体)是当下最火热的技术方向,但很多人只知道「智能体能自动完成任务」,却不理解它到底是怎么工作的。
智能体的核心,其实是决策模式 。今天,我们就来深入对比两种最经典的决策模式:ReAct 和 Plan-and-Solve。
我不仅会从理论上分析它们的差异,还会用真实的运行数据,让你亲眼看到它们的工作过程。
一、两种模式的核心思想
ReAct:边想边做
ReAct = Reasoning(推理)+ Acting(行动)
这个名字就道出了它的精髓:把思考和行动交织在一起,形成一个动态循环。
Thought(思考)→ Action(行动)→ Observation(观察)→ 循环 → Finish(完成)
生活比喻:像侦探办案。先调查现场,发现线索后决定下一步查什么,根据新线索再调整方向...整个过程是动态的、反应式的。
Plan-and-Solve:先想好再做
Plan-and-Solve = Plan(规划)+ Execute(执行)+ Solve(解答)
核心思想:先把整个流程规划好,再按计划一步步执行,最后汇总结果。
sql
Plan(制定完整计划)→ Execute(按计划执行)→ Solve(综合解答)
生活比喻:像工程师施工。先画好图纸、规划施工步骤,然后按图纸一步步施工,最后验收交付。整个过程是结构化的、计划式的。
二、一张图看懂区别
sql
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ 🔄 ReAct:动态循环模式 │
│ │
│ 问题 ─→ Thought ─→ Action ─→ Observation ─→ Thought ─→ Action ─→ ... │
│ │ │ │ │
│ └──────────┴────────────┴── 每一步都重新思考 │
│ │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 📋 Plan-and-Solve:结构执行模式 │
│ │
│ 问题 ─→ Plan(规划)────────────────→ Execute(执行)─────→ Solve │
│ │ │ │ │
│ │ 步骤1: 查北京天气 │ 步骤1 → 结果1 │ │
│ │ 步骤2: 查上海天气 │ 步骤2 → 结果2 │ │
│ │ 步骤3: 对比分析 │ 步骤3 → 结果3 │ │
│ │ 步骤4: 给出推荐 │ 步骤4 → 结果4 │ │
│ │ │ │ │
│ └── 一次性规划 ────────────────┴── 按计划执行 ────┴── 汇总 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
三、实战运行对比
为了让大家直观感受两种模式的差异,我用同一个 LLM(glm-5)分别运行了两种模式的智能体。
场景设定
- ReAct 任务:查询北京天气,判断是否适合户外活动
- Plan-and-Solve 任务:查询北京和上海天气,对比哪个更适合户外活动
ReAct 实际运行过程
erlang
======================================================================
🤖 ReAct 智能体启动
======================================================================
📝 用户问题: 帮我查询北京今天的天气,然后判断是否适合户外活动
🔄 --- 第 1 轮循环 ---
┌─────────────────────────────────────
│ 🧠 Thinking... (调用 LLM)
│
│ 💭 Thought:
│ 用户需要查询北京天气并判断是否适合户外活动,
│ 我需要先调用天气查询工具获取信息...
│
│ 🎬 Action: get_weather(city="北京")
│ ⚙️ 执行工具...
│
│ 👁️ Observation:
│ 北京当前天气:Sunny,气温17摄氏度,湿度32%
└─────────────────────────────────────
🔄 --- 第 2 轮循环 ---
┌─────────────────────────────────────
│ 🧠 Thinking... (调用 LLM)
│
│ 💭 Thought:
│ 已获取北京天气:晴天,17°C,湿度32%。
│ 这个天气条件非常适合户外活动------温度舒适、阳光充足...
│
│ 🎬 Action: Finish[北京今天天气晴朗,气温17°C...非常适合户外活动!]
│
│ ✅ 任务完成!
└─────────────────────────────────────
🎉 最终答案:
北京今天天气晴朗,气温17°C,湿度32%,非常适合户外活动!
建议您可以安排公园散步、郊游、骑行等户外活动。
关键数据:
| 指标 | 数值 |
|---|---|
| LLM 调用次数 | 2次 |
| 循环轮数 | 2轮 |
| 工具调用次数 | 1次 |
| 完成状态 | ✅ 成功 |
Plan-and-Solve 实际运行过程
markdown
======================================================================
🤖 Plan-and-Solve 智能体启动
======================================================================
📝 用户问题: 帮我查询北京和上海的天气,对比哪个城市更适合户外活动
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Phase 1: Plan(规划阶段)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
正在分析问题,制定执行计划...
📝 生成的计划:
┌──────────────────────────────────────────────────────────────────
│ 1. 调用 get_weather 工具查询北京的天气情况。
│ 2. 调用 get_weather 工具查询上海的天气情况。
│ 3. 根据获取的天气数据,对比分析两个城市的天气条件。
│ 4. 结合户外活动的适宜性标准,给出最终建议。
└──────────────────────────────────────────────────────────────────
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️ Phase 2: Execute(执行阶段)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔹 执行步骤 1: 查询北京天气
│ 🎬 执行工具: get_weather
│ ✅ 结果: 北京天气:Sunny,气温17°C,湿度32%
🔹 执行步骤 2: 查询上海天气
│ 🎬 执行工具: get_weather
│ ✅ 结果: 上海天气:Partly cloudy,气温18°C,湿度64%
🔹 执行步骤 3: 对比分析天气条件
│ 🧠 进行分析: 对比两个城市的天气数据
🔹 执行步骤 4: 给出最终建议
│ 🧠 进行分析: 结合户外活动适宜性给出建议
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎉 Phase 3: Solve(解答阶段)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🏆 最终答案:
根据查询结果对比:
- 北京:晴天,17°C,湿度32%
- 上海:多云,18°C,湿度64%
北京更适合户外活动:
1. 晴天天气更适合户外拍照和观光
2. 湿度32%比64%更舒适,不会感到闷热
3. 温度适中,适合各类户外运动
推荐今天在北京进行户外活动。
关键数据:
| 指标 | 数值 |
|---|---|
| LLM 调用次数 | 约6次(规划+执行4步+解答) |
| 执行阶段数 | 3个阶段 |
| 工具调用次数 | 2次 |
| 完成状态 | ✅ 成功 |
四、运行数据深度分析
对比一:LLM 调用效率
| 任务复杂度 | ReAct | Plan-and-Solve |
|---|---|---|
| 单次查询(如查北京天气) | 2次调用 | 3次调用(规划+执行+解答) |
| 双次查询(如查两个城市) | 4次调用 | 6次调用 |
| 三次查询(如查三个城市) | 6次调用 | 7次调用 |
| 复杂推理任务 | 5-8次调用 | 7-10次调用 |
发现:对于简单任务,ReAct 更高效;对于需要多个独立查询的任务,Plan-and-Solve 的结构更清晰。
对比二:决策时机
ReAct 的每一次决策都在「当下」:
arduino
第1轮:看到问题 → 思考"先查天气" → 执行
第2轮:看到天气结果 → 思考"可以回答了" → Finish
每一步决策都基于最新的观察结果。
Plan-and-Solve 的决策在「开始时」:
Phase 1:一次性规划全部步骤
Phase 2:按计划执行,不再重新思考
Phase 3:汇总结果
决策集中在规划阶段,执行阶段只是「照章办事」。
对比三:适应性
假设任务发生变化:查询北京天气后,发现下雨了,应该推荐室内活动而不是户外。
ReAct 可以应对:
vbnet
Observation: 北京下雨,15°C
Thought: 天气不适合户外,我应该推荐室内活动
Action: recommend_indoor("北京")
ReAct 能根据观察结果动态调整策略。
Plan-and-Solve 可能出问题:
markdown
Plan:
1. 查询天气
2. 推荐户外景点 ← 已经规划了户外,但实际下雨!
初始计划可能不适应实际情况。
五、优劣点深度剖析
ReAct 的优势
| 优势 | 说明 | 实际体现 |
|---|---|---|
| 动态适应 | 能根据观察结果调整策略 | 第2轮根据天气结果做出判断 |
| 减少幻觉 | 通过工具获取真实信息 | 调用真实天气API,不凭空编造 |
| 可解释性强 | 每一步思考都可见 | Thought 内容清晰展示推理过程 |
| 纠错能力 | 观察到错误可以重新思考 | 未找到Action时会提示重新思考 |
ReAct 的劣势
| 劣势 | 说明 | 潜在风险 |
|---|---|---|
| 效率问题 | 每步都调用LLM | 简单任务也需要多次调用 |
| 上下文累积 | 历史记录不断增长 | 复杂任务可能超出Token限制 |
| 缺乏全局规划 | 只关注当前一步 | 可能走弯路或重复操作 |
Plan-and-Solve 的优势
| 优势 | 说明 | 实际体现 |
|---|---|---|
| 结构清晰 | 三阶段分明 | Plan → Execute → Solve 流程一目了然 |
| 全局规划 | 开始就考虑完整流程 | 一次规划4个步骤,逻辑连贯 |
| 易于并行 | 独立步骤可同时执行 | 查北京和上海天气可并行 |
| 效率可控 | 规划一次,执行多次 | 明确知道需要多少次调用 |
Plan-and-Solve 的劣势
| 劣势 | 说明 | 潜在风险 |
|---|---|---|
| 适应性差 | 计划难以动态调整 | 遇到意外情况无法灵活应对 |
| 规划依赖 | 初始计划决定效果 | 规划出错会导致全盘失败 |
| 无法纠错 | 执行中不能修改计划 | 遇到问题只能继续或重新开始 |
六、核心代码对比
ReAct 核心循环
javascript
while (未完成 && 循环次数 < 限制) {
// 1. Thought: 调用 LLM 获取思考
const response = await llm.thinkSync(prompt);
// 2. 解析 Action
const action = parseAction(response);
// 3. 判断是否结束
if (action.type === 'finish') {
return action.answer;
}
// 4. 执行工具,获取 Observation
const observation = await executeTool(action);
// 5. 加入历史,继续下一轮
history.push(response);
history.push(`Observation: ${observation}`);
}
Plan-and-Solve 三阶段
javascript
// Phase 1: Plan(规划)
const plan = await llm.thinkSync("分析问题,制定步骤列表");
const steps = parsePlan(plan);
// Phase 2: Execute(执行)
const results = [];
for (const step of steps) {
const result = await executeStep(step);
results.push(result);
}
// Phase 3: Solve(解答)
const answer = await llm.thinkSync("综合结果,给出答案");
return answer;
七、选型决策指南
什么时候用 ReAct?
✅ 任务步骤不确定
✅ 需要根据结果动态调整
✅ 任务可能需要纠错
✅ 追求可解释性(每一步都可见)
✅ 简单的线性任务(2-3步就能完成)
典型场景:
- 查天气后根据结果做判断
- 搜索后根据结果决定下一步查什么
- 调试类任务(边查边改)
什么时候用 Plan-and-Solve?
✅ 任务目标明确,步骤可预测
✅ 需要执行多个独立查询后综合分析
✅ 追求效率,控制成本
✅ 需要清晰的结构化执行流程
✅ 步骤之间可以并行执行
典型场景:
- 查询多个城市天气后对比
- 搜索多个关键词后汇总
- 执行固定的多步骤流程
混合方案建议
实际项目中,可以结合两种模式:
yaml
┌─────────────────────────────────────────────────────────────┐
│ │
│ Phase 1: Plan(用 Plan-and-Solve 的规划能力) │
│ 制定基本计划 │
│ │
│ Phase 2: Execute + ReAct(保留 ReAct 的灵活性) │
│ 按计划执行,但遇到意外情况时启动 ReAct 循环纠错 │
│ │
│ Phase 3: Solve(汇总结果) │
│ │
└─────────────────────────────────────────────────────────────┘
这样既保证了结构清晰,又保留了动态适应能力。
八、总结
| 维度 | ReAct | Plan-and-Solve |
|---|---|---|
| 一句话 | 边想边做,动态应变 | 先想好再做,高效执行 |
| 比喻 | 侦探办案 | 工程师施工 |
| 决策时机 | 每一步 | 开始时一次 |
| 适应性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 效率 | ⭐⭐ | ⭐⭐⭐⭐ |
| 可解释性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 全局规划 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 适用场景 | 不确定任务 | 明确任务 |
最终建议:
任务不确定 → ReAct
任务明确 → Plan-and-Solve
追求完美 → 结合两者
智能体设计没有银弹。理解两种模式的本质,根据实际任务特点灵活选择,才是正确的做法。
附录:完整代码与运行
本文涉及的完整代码已开源,包含:
react-agent/:ReAct 模式完整实现plan-and-solve-agent/:Plan-and-Solve 模式完整实现
运行方式:
bash
# ReAct
cd react-agent
LLM_MODEL_ID='your_model' LLM_API_KEY='your_key' LLM_BASE_URL='your_url' node index.js
# Plan-and-Solve
cd plan-and-solve-agent
LLM_MODEL_ID='your_model' LLM_API_KEY='your_key' LLM_BASE_URL='your_url' node index.js
智能体的灵魂,是决策模式。理解 ReAct 和 Plan-and-Solve,你就理解了智能体设计的核心。
参考资料: