延伸阅读:
- Reflexion 论文 —— Shinn et al., 2023。(arxiv.org)
- LangGraph Reflection 相关实现 —— 一个更接近工程实践的 Reflection 架构参考。(github.com)
- Anthropic:Building Effective AI Agents —— 对“什么时候该加反思、什么时候不该加”很有启发。(anthropic.com)
Reflection
flowchart LR
A["Reflection"]
A --> B["分类:智能体 (Agents)"]
A --> C["关键词:Agent"]
A --> D["关键词:Reflection"]
A --> E["关键词:Reflexion"]
A --> F["关键词:Self-Critique"]
前面几篇文章已经逐步把 Agent 的骨架搭出来了:
- ReAct 解决“边做边想”的问题;
- Plan & Execute 解决“先有全局视野再执行”的问题。
但无论是边走边看,还是先规划再执行,都还缺一个现实世界里非常重要的能力:做完之后,知道自己做得好不好。
这件事对普通聊天机器人当然也重要,但对 Agent 来说更关键。因为 Agent 的输出不再只是“一段话”,它可能是:
- 一段代码;
- 一份报告;
- 一个查询结果;
- 一次多步推理;
- 一次业务操作;
- 一串工具调用后的综合结论。
一旦第一次输出有问题,错误往往不会停留在文本层面,而会继续扩散:代码测试失败、摘要遗漏关键信息、推理结论站不住脚、后续步骤建立在错误前提上。 所以,很多 Agent 系统真正需要的,不只是“能生成”,而是“生成后还能检查、发现问题、再修一次”。
这就是 Reflection 要解决的问题。
Reflection 是什么
先看定义:Reflection 是让 Agent 对自己的输出进行评估,并在必要时基于评估结果进行修正的机制。
如果把 ReAct 概括为“想 → 做 → 看”,那 Reflection 可以理解成在结果产出后,再插入一个额外问题:
“这次做得对吗?如果不对,错在哪?下一轮应该怎么改?”
所以,Reflection 不是简单的“再生成一次”,而是更接近这样一个闭环:
生成 -> 评估 -> 发现问题 -> 修正 -> 再评估
从系统设计角度看,它的本质不是“让模型更会反省”,而是:
- 不把第一次输出当作最终结果;
- 给系统一个显式的质量检查环节;
- 让后续重试不再盲目,而是基于反馈调整。
Reflexion 论文把这一点表达得很明确:它不是通过更新模型权重来学习,而是通过自然语言形式的反馈和反思,让 Agent 在后续尝试中做出更好的决策。论文摘要明确提到,Reflexion agent 会根据任务反馈进行 verbal reflection,并把这些反思存入 episodic memory,以指导后续试验。(arxiv.org)
为什么 Reflection 不是“锦上添花”,而是很多 Agent 的必要层
大模型的第一轮输出,经常有三个特点:
- 看起来像对的
- 局部有道理
- 但并不总能经得起验证
这也是为什么在 Agent 场景中,“一次生成即交付”往往不够稳。
它能缓解哪些问题
| 问题 | 常见表现 | Reflection 的作用 |
|---|---|---|
| 幻觉 | 编造事实、无依据补全 | 逼系统检查“依据是否存在” |
| 逻辑错误 | 中间推理跳步、结论不成立 | 要求逐项核查或回放关键推理链 |
| 遗漏 | 漏掉需求、边界条件、约束 | 按检查清单逐项对照 |
| 格式问题 | 输出格式不符合要求 | 先校验结构,再修正 |
| 执行失败 | 代码报错、测试不通过、工具结果异常 | 把失败结果转化为下一轮修复信号 |
先看定义:Reflection 不是为了让输出更“漂亮”,而是为了让交付前多一道质量关。
为什么 Agent 比普通问答更需要 Reflection
因为 Agent 做的很多任务,本来就天然带“可验证性”:
- 代码能不能通过测试;
- SQL 能不能执行;
- 摘要有没有覆盖关键点;
- 报告有没有回答任务要求;
- 检索结论是否真能被引用支持;
- 某一步执行是不是把状态改错了。
这意味着,Agent 很多时候并不缺“再想一次”的能力,而是缺“基于反馈有方向地再想一次”。
Reflexion:Reflection 的代表性模式
先看定义:Reflexion 是一种“行动 → 评估 → 反思 → 重试”的闭环模式,它强调把反思写成自然语言经验,并带入下一轮尝试。
Reflexion 论文提出的核心思想很值得注意,因为它不是简单说“失败了就再试一次”,而是强调中间要有一层语言化的经验总结。
一个典型的 Reflexion 流程可以写成:
- Act:先完成一次任务尝试
- Evaluate:对这次结果做评估
- Reflect:生成反思,说明哪里有问题、为什么有问题、下次应注意什么
- Retry:把反思加入上下文,再重新尝试
如果写成图示,大致是:
Task
-> Act
-> Evaluate
-> Reflect
-> Retry
-> ...
-> Finish
Reflexion 论文摘要中强调,这种方法可以结合不同来源和形式的反馈信号:既可以是标量反馈,也可以是自然语言反馈;既可以来自外部环境,也可以来自模型内部模拟。(arxiv.org)
这里真正重要的,不是“反思”这个词本身,而是两个工程含义:
1. 失败信息要转化成可复用经验
不是简单把“测试失败”四个字塞回模型,而是把它转化成:
- 是哪类错误;
- 为什么发生;
- 下一次应该避免什么。
2. 下一轮重试不该是盲重试
如果没有 reflection,系统的重试很容易变成:
- 再生成一次;
- 再改一版;
- 再试一个相近答案;
- 但本质上还是在同一个错误空间里打转。
有了 reflection,重试才更像“带着经验修正”。
Reflection 的本质:不是“再想一遍”,而是“引入一个评估者”
要真正理解 Reflection,关键不是盯着“反思”两个字,而是看清中间的那个评估环节。
因为系统之所以能改,是因为先知道“哪里不对”。 而“哪里不对”来自评估。
所以更准确的结构应该写成:
生成 -> 评估 -> 生成反馈 -> 修正
这意味着 Reflection 系统里通常至少有两个角色:
- Producer / Actor:负责生成结果
- Evaluator / Critic:负责检查结果
这两个角色未必是不同模型,但逻辑上最好区分开。 否则系统很容易退化成“自己随口说自己不错”。
谁来评估:Self-Critique 的几种来源
Reflection 里最核心的问题之一是:到底谁来做 Critic?
常见方式有四类:
| 方式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 同一 LLM 自评 | 生成后再让同一个模型评估 | 简单、便宜、实现快 | 容易“自我感觉良好” |
| 不同 LLM 评估 | 用另一个模型当 critic | 视角分离、常更严格 | 成本更高,调度更复杂 |
| 规则 / 测试评估 | 用测试、规则、validator 判断 | 客观、稳定、可自动化 | 只适用于有明确验证标准的任务 |
| 人工评估 | 人类审核结果 | 最可靠 | 不可扩展,成本高 |
有明确对错标准的任务,优先用外部验证
这是一个非常重要的工程原则。
如果任务本来就有客观验证方式,最好不要只依赖 LLM 自评。 例如:
- 代码生成:跑单元测试
- SQL:实际执行或 dry-run
- JSON 输出:schema 校验
- 检索回答:看引用是否存在
- 表单生成:字段完整性检查
因为在这些场景里,外部反馈通常比模型自评更可信。
先看定义:能用测试验证,就别只靠模型感觉。
这也是为什么代码生成会成为 Reflection 最典型、也最容易成功的落地场景——因为它天然有编译器、测试、lint、报错信息这些强反馈信号。
没有客观验证时,Critic prompt 就变得关键
如果任务是总结、写作、分析、问答等没有硬性测试标准的场景,那就只能借助:
- 更清晰的评审 prompt
- 更明确的评分维度
- 更具体的检查清单
- 必要时多轮评估或多评审者交叉检查
此时 Reflection 的难点不在“怎么重试”,而在“怎么避免评估本身变得空泛”。
最典型的 Reflection 场景:代码生成
代码生成几乎是 Reflection 最经典的应用场景,因为它天然符合“做 → 评 → 改”的结构。
一个最常见的工程循环是:
- 根据需求生成代码
- 运行测试 / lint / 编译
- 如果失败,把失败信息反馈给模型
- 模型分析失败原因
- 生成修复版本
- 再次验证
如果写成简化版:
生成代码 -> 跑测试 -> 看报错 -> 修代码 -> 再跑测试
这和纯聊天式“写一段代码给我”完全不是一个系统难度层级。 因为真正决定效果的,不是第一次代码写得多漂亮,而是系统能否利用测试反馈持续收敛。
这里要注意一个细节:
测试输出本身不是 Reflection,测试输出只是 Reflection 的输入。
真正的 Reflection,发生在模型把这些报错转化成“问题在哪、该怎么修”的时候。
例如:
- “测试失败”只是信号;
- “函数在空输入下未处理边界条件,应先检查空列表”才是反思。
这也是为什么 Reflexion 模式强调 verbal reflection,而不是单纯重试。
Reflection 不只用于“这一轮修正”,还可以沉淀为经验
这是 Reflexion 和普通 retry 最大的差异之一。
很多系统会在失败后重试,但失败信息只在当前轮有效。 任务结束后,这些经验就丢了。
Reflexion 的一个重要想法是: 把反思作为一种可持久化的语言经验存起来。
这意味着,如果系统今天在某类任务上踩过坑,明天再遇到相似任务时,它可以优先检索这些经验。
例如:
- “生成 SQL 时先确认是否有限制条件,避免全表更新”
- “比较产品方案时,不要只列优点,必须补适用边界”
- “写总结时先核对是否覆盖了用户明确列出的三点要求”
- “修复测试失败时,先读报错栈,不要直接重写整段逻辑”
这些经验未必属于“长期知识”,但它们非常适合作为任务型经验记忆。
这也是为什么 Reflection 往往和 Memory 结合得很好: 它不仅提高这一轮的结果质量,还能逐步改善未来类似任务的行为。
Reflection 的实现模式
最简单的模式:单次输出后加一次 Critic
这是最轻量的做法:
- 先让模型生成结果;
- 再让模型或另一个模型审查这份结果;
- 如果审查通过,直接交付;
- 如果不通过,再做一次修订。
这个模式简单、便宜,适合:
- 输出本身不算太长;
- 只需要轻量质检;
- 任务风险中等;
- 你不想引入太多控制流复杂度。
更完整的模式:生成—评估—反思—重试循环
这就是更接近 Reflexion 的方式:
Attempt 1
-> Evaluate
-> Reflection
-> Attempt 2
-> Evaluate
-> Reflection
-> Attempt 3
-> ...
适合:
- 任务可验证;
- 单次输出失败代价较高;
- 允许有限次迭代;
- 需要显式利用失败经验。
分角色模式:Actor + Critic
这种模式里,生成者和评审者逻辑分离:
- Actor 负责完成任务;
- Critic 负责找问题;
- 有时还会再加一个 Revision 节点负责改稿。
这比“同一模型自评自改”更稳定一些,但成本也更高。
与工作流框架结合
LangGraph 社区和官方周边示例里,Reflection 往往被实现为一种图式流程:生成节点先产出结果,评审节点检查是否通过,不通过则回到修订节点或再次生成。LangGraph 相关 Reflection 预构建图也明确说明,这是一种用 reflection-style architecture 来检查并改进初始输出的方式。(github.com)
这类实现的优势在于:
- 节点职责清楚;
- 容易插入规则校验;
- 容易设置最大重试次数;
- 容易记录每轮输出与反馈。
Critic Prompt:Reflection 的好坏,很大程度上取决于“评得准不准”
在没有外部测试的场景里,Critic prompt 非常关键。 因为如果评估维度模糊,反思也会变得模糊。
一个好的 Critic prompt 通常要回答三件事:
- 你评什么
- 你按什么标准评
- 你输出什么形式的反馈
例如,不要只写:
“请帮我检查这段回答是否有问题。”
这太空泛。
更好的写法是:
你是一个严格的评审员,请根据以下标准审查这份输出:
1. 是否完整回答了用户问题
2. 是否遗漏用户明确要求的约束
3. 是否存在未经支持的事实性断言
4. 逻辑是否连贯
5. 格式是否符合要求
输出:
- 是否通过
- 问题列表
- 每个问题的修改建议
这里的关键不是措辞多“严厉”,而是维度足够具体。 没有具体维度,Reflection 很容易退化成“请再改得更好一点”的空洞循环。
什么时候 Reflection 真的有用,什么时候只是浪费 token
这是实践中最重要的问题之一。
Reflection 当然听起来总是有益,但它并不是“默认该加的一层”。 因为它天然会增加:
- 模型调用次数;
- 延迟;
- token 消耗;
- 控制流复杂度;
- 调试负担。
Anthropic 在 Agent 实践文章里反复强调,成功系统的关键常常不是“模式越多越好”,而是只在真正需要的地方引入额外复杂度。(anthropic.com)
更适合用 Reflection 的场景
| 场景 | 原因 |
|---|---|
| 代码生成 | 有编译、测试、lint 等明确反馈 |
| 高精度任务 | 错误代价高,值得多一道检查 |
| 长答案 / 复杂交付物 | 一次输出更容易遗漏或跑偏 |
| 有清晰验收标准的任务 | 便于构造 Critic 和 validator |
| 多步 Agent 的阶段性交付 | 可在关键节点插质检层 |
不一定值得用 Reflection 的场景
| 场景 | 原因 |
|---|---|
| 简单事实问答 | 一次检索+回答往往已足够 |
| 极短输出 | 再加一轮评估收益太小 |
| 创意写作 | “对错”标准模糊,critic 容易变成主观口味 |
| 强实时场景 | 延迟预算不足 |
| 已有强外部验证且修正空间有限 | Reflection 可能变成重复检查 |
先看定义:任务越可验证,Reflection 的收益越高;任务越主观,Reflection 越容易流于形式。
Reflection 可以嵌在哪里
Reflection 并不一定总发生在最终输出之后。 在多步 Agent 里,它可以插在不同层级。
1. 最终输出前
最常见,也最容易理解。 先生成结果,再做最后一轮审查。
适合:
- 单次交付型任务;
- 文案、总结、报告;
- 最终答案质检。
2. 每个关键步骤后
在 Plan & Execute 里尤其有用。 每完成一个子目标,就检查这一步是否达标,再决定继续还是返工。
适合:
- 长任务;
- 子任务依赖强;
- 一步错会影响后面所有步骤的场景。
3. 每 N 步插一次
在 ReAct 系统里,有时不必每一步都评估,而是每几步做一次“阶段反思”:
- 有没有偏离目标;
- 是否陷入重复;
- 还缺什么关键信息;
- 下一步是否该换策略。
这种做法比“每一步都反思”更节省,也更接近真实工程需求。
4. 执行失败时才触发
这是很经济的一种方式:
- 正常情况直接往前走;
- 只有当测试失败、工具报错、验证器不通过时,才进入 Reflection 模式。
在有强反馈信号的系统里,这通常非常实用。
Reflection 的常见失败模式
Reflection 并不是天然可靠。它也会出错,而且有自己独特的失败方式。
1. 自评偏宽松
同一个模型既当作者又当评审时,很容易出现:
- 对自己生成的内容过于宽容;
- 关键问题没看出来;
- 给出很表面的修改建议;
- 最后说“整体不错,只需小修”。
这不是模型“偷懒”,而是自评天然存在盲区。
2. 过度批评,反而越改越差
另一种极端是 critic 太苛刻:
- 对本来已经够用的输出不断挑刺;
- 把风格问题当作正确性问题;
- 逼系统持续重写,反而丢掉原本正确部分。
这会导致典型问题:不是修正错误,而是引入新错误。
3. 反思太抽象,无法指导修正
例如:
- “逻辑可以更清晰”
- “建议更完整一些”
- “回答还不够深入”
这种反馈几乎没有执行价值。 它听起来像意见,但不能变成下一步动作。
4. 无限反思
如果系统缺少终止条件,就会出现:
- 一直认为还能再改一点;
- 每轮都发现一个小问题;
- 迟迟不愿交付;
- 成本不断上升。
所以 Reflection 系统一定要有上限。
最大重试限制:Reflection 不是无限打磨
原文已经提到这点,但它值得强调得更明确一些。
一个成熟的 Reflection 机制,通常都需要明确这些边界:
- 最多允许几轮反思;
- 失败几次后停止;
- 什么时候返回“当前最佳版本”;
- 什么时候交给用户或人工;
- 什么问题值得修,什么问题不值得继续修。
如果没有这些边界,Reflection 很容易从“质量增强机制”变成“延迟和成本放大器”。
先看定义:Reflection 的目标不是无限接近完美,而是在可接受成本下显著降低明显错误。
Reflection 与 Guardrails、Evals 的关系
这是工程上很容易混淆的三个概念。
Reflection
强调的是: 系统基于当前输出做修正。
Guardrails
强调的是: 在输入、工具调用或输出阶段做约束和阻断。
OpenAI Agents SDK 的 guardrails 文档就把这一层定义得很明确:可以在工具调用前后、以及 agent 输入输出周围做检查,而不只是等到最终结果出来再说。(openai.github.io)
Evals
强调的是: 对系统整体质量做离线或在线评估,用于判断系统是不是在变好。
三者关系可以这么理解:
- Reflection 解决“这一条输出怎么修”
- Guardrails 解决“哪些行为根本不该发生”
- Evals 解决“整个系统长期到底好不好”
它们互补,但不等价。
和 ReAct / Plan & Execute 怎么结合
Reflection 很少独立存在,它更常见的角色是:插在已有 Agent 流程中的质量关卡。
与 ReAct 结合
在 ReAct 里,Reflection 常见的插法有两种:
- 每几步插一次阶段反思;
- 在最终答案前做一次输出审查。
它主要解决 ReAct 容易局部合理但整体偏航的问题。
与 Plan & Execute 结合
在 Plan & Execute 里,Reflection 更自然地出现在:
- 每个关键子任务结束后;
- 执行失败时;
- 阶段性检查点;
- 最终交付前。
它和 Replanning 也容易配合: 如果 Reflection 发现某一步产物根本不达标,系统可以不是“就地小修”,而是触发重新规划剩余路径。
与代码 Agent 结合
这几乎是当前最成熟的组合:
生成
-> 测试
-> 失败
-> Reflection
-> 修复
-> 再测试
这种结构之所以有效,不是因为“模型更会反省”,而是因为它接上了明确、强约束的外部反馈。
一个更克制的结论:Reflection 不是让 Agent 更聪明,而是让它更不容易把明显错误带到交付端
这是本文最想强调的判断。
Reflection 的价值,不在于它让系统拥有某种神秘的“自省意识”,而在于它从工程上做了三件非常实际的事:
- 打断第一次输出即终局的默认路径
- 把外部反馈转化为后续修正信号
- 让重试变得有方向,而不是盲目重复
所以,Reflection 更像一种质量控制机制,而不是一种人格特征。
核心概念速查
| 概念 | 一句话 |
|---|---|
| Reflection | 对输出进行评估并基于反馈修正的机制 |
| Reflexion | 把行动、评估、反思、重试串成闭环,并把反思存为经验 |
| Self-Critique | 用模型自身或另一模型对结果做审查 |
| Critic | 负责判断输出是否达标的评估角色 |
| Retry | 基于反馈重新生成,而不是盲重试 |
| 验证信号 | 测试、规则、引用、人工审核等外部反馈来源 |
| 适用场景 | 代码生成、高精度任务、可验证交付物 |
小结
Reflection 要解决的,不是“模型会不会生成”,而是“第一次生成之后,系统能不能识别明显问题并修回来”。 它通过在输出和交付之间插入评估环节,让 Agent 从“一次性生成器”变成“带质检和修订能力的系统”。
Reflexion 把这个思路进一步推进:不只是失败后重试,而是把失败经验语言化、记忆化,让下一轮尝试真正带着经验前进。这让 Reflection 尤其适合那些有明确反馈信号的任务,比如代码生成、测试修复、高精度分析和阶段性交付。
但它也不是默认该加的万金油。没有明确评估标准、输出高度主观、延迟预算严格时,Reflection 很容易变成昂贵但收效有限的额外环节。真正好的设计,不是“处处加反思”,而是在真正值得检查的节点上,把它变成一层有效的质量控制。
下一篇会进入另一个常被讨论、也常被过度设计的话题: 当一个 Agent 不够时,多个 Agent 协作到底什么时候有意义?