从零开始的LLM 5.智能体经典范式构建
前言
从零开始学习ai文章系列已完成《动手学深度学习》和《磨菇书》两本书的学习,新开的LLM系列课本来自《Happy-LLM》和《Hello-Agents》,但是内容和排版等个人重新进行整理,因此不会按照原来课本中的章节来写。如果哪里有错误的欢迎指正。或者不清晰的可以直接查看原文部分。
本章内容参考自 第四章 智能体经典范式构建 。原文已经写的很好了,因此这里仅作个人总结笔记记录。
1. 概述
在介绍智能体(Agent)之前,需要先理解两个重要概念:范式(Paradigm) 与 提示词工程(Prompt Engineering)。
1.1 什么是范式
范式(Paradigm)可以理解为解决某类问题的通用模式或设计框架。
在软件开发中,我们熟悉的面向对象、函数式编程都属于编程范式;而在智能体领域,范式则指:
如何组织大模型、工具、记忆以及决策流程,使其能够完成特定任务的一套方法论。
例如:
- ReAct(Reason + Act)范式
- Plan-and-Execute(规划-执行)范式
- Reflection(反思)范式
- Multi-Agent(多智能体协作)范式
这些范式并不会改变大模型本身,而是在大模型外部构建不同的工作流程,从而获得不同的能力表现。
简单来说:
大模型决定智能体的能力上限,而范式决定智能体如何发挥这些能力。
1.2 什么是提示词工程
提示词工程(Prompt Engineering)是指通过设计输入给大模型的提示词(Prompt),引导模型按照预期方式进行思考和输出。
由于大模型本质上是一个根据上下文预测下一个 Token 的概率模型,因此输入内容会直接影响最终结果。
一个简单的问题:
1 | 北京到上海有多远? |
与:
1 | 你是一名资深旅游顾问,请从高铁、飞机、自驾三个角度分析北京到上海的距离和出行方案。 |
模型给出的回答质量通常会存在明显差异。
因此,提示词工程的核心目标是:
- 提高回答质量
- 降低模型幻觉
- 引导模型按照指定格式输出
- 让模型具备特定角色和行为模式
1.3 范式与提示词工程的关系
范式定义了智能体应该按照什么流程完成任务,而提示词工程则负责将这一流程描述给大模型。
换句话说:
范式负责设计流程,提示词负责让大模型执行流程。
因此,大部分智能体范式都可以理解为:
- 先设计一套任务处理流程(范式);
- 再通过提示词将该流程描述给大模型;
- 最终让大模型按照该流程进行思考和决策。
从某种程度上来说,许多早期 Agent 系统本质上就是一组精心设计的提示词。随着发展,人们又在此基础上加入了工具调用、记忆管理、状态维护以及工作流控制等机制,最终形成了今天的智能体系统。
1.4 本章内容
理解了范式与提示词工程之间的关系后,接下来将介绍智能体领域最经典的三种范式。
这些范式本质上都是通过不同的流程设计,引导大模型以不同方式完成任务,从而获得推理、规划、反思等能力。
本章将依次介绍:
- ReAct(Reason + Act)范式:通过“思考 → 行动 → 观察”的循环过程完成任务,是当前最经典、应用最广泛的 Agent 范式之一。
- Plan-and-Execute(规划-执行)范式:先生成完整任务计划,再按照计划逐步执行,适用于复杂任务拆解与长期任务管理。
- Reflection(反思)范式:在完成阶段性任务后进行自我审查和总结,根据发现的问题调整后续行动,从而持续提升任务完成质量。
这三种范式构成了现代智能体设计的重要基础思想,许多 Agent 框架和研究工作都可以看作是在这些经典范式之上的扩展与组合。
2. 环境准备
接下来的内容将沿用原文的讲解方式,通过「代码实践 + 原理分析」的形式逐步介绍各种智能体范式。因此,在正式开始之前,需要先完成一些基础环境配置。
2.1 配置 API 密钥
为了提高代码的通用性,我们将模型服务相关配置统一放置在环境变量中,包括:
- API Key
- 模型 ID
- 服务地址(Base URL)
这样在切换不同模型服务商时,只需要修改配置文件,而无需改动业务代码。
首先,在项目根目录下创建一个名为 .env
的文件,并填写对应配置:
1 | # .env |
上述配置仅为示例,你可以根据自己的需求替换为:
- OpenAI 官方接口
- 本地部署的模型服务
- 兼容 OpenAI API 的第三方服务
本文示例中,作者使用的是 Groq 提供的免费模型服务,因此配置内容指向 Groq 的 API 接口。
配置完成后,将 .env
文件放置在运行脚本所在目录(或项目根目录)下,并在程序启动时加载环境变量:
1 | from dotenv import load_dotenv |
这样后续代码便可以直接从环境变量中读取模型相关配置,而无需在代码中硬编码敏感信息。
2.2 封装基础 LLM 调用函数
为了简化后续 Agent 开发,我们首先对大模型调用过程进行统一封装。
这里与原文保持一致,采用在线 API 的方式调用大模型。这样能够更专注于理解 Agent 范式本身,而无需额外关注模型部署与推理细节。
如果希望使用本地模型,可以参考上一章介绍的模型加载方法,将本地模型封装成与 OpenAI API 类似的调用接口即可。对于后续 Agent 代码而言,无论底层使用在线模型还是本地模型,调用方式基本保持一致。
1 |
|
2.3 配置 SerpApi API 密钥
在后续实现 Agent 工具调用时,我们会使用 SerpApi 作为搜索引擎接口。因此,需要提前申请并配置对应的 API 密钥。
首先前往 SerpApi 官网 注册账户。SerpApi 提供一定额度的免费调用次数,对于学习和实验场景通常已经足够使用。
注册完成后,在控制台获取你的 API Key,并将其添加到项目根目录下的
.env 文件中:
1 | SERPAPI_API_KEY="YOUR_SERPAPI_API_KEY" |
3. ReAct(Reason + Act)范式
3.1 ReAct 的工作流程
ReAct(Reason + Act)由 Shunyu Yao 等人在 2022 年提出。其核心思想是模仿人类解决问题的过程,将推理(Reasoning)与行动(Acting)显式结合,使大语言模型能够在思考过程中主动获取外部信息,而不仅仅依赖预训练阶段学习到的知识。
传统的大语言模型通常采用一次性生成(One-shot Generation)的方式:模型读取用户问题后直接给出答案。
而 ReAct 则引入了一个持续迭代的决策过程,使模型能够在推理过程中动态调用工具、获取反馈并调整后续行为。
整个流程可以概括为一个循环:
1 | Thought → Action → Observation |
其中:
Thought(思考)
智能体的内部推理过程。模型会分析当前任务、制定计划、评估已有信息,并决定下一步需要采取什么行动。
Action(行动)
智能体执行的具体操作,通常表现为调用外部工具。例如:
1
Search["华为最新款手机"]
Observation(观察)
工具执行后返回的结果。例如搜索引擎返回的网页摘要、数据库查询结果或 API 响应等。
一个典型的执行过程如下:
1 | 用户问题: |
随着循环不断进行,新的 Observation 会被追加到上下文中,成为后续推理的依据。模型通过不断地“思考—行动—观察”,逐步缩小问题空间,最终得到答案。
从形式化角度来看,在时间步 t 时,大语言模型策略 \(\pi\) 会根据用户问题 q 以及历史轨迹 \(((a_1,o_1),(a_2,o_2),...,(a_{t-1},o_{t-1}))\) 生成当前的思考 \(th_t\) 和行动 \(a_t\): \[ (th_t,a_t)=\pi(q,((a_1,o_1),...,(a_{t-1},o_{t-1}))) \] 随后,环境中的工具 T 执行行动 \(a_t\),并返回新的观察结果: \[ o_t=T(a_t) \] 新的 \((a_t,o_t)\) 将被追加到历史轨迹中,供下一轮推理使用。该过程持续迭代,直到模型认为已经获得足够信息,并输出最终答案。

相比于单纯依赖参数记忆的大语言模型,ReAct 的优势在于能够将模型推理能力与外部工具能力结合起来,从而突破知识时效性和计算能力的限制。
因此,ReAct 特别适用于以下场景:
需要实时信息的任务
例如查询天气、新闻、股票价格、航班状态等动态变化的信息。
需要外部知识支撑的任务
例如搜索专业领域资料、阅读文档、检索企业内部知识库等。
需要精确计算的任务
将数学运算交给计算器或代码执行器完成,避免大语言模型产生计算错误。
需要调用系统能力的任务
例如访问数据库、调用 API、执行代码、发送邮件或操作文件系统等。
可以发现,ReAct 的本质并不是让模型“知道更多”,而是让模型学会在不知道答案时主动寻找答案。
接下来,我们将构建一个具备外部工具调用能力的 ReAct 智能体,并让其解决一个仅依赖模型参数无法准确回答的问题。例如:
华为最新发布的手机是哪一款?它的主要卖点是什么?
为了回答这个问题,智能体需要首先意识到自身缺乏实时信息,然后主动调用搜索工具获取最新资料,最后基于检索结果完成总结与回答。这正是 ReAct 范式最典型的应用场景。
3.2 工具的定义与实现
如果将大语言模型看作智能体的“大脑”,那么工具(Tools)就是其与外部世界交互的能力。通过工具,智能体不仅能够利用自身的推理能力,还能够获取实时信息、执行计算任务,以及与各种外部系统进行交互。
对于本节的示例任务——回答“华为最新发布的手机是哪一款?它的主要卖点是什么?”,仅依赖模型参数中的知识是不够的。由于手机产品会不断更新,大语言模型掌握的信息很可能已经过时。因此,我们需要为智能体提供一个能够访问互联网的搜索工具。
这里选择使用 SerpApi。它提供了搜索引擎结果的结构化 API 接口,可以直接获取搜索结果,而无需自行实现网页抓取和解析逻辑。
首先安装相关依赖:
1 | pip install google-search-results |
接下来,我们通过代码实现并管理这个工具。
3.2.1 实现搜索工具的核心逻辑
一个工具通常包含以下三个组成部分:
名称(Name)
工具的唯一标识符,用于在 Action 中指定需要调用的工具。
描述(Description)
对工具功能的自然语言说明,用于告诉大语言模型该工具能够完成什么任务,以及适用于哪些场景。
在 ReAct 模式下,模型通常会根据工具描述判断是否需要调用该工具,因此清晰准确的描述十分重要。
执行逻辑(Execution Logic)
工具对应的具体实现代码,负责接收输入、执行任务并返回结果。
我们的第一个工具是搜索工具(Search Tool)。它接收一个查询字符串作为输入,通过 SerpApi 调用搜索引擎获取结果,并将搜索内容返回给智能体。
下面实现搜索工具的核心逻辑 search 函数:
1 | from serpapi import SerpApiClient |
3.2.2 构建通用的工具执行器
目前我们只实现了一个搜索工具,但在实际应用中,智能体往往需要使用多种工具,例如计算器、数据库查询工具、代码执行工具等。
为了统一管理这些工具,我们创建一个 ToolExecutor
类。它负责工具的注册、查询与调用,使智能体无需关心工具的具体实现细节,只需指定工具名称和输入参数即可完成调用。
下面实现通用工具执行器:
1 | from typing import Dict, Any |
3.2.3 测试
现在,我们将搜索工具注册到 ToolExecutor
中,并模拟一次工具调用,以验证整个工具调用流程是否能够正常工作。
下面进行测试:
1 | # --- 工具初始化与使用示例 --- |

3.3 ReAct 智能体的编码实现
前面我们已经完成了两个核心组件:
- LLM 客户端:负责与大语言模型进行交互;
- ToolExecutor:负责管理和执行工具。
接下来,我们将这些组件组合起来,构建一个完整的 ReAct 智能体。整个智能体的核心职责包括:
- 构造提示词并发送给 LLM;
- 解析 LLM 返回的 Thought 和 Action;
- 调用对应工具执行 Action;
- 将执行结果作为 Observation 加入历史记录;
- 重复上述过程,直到获得最终答案。
为了便于理解,我们将 ReActAgent
的实现拆分为几个部分进行介绍。
3.3.1 系统提示词设计
提示词是 ReAct 智能体的核心,它决定了模型如何思考以及如何调用工具。
为了让模型按照 ReAct 的方式工作,我们需要通过系统提示词明确告知:
- 智能体的角色定位;
- 当前可用的工具列表;
- 输出格式要求;
- 用户问题与历史记录。
下面定义 ReAct 使用的提示词模板:
1 | # ReAct 提示词模板 |
该模板主要包含以下几个部分:
角色定义
指定模型扮演一个能够使用外部工具的智能助手。
工具列表({tools})
动态注入当前可用工具及其描述,帮助模型判断应该调用哪个工具。
输出格式约束
要求模型按照固定格式输出 Thought 和 Action,便于后续程序解析。
上下文信息({question}/{history})
包含用户问题以及历史交互记录,使模型能够基于已有信息继续推理。
3.3.2 输出解析器的实现
大语言模型返回的内容本质上仍然是一段文本,因此我们需要从文本中提取出 Thought 和 Action。
为此,我们实现几个辅助解析函数:
1 | def _parse_output(self, text: str): |
其中:
- **_parse_output** : 从模型输出中提取 Thought 和 Action。
- **_parse_action** : 解析 Action 内容,获取工具名称以及工具输入参数。
3.3.3 核心循环的实现
ReActAgent 的核心是一个循环。
在每一轮中,智能体都会构造提示词、调用模型、解析结果、执行工具,并将新的 Observation 追加到历史记录中。这个过程会持续进行,直到模型给出最终答案或达到最大迭代次数。
下面实现 ReActAgent 的核心逻辑:
1 | def run(self, question: str): |
3.3.4 运行实例与分析
至此,我们已经完成了完整的 ReAct 智能体实现。
下面运行一个实际示例,观察智能体如何通过调用搜索工具获取实时信息,并最终生成答案:
1 |
|


(2026.6.24)
从运行结果可以看到,智能体会先调用搜索工具获取信息,再结合搜索结果完成推理并生成答案。
由于互联网信息会不断变化,你实际运行时得到的结果可能与本书中的示例有所不同。这也体现了 ReAct 范式的优势:能够利用外部工具获取实时信息,而不完全依赖模型参数中的静态知识。
3.4 ReAct 的特点、局限性与调试技巧
通过本章的实现过程,我们已经了解了 ReAct 智能体的工作方式。下面对其特点、局限性以及常见调试方法进行简单总结。
(1)ReAct 的主要特点
高可解释性
ReAct 会显式输出 Thought 过程,使我们能够观察智能体的推理步骤,更容易理解和调试其行为。
动态决策能力
智能体会根据每一步获得的 Observation 调整后续行动,而不是在任务开始时一次性生成完整计划。
工具协同能力
ReAct 将 LLM 的推理能力与外部工具的执行能力结合起来,使模型能够获取实时信息、执行计算以及完成各种外部操作。
(2)ReAct 的局限性
依赖模型能力
如果模型的推理能力、指令遵循能力或格式输出能力较弱,整个 ReAct 流程的稳定性也会受到影响。
执行效率较低
一个任务通常需要多轮 LLM 调用和工具调用,因此相比直接生成答案会消耗更多时间和成本。
依赖提示词设计
提示词的设计会直接影响模型行为,不同模型对提示词的响应也可能存在较大差异。
缺乏全局规划能力
ReAct 更倾向于逐步决策,对于需要长期规划的复杂任务并不一定是最优选择。
(3)调试技巧
当 ReAct 智能体运行结果不符合预期时,可以从以下几个方面进行排查:
检查完整 Prompt
打印最终发送给模型的提示词,确认上下文和历史记录是否正确。
查看模型原始输出
当解析失败时,优先检查模型返回的原始文本,而不是直接修改解析逻辑。
验证工具调用
确认工具输入格式正确,并检查工具返回结果是否符合预期。
增加 Few-shot 示例
在提示词中加入正确示例,通常能够提升模型遵循格式的稳定性。
调整模型与参数
更换能力更强的模型,或降低 temperature 等参数,有时能够有效减少异常输出。
4. Plan-and-Execute(规划-执行)范式
在理解了 ReAct 这种“边思考边行动”的智能体范式之后,我们接下来介绍一种结构更加清晰的策略:Plan-and-Solve。
顾名思义,该方法将任务显式划分为两个阶段:先规划(Plan),后执行(Solve)。
如果说 ReAct 更像是一名侦探,在信息不断变化的过程中逐步推理并调整方向;那么 Plan-and-Solve 更像一名建筑师,在施工前完成完整设计图(Plan),再按图施工(Solve)。
这一范式的核心思想是:先形成全局规划,再进行局部执行。
4.1 Plan-and-Solve 的工作原理
Plan-and-Solve Prompting 由 Lei Wang 等人在 2023 年提出,其主要动机是缓解思维链在多步骤复杂任务中容易出现的“中途偏移”问题。
与 ReAct 将推理与行动交织进行不同,Plan-and-Solve 将整个过程拆分为两个相对独立的阶段:
(1)规划阶段(Planning Phase)
智能体首先接收完整问题,但不直接求解,而是生成一个分步骤的解决计划。该计划用于指导后续执行过程,本质上是一次对任务结构的显式建模。
形式化表示为: \[ P = \pi_{plan}(q) \] 其中:
- q:用户输入问题
- P:生成的执行计划(由多个步骤组成)
(2)执行阶段(Solving Phase)
在获得完整计划后,智能体进入执行阶段。此时模型会按照计划逐步完成每个子任务。
对于第 i 个步骤,其结果 \(s_i\) 的生成依赖于原始问题、完整计划以及之前的执行结果: \[ s_i = \pi_{solve}(q, P, (s_1, ..., s_{i-1})) \] 最终答案由最后一步结果 \(s_n\) 给出。
该流程可以概括为:
- 先生成整体计划
- 再按步骤逐步执行
- 最终汇总得到答案

Plan-and-Solve 特别适用于结构清晰、可分解性强的任务,例如:
多步数学问题
先列出解题步骤,再逐步计算。
结构化内容生成
如报告写作,需要先确定整体结构(引言、分析、结论),再逐段生成内容。
代码生成任务
先设计模块与函数结构,再逐步实现具体功能。
4.2 规划阶段
为了体现 Plan-and-Solve 在结构化推理任务中的优势,本节不依赖工具调用,而是通过提示词设计完成一个纯推理任务。
这类任务的特点是无法通过单步计算直接得到答案,必须先将问题拆解为多个逻辑子步骤,再逐步求解。这正是 Plan-and-Solve 中“先规划,后执行”策略最适合的场景。
我们以如下问题为例:
一个水果店周一卖出了 15 个苹果。周二卖出的数量是周一的两倍。周三比周二少卖 5 个苹果。请问三天总共卖出了多少个苹果?
该问题本身并不复杂,但包含清晰的多步依赖关系,适合作为规划式推理的示例任务。
(1)规划阶段
首先将原始问题拆解为一组有序的子任务,例如:
- 计算周二的销量
- 计算周三的销量
- 计算三天总销量
这些步骤构成后续执行的“计划”。
(2)执行阶段
智能体严格按照规划好的步骤逐步执行计算,每一步都以前一步的结果作为输入,持续推进直到所有步骤完成,最终得到总结果。
下面是规划阶段使用的提示词模板:
1 | PLANNER_PROMPT_TEMPLATE = """ |
该提示词通过以下方式保证输出稳定性:
角色设定
将模型定义为“专业的任务规划者”,引导其进行结构化拆解。
任务约束
明确要求模型只进行步骤分解,而不直接计算最终答案。
格式约束
强制输出为 Python list 结构,从而便于程序直接解析,无需复杂 NLP 处理。
接下来,我们将该提示词逻辑封装为一个 Planner
类,用于统一生成任务分解计划,这个类也构成了整个规划阶段的核心组件。
1 | import ast |
4.3 执行器与状态管理-
在规划器(Planner)生成完整的执行计划后,就需要执行器(Executor)按照计划逐步完成每一个子任务。
与规划器不同,执行器不再负责拆解问题,而是专注于执行当前步骤。同时,它还需要维护整个任务的执行状态,将前面步骤的结果保存下来,并作为后续步骤的输入,从而保证整个推理过程能够连续进行。
因此,执行器的提示词需要包含以下几部分信息:
- 原始问题:确保模型始终围绕最终目标进行推理。
- 完整计划:帮助模型了解当前步骤在整个计划中的位置。
- 历史执行结果:提供已经完成步骤的结果,作为当前步骤的输入。
- 当前步骤:明确本轮需要完成的具体任务。
下面定义执行器使用的提示词模板:
1 | EXECUTOR_PROMPT_TEMPLATE = """ |
可以看到,相较于 ReAct 的提示词,这里新增了 完整计划({plan})。这是规划阶段生成的结果,也是 Plan-and-Solve 与 ReAct 最主要的区别之一:模型在执行之前已经拥有完整的任务规划,而不是边推理边决定下一步行动。
接下来,我们将执行逻辑封装到 Executor
类中。该类负责遍历规划得到的步骤列表,依次调用大语言模型完成每一步任务,并维护整个执行过程中的状态信息。
1 |
|
由于本节示例仅涉及逻辑推理,不需要调用任何外部工具,因此执行器只负责调用 LLM 完成各个步骤的推理。
至此,我们已经分别实现了负责规划的 Planner 和负责执行的
Executor。
最后,我们将二者组合成一个统一的
PlanAndSolveAgent,用于完成整个 Plan-and-Solve
流程。该类负责接收 LLM 客户端,初始化规划器和执行器,并提供统一的
run 方法作为智能体的入口。
1 | class PlanAndSolveAgent: |
PlanAndSolveAgent 本身并不负责具体的规划或执行,而是协调
Planner 与 Executor
两个组件完成整个任务流程,使各模块职责更加清晰,也便于后续扩展和维护。
4.4 运行实例与分析
下面给出 main 函数部分,通过创建
PlanAndSolveAgent 实例并调用 run()
方法即可完成整个推理流程。
1 | # --- 5. 主函数入口 --- |

从运行结果可以看到,Plan-and-Solve 将整个任务划分为规划和执行两个独立阶段。
首先,Planner
根据原始问题生成了一份结构化的执行计划,将复杂问题拆解为多个有序的子任务。随后,Executor
严格按照计划依次执行每个步骤,并将前一步的执行结果作为后续步骤的输入,使整个推理过程能够连续进行。
最终,智能体顺利完成所有步骤,并得到正确答案 70。
相比于直接一步生成答案,Plan-and-Solve 将复杂推理拆分为多个简单步骤,使整个求解过程更加清晰,也降低了长链路推理过程中出现偏差的可能性。
5. Reflection(反思)范式
在前面介绍的 ReAct 和 Plan-and-Solve 范式中,智能体完成任务后便结束整个执行流程。然而,模型生成的结果并不总是正确,可能存在事实错误、逻辑漏洞或表达不够完善等问题。
Reflection 的核心思想,就是让智能体在完成任务后对自己的输出进行检查与修正,形成一个"执行—反思—优化"的闭环,不断提升最终结果的质量。
5.1 Reflection 机制的核心思想
Reflection 的思想来源于人类解决问题的过程:完成一份初稿后会进行校对,解出一道数学题后会进行验算,根据发现的问题不断修改,直到得到更满意的结果。
这一思想在多个研究中得到了体现,例如 Shinn 等人在 2023 年提出的 Reflexion 框架。其整体流程可以概括为三个阶段:
(1)执行
智能体首先完成一次任务,生成初始结果。这里的执行过程可以采用前面介绍的 ReAct、Plan-and-Solve,或其他 Agent 范式。
(2)反思
随后,智能体开始审查自己的输出,对执行结果进行分析,并生成改进建议。
反思通常会重点关注以下几个方面:
- 是否存在事实错误;
- 推理过程是否合理;
- 是否遗漏了关键条件;
- 是否存在更优的解决方案。
最终,反思阶段会输出一份反馈(Feedback),指出当前结果存在的问题以及改进方向。
其形式化表示为: \[ F_i=\pi_{reflect}(Task,O_i) \] 其中:
- Task:原始任务;
- \(O_i\):第 \(i\) 次迭代产生的结果;
- \(F_i\):针对当前结果生成的反馈。
(3)优化
获得反馈后,智能体会结合原始任务、当前结果以及反馈信息,对答案进行重新生成,得到新的输出。
形式化表示为: \[ O_{i+1}=\pi_{refine}(Task,O_i,F_i) \] 新的结果随后又可以进入下一轮反思,从而形成持续迭代的优化过程,直到达到预设的迭代次数,或模型认为结果已经足够完善。

相比于前面介绍的两种范式,Reflection 最大的特点在于为智能体增加了一条内部反馈回路,使其能够主动发现并修正自身的问题,而不是一次生成答案后立即结束任务。
对于复杂推理、代码生成、文档写作等任务,这种多轮自我修正机制通常能够获得比单次生成更高质量的结果。
5.2 案例设定与记忆模块设计
为了更直观地展示 Reflection 范式在实际任务中的工作流程,本节将结合一个代码生成案例,引入一个简单的短期记忆(Memory)模块。
Reflection 的核心思想并不是一次性生成最终答案,而是在完成一次初始执行后,不断经历反思(Reflection)→优化(Optimization)的迭代过程,使模型能够根据已有结果持续发现问题、提出改进,并逐步提升最终答案的质量。
如果每一轮都将全部历史上下文直接输入给负责反思的模型,不仅会引入大量冗余信息,还会增加 Token 消耗,并影响模型关注真正重要的信息。因此,我们需要一个记忆模块,对历史信息进行统一管理,并按需组织为后续推理所需的上下文。
本节将通过一个简单的代码生成任务来演示这一过程。
目标任务:编写一个 Python 函数,找出 1 到 n 之间所有的素数(Prime Numbers)。
之所以选择该任务,是因为它非常适合作为 Reflection 的演示案例,主要体现在以下几个方面:
- 存在清晰的优化空间。 大语言模型首次生成的代码通常能够正确完成任务,但往往采用较为朴素的实现方式,例如逐个判断每个数字是否为素数,整体效率较低。
- 反思点明确。 模型可以较容易发现当前实现存在的问题,例如时间复杂度较高、存在重复计算、缺少边界条件处理等。
- 优化方向清晰。 根据反思结果,可以进一步将算法优化为仅判断至平方根、跳过偶数、使用埃拉托斯特尼筛法(Sieve of Eratosthenes)等更高效的实现,从而形成一个完整的"生成—反思—优化"迭代过程。
由于 Reflection 需要不断参考历史执行结果,因此我们首先实现一个用于保存历史轨迹的短期记忆模块,其整体结构如下:
1 | from typing import List, Dict, Any, Optional |
这个 Memory 类的设计十分简单,主要承担以下几个职责:
records:使用列表按时间顺序保存每一轮迭代的信息,包括模型生成的结果、执行结果以及对应的反思内容。add_record():向记忆中新增一条记录,完成一次迭代轨迹的保存。get_trajectory():将历史记录序列化为文本,供后续提示词直接引用,使模型能够快速了解之前的尝试过程,而无需重新组织上下文。get_last_execution():获取最近一次执行产生的结果,作为下一轮 Reflection 的输入,便于模型针对最新方案进行分析与优化。
5.3 Reflection 智能体的编码实现
完成 Memory 模块后,我们便可以开始构建 ReflectionAgent 的核心逻辑。
与 ReAct 等范式不同,Reflection 更强调对已有结果进行持续改进。因此,整个智能体的工作流程可以概括为:
首先完成一次初始执行,随后围绕当前结果不断进行反思(Reflection)→优化(Optimization)迭代,直到达到预期效果。
在这一过程中,Memory 模块负责记录每一次生成结果和反思内容,为后续迭代提供历史上下文。
为了实现这一流程,我们需要分别设计不同阶段所使用的提示词,使模型在不同阶段承担不同的职责。
(1)提示词设计
Reflection 智能体并不会始终使用同一套提示词,而是根据当前所处阶段动态切换 Prompt,使模型分别完成代码生成、结果评审以及方案优化等不同任务。
① 初始执行提示词(Execution Prompt)
该提示词用于智能体的第一次生成,仅负责根据用户需求完成任务,不考虑历史反馈或优化建议,其目标是生成一个能够解决问题的初始方案。
1 | INITIAL_PROMPT_TEMPLATE = """ |
② 反思提示词(Reflection Prompt)
这是 Reflection 机制中最重要的一部分。该提示词引导模型扮演代码评审员(Reviewer)的角色,对上一轮生成的代码进行分析,指出存在的问题,并给出具体、可执行的改进建议,而不是直接修改代码。
1 | REFLECT_PROMPT_TEMPLATE = """ |
③ 优化提示词(Refinement Prompt)
在获得反思结果后,该提示词负责引导模型根据反馈重新生成代码。它会结合上一轮代码及对应的评审意见,对已有实现进行修正和优化,从而得到质量更高的新版本。
1 | REFINE_PROMPT_TEMPLATE = """ |
可以发现,Reflection 将代码生成与代码评审拆分为两个独立阶段,使模型能够分别专注于"解决问题"和"发现问题"。这种角色分离能够有效减少模型一次性完成所有工作的负担,从而提高迭代优化的效果。
(2)智能体封装与实现
完成提示词设计后,我们便可以将 Memory 模块与三类 Prompt
进行整合,实现完整的 ReflectionAgent。
整个 Agent 的执行流程如下:
- 使用 Execution Prompt 生成初始代码;将生成结果保存到 Memory;
- 使用 Reflection Prompt 对最新代码进行分析,并生成评审意见;将反思内容保存到 Memory;
- 使用 Refinement Prompt 结合代码与反馈重新生成优化后的代码;
- 重复执行第 2~5 步,直到达到设定的迭代次数或满足终止条件。
1 |
|
需要注意的是,当前实现中的 ReflectionAgent 并未显式利用完整的历史轨迹进行推理,而是采用了一种更为轻量的“单步状态驱动”策略。
在每一轮迭代中,反思(Reflection)与优化(Optimization)阶段均仅依赖于最近一次的代码输出,即通过
get_last_execution()
获取当前版本,而不会显式引入此前所有迭代的完整历史记录。因此,该实现本质上是一种基于“最新状态”的逐步改进过程,而非严格意义上基于全局轨迹的反思机制。
这种设计的优势在于实现简单、上下文长度固定、Token 开销较低,适合快速迭代与教学演示场景;但其局限性在于模型无法回顾早期决策与修改路径,可能导致重复修正相同问题,或在复杂任务中出现信息遗忘与优化震荡。
因此,该版本更准确地可以描述为一种轻量级迭代优化型 Reflection Agent,而非完全依赖历史轨迹的增强型 Reflection 系统。
5.4 运行实例与分析
为了验证 Reflection Agent 的实际效果,我们在本节给出一个完整的运行示例。读者可以直接复现实验结果。
1 | if __name__ == '__main__': |






这个运行实例展示了 Reflection 机制是如何驱动智能体进行深度优化的:
- 有效“批判”是优化的起点 在第一轮反思中,由于引入了“极其严格”且“以算法效率为核心”的提示,智能体没有停留在“功能正确”的初级解,而是识别出原始实现中 \(O(n \cdot \sqrt{n})\) 的时间复杂度瓶颈,并进一步提出算法级改进方向——埃拉托斯特尼筛法。
- 迭代式性能提升 在接收到明确反馈后,智能体进入优化阶段,并成功将算法重构为更高效的筛法实现,使时间复杂度降至 \(O(n \log n)\),完成了第一次具有实际意义的性能跃迁。
- 收敛判断与终止机制 在第二轮反思中,智能体对已有方案进行了更高层次的评估:既肯定了当前算法的高效性,也进一步讨论了分段筛法等更高级优化方向。但最终其判断为“在一般场景下已无进一步优化必要”,从而触发终止条件,使整个优化流程自然收敛。
这个案例充分证明,一个设计良好的 Reflection 机制,其价值不仅在于修复错误,更在于驱动解决方案在质量和效率上实现阶梯式的提升,这使其成为构建复杂、高质量智能体的关键技术之一。
5.5 Reflection 机制的成本收益分析
尽管 Reflection 机制在提升任务解决质量方面表现突出,但这种能力并非“免费午餐”。在实际应用中,需要在性能收益与系统成本之间进行权衡。
(1)主要成本
- 模型调用开销增加 这是最直接的成本来源。每增加一轮 Reflection 迭代,通常需要至少两次大模型调用(反思阶段 + 优化阶段)。随着迭代轮数上升,API 调用费用与算力消耗会线性甚至倍增增长。
- 任务延迟显著增加 Reflection 本质上是一个严格串行的优化流程,每一轮优化都必须等待上一轮反思完成后才能继续推进。因此整体执行链路被显著拉长,在多轮迭代情况下尤为明显,不适用于低延迟或实时性要求较高的任务。
- 提示工程复杂度上升 如前文案例所示,Reflection 的效果高度依赖阶段化提示词设计(执行 / 反思 / 优化)。如何为不同阶段构造稳定、可控且具有引导性的 prompt,本身就需要较高的工程调试成本与经验积累。
(2)核心收益
- 解决方案质量的阶梯式提升 Reflection 的核心价值在于“迭代优化能力”。它能够将初始的“可用解”逐步提升为“高质量解”,实现从功能正确到性能最优、从逻辑可用到结构严谨的跨越。这种质量跃迁在复杂任务中尤为关键。
- 鲁棒性与可靠性增强 通过“生成—审查—修正”的闭环机制,智能体能够主动识别初始解中的逻辑缺陷、边界问题或潜在错误,从而显著提升最终输出的稳定性与可靠性。
(3)小结与适用场景
总体而言,Reflection 机制是一种典型的“以计算与时间换取质量”的策略。其适用场景通常具备以下特征:
- 对输出质量、准确性与可靠性要求较高
- 对任务完成时间不敏感
例如:
- 关键业务代码生成与技术方案设计
- 科学研究中的复杂推导与分析任务
- 高价值决策支持与深度规划系统
相对而言,在以下场景中其性价比可能不足:
- 强实时性任务(如在线交互、低延迟问答)
- 容忍一定误差的轻量级生成任务
在这些情况下,采用更轻量的 ReAct 或 Plan-and-Solve 等范式,往往能够在成本与效果之间取得更优平衡。