[Hello-Agents] Day 6: 第四章(下)智能体经典范式构建 — Plan-and-Solve 与 Reflection

[Hello-Agents] Day 6: 第四章(下)智能体经典范式构建 — Plan-and-Solve 与 Reflection

📅 2026-03-31 | 📖 Datawhale Hello-Agents 课程

📚 本篇概要

在上一篇中,我们深入探讨了 ReAct 范式——一种"边想边做"的反应式智能体架构。今天,我们将继续第四章的下半部分,探索两种截然不同但同样强大的智能体范式:Plan-and-Solve(先规划后执行)与 Reflection(反思迭代)。前者让智能体学会"三思而后行",后者赋予智能体"自我审视"的能力。这两种范式的掌握,将为你构建更复杂、更可靠的智能体系统奠定坚实基础。

一、Plan-and-Solve:三思而后行的架构师思维

1.1 从侦探到建筑师:范式的转变

如果说 ReAct 像一位经验丰富的侦探,根据现场线索步步推理、随时调整调查方向;那么 Plan-and-Solve 则更像一位严谨的建筑师——在动工之前,必须先绘制出完整的蓝图,然后严格按照图纸施工。这种"先谋后动"的策略,使得智能体在处理需要长远规划的复杂任务时,能够保持更高的目标一致性,避免在中间步骤中迷失方向。

Plan-and-Solve Prompting 由 Lei Wang 在 2023 年提出,其核心动机是为了解决思维链在处理多步骤、复杂问题时容易"偏离轨道"的问题。与 ReAct 将思考和行动融合在每一步不同,Plan-and-Solve 将整个流程明确解耦为两个核心阶段:

🏗️ 规划阶段(Planning Phase)

智能体首先接收用户的完整问题,不是直接解决问题或调用工具,而是将问题分解,制定出一个清晰、分步骤的行动计划。这个计划本身就是一次大语言模型的调用产物,是后续执行的"蓝图"。

🔧 执行阶段(Solving Phase)

在获得完整计划后,智能体进入执行阶段。严格按照计划中的步骤,逐一执行。每一步的执行都可能是一次独立的 LLM 调用,或者是对上一步结果的加工处理,直到计划中的所有步骤都完成。

1.2 数学形式化:让逻辑更清晰

我们可以用形式化的数学语言来描述这个两阶段过程。首先,规划模型 πplan 根据原始问题 q 生成一个包含 n 个步骤的计划 P = (p₁, p₂, ..., pn)

P = πplan(q)

随后,在执行阶段,执行模型 πsolve 会逐一完成计划中的步骤。对于第 i 个步骤,其解决方案 si 的生成会同时依赖于原始问题 q、完整计划 P 以及之前所有步骤的执行结果 (s₁, ..., si-1):

si = πsolve(q, P, (s₁, ..., si-1))

最终的答案就是最后一个步骤的执行结果 sn。这种形式化表达清晰地展示了信息是如何在执行链条中流动的:每一步都站在前人肩膀上,继承并利用之前所有步骤的成果。

1.3 核心代码实现:规划器与执行器

Plan-and-Solve 的实现关键在于两个独立但协同的组件:规划器(Planner)执行器(Executor)。让我们深入分析其核心设计。

📋 规划器提示词设计

规划器的提示词需要明确告诉模型:你的任务是将复杂问题分解为简单步骤,输出必须是结构化的 Python 列表格式。这种格式约束极大地简化了后续代码的解析工作,比解析自然语言更稳定可靠。

PLANNER_PROMPT_TEMPLATE = """
你是一个顶级的AI规划专家。你的任务是将用户提出的复杂问题
分解成一个由多个简单步骤组成的行动计划。

请确保计划中的每个步骤都是一个独立的、可执行的子任务,
并且严格按照逻辑顺序排列。

你的输出必须是一个Python列表:
```python
["步骤1", "步骤2", "步骤3", ...]
```

问题: {question}
"""

🔄 执行器与状态管理

执行器的设计体现了 Plan-and-Solve 的精髓——状态管理。它必须记录每一步的执行结果,并将其作为上下文提供给后续步骤。这种"累积式"的信息传递确保了整个执行链条中信息的一致性和完整性。

class Executor:
    def __init__(self, llm_client):
        self.llm_client = llm_client

    def execute(self, question: str, plan: list[str]) -> str:
        history = ""  # 关键:状态累积
        
        for i, step in enumerate(plan):
            prompt = EXECUTOR_PROMPT_TEMPLATE.format(
                question=question,
                plan=plan,
                history=history if history else "无",
                current_step=step
            )
            
            response = self.llm_client.think(messages=[...])
            
            # 更新历史记录,为下一步做准备
            history += f"步骤 {i+1}: {step}\n结果: {response}\n\n"
        
        return response

1.4 实战案例:数学应用题的优雅解决

课程中用一个经典案例展示了 Plan-and-Solve 的威力:

"一个水果店周一卖出了15个苹果。周二卖出的苹果数量是周一的两倍。周三卖出的数量比周二少了5个。请问这三天总共卖出了多少个苹果?"

智能体的执行过程展现了教科书般的逻辑清晰:

规划阶段输出:

["计算周一卖出的苹果数量:15个",
 "计算周二卖出的苹果数量:周一数量 × 2 = 15 × 2 = 30个",
 "计算周三卖出的苹果数量:周二数量 - 5 = 30 - 5 = 25个",
 "计算三天总销量:周一 + 周二 + 周三 = 15 + 30 + 25 = 70个"]

每一步执行都精确地继承了前一步的结果:步骤2正确使用了步骤1的"15个",步骤3正确使用了步骤2的"30个"。最终答案"70个"水到渠成。这种结构化的执行过程,使得复杂问题的解决变得可追溯、可验证、可调试。

二、Reflection:赋予智能体自我审视的能力

2.1 从一次完成到迭代优化

ReAct 和 Plan-and-Solve 范式有一个共同特点:一旦任务完成,流程便告结束。然而,现实世界中,无论是人类的文章写作、代码开发还是方案设计,初稿往往只是起点,而非终点。Reflection 机制的灵感正是来源于人类的学习过程:我们完成初稿后会校对,解出数学题后会验算。

Shinn Noah 在 2023 年提出的 Reflexion 框架,将这种"事后反思"的思想引入智能体系统。其核心工作流程是一个简洁的三步循环:执行 → 反思 → 优化

1️⃣

执行

生成初步方案

2️⃣

反思

多维度评估

3️⃣

优化

根据反馈改进

2.2 反思的多维度视角

Reflection 的核心在于引入一个独立的"评审员"角色,从多个维度审视初稿:

  • 事实性错误:是否存在与常识或已知事实相悖的内容?
  • 逻辑漏洞:推理过程是否存在不连贯或矛盾之处?
  • 效率问题:是否有更直接、更简洁的路径来完成任务?
  • 遗漏信息:是否忽略了问题的某些关键约束或方面?

根据评估结果,"评审员"会生成一段结构化的反馈,指出具体问题所在和改进建议。然后,优化模型结合初稿和反馈,生成更完善的修订稿。这个循环可以重复进行,直到反思阶段不再发现新问题,或达到预设的迭代次数上限。

2.3 记忆模块:迭代的前提

Reflection 的核心在于迭代,而迭代的前提是能够记住之前的尝试和获得的反馈。因此,一个"短期记忆"模块成为实现该范式的必需品。课程设计了一个简洁但功能完备的 Memory 类:

class Memory:
    def __init__(self):
        self.records: List[Dict[str, Any]] = []
    
    def add_record(self, record_type: str, content: str):
        """添加执行或反思记录"""
        record = {"type": record_type, "content": content}
        self.records.append(record)
    
    def get_trajectory(self) -> str:
        """将记忆序列化为可插入提示词的文本"""
        trajectory_parts = []
        for record in self.records:
            if record['type'] == 'execution':
                trajectory_parts.append(
                    f"--- 上一轮尝试 (代码) ---\n{record['content']}"
                )
            elif record['type'] == 'reflection':
                trajectory_parts.append(
                    f"--- 评审员反馈 ---\n{record['content']}"
                )
        return "\n\n".join(trajectory_parts)

这个设计简洁但关键:get_trajectory 方法将记忆轨迹"序列化"成一段文本,可以直接插入后续的提示词中,为模型的反思和优化提供完整的上下文。

2.4 实战案例:从低效到高效的代码进化

课程选择了一个经典任务来展示 Reflection 的威力:"编写一个 Python 函数,找出 1 到 n 之间所有的素数"。这个任务的特点是:

  • 存在明确的优化路径:从暴力试除法到埃拉托斯特尼筛法
  • 反思点清晰:时间复杂度从 O(n√n) 到 O(n log log n)
  • 优化方向明确:算法层面的跃迁

第一轮:初始执行

模型生成了一个基于试除法的初步实现,时间复杂度 O(n√n)。这对于小规模数据够用,但 n 很大时性能会显著下降。

第二轮:反思与优化

"当前代码的时间复杂度为 O(n * sqrt(n))。建议使用埃拉托斯特尼筛法(Sieve of Eratosthenes),时间复杂度为 O(n log(log n)),能够显著提高查找素数的效率。"

模型根据这个反馈,实现了更高效的筛法版本。

第三轮:深度反思

"当前代码使用了 Eratosthenes 筛法,时间复杂度为 O(n log log n),空间复杂度为 O(n)。此算法已非常高效。在某些特定场景下,可考虑分段筛法或奇数筛法,但对于大多数应用场景,无需改进。"

这个"无需改进"的判断触发了终止条件,优化过程得以收敛。最终产出的代码不仅功能正确,而且算法高效——这正是 Reflection 机制的核心价值:将一个"合格"的初版方案,迭代优化成一个"优秀"的最终方案。

三、三种范式的深度对比

3.1 核心差异总结

范式 核心思想 工作方式 适用场景
ReAct 边想边做 Thought → Action → Observation 循环 探索性任务、需外部工具输入
Plan-and-Solve 三思后行 先规划 → 后执行 逻辑路径确定、内部推理密集
Reflection 自我审视 执行 → 反思 → 优化 迭代 高质量要求、可迭代优化

3.2 成本收益权衡

维度 ReAct Plan-and-Solve Reflection
API调用次数 中等(按需) 固定(n+1次) 高(迭代×2)
响应延迟 不确定 可预测 较高
结果质量 依赖工具反馈 结构稳定 迭代提升
可解释性 高(Thought链) 高(计划清晰) 中等(迭代复杂)

四、个人思考与反思

4.1 关于范式的本质

这三种范式本质上解决的是同一个问题:如何让大语言模型更可靠地完成复杂任务。但它们的切入点截然不同:

  • ReAct 解决的是"如何与外部世界交互"的问题——通过工具调用获取真实信息。
  • Plan-and-Solve 解决的是"如何保持目标一致性"的问题——通过预先规划避免中途迷失。
  • Reflection 解决的是"如何提升结果质量"的问题——通过自我审视实现迭代优化。

这三者并非互斥,而是可以组合使用。一个强大的智能体系统可能同时包含:用 Plan-and-Solve 制定宏观策略,用 ReAct 执行具体步骤,用 Reflection 在关键节点进行质量把控。

4.2 关于"造轮子"的价值

课程在第四章开头提出了一个好问题:市面上已有 LangChain、LlamaIndex 等优秀框架,为何还要"重复造轮子"?答案在于:

直接使用高度抽象的工具,并不利于我们了解背后的设计机制是怎么运行的。亲手处理模型输出格式解析、工具调用失败重试、防止智能体陷入死循环等问题,是培养系统设计能力的最直接方式。掌握了设计原理,你才能真正从一个框架的"使用者"转变为一个智能体应用的"创造者"。

这种"造轮子"思想在 AI 领域尤为重要。框架封装了复杂性,但也隐藏了原理。只有亲手实现过 ReAct 的 Thought-Action-Observation 循环,才能真正理解为什么"思考"和"行动"需要显式分离;只有亲手实现过 Plan-and-Solve 的状态传递机制,才能体会"累积历史"在执行链条中的关键作用。

4.3 关于提示词工程的艺术

三种范式的实现都高度依赖于精心设计的提示词模板。课程中的提示词设计有几个共同特点:

  • 角色设定:"你是一个顶级的AI规划专家"——激发模型的专业能力。
  • 任务描述:清晰定义"分解问题"或"审视代码"的具体目标。
  • 格式约束:强制要求输出为特定格式(Python 列表、Thought/Action 分隔),便于后续解析。
  • 上下文注入:动态插入历史记录、计划内容、反馈信息等。

这些技巧的组合使用,构成了"提示词工程"的核心方法论。值得注意的是,Reflection 的提示词特别强调了"评审员"的角色定位——"你是一位极其严格的代码评审专家和资深算法工程师,对代码的性能有极致的要求"。这种角色设定直接影响了模型反思的深度和方向。

五、实践建议与最佳实践

5.1 如何选择合适的范式

✅ 选择 ReAct 当:

  • 任务需要查询实时信息(天气、新闻、股价)
  • 任务需要精确计算或数据库操作
  • 任务具有探索性,需要根据中间结果调整策略

✅ 选择 Plan-and-Solve 当:

  • 任务可以被清晰分解为顺序步骤
  • 任务需要多步推理(数学应用题、逻辑题)
  • 需要生成结构化报告(引言、数据来源、分析、总结)

✅ 选择 Reflection 当:

  • 任务对结果质量有极高要求
  • 任务可以通过迭代逐步优化(代码生成、文档撰写)
  • 可以容忍较长的处理时间

5.2 混合架构的实践建议

在实际项目中,单一范式往往不足以应对复杂场景。以下是混合架构的几种常见模式:

模式一:Plan-and-Solve + ReAct

先用 Plan-and-Solve 生成宏观计划,每个步骤的执行交给 ReAct 完成。这样既有全局规划,又有局部灵活性。适用于需要多步骤且每步都可能需要外部工具的任务。

模式二:ReAct + Reflection

在 ReAct 的基础上,每次获得工具结果后加入一个反思步骤,判断当前路径是否正确。这可以有效避免 ReAct 陷入"原地打转"的问题。

模式三:Plan-and-Solve + Reflection

在计划生成后加入反思,判断计划是否合理;在执行完成后加入反思,判断结果是否达标。这种"双反思"机制可以显著提升复杂任务的完成质量。

六、总结与展望

第四章的下半部分,我们学习了 Plan-and-Solve 和 Reflection 两种经典范式。如果说 ReAct 让智能体学会了"动手",那么 Plan-and-Solve 让智能体学会了"规划",Reflection 让智能体学会了"反思"。这三种能力——行动、规划、反思——恰恰也是人类认知的核心维度。

从工程角度看,这三种范式各有其成本收益曲线:

  • ReAct:中等成本,高适应性,适合探索性任务。
  • Plan-and-Solve:可预测成本,高稳定性,适合结构化任务。
  • Reflection:高成本,高质量,适合关键任务。

下一章我们将进入低代码平台实践,探索 Dify 等工具如何帮助快速构建智能体。但在此之前,深刻理解这些底层范式的设计原理,将使你在使用任何高级框架时都能做到"知其然,更知其所以然"。

📌 下一篇预告

第五章:基于低代码平台的智能体搭建 —— 当我们掌握了底层原理后,如何用 Dify 等工具实现"降维打击"?敬请期待。

📝 本文基于 Datawhale Hello-Agents 课程第四章内容撰写,部分代码和案例来源于课程材料。感谢课程团队的精心编排。

评论

此博客中的热门博文

OpenClaw 救援机器人建设与演进全记录 - 从单点故障到双实例自愈体系

Lossless Claw:无损上下文管理插件分析报告

[Hello-Agents] Day 2: 第一章 初识智能体