Reflexion: Language Agents with Verbal Reinforcement Learning
Paper: arXiv:2303.11366 Code: noahshinn/reflexion Code reference:
main@218cf0ef(2025-01-13)
1. Motivation(研究动机)
LLM agent 在 2023 年前后已经能通过 ReAct、Chain-of-Thought、tool use 与外部环境交互, 但这些方法大多仍然是“单回合推理器”而不是“可积累经验的学习者”。 它们可以在当前上下文中展开很长的 reasoning trace, 却很难把上一次失败真正转化为下一次更强的行为策略。 论文开篇点出的核心矛盾是: trial-and-error 对 agent 很重要,但经典 RL 的优化路径对大语言模型并不友好。 如果沿用标准 RL, 就需要大规模环境交互样本、稳定的 reward 设计、昂贵的 rollout 采集, 以及实际的参数更新或 fine-tuning。 对于依赖 API 调用的闭源模型, 这条路径既昂贵又不现实。 与此相对, prompting 方法虽然便宜, 但通常只会把 few-shot exemplars、上一轮 scratchpad、或者静态 instruction 塞进上下文。 一旦本轮失败, 模型并不会自动形成“以后遇到这种局面应该怎么改”的持久经验。 它下一轮往往只是重新采样一次, 或者在局部轨迹上小修小补。 作者具体瞄准的痛点不是“让 LLM 更会聊天”, 而是让它在三类高价值 agent 任务中更快从错误中恢复:
- sequential decision-making,例如 AlfWorld 这类多步环境交互;
- reasoning,例如 HotPotQA 这类检索 + 推理结合的问题回答;
- programming,例如 HumanEval / MBPP 这类能被单元测试直接验证的代码生成。
这些任务共享一个共同难点: 错误通常不是最终答案错这么简单,而是中间策略错了、检索路径错了、行动顺序错了、或者局部假设错了。 如果只给一个 scalar reward 或二值成败标签, 模型很难知道“究竟哪里出了问题”。 这本质上是 credit assignment 问题。 论文因此提出一个非常具体的问题表述: 能不能不更新模型权重, 而是把环境给出的 binary / scalar / free-form feedback 转写成自然语言经验, 再让模型在下一轮试错时显式读取这些经验? 这个问题值得研究, 因为它对应的是一种介于纯 prompting 与 full RL 之间的中间路线:
- 比 RL 轻量,因为不需要参数更新;
- 比单轮 prompt engineering 更强,因为允许跨 trial 累积经验;
- 比简单地把上次完整轨迹塞回上下文更高效,因为它强调“压缩后的 actionable lesson”。
作者把这种反馈视为一种 semantic gradient。 它不是数值梯度, 却起到类似“指明该往哪改”的作用。 如果这种语言化反馈有效, 那么 agent 的改进就可以在 inference-time 完成, 而不必等待离线训练管线。 从应用角度看, 这件事的重要性在于: 一旦 agent 能把失败总结成短小、可复用、任务相关的经验, 它就不再只是“独立完成每一道题”的一次性系统, 而会变成能在相同任务分布上持续提高成功率的系统。 这对代码修复、知识密集型问答、交互式决策都很关键。 论文还强调一个现实判断: 不同任务可以提供不同形态的反馈。 有的任务只能给 success / fail, 有的任务能给 unit test execution logs, 有的任务甚至能让另一个更强的 LLM 充当 evaluator。 如果一个框架能兼容这些反馈形式, 它就比依赖单一 reward 设计的 RL 管线更具普适性。 因此, Reflexion 的 motivation 不是抽象地“给 agent 加 memory”, 而是更具体地解决三个问题:
- 如何把稀疏反馈改写成可执行的文本建议;
- 如何让这些建议在下一轮真正影响行动;
- 如何在不做权重更新的前提下实现跨回合性能提升。
2. Idea(核心思想)
Reflexion 的核心 insight 可以概括成一句话: 把“奖励”从数字信号提升为语言信号,再把这段语言当作下一轮决策的条件输入。 也就是说, 作者不试图训练一个更好的 policy network, 而是把“从失败中学习”这件事迁移到 prompt / memory 层面完成。
更具体地说, Reflexion 将一次失败 episode 拆成三个可组合的模块:
- Actor 负责生成行为或答案;
- Evaluator 负责判定本轮表现好坏;
- Self-Reflection model 负责把失败转写成简洁、可执行的文本经验。
这三个模块组成的循环与传统 actor-critic 有明显类比, 但更新对象完全不同。经典 RL 中, critic 给出的信号用于更新参数 ;Reflexion 中, Evaluator 与 Self-Reflection 产生的信号不会反向传播到模型权重, 而是被写入 episodic memory, 作为下一轮 Actor 的补充上下文。作者把这种机制称为 verbal reinforcement learning。“reinforcement” 仍然存在, 但强化的媒介不再是数值梯度, 而是反映错误模式的自然语言总结。
这些总结通常很短, 例如“先找 desklamp 再找 mug”、 “不要重复走回已经搜索过的路径”、 “如果测试通过但答案仍错,说明测试覆盖不够”。这个思想与现有方法的差别要点如下。与 ReAct 相比: ReAct 主要依赖单个 episode 内的 reasoning/action trace;它会观察、思考、行动, 但不同 trial 之间没有显式长期记忆。Reflexion 则让“上一轮失败的复盘结论”显式进入下一轮 prompt。与 Self-Refine / self-correction 类方法相比: 后者通常在同一个样本上做局部修订, 更像一次 answer revision;
Reflexion 则面向多轮试错场景, 强调跨 trial 的 persistent memory, 目标是改变下一轮搜索策略,而不是只改当前输出。与 beam search / sample-and-rerank 相比: 后者依赖并行搜索更多候选;Reflexion 依赖序列化试错, 但每次失败后都会提炼“为什么失败以及下次该怎么做”。它不是单纯增加采样量, 而是提升后续采样的条件质量。
与 full RL fine-tuning 相比: Reflexion 最大的不同是完全不碰模型参数。 这让它非常适合 API-only 模型, 也更容易跨任务迁移, 因为你只需要替换 evaluator 与 prompt 模板, 而不需要重新训练底层模型。 作者的设计中有三个特别关键的抽象:
2.1 反馈语言化
环境通常只能给 sparse signal, 例如 success / fail、 unit tests pass / fail、 或者某个 score。 Reflexion 不直接把这些值喂给 Actor, 而是要求 Self-Reflection 模块结合 trajectory 把信号解释成一条“面向未来的建议”。
2.2 经验压缩
作者明确不把完整失败轨迹无限制地堆到上下文里。 完整轨迹往往又长又噪声大, 还容易让模型重复沉浸在错误路径中。 Reflexion 的做法是把长轨迹压缩成几句高信息密度的 reflection。 这使得 memory 既节省上下文, 又更像抽象经验而不是原始日志。
2.3 记忆驱动的再决策
reflection 的价值不在于“解释过去”, 而在于改变下一轮行为。 因此 memory 不是存档系统, 而是 inference-time control signal。 Actor 每轮都会读取这些 reflection, 让新的 reasoning trace 从一开始就避开过去的错误模式。
从直觉上看, Reflexion 成功的前提有两个:
- Self-Reflection 模型必须足够强,能把失败归因到具体、可操作的错误;
- Actor 必须足够听话,能把 memory 中的建议真正转化为新的行为序列。
这也是为什么论文在 HotPotQA 中发现, 更强的基础模型更能从 Reflexion 机制中受益。 如果模型本身没有足够强的分析与执行能力, 那么它也未必能产出有用 reflection, 或者无法正确利用这些 reflection。
因此, Reflexion 不是一个“任何小模型都能自动提升”的神奇技巧, 而是一种把强模型的反思能力系统化、持久化的 inference-time learning 框架。
3. Method(方法)
3.1 Overall framework
Figure 1 解读:左侧是环境交互回路, Actor 在状态 下生成 action / text, 环境返回 observation 与 reward; 中间是 evaluator 对整个 trajectory 给出成功判定或其他反馈; 右侧是 self-reflection model 把“这次为什么没做好、下次该怎么做”改写成 concise reflective text, 并写入长期 memory。 图中最关键的不是单次轨迹本身, 而是“trajectory 作为短期记忆、reflection 作为长期记忆”的二层结构。
论文给出的模块化定义是:
- Actor:,负责生成文本和动作;
- Evaluator:,负责给 Actor 输出打分;
- Self-Reflection:,负责从反馈中生成 verbal reinforcement cue。
在第 轮 trial 中, Actor 条件化于当前输入和 memory, 生成轨迹 。 然后 evaluator 计算反馈: 如果任务失败, 则 self-reflection model 基于轨迹、反馈以及已有记忆生成新的 reflection: 随后 memory 更新为: 并在下一轮作为 Actor 的附加上下文参与决策。 这个循环持续到任务成功, 或达到预设的最大 trial 数。 论文的关键点不是公式本身复杂, 而是它把 RL 里的“优化环路”完整保留了下来, 只不过把参数更新替换成了 memory update。 因此, Reflexion 可以被理解为一种 inference-time policy improvement loop。 作者还特别强调 short-term 与 long-term memory 的分工:
- short-term memory 是当前 episode 的 trajectory history;
- long-term memory 是跨 episode 的 distilled reflections。
前者保留 fine-grained 交互细节, 后者保留任务层面的高价值 lesson。 这与人类在执行复杂任务时同时依赖工作记忆与经验记忆的方式非常相似。 从 released code 看, AlfWorld 分支通过 EnvironmentHistory 把 memory 前置到 base prompt 前面, 然后再拼接 Here is the task: 与后续 action/observation 历史。 这意味着 reflection 会在 agent 开始新一轮搜索之前, 先占据 prompt 中最“指导性”的位置。 这一设计有两个实际好处:
- reflection 出现在 trial 开始前,更像 planning hint,而不是事后解释;
- memory 被压缩成短计划后,能够在有限 context budget 内稳定保留多轮经验。
直觉上, Reflexion 把“失败原因”从隐式 token pattern 变成显式经验文本, 因此下一轮并不是简单重采样, 而是带着更明确的 search bias 重新进入环境。 这就是作者所谓 semantic gradient 的真正含义。
3.2 Key components
Actor
Actor 负责在环境中执行动作并形成 trajectory。论文没有把 Actor 固定成某一种 prompting 范式, 而是显式允许不同任务采用不同 actor instantiation。在 HotPotQA 中, Actor 可以是 ReAct agent, 也可以是 CoT agent。ReAct 版本需要交替输出 Thought / Action / Observation, 通过 Wikipedia search / lookup 完成检索驱动的推理;CoT 版本则直接面向 reasoning 本身, 尤其在给定 ground-truth context 的设置里用于隔离纯推理能力。
在 AlfWorld 中, Actor 是一个交互式语言 agent, 每步从环境 observation 出发生成 action。alfworld_runs/alfworld_trial.py 中的 alfworld_run 会循环最多 49 步, 把 action 发送给环境, 再把返回 observation 追加到 EnvironmentHistory 中。如果动作重复导致 EnvironmentHistory.check_is_exhausted() 为真, 就提前认定这轮搜索已经陷入死循环。在编程任务中, Actor 不仅要写出函数实现, 还要在部分设置下与内部 test generation / execution 协同工作。
这使得编程场景里的 Actor 不再只是静态 code completion 模型, 而是带有“生成实现 - 看执行反馈 - 再修正”能力的 agent。从实现角度看, Actor 的一个重要特征是它总是条件化于 memory。例如 AlfWorld 的 EnvironmentHistory._get_base_query 会在 prompt 开头插入: Your memory for the task below: 然后逐条列出过去的 reflection。HotPotQA 的 ReactReflectAgent._build_agent_prompt 也会把 reflections 字符串显式注入 prompt template。
这意味着 Reflexion 不是在 actor 外部做 reranking, 而是直接改变 actor 的 conditional distribution: 如果移除 Actor 对 memory 的条件化, 那么 reflection 就无法作用到后续策略, 框架也会退化成“生成完总结一下,但不真正利用总结”的空转系统。
Evaluator
Evaluator 给出 trial 级反馈, 它可以非常简单, 只要能稳定地区分“成功 / 失败”或提供某种可解释信号即可。 论文的一个贡献正是说明 evaluator 不必局限于单一形式。
作者讨论了三类 evaluator 来源:
- external feedback 来自环境本身, 例如 AlfWorld 的任务完成状态、 HotPotQA 的答案是否与 gold answer Exact Match;
- internal self-evaluation 由模型自己或附属程序执行检查, 例如编程任务里的 unit tests;
- simulated language feedback 由更强的 LLM 或特定 prompt 生成自然语言评价。
在编程任务中, evaluator 最具“可操作性”。 因为代码能被直接执行, 单元测试结果会告诉系统当前实现是否通过, 编译器或测试框架还能返回错误日志。 这些信息远比纯二值 reward 更利于后续 self-reflection。 在 HotPotQA 中, evaluator 则更接近答案级判定。 CoTAgent.is_correct() 与 ReactAgent.is_correct() 最终都基于 EM 风格匹配, 也就是只要归一化后的最终答案与 gold key 相同就视为成功。 这使得 HotPotQA 成为一个很适合验证“二值反馈能否经由 reflection 转化为性能提升”的场景。 Evaluator 在 Reflexion 中的职责不是直接给出优化梯度, 而是提供一条足够可靠的“成败证据”。 如果 evaluator 噪声过大, 那么 self-reflection 很可能围绕错误的归因展开, 最终把错误 lesson 写进 memory。 论文在 MBPP 上观察到的退化, 就与自生成测试可能产生 false positive / false negative 密切相关。 因此, Evaluator 的核心价值不是复杂, 而是 grounded。 它必须让 reflection 建立在真实执行结果之上, 而不是仅靠模型主观感觉。
Self-Reflection
Self-Reflection 是 Reflexion 中最有辨识度的模块。 它不是简单地“让模型反思一下”, 而是把反思严格约束成一种面向未来的计划文本。
以 AlfWorld 为例, alfworld_runs/generate_reflections.py 中 _generate_reflection_query 的提示词明确要求:
- 不要总结环境;
- 要分析过去尝试的策略与路径;
- 要给出一个 concise, new plan of action;
- 要点名本该采取哪些 environment-specific actions;
- 最终输出放在
Plan之后。
这个约束非常关键。 因为如果 reflection 只是泛泛而谈, 例如“下次更小心一些”, 那它就难以成为有效 control signal。 作者真正想要的是“先去找 desklamp,再回来拿 mug”这类可执行经验。 在 HotPotQA 的 ReactReflectAgent 中, reflection 是通过 prompt_reflection() 基于失败 scratchpad 生成的。 代码还会对 scratchpad 做截断, 把过长 observation 替换成 [truncated wikipedia excerpt], 从而把反思资源集中在关键 reasoning trace 上, 而不是被冗长检索文本淹没。 这说明论文虽然概念上强调 verbal feedback, 但实现上非常重视 prompt budget management。 只有把原始轨迹裁剪成更易归因的上下文, self-reflection 才更可能抓住真正的失败原因。 从功能上看, self-reflection 至少承担三件事:
- 对失败做 credit assignment;
- 把长轨迹压缩成短经验;
- 把“问题诊断”改写成“下次如何行动”的规划建议。
如果去掉第二步, memory 会迅速膨胀; 如果去掉第三步, reflection 只会变成 retrospective commentary, 对下一轮帮助有限。
论文在 Figure 5 的案例中展示了这种转化: agent 第一次在 AlfWorld 中因为 inefficient planning 失败; 反思阶段识别出错误在于先找 mug 再找 desklamp; 下一轮则依据该计划更简洁地完成任务。 这正是 self-reflection 的目标形态。
Memory
Memory 是 Reflexion 真正实现“学习”的载体。 没有 memory, Reflexion 最多只是一次性的 self-critique; 有了 memory, 它才变成跨 trial 持续改进的系统。
论文把 memory 分成两层:
- short-term memory:当前轨迹历史;
- long-term memory:过去 trials 的 distilled reflections。
这一区分很重要。 原始轨迹包含大量局部细节, 适合支撑当前一步 action 的选择; reflection 则是跨轮共享的高阶经验, 适合提供任务层面的 bias。 released code 中, memory 容量并不是无限的。 AlfWorld 的 update_memory 与 alfworld_run 都只保留最近 3 条 reflection; 如果已有 memory 超过 3 条, 就切片为 memory[-3:]。 这说明作者非常清楚 context window 的约束, 因此把 Reflexion 设计成 sliding-window episodic memory, 而不是无界知识库。 这种设计的含义有两层:
- 近期错误通常比很久以前的错误更 relevant;
- 长期记忆必须经过压缩才能高频复用。
HotPotQA 中的 episodic memory ablation 也直接验证了 memory 的必要性。 论文在 Figure 4(c) 中单独比较了有无 episodic memory 的情况, 用来证明提升不仅来自“多试几次”, 更来自“把过去经验真正写进下一轮条件”。
直觉上, memory 的作用不是补充事实知识, 而是补充 strategy knowledge。 它告诉模型:
- 过去哪些搜索路径是坏的;
- 哪种思考顺序更可能成功;
- 哪类测试误判值得警惕;
- 哪些局部模式在本任务分布中反复出现。
因此 Reflexion 的 memory 与 retrieval-augmented generation 中的文档检索不是一回事。 RAG 检索外部知识, Reflexion 检索自身经验。 这也是该论文后来影响一系列 “agent memory / self-improvement” 工作的核心原因之一。
3.3 Algorithm
def reflexion_loop(actor, evaluator, self_reflector, max_trials=3):
memory = []
for t in range(max_trials):
trajectory = actor.run(memory=memory)
reward = evaluator(trajectory)
if reward.success:
return trajectory, memory
reflection = self_reflector(trajectory, reward, memory)
memory.append(reflection)
memory = memory[-3:]
return trajectory, memory这段伪代码对应论文 Algorithm 1 的主循环, 但还可以进一步拆成 paper 中真正有辨识度的三个子过程。
3.3.1 Actor rollout
def actor_rollout(actor, task_input, memory, max_steps):
scratchpad = []
for step in range(max_steps):
action = actor(task_input=task_input, memory=memory, scratchpad=scratchpad)
obs, done = env_step(action)
scratchpad.append((action, obs))
if done:
return scratchpad, True
return scratchpad, False这部分对应单个 episode 内部的 action/observation 交替, 例如 AlfWorld 中最多 49 步的环境交互, 或 HotPotQA 中有限步数的 Search / Lookup / Finish 序列。
3.3.2 Reflection synthesis
def synthesize_reflection(self_reflector, trajectory, reward, memory):
prompt = build_reflection_prompt(
trajectory=trajectory,
reward=reward,
prior_memory=memory,
)
reflection = self_reflector(prompt)
return reflection.strip()关键点在于 build_reflection_prompt 不只是简单拼接轨迹, 而是要求模型输出“新计划”。 在 AlfWorld released code 中, prompt 明确要求: 不要总结环境, 而要针对失败路径提出简明的新行动计划。
3.3.3 Memory-conditioned retry
def retry_with_memory(actor, task_input, memory, num_trials):
for _ in range(num_trials):
trajectory, success = actor_rollout(actor, task_input, memory, max_steps=49)
if success:
return trajectory, memory, True
reward = {"success": False}
reflection = synthesize_reflection(actor, trajectory, reward, memory)
memory = (memory + [reflection])[-3:]
return trajectory, memory, False这一段最能体现 Reflexion 与“纯重采样”的区别。 同一个任务并不是被独立求解多次, 而是每次都带着更新后的 memory 再求解。
若把论文写成更抽象的形式, Reflexion 实际上是在迭代下面这个条件分布: 其中 是任务输入, 由过去失败中提炼出的 reflections 构成。 随后利用 evaluator 与 reflector 更新 memory: 这里的 在论文概念层面是 append, 在 released code 中则是 append 后保留最近 3 条。
3.3.4 为什么这个算法有效
它有效的前提不是“多试几次一定会更好”, 而是每次试错都必须产出更具方向性的后验经验。 如果 reflection 无法正确定位失败原因, 或者 memory 没有真正进入下一轮 actor prompt, 那么多轮循环只会累积成本而不带来收益。
论文的 ablation 恰好支持这一点: 在编程任务中, 去掉 self-reflection, 即便保留 test generation, 性能也不会超过 baseline; 仅仅有 external signal 不够, 还需要把 signal 转化成语言经验并反馈给下一轮决策。
3.4 论文公式与 released code 实现差异
论文把 memory 写成一般的 episodic buffer, 但 released code 在 alfworld_runs/generate_reflections.py 与 alfworld_runs/alfworld_trial.py 中都明确把可见 memory 截断为最近 3 条 reflection。也就是说, 论文里的 是一个抽象容量, 代码里则是硬编码的 sliding window。论文将 evaluator 描述成统一抽象的 , 仿佛不同任务里只是替换一个评分器即可;
但 released code 的实现更任务特化: HotPotQA 直接用最终答案是否 EM 正确, AlfWorld 用 environment done / won 状态, 编程则依赖可执行测试与编译反馈。因此 paper-level modularity 在 code-level 上表现为多套专用 evaluator 逻辑, 而不是一个共享接口。
论文强调 self-reflection 由奖励、轨迹、memory 共同决定, released code 则通过非常具体的 prompt engineering 落地: 例如 AlfWorld 的 reflection prompt 明确要求输出 Plan, 并提供 few-shot failed-attempt examples;HotPotQA 则通过 truncate_scratchpad 裁掉过长 observation, 避免检索文本淹没错误归因。这些实现细节并未在 paper 公式中展开, 但对实际效果很关键。论文看起来像是一个单一统一算法, released code 实际上是“统一思想 + 多任务 prompt 特化”的组合。
这也是它能跨 reasoning、decision-making、programming 三个域工作的现实原因。另一个值得点明的差异是 code reference 本身: 论文正文在 2023 年描述的是当时实验系统, 当前 released repo 的提交 main@218cf0ef 日期为 2025-01-13, 因此本文笔记中的伪代码与 mapping 以该提交为锚点, 不保证与论文写作时的内部实验脚本逐行一致。
3.5 Code-to-paper mapping
Code reference:
main@218cf0ef(2025-01-13) — pseudocode and mapping based on this commit
| Paper Concept | Source File | Key Class/Function |
|---|---|---|
| Overall Reflexion loop | alfworld_runs/main.py | main, run_trial, update_memory |
| Reflection generation | alfworld_runs/generate_reflections.py | _generate_reflection_query, update_memory |
| Memory injection into task prompt | alfworld_runs/env_history.py | _get_base_query, EnvironmentHistory |
| AlfWorld action rollout | alfworld_runs/alfworld_trial.py | alfworld_run, run_trial |
| Long-term reflection injection | hotpotqa_runs/react.py | ReactReflectAgent, format_reflections |
| Reflexion strategy enum and multi-agent variants | hotpotqa_runs/agents.py | ReflexionStrategy, CoTAgent, ReactReflectAgent |
| ReAct baseline | hotpotqa_runs/agents.py, hotpotqa_runs/react.py | ReactAgent |
| Prompt / example templates | hotpotqa_runs/prompts.py | reflect_prompt, react_agent_prompt, react_reflect_agent_prompt, cot_reflect_prompt |
| Few-shot reflection examples | alfworld_runs/reflexion_few_shot_examples.txt | prompt source |
这张 mapping 表反映出一个很重要的工程事实: 论文中的“Reflexion”并不是一个高度抽象、完全解耦的库, 而是围绕不同任务分别写了一套任务脚本, 再通过共享的“reflection + memory”思想将它们统一起来。 因此读 code 时最应该对齐的是 paper concept, 而不是期待存在一个名为 ReflexionAgent 的统一类。
4. Experimental Setup(实验设置)
Datasets and scale
- HotPotQA:论文在主结果表中报告 100 道问题上的 pass@1 accuracy。 该任务要求 agent 结合 Wikipedia 检索与 multi-hop reasoning 得到最终答案。
- AlfWorld:论文在 Figure 3 中汇报 134 个 tasks 上的累计 solved proportion。 这是一个 household sequential decision-making benchmark, 很适合测试 planning error、hallucination、以及动作顺序错误。
- HumanEval (Python):标准代码生成基准, 通过可执行测试计算 pass@1。
- MBPP (Python):另一套函数级代码生成数据集, 与 HumanEval 一起用于验证 Reflexion 在编程上的泛化。
- HumanEval (Rust):论文使用 MultiPL-E 将 HumanEval Python 的 50 hardest problems 翻译到 Rust, 用来测试在编译型语言场景下 Reflexion 是否仍然有效。
- MBPP (Rust):同样通过 MultiPL-E 翻译得到, 用于补充 Rust 结果。
- LeetcodeHardGym:论文引入的新交互式编程 gym, 含 40 道在 GPT-4 预训练截止日期之后发布的 Leetcode hard 题, 用于降低数据泄漏风险。
- WebShop:附录中作为 limitation case 使用, 论文在 100 个环境中测试两-shot ReAct + Reflexion agent, 但在四轮试错后几乎没有改善。
Baselines
- ReAct:decision-making 与 reasoning 的核心 baseline, 用于衡量“只做当前回合 reasoning/action trace”时的表现。
- CoT:尤其在 HotPotQA 中, 论文使用 CoT 与 CoT (GT) 来区分“纯 reasoning 能力”与“检索 + reasoning 能力”。
- GPT model family baselines:包括
text-davinci-003、gpt-3.5-turbo、gpt-4, 用于比较 Reflexion 是否随着基础模型增强而收益更大。 - Programming baseline:同一基础模型直接做 code generation, 不使用 Reflexion memory loop。
- Compromised approaches in Table 3:
test generation omission与self-reflection omission, 用于分离“执行反馈”与“语言反思”两个因素的独立贡献。 - starchat-beta baseline:Table 4 用于验证较弱开源模型上 Reflexion 不一定带来收益, 说明反思能力是模型能力的 emergent property。
Metrics
- pass@1:一次采样 / 一次运行最终得到正确解的比例, 是编程与 HotPotQA 主表中的核心指标。
- success rate / solved proportion:AlfWorld 与 HotPotQA 图中常用, 表示在若干 trial 后累计解决的任务比例。
- Exact Match (EM):HotPotQA answer correctness 的最终判定标准。
- TP / FN / FP / TN:Table 2 对编程任务额外统计 test generation 质量, 其中 TP 表示 unit tests pass 且 solution pass, FP 表示 unit tests pass 但真实 solution fail, 它能暴露“测试通过但代码其实错了”的问题。
- avg over 8 trials / std:Table 4 在 starchat-beta 上报告平均 pass@1 与标准差, 用于显示较弱模型收益不稳定甚至不存在。
Training / run config
- 这篇论文本质上是 inference-time prompting system, 不是梯度训练论文, 因此没有传统意义上的 GPU 数量、optimizer、learning rate、training steps。 这一点需要明确写出来, 否则容易误以为“Reflexion”是一个微调算法。
- 代码运行依赖
OPENAI_API_KEY, 主要调用 OpenAI 系列模型, 成本瓶颈是 API 调用而非 GPU 训练。 alfworld_runs/main.py暴露的关键运行参数包括:num_trials、num_envs、run_name、use_memory、is_resume、resume_dir、start_trial_num、model。- AlfWorld rollout 在
alfworld_runs/alfworld_trial.py中最多执行 49 environment steps。 alfworld_runs/generate_reflections.py与alfworld_runs/alfworld_trial.py都将长期 memory 截断到最近 3 条。- HotPotQA 的
ReactAgent默认使用:temperature=0,max_tokens=100,model_name="gpt-3.5-turbo";ReactReflectAgent的 reflection model 则使用max_tokens=250。 CoTAgent的 action LLM 与 self-reflect LLM 在hotpotqa_runs/agents.py中也默认设为gpt-3.5-turbo, 但论文主结果还单独对比了text-davinci-003与gpt-4。- 编程任务的一个关键实现细节是: 先用 Chain-of-Thought prompting 生成多样化 tests, 然后过滤语法有效的测试语句, 最后执行这些 tests 作为 evaluator。
- 由于这是 prompt-based setup, 更合理的复现实验单位是“每个 benchmark 上的 trial budget、base model、memory 开关、reflection prompt 模板”, 而不是传统深度学习中的训练超参。
5. Experimental Results(实验结果)
Main results
- HumanEval (Python): baseline 0.80, Reflexion 0.91, 提升 +0.11。
- MBPP (Python): baseline 0.80, Reflexion 0.77, 下降 -0.03。
- HumanEval (Rust, hardest 50): baseline 0.60, Reflexion 0.68, 提升 +0.08。
- MBPP (Rust): baseline 0.71, Reflexion 0.75, 提升 +0.04。
- HotPotQA on 100 questions:
CoT (GT) + text-davinci-003从 0.60 提升到 0.77;CoT (GT) + gpt-3.5-turbo从 0.57 提升到 0.71;CoT (GT) + gpt-4从 0.68 提升到 0.80;ReAct + text-davinci-003从 0.30 提升到 0.55;ReAct + gpt-3.5-turbo从 0.26 提升到 0.38;ReAct + gpt-4从 0.39 提升到 0.51。
这些结果说明 Reflexion 在 reasoning 与 programming 上都能带来显著提升, 但收益并不均匀。 最强的 headline result 是 HumanEval Python 上 GPT-4 从 0.80 到 0.91, 而最明显的负例则是 MBPP Python 从 0.80 降到 0.77。
AlfWorld 的主结果主要通过 Figure 3 以累计 solved proportion 展示, 论文强调在 134 tasks 上, Reflexion 明显快于纯 ReAct, 并且几乎消除了大量由 hallucination 与 inefficient planning 导致的失败轨迹。 这里 paper 更关注“随 trial 数增加的解题曲线形状”, 而不是只报一个静态终点数字。
Key findings
- memory 不是可有可无的附属品,而是性能来源本身。 HotPotQA Figure 4(c) 的 episodic memory ablation 专门验证了, 提升并非仅来自重复尝试, 而是来自把过去经验显式写入下一轮 prompt。
- self-reflection 本身具有独立贡献。
Table 3 中,
self-reflection omission的 pass@1 只有 0.60, 与 base model 0.60 持平; 只有当 test generation 与 self-reflection 同时存在时, 才达到 0.68。 - 可执行反馈对编程场景极其关键。 Table 3 中, 去掉 test generation 后性能下降到 0.52, 低于 baseline 0.60。 这说明如果 agent 无法获得 grounded execution signal, 它甚至可能在多轮修订中越改越坏。
- 更强模型更能利用 Reflexion。
Table 4 显示在
starchat-beta上, baseline 与 Reflexion 都是 0.26, 说明并非任何模型都能从 verbal reinforcement 学到东西。 作者据此认为“能写出有用自我修正”是 stronger / larger models 的 emergent quality。 - Reflexion 主要改善的是策略错误,而不是知识缺失。 AlfWorld Figure 3 / Figure 5 展示, 它尤其擅长减少 hallucination 和 inefficient planning, 即 agent 明明拥有所需能力, 但执行顺序或局部假设出错。
- 编程任务中的收益与 test quality 紧密耦合。 Table 2 显示 HumanEval (PY) 的 FP 仅 0.01, 但 MBPP (PY) 的 FP 达 0.16; 这很好地解释了为何 Reflexion 在 HumanEval 提升明显, 却在 MBPP Python 上退化。
Limitations
- 会陷入 local minima。 论文第 5 节明确指出, Reflexion 仍然可能卡在非最优策略中, 特别是那些需要非常有创造性的跳出路径的任务。
- WebShop 是明确的失败案例。 附录写到, 在 100 个 WebShop environments 上测试两-shot ReAct + Reflexion agent, 跑到第 4 轮后作者就终止实验, 因为 agent 没有表现出明显改进, 且无法生成真正有帮助、直观的 self-reflection。
- memory 仍然非常原始。 论文承认当前长期记忆只是一个固定容量 sliding window, 并建议未来可扩展到 vector embedding database 或传统 SQL database。
- credit assignment 仍然难。 即便有 reflection, 模型也未必总能把一次长轨迹失败准确归因到关键步骤。
- 编程结果受测试质量上限约束。 如果自生成 test suite 有缺陷, 可能出现 false positive: tests 全过但 solution 实际错误; 也可能出现 false negative: tests 失败但解其实是对的。 前者尤其危险, 因为系统会过早接受错误实现。
- 需要多次 LLM 调用,推理成本明显增加。 每一轮 trial 至少包含 actor rollout, 失败时还要额外调用 self-reflection model。 当 evaluator 也由 LLM 模拟时, 成本会进一步上升。
- 它更像 task-distribution adaptation,而不是 open-ended lifelong learning。 Reflexion 假设后续 trial 仍围绕同一任务或同分布任务展开, 因此过去的经验才有价值。 若任务分布变化过大, memory 可能不再相关。
Overall conclusion
Reflexion 最重要的结论不是“加一个反思 prompt 会涨点数”, 而是它证明了: LLM agent 可以在不更新权重的情况下,通过 verbal feedback + episodic memory 完成某种意义上的 policy improvement。
这项工作把 RL 中的 reward / feedback / improvement loop 重新解释为语言系统中的三个对象:
- feedback 被写成自然语言;
- update 发生在 memory 而非参数;
- improvement 发生在下一轮 prompt-conditioned decision making。
实验结果显示, 当任务具备可靠 evaluator、 基础模型足够强、 且错误主要来自策略选择而不是知识完全缺失时, Reflexion 往往能显著提升性能。 HumanEval Python 从 0.80 到 0.91、 HotPotQA 多种 base model 上的稳定提升、 以及 AlfWorld 中对 hallucination / planning failure 的明显缓解, 共同支撑了这一点。 同时, 论文也没有掩盖它的边界: MBPP Python 的退化、 starchat-beta 上零收益、 WebShop 上难以跳出 local minima, 都表明 verbal reinforcement 不是无条件有效的万能解法。 即便如此, Reflexion 仍然是 agent literature 中一个非常关键的转折点。 它首次把“self-reflection + memory”系统性地组织成可复现的优化回路, 并清楚展示了为何 agent 的学习不一定非要依赖参数更新。 后续大量 agent memory、self-improvement、language feedback RL 工作, 都可以看作是在沿着这条路线继续展开。