Reflection

Agent 如何通过自我评估与修正提升输出、Reflexion 模式、实现方式与适用场景

16 min read Part of Agent · Ch. 5
← 上一层级:学习路径 · Part 03 · Agent 设计与工程

延伸阅读

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 的必要层

大模型的第一轮输出,经常有三个特点:

  1. 看起来像对的
  2. 局部有道理
  3. 但并不总能经得起验证

这也是为什么在 Agent 场景中,“一次生成即交付”往往不够稳。

它能缓解哪些问题

问题常见表现Reflection 的作用
幻觉编造事实、无依据补全逼系统检查“依据是否存在”
逻辑错误中间推理跳步、结论不成立要求逐项核查或回放关键推理链
遗漏漏掉需求、边界条件、约束按检查清单逐项对照
格式问题输出格式不符合要求先校验结构,再修正
执行失败代码报错、测试不通过、工具结果异常把失败结果转化为下一轮修复信号

先看定义:Reflection 不是为了让输出更“漂亮”,而是为了让交付前多一道质量关。

为什么 Agent 比普通问答更需要 Reflection

因为 Agent 做的很多任务,本来就天然带“可验证性”:

  • 代码能不能通过测试;
  • SQL 能不能执行;
  • 摘要有没有覆盖关键点;
  • 报告有没有回答任务要求;
  • 检索结论是否真能被引用支持;
  • 某一步执行是不是把状态改错了。

这意味着,Agent 很多时候并不缺“再想一次”的能力,而是缺“基于反馈有方向地再想一次”。

Reflexion:Reflection 的代表性模式

先看定义:Reflexion 是一种“行动 → 评估 → 反思 → 重试”的闭环模式,它强调把反思写成自然语言经验,并带入下一轮尝试。

Reflexion 论文提出的核心思想很值得注意,因为它不是简单说“失败了就再试一次”,而是强调中间要有一层语言化的经验总结

一个典型的 Reflexion 流程可以写成:

  1. Act:先完成一次任务尝试
  2. Evaluate:对这次结果做评估
  3. Reflect:生成反思,说明哪里有问题、为什么有问题、下次应注意什么
  4. 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 最经典的应用场景,因为它天然符合“做 → 评 → 改”的结构。

一个最常见的工程循环是:

  1. 根据需求生成代码
  2. 运行测试 / lint / 编译
  3. 如果失败,把失败信息反馈给模型
  4. 模型分析失败原因
  5. 生成修复版本
  6. 再次验证

如果写成简化版:

生成代码 -> 跑测试 -> 看报错 -> 修代码 -> 再跑测试

这和纯聊天式“写一段代码给我”完全不是一个系统难度层级。 因为真正决定效果的,不是第一次代码写得多漂亮,而是系统能否利用测试反馈持续收敛。

这里要注意一个细节:

测试输出本身不是 Reflection,测试输出只是 Reflection 的输入。

真正的 Reflection,发生在模型把这些报错转化成“问题在哪、该怎么修”的时候。

例如:

  • “测试失败”只是信号;
  • “函数在空输入下未处理边界条件,应先检查空列表”才是反思。

这也是为什么 Reflexion 模式强调 verbal reflection,而不是单纯重试。

Reflection 不只用于“这一轮修正”,还可以沉淀为经验

这是 Reflexion 和普通 retry 最大的差异之一。

很多系统会在失败后重试,但失败信息只在当前轮有效。 任务结束后,这些经验就丢了。

Reflexion 的一个重要想法是: 把反思作为一种可持久化的语言经验存起来。

这意味着,如果系统今天在某类任务上踩过坑,明天再遇到相似任务时,它可以优先检索这些经验。

例如:

  • “生成 SQL 时先确认是否有限制条件,避免全表更新”
  • “比较产品方案时,不要只列优点,必须补适用边界”
  • “写总结时先核对是否覆盖了用户明确列出的三点要求”
  • “修复测试失败时,先读报错栈,不要直接重写整段逻辑”

这些经验未必属于“长期知识”,但它们非常适合作为任务型经验记忆

这也是为什么 Reflection 往往和 Memory 结合得很好: 它不仅提高这一轮的结果质量,还能逐步改善未来类似任务的行为。

Reflection 的实现模式

最简单的模式:单次输出后加一次 Critic

这是最轻量的做法:

  1. 先让模型生成结果;
  2. 再让模型或另一个模型审查这份结果;
  3. 如果审查通过,直接交付;
  4. 如果不通过,再做一次修订。

这个模式简单、便宜,适合:

  • 输出本身不算太长;
  • 只需要轻量质检;
  • 任务风险中等;
  • 你不想引入太多控制流复杂度。

更完整的模式:生成—评估—反思—重试循环

这就是更接近 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. 你输出什么形式的反馈

例如,不要只写:

“请帮我检查这段回答是否有问题。”

这太空泛。

更好的写法是:

你是一个严格的评审员,请根据以下标准审查这份输出:
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 的价值,不在于它让系统拥有某种神秘的“自省意识”,而在于它从工程上做了三件非常实际的事:

  1. 打断第一次输出即终局的默认路径
  2. 把外部反馈转化为后续修正信号
  3. 让重试变得有方向,而不是盲目重复

所以,Reflection 更像一种质量控制机制,而不是一种人格特征。

核心概念速查

概念一句话
Reflection对输出进行评估并基于反馈修正的机制
Reflexion把行动、评估、反思、重试串成闭环,并把反思存为经验
Self-Critique用模型自身或另一模型对结果做审查
Critic负责判断输出是否达标的评估角色
Retry基于反馈重新生成,而不是盲重试
验证信号测试、规则、引用、人工审核等外部反馈来源
适用场景代码生成、高精度任务、可验证交付物

小结

Reflection 要解决的,不是“模型会不会生成”,而是“第一次生成之后,系统能不能识别明显问题并修回来”。 它通过在输出和交付之间插入评估环节,让 Agent 从“一次性生成器”变成“带质检和修订能力的系统”。

Reflexion 把这个思路进一步推进:不只是失败后重试,而是把失败经验语言化、记忆化,让下一轮尝试真正带着经验前进。这让 Reflection 尤其适合那些有明确反馈信号的任务,比如代码生成、测试修复、高精度分析和阶段性交付。

但它也不是默认该加的万金油。没有明确评估标准、输出高度主观、延迟预算严格时,Reflection 很容易变成昂贵但收效有限的额外环节。真正好的设计,不是“处处加反思”,而是在真正值得检查的节点上,把它变成一层有效的质量控制。

下一篇会进入另一个常被讨论、也常被过度设计的话题: 当一个 Agent 不够时,多个 Agent 协作到底什么时候有意义?