Reflexion - Verbal Reinforcement Learning · essay

20. Reflexion:把失败后的反思写成语言记忆

论文:Reflexion: Language Agents with Verbal Reinforcement Learning
本地原文:

![[papers/20-Reflexion-2303.11366.pdf]]

论文定位与阅读路径

核心定位

Reflexion 的核心非常朴素:Agent 失败后,不马上训练模型,而是让它用自然语言总结失败原因,把这段反思放进记忆,下次尝试时读出来避免重复犯错。

概念解释:

不改模型参数,给 Agent 一本错题本。

原文结构导读

章节内容重点
Abstract用语言反思增强 Agentverbal reinforcement 是关键词
1 Introduction传统 RL 成本高,LLM Agent 需要快速试错为什么不用梯度训练
2 Related WorkRL、推理、编程相关工作可略读
3 Reflexion核心框架重点
4 Experiments决策、编程、推理任务看反思是否提升多轮表现
5 Limitations局限反思质量依赖模型
6-8影响、结论、复现快速读

证据链阅读

证据点读什么工程判断
多轮尝试曲线加入反思后是否随 attempt 变好证明反思记忆能把失败转成下一轮策略
任务类型差异决策、编程、推理任务效果是否一致判断 Reflexion 适合哪类 Agent
Evaluator 可靠性反馈信号是否客观、可检查没有可靠反馈,反思可能只是自我合理化
反思文本质量是否具体指出错误和下一步动作工程上要约束反思格式,不能只写“更仔细”

研究背景与问题定义

传统强化学习和 Reflexion 的区别

传统 RL 大致是:

代码块TEXT · 1 行收起展开
行动 -> 奖励 -> 更新参数/策略

Reflexion 是:

代码块TEXT · 1 行收起展开
行动 -> 失败/反馈 -> 生成文字反思 -> 存入记忆 -> 下次 prompt 使用

对比:

维度传统 RLReflexion
更新对象模型参数/策略语言记忆
成本
是否需要训练通常需要不需要微调
可解释性较弱强,反思是文本
稳定性取决于训练取决于反思质量

方法框架与核心机制

核心循环

Reflexion:失败轨迹生成语言记忆 任务输入 Actor 反馈/测试 成功? 结束 Evaluator Reflection 反思记忆

这套循环非常适合编程 Agent:

代码块TEXT · 1 行收起展开
写代码 -> 跑测试 -> 失败 -> 总结原因 -> 改代码 -> 再跑测试

Reflexion 里的三个角色

角色作用编程类比
Actor尝试完成任务写代码的人
Evaluator判断结果好坏单元测试/评测器
Self-Reflection总结经验教训写错题本/复盘

这就是为什么它适合 Agent:Agent 不只是生成答案,还能根据环境反馈迭代。

反思记忆是什么

反思记忆不是事实记忆,而是经验记忆。

例子:

代码块TEXT · 1 行收起展开
上次失败是因为只考虑了正数数组,没有处理全负数情况。下次先检查边界条件。

这种记忆不一定长期保存几个月,但在当前任务的多次尝试中很有用。

为什么它有效

LLM 很擅长读自然语言指令。如果你把失败原因写成清晰语言,它下一轮就可能避开错误。

它利用了 LLM 的强项:

  1. 总结错误。
  2. 从反馈中提取规则。
  3. 根据文字提示调整行为。

这比直接训练参数快得多。

实验论证与评价方式

实验阅读方法

论文测试了不同类型任务,包括决策、推理和编程。你读实验时看:

  1. 加反思后,多次尝试的成功率有没有提升。
  2. 反思记忆长度有限时是否还有效。
  3. 和普通 ReAct、Chain-of-Thought 等方法相比差在哪里。
  4. 失败案例中反思是不是具体,而不是空话。

重点不是某个 benchmark 数字,而是这个机制:

代码块TEXT · 1 行收起展开
自然语言反馈能否替代一部分参数更新?

概念校准

你刷算法题时,如果只是看答案然后下一题,很容易重复错。
如果你写一条错题反思:

代码块TEXT · 3 行收起展开
这题我漏了空数组。
双指针移动条件写反。
以后先列边界条件。

下一次遇到类似题就更稳。Reflexion 就是给 Agent 做这个。

相关工作与方法对比

和其他记忆论文的关系

论文记忆内容
MemoryBank用户对话和画像
Zep时序事实图谱
Voyager成功技能代码
Reflexion失败后的语言反思
CoALA把反思归到经验/工作记忆

Reflexion 的价值是提醒你:

记忆不只记录事实,也要记录“为什么失败”和“下次怎么改”。

工程映射与实践启发

工程落地方案

编程 Agent 的反思表:

代码块SQL · 9 行收起展开
agent_reflection(
  id,             -- 反思记录 ID。
  task_id,        -- 对应哪一个任务。
  attempt_no,     -- 第几次尝试后产生的反思。
  failure_signal, -- 失败信号,例如测试错误、环境反馈、评分失败。
  reflection,     -- 模型总结出的失败原因。
  next_strategy,  -- 下一次尝试应采用的策略。
  created_at      -- 反思生成时间。
)

一次循环:

flowchart TD
    A[生成代码] --> B[运行测试]
    B --> C{测试通过}
    C -->|是| D[保存成功经验]
    C -->|否| E[提取错误日志]
    E --> F[生成反思]
    F --> G[下一轮 prompt]
    G --> A

反思要写得具体

差反思:

代码块TEXT · 1 行收起展开
我应该更仔细。

好反思:

代码块TEXT · 1 行收起展开
失败原因是没有处理空输入,下一轮先添加空数组判断,再检查循环边界。

所以工程上要给反思生成器约束:

  1. 指出具体失败点。
  2. 指出证据。
  3. 给下一步动作。
  4. 不要写泛泛而谈。

局限、对比与阅读检查

局限与边界

  1. 反思可能是错的。
  2. 如果 evaluator 不可靠,反思也会偏。
  3. 反思太多会污染上下文。
  4. 它适合短期迭代,不等于长期知识库。
  5. 对需要真实环境探索的任务,仍可能尝试成本高。

阅读检查清单

  1. verbal reinforcement learning 是什么。
  2. Reflexion 为什么不需要更新模型参数。
  3. Actor/Evaluator/Self-Reflection 三角色。
  4. 反思记忆和事实记忆、技能记忆的区别。
  5. 如何把 Reflexion 用到编程 Agent 和学习 Agent。

深度精读:Reflexion 是最容易落地的“经验记忆”

1. 为什么它不需要训练

传统强化学习要更新策略参数。Reflexion 利用 LLM 的语言理解能力,把奖励/失败转换成自然语言提示:

代码块TEXT · 1 行收起展开
失败信号 -> 反思文本 -> 下一轮上下文

这意味着你用 API 模型也能做,不需要训练模型。

2. 反思必须来自反馈

没有反馈的反思容易变成自嗨。有效 Reflexion 需要:

任务反馈
编程测试失败、编译错误
网页操作页面状态变化
问答标准答案/用户纠正
学习用户说哪里没懂

反馈越具体,反思越有用。

3. 反思不是总结

总结:

代码块TEXT · 1 行收起展开
这次做了什么。

反思:

代码块TEXT · 1 行收起展开
为什么失败,下次要改变什么策略。

差反思:

代码块TEXT · 1 行收起展开
我应该更仔细。

好反思:

代码块TEXT · 1 行收起展开
这次讲解太短,因为只概括论文结论,没有拆 Method 和 Experiment;下一轮每篇必须增加机制流程、变量解释、工程伪代码和读实验问题。

4. Reflexion buffer 应该有限

如果把所有反思都塞进上下文,会越来越乱。应该只保留:

  1. 当前任务相关反思。
  2. 最近失败原因。
  3. 高价值稳定教训。

长期反思可以沉淀成 procedural memory,短期反思留在 working memory。

5. 编程 Agent 落地

flowchart TD
    A[生成修改] --> B[运行测试]
    B --> C{通过}
    C -->|是| D[保存成功技能]
    C -->|否| E[提取失败信号]
    E --> F[生成反思]
    F --> G[下一轮修改约束]
    G --> A

反思 prompt 要要求:

  1. 指出具体错误。
  2. 引用失败证据。
  3. 给下一步动作。
  4. 不要泛泛道歉。

6. 学习 Agent 落地

当你说“太浅”时,系统应该形成反思:

代码块TEXT · 2 行收起展开
用户不是要摘要,而是要论文级拆解。
之后每篇必须包括原文结构、方法细节、实验读法、工程迁移和易混点。

这条反思应该立刻影响后续输出。

7. Reflexion 的风险

  1. 反思可能错。
  2. 反馈可能不完整。
  3. 反思可能过拟合一次失败。
  4. 反思太多会干扰。

所以反思也要有置信度和适用范围。

8. 和 Voyager 组合

最强闭环是:

代码块TEXT · 2 行收起展开
失败 -> Reflexion 保存教训
成功 -> Voyager-style skill 保存做法

这就同时有“错题本”和“技能库”。

精读补强:Reflexion 的证据链与工程判断

Reflexion 最容易落地,但也最容易被滥用成“失败后写一句鸡汤”。读它时要看反思是否由可验证失败信号驱动。

判断点原文证据工程含义
失败信号环境反馈、测试结果、评分器输出反思必须绑定具体失败,不是泛泛总结
反思内容verbal reflection 写入长期记忆记录应包含原因、约束、下次策略
再尝试机制下一轮 prompt 读取反思反思必须进入后续决策链路才有价值
评价方式多轮尝试成功率提升要测“有反思 vs 无反思”的差异

工程落地时,agent_reflection 表至少要保存 task、attempt、failure_signal、reflection、next_strategy。没有 failure_signal,反思会变成无法审计的自然语言缓存。

工程落地的最小闭环

Reflexion 在代码 Agent 里最容易做成可验证闭环:

代码块TEXT · 1 行收起展开
生成方案 -> 执行/测试 -> 提取失败信号 -> 写反思 -> 下一轮读取反思

关键是反思不能脱离测试。比如一次 npm test 失败,系统应该保存:

字段示例作用
failure_signalExpected 200, received 500锚定真实失败
reflection接口没有处理空 userId总结可迁移原因
next_strategy先补参数校验,再跑 user API 测试约束下一轮行动
evidence_ref测试日志路径或 trace span方便复查反思是否可靠

如果下一轮没有读取 next_strategy,这条反思就只是日志,不是记忆。真正的 Reflexion 必须让失败经验改变下一次行动。

还有一个硬约束:反思只能总结已观察到的失败,不能编造原因。比如测试日志只说明断言失败,就不要直接写“数据库连接池有问题”;应先写“接口返回值与期望不一致”,下一轮再通过更小的检查定位根因。这样反思才不会把猜测固化成长期记忆。

这条约束比“多写反思”更重要。

论文精读主线:问题-方法-验证-局限-启发

1. 核心结论

Reflexion 把失败反馈转成自然语言反思记忆,让 Agent 不更新参数也能在下一次尝试中避免同类错误。

本篇的阅读重心是:把失败反馈写成自然语言反思,使下一次尝试少犯同类错误。读完后要能说清它改变的是 runtime、存储、检索、更新还是评测层;否则只是记住了论文名。

2. 问题背景

LLM Agent 在编程、推理和网页任务中常会重复犯错。传统强化学习要训练参数,成本高;普通 ReAct 失败后未必吸取教训。问题是如何用低成本方式把失败经验转成可复用策略。

把问题具体化为失败样例:Agent 测试失败后只重试 prompt,不记录失败原因;下一轮又犯同一类 API、路径或逻辑错误。用这个样例反推论文动机,比泛泛说“上下文不够”或“记忆不准”更有判断力。

3. 核心方法

循环由 Actor、Evaluator、Self-Reflection 组成。Actor 执行任务,Evaluator 给成功/失败和反馈,Self-Reflection 把失败原因和下次策略写成反思,下一轮 Actor 把反思放入上下文。

flowchart TD
    T[任务] --> A[Actor 尝试]
    A --> E[Evaluator 反馈]
    E --> D{成功?}
    D -->|是| S[结束]
    D -->|否| R[Self-Reflection]
    R --> M[反思记忆]
    M --> A

方法部分按数据流读:Actor 执行任务,Evaluator 判断成败并给证据,Self-Reflection 生成 lesson,下一轮把 lesson 注入上下文。每一步都要能标出输入、输出、控制点和失败后该记录的日志。

4. 技术细节

反思不是总结,而是可执行改进策略。好的反思包含失败原因、证据、下次动作、适用边界。Evaluator 的可靠性决定反思质量;反馈错了,Agent 会学错。

代码块JAVA · 15 行收起展开
final class ReflexionLoop {
    private final TaskActor actor; // 根据任务和反思记忆执行下一次尝试
    private final FeedbackEvaluator evaluator; // 用测试、规则或人工反馈判断成功失败
    private final ReflectionGenerator reflector; // 把失败转成具体、可执行、有限长度的反思
    private final ReflectionBuffer buffer; // 保存最近有效反思,过期或无效反思要清理

    MemoryResult handle(MemoryInput input) {
        // 1. 根据任务和反思记忆执行下一次尝试
        // 2. 用测试、规则或人工反馈判断成功失败
        // 3. 把失败转成具体、可执行、有限长度的反思
        // 4. 保存最近有效反思,过期或无效反思要清理
        // 输出中保留 traceId、sourceIds、decisionReason,方便复盘和回滚。
        return MemoryResult.withTrace(input.traceId());
    }
}

字段检查重点是 failureEvidencelessonnextActionscopettl 决定反思是否可执行。这些字段不是装饰,它们决定后续能否检索、审计、回滚、限权和做离线评测。

5. 实验验证

实验看多次尝试成功率是否提升,特别是失败后是否减少同类错误。要和 ReAct、CoT、无反思记忆对比,并分析反思文本是否具体有效。

实验阅读重点:看多轮成功率、同类错误复发率、反思文本质量;没有可靠 evaluator 时不应写反思。如果论文没有直接给出这层证据,复现时就要自己补机制级指标。

6. 局限与启发

没有可靠反馈就不适合 Reflexion。启发是编程 Agent 可以把测试失败、lint 错误、用户批评写成短期反思;学习笔记任务可以把“太浅、标题不专业、代码没注释”转成写作约束。

迁移到你的项目时,结论是:你批评笔记“浅、废话、标题不专业、代码没注释”本身就可以转成写作反思约束。先把边界做对,再追求更复杂的模型或更大的记忆规模。

7. 关键术语表

术语在论文里的意思工程落地时要看什么
Verbal reinforcement自然语言强化反馈把失败经验写成文本策略
Actor执行任务的 Agent读取反思并尝试解决
Evaluator评估器测试、规则、用户反馈
Reflection buffer反思缓存有限条数、可过期的经验记忆

8. 复现难点

反思最容易变空话,例如“下次更仔细”。必须要求具体到错误原因和下一步动作。反思过多会污染上下文,所以 buffer 要有限,且成功后要清理无效反思。

复现入口应从失败集开始:构造会失败的代码/写作任务,让系统读取上一轮反思后重做,检查是否避免同一错误。只有先证明旧方案会坏,才知道新机制是否真的解决了问题。

9. 代码框架建议

实现 Reflection(id,taskType,failureEvidence,lesson,nextAction,scope,createdAt,ttl)。生成反思前必须有 evaluator 输出;没有反馈不允许自我脑补。

代码验收门槛:反思必须绑定具体失败证据;没有证据的“下次更仔细”直接丢弃。这条门槛应写进测试或 trace 字段里,避免实现只停留在 demo。

10. 相关论文对比

Voyager 保存成功技能,Reflexion 保存失败教训。Generative Agents 的 reflection 是高层社会理解,Reflexion 的 reflection 是任务改进策略。CoALA 可把它放在 episodic/reflective 机制里。

横向比较时抓这个角度:Reflexion 存失败教训,Voyager 存成功技能,Generative Agents 存行为反思。比较对象不是谁“更先进”,而是谁负责哪一层失败。

11. 批判性思考

Reflexion 便宜好用,但不是万能 RL。它依赖反馈覆盖真实目标,也依赖模型正确解释失败。长期反思库如果不清理,会积累错误经验。

批判边界:错误反馈会产生错误反思;反思库必须有过期、覆盖和成功后清理机制。这不是否定论文,而是把论文结论放回真实系统的成本、权限和恢复约束里。