1. 研究背景:语言智能体的现状与瓶颈

大型语言模型(LLM)不仅在文本生成领域展现了惊人的能力,更逐渐演变为能够与外部环境交互 的决策智能体。近年来的研究,如 ReAct、SayCan、Toolformer、 HuggingGPT 和 WebGPT 等,展示了以 LLM 为核心构建自主系统的巨大潜力 。这些系统通过 生成文本和动作,调用 API、操作编译器或在虚拟环境中执行任务.

然而,这些方法的根本局限在于其学习方式。目前的语言智能体主要依赖于上下文学习( In-context Learning),即通过在提示词(Prompt)中提供静态的示例来指导模型行为。虽然这种方法在 Few-shot 场景下有效,但它缺乏一种机制让智能体从自身的错误中快速、高效地学习。

传统的优化路径——基于梯度下降的强化学习——虽然在游戏和控制领域取得了巨大成功(如 AlphaGo),但在 LLM 智能体场景下面临严峻挑战:

1. 样本效率低:传统强化学习需要数以万计甚至百万计的训练样本才能收敛,而与现实世界(如 API 或 编译器)交互的成本极高。

2. 微调成本高昂:对于拥有数十亿甚至上万亿参数的 LLM(如 GPT-4),进行参数微调需要庞大的计算资源,且容易导致模型能力的灾难性遗忘。

3. 奖励信号稀疏:在复杂的推理或编程任务中,环境通常只能提供二元的成功/失败反馈,难以通过标量奖励精确指导模型“哪一步做错了”。

2 Reflexion 范式转移的初步认知

针对上述痛点,Reflexion 提出了一种全新的视角:如果我们将“反思”本身视为一种强化信号,会 发生什么?

Reflexion 框架的核心假设是:智能体不需要修改神经网络的权重来学习,而是可以通过修改其 “记忆”(上下文)来优化策略 。这种方法利用了 LLM 强大的语言理解和生成能力,将环境的二元或标量反馈转化为语言形式的文本摘要。

这个文本摘要充当了一种语义梯度(Semantic Gradient)。在深度学习中,梯度向量指示了权重更新的方向;而在 Reflexion 中,语言反思指示了思维更新的方向。例如,当智能体在游戏中因为“找不到钥匙”而失败时,传统的 RL 可能会收到一个 -1 的奖励,而 Reflexion 智能体则会生成一段反思:“我在尝试打开门之前没有检查桌子上的盒子,下次我应该先检查盒子。” 。

这种机制模拟了人类的高级认知过程。人类在学习复杂任务时,并非通过调整神经突触的连接强度从一次失败中学习,而是通过内省和元认知来分析错误原因,并在短期记忆形成新的行动计划 。

3.方法论:ReAct是基于语言反思的强化框架

Reflexion 框架的设计高度模块化,通过三个核心组件的协同工作来实现自我进化:演员(Actor)、 评估器(Evaluator)和自我反思(Self-Reflection)。这一架构不仅是对 ReAct 等现有框架的扩展,更是引入了闭环控制系统中的“反馈控制”理念。

3.1 理论架构与组件定义

Reflexion 的工作流程可以被形式化为一个迭代优化过程。我们定义智能体为一组模型的集合: $M_a$(演员)、$M_e$(评估器)和 $M_{sr}$(自我反思)。

3.1.1 演员模型 $M_a$

演员是系统的执行引擎,基于 LLM 构建。它的任务是根据当前的状态观察生成文本和动作。

策略定义: 类似于传统 RL 中的策略 $\pi_\theta(a_t|s_t)$,演员在时间 $t$ 根据当前状态 $s_t$ 采样动作 $a_t$

上下文增强: 与传统 RL 不同,Reflexion 中的状态 $s_t$ 不仅包含当前的观察 $o_t$,还包含来自记忆组件 $mem$ 的反思性上下文。这意味着演员的决策不仅受限于当前的感知,还受到过去经验指导 。

模型兼容性: 演员可以使用 Chain of Thought (CoT) 或 ReAct 等不同的提示策略。这表明 Reflexion 是一个通用的元框架,可以增强任何现有的生成模型。

3.1.2 评估器模型 $M_e$

评估器是质量控制机制,负责评估演员生成的轨迹 $\tau$ 的质量,并计算奖励分数 $r$

语义价值函数的挑战: 在自然语言任务中,定义一个能够精确衡量“好坏”的价值函数极其困难。Reflexion 通过针对不同任务设计特定的评估器来解决这个问题:

推理任务(HotPotQA): 使用精确匹配(Exact Match, EM)评分,直接对比预测答案与标准答案(在训练或验证阶段)。

决策任务(AlfWorld): 使用预定义的启发式函数(Heuristics)。例如,如果智能体陷入循环动作或在特定时间内未完成任务,评估器将返回失败信号。

编程任务(HumanEval): 这是最接近真实世界应用的场景。评估器通过执行单元测试来生成确定性的二元奖励(通过/失败)。更有趣的是,研究还探索了使用另一个 LLM 作为评估器,对生成的代码进行打分 。

3.1.3 自我反思模型 $M_{sr}$

$M_{sr}$ 也是一个 LLM,其作用是解决强化学习中著名的信用分配问题。

输入: 稀疏的奖励信号(如“失败”)、当前的行动轨迹、以及持久记忆 $mem$

功能: 它将难以解释的标量奖励转化为具体的、有针对性的语言反馈。

机制: 当收到失败信号时,$M_{sr}$ 会分析轨迹,推断是哪一步动作导致了后续的连锁反应。例如,它可能会指出:“我在第 3 步选择了错误的工具,导致第 5 步无法获取数据。下次我应该在第 3 步尝试使用搜索工具。”

语义梯度: 这种语言反馈为下一次试验提供了“梯度方向”,指导演员在提示空间中进行调整。

3.1.4 记忆系统 (Memory System)

Reflexion 引入了类人的记忆机制,分为短期记忆和长期记忆 。

短期记忆: 记录当前试验中的动作序列和环境观察。这对应于 ReAct 框架中的上下文。

长期记忆: 存储由 $M_{sr}$ 生成的反思摘要。在推理时,这些摘要被追加到提示词的上下文中。为了适应 LLM 的上下文窗口限制,系统通常采用滑动窗口机制,仅保留最近的 $\Omega$个(通常为 1-3 个)反思经验。这模拟了人类容易遗忘久远细节但能记住最近教训的特性。

class Memory:
    """
    一个简单的短期记忆模块,用于存储智能体的行动与反思轨迹。
    """

    def __init__(self):
        """
        初始化一个空列表来存储所有记录。
        """
        self.records: List[Dict[str, Any]] = []

    def add_record(self, record_type: str, content: str):
        """
        向记忆中添加一条新记录。

        参数:
        - record_type (str): 记录的类型 ('execution' 或 'reflection')。
        - content (str): 记录的具体内容 (例如,生成的代码或反思的反馈)。
        """
        record = {"type": record_type, "content": content}
        self.records.append(record)
        print(f"📝 记忆已更新,新增一条 '{record_type}' 记录。")

    def get_trajectory(self) -> str:
        """
        将所有记忆记录格式化为一个连贯的字符串文本,用于构建提示词。
        """
        trajectory_parts = []
        for record in self.records:
            if record['type'] == 'execution':
                trajectory_parts.append(f"--- 上一轮尝试 (代码) ---\n{record['content']}")
            elif record['type'] == 'reflection':
                trajectory_parts.append(f"--- 评审员反馈 ---\n{record['content']}")

        return "\n\n".join(trajectory_parts)

    def get_last_execution(self) -> Optional[str]:
        """
        获取最近一次的执行结果 (例如,最新生成的代码)。
        如果不存在,则返回 None。
        """
        for record in reversed(self.records):
            if record['type'] == 'execution':
                return record['content']
        return None

3.2 算法流程详解

第一步:初始化

初始化演员 $M_a$、评估器 $M_e$、自我反思模型 $M_{sr}$。清空记忆 ,设定最大试验次数 max_trials。

第二步:初始尝试

生成轨迹 ($\tau_0$): 演员 $M_a$基于初始策略与环境交互,生成第一个轨迹 $\tau_0 = [a_0, o_0,..., a_n, o_n]$

第三步:评估

评分 ($r_0$): 评估器 $M_e$$\tau_0$ 进行评 估。如果任务成功,直接返回结果;如果失败,进入反思循环。

第四步:反思生成

生成反思 ($sr_0$): $M_{sr}$ 接收 $\{\tau_0, r_0\}$ 作为输入,生成第一条反思摘要。

第五步:记忆存储

更新记忆: 将 $sr_0$ 追加到 $mem$ 中。

第六步:迭代循环

While (评估未通过且 $t <$ max_trials): 

上下文增强: 将 $mem$ 中的内容作为附加上下文输入给演员。

生成新轨迹 ($\tau_t$): 演员利用包含反思的上下文, 生成新的动作序列。由于有了之前的教训,演员倾向于避开已知的错误路径。

再次评估: 评估器 $M_e$$\tau_t$ 评分。

递归反思: 如果仍未通过, $M_{sr}$ 基于 $\tau_t$ 和 历史 $mem$ 生成新的反思 $sr_t$,并追加到 $mem$

第七步:中止

返回成功的轨迹或在达到最大次数后返回最终状态。

4. Reflexion与其他范式的联系和对比

Reflexion 与主流智能体框架的对比
特性 ReAct Self-Refine Chain of Thought (CoT) Reflexion 
核心机制 推理 + 行动交替 迭代式自我修正 逐步推理 语言反馈 + 情景记忆闭环
记忆类型 短期上下文 无显式长期记忆 长期情景记忆 
反馈来源 外部观察 内部自我评估 外部环境 + 内部模拟 + 语言反思
适用场景 交互式决策 单轮生成优化 逻辑推理 复杂多步决策、 编程、推理
权重更新 无 (语义梯度更新)

与 ReAct 的对比: ReAct 强调“行动”与“观察”的交织,适合探索环境。Reflexion 可以看作是 ReAct 的上层封装,为其添加了一个“事后诸葛亮”的机制,通过长期记忆修正 ReAct 的短期决策偏差。

与 Self-Refine 的对比: Self-Refine 主要关注单次生成的优化(如文本重写),通常缺乏与外部环境的深度交互和长期记忆的累积。Reflexion 更强调从多次试验的失败中学习,适用于需要试错的长程任务。

5. 局限性

5.1 数据污染的争议

Reflexion 在 HumanEval 上 91% 的准确率虽然惊人,但也引发了关于数据污染的强烈质疑 。

核心论点: 批评者认为,GPT-4 的预训练数据中极可能包含了 HumanEval 的题目和标准答。如果模型“见过”答案,Reflexion 的反思过程可能并不是真正的“推理修正”,而是通过提示词诱导模型“回忆”起训练数据中的正确答案。

后续验证: 在更晚发布的、确保未被 GPT-4 见过的基准测试(如 Leetcode 新题)中,Reflexion 的表现虽然仍优于基准,但绝对数值大幅下降(如 LeetcodeHard 上仅为 15%)。这表明 91% 的数值可能部分归功于记忆效应。

5.2 局部最优与探索能力的缺乏

Reflexion 本质上是一种贪婪的优化策略。它基于当前的错误进行修正,这在数学上类似于梯度下 降,因此也继承了梯度下降的缺点——容易陷入局部最优。

WebShop 案例: 在需要高度创造性和多样化探索的 WebShop 任务中,Reflexion 未能显著超越 ReAct。

后续演进: 为了解决这一问题,后续工作如 LATS (Language Agent Tree Search) 引入了蒙特卡洛树搜索,允许智能体在反思的同时回溯并探索其他分支,从而不仅能“修正”当前路径,还能“放弃”当前路径去寻找全局最优解。

5.3 对评估器质量的依赖

Reflexion 的有效性完全取决于 $M_e$(评估器)的准确性。

这一点非常重要,一旦评估器的能力并没有演员好,会导致原地踏步甚至效果回退。gpt-4o-mini以上才有初步的代码评估和反馈能力,使用不同模型作为三个组件效果可能差距非常大。

误导性反馈: 如果评估器给出了错误的反馈(例如,错误的单元测试通过了错误的代码),智能体就会将错误的行为固化到记忆中。

能力悖论: 期望一个无法解决任务的模型能够准确评估该任务的解决方案,在逻辑上存在一 定的悖论。Reflexion 在编程任务上的成功部分得益于编译器这一客观、完美的“外部评估器”,而在开放式生成任务中,这一优势将不复存在。

6.Reflection的demo代码实现

如果有想实现一个ReAct智能体的demo,可以参考:datawhale的三种智能体经典范式构建

对于参考链接中的实现,Reflexion 机制的终止条件是"反馈中包含无需改进"或"达到最大迭代次数"。我优化了Reflexion 机制的终止条件,使其更加智能化。

首先,修改评估器的提示词逻辑(引入一个打分的json格式):

REFLECT_PROMPT_TEMPLATE = """
你是一位极其严格的代码评审专家和资深算法工程师,对代码的性能有极致的要求。
你的任务是审查以下Python代码,并专注于找出其在<strong>算法效率</strong>上的主要瓶颈。

# 原始任务:
{task}

# 待审查的代码:
```python
{code}
```

请分别分析该代码的时间复杂度与空间复杂度,并思考是否存在一种<strong>算法上更优</strong>的解决方案来显著提升性能或节省内存。
如果存在,请清晰地指出当前算法的不足,并提出具体的、可行的改进算法建议(例如,使用筛法替代试除法或采用更节省内存的结构)。
如果代码在算法层面已经达到最优,才能回答“无需改进”。

请严格输出以下 JSON(不要包含额外文本或代码块标记):
{{
    "score": 0-100之间的整数分数,表示当前算法的整体质量,
    "time_complexity": "时间复杂度分析",
    "space_complexity": "空间复杂度分析",
    "analysis": "核心瓶颈分析",
    "recommendations": ["改进建议1", "改进建议2" ...]
}}
当确实无需改进时,将 "score" 设为 100,并在 "recommendations" 中写入 "无需改进"。
"""

以下是我优化后的ReflexionAgent类,基类和main函数参考上方链接。

class ReflexionAgent:
    def __init__(self, llm_client, max_iterations=5, high_score_threshold: int = 90,
                 min_improvement: int = 2, stagnation_patience: int = 2):
        self.llm_client = llm_client
        self.memory = Memory()
        self.max_iterations = max_iterations
        # --- 智能化终止条件的配置参数 ---
        self.high_score_threshold = high_score_threshold  # 高分阈值:当分数超过此值,认为代码质量已很高
        self.min_improvement = min_improvement            # 最小改进幅度:用于判断迭代是否带来了实质性提升
        self.stagnation_patience = stagnation_patience    # 停滞容忍度:连续多少轮改进微小后,判定为陷入停滞

    def run(self, task: str):
        print(f"\n--- 开始处理任务 ---\n任务: {task}")

        # --- 1. 初始执行 ---
        print("\n--- 正在进行初始尝试 ---")
        initial_prompt = INITIAL_PROMPT_TEMPLATE.format(task=task)
        initial_code = self._get_llm_response(initial_prompt)
        self.memory.add_record("execution", initial_code)

        # --- 新增:初始化最佳记录 ---
        best_code = initial_code
        best_score = -1  # 初始分数设为负值

        # --- 2. 迭代循环:反思与优化 ---
        last_score = None
        stagnant_rounds = 0  # 用于追踪连续未达到最小改进的轮数
        last_feedback_text = None # 用于追踪上一轮的反馈文本,以检测重复

        for i in range(self.max_iterations):
            print(f"\n--- 第 {i + 1}/{self.max_iterations} 轮迭代 ---")

            # 获取当前待评估的代码(上一轮执行的结果)
            current_code_to_evaluate = self.memory.get_last_execution()

            # a. 反思
            print("\n-> 正在进行反思...")
            reflect_prompt = REFLECT_PROMPT_TEMPLATE.format(task=task, code=current_code_to_evaluate)
            feedback = self._get_llm_response(reflect_prompt)
            self.memory.add_record("reflection", feedback)

            parsed_feedback = self._parse_feedback_metadata(feedback)
            current_score = parsed_feedback.get("score", 0)  # 默认给0分防止None报错

            # 如果当前分数有效且比历史最高分更高,则保存当前代码为最佳代码
            if current_score is not None and current_score > best_score:
                print(f"🌟 发现更好的版本!分数从 {best_score} 提升到 {current_score}")
                best_score = current_score
                best_code = current_code_to_evaluate

            # --- 终止条件检查 ---

            # --- 终止条件 1: 基于LLM的明确判断 ---
            # 如果反思阶段LLM明确表示代码已无需改进,则直接终止。
            # 这是最直接的智能化信号,尊重LLM的自我评估能力。
            if "无需改进" in feedback or (current_score >= 100):
                print("\n✅ 代码已达到最优状态,任务完成。")
                break

            # --- 终止条件 2: 基于分数的收敛判断 ---
            # 调用辅助函数判断是否因分数足够高且改进微小而停止。
            if self._should_stop_by_score(current_score, last_score):
                print("\n✅ 评分显示已收敛且分数较高,停止迭代。")
                break

            # --- 终止条件 3: 检测改进停滞 ---
            # 追踪连续改进幅度低于 `min_improvement` 的次数。
            # 如果超过 `stagnation_patience`,说明可能已达到平台期,继续迭代收益不大,因此终止。
            if last_score is not None:
                if current_score - last_score < self.min_improvement:
                    stagnant_rounds += 1
                else:
                    stagnant_rounds = 0

            if stagnant_rounds >= self.stagnation_patience:
                print("\n⚠️ 连续多轮改进幅度不足,停止迭代。")
                break

            # --- 终止条件 4: 检测反馈循环 ---
            # 如果本轮的反馈文本与上一轮完全相同,说明LLM可能陷入了“反思-优化”的局部最优循环,
            # 无法产生新的有效改进,因此终止。
            current_feedback_text = feedback.strip()
            if current_feedback_text and current_feedback_text == last_feedback_text:
                print("\n⚠️ 反馈内容重复,停止迭代。")
                break

            last_score = current_score
            last_feedback_text = current_feedback_text

            # c. 优化
            # 注意:如果这轮优化导致分数降低,下一轮循环开头评分时 best_score 不会更新,
            # 从而保证了我们永远持有历史最好的那个版本。
            print("\n-> 正在进行优化...")
            refine_prompt = REFINE_PROMPT_TEMPLATE.format(
                task=task,
                last_code_attempt=current_code_to_evaluate,
                feedback=feedback
            )
            refined_code = self._get_llm_response(refine_prompt)
            self.memory.add_record("execution", refined_code)

        print(f"\n--- 任务完成 ---\n最终保留的代码 (最高分: {best_score}):\n```python\n{best_code}\n```")
        return best_code

    def _get_llm_response(self, prompt: str) -> str:
        """一个辅助方法,用于调用LLM并获取完整的流式响应。"""
        messages = [{"role": "user", "content": prompt}]
        response_text = self.llm_client.think(messages=messages) or ""
        return response_text

    def _parse_feedback_metadata(self, feedback: str) -> Dict[str, Any]:
        metadata = {
            "score": None,
            "analysis": None,
            "recommendations": [],
            "time_complexity": None,
            "space_complexity": None,
        }
        if not feedback:
            return metadata

        json_str = self._extract_json_block(feedback)
        if not json_str:
            return metadata

        try:
            data = json.loads(json_str)
        except json.JSONDecodeError:
            return metadata

        if isinstance(data, dict):
            metadata["score"] = data.get("score")
            metadata["analysis"] = data.get("analysis")
            metadata["time_complexity"] = data.get("time_complexity")
            metadata["space_complexity"] = data.get("space_complexity")
            recs = data.get("recommendations") or []
            metadata["recommendations"] = recs if isinstance(recs, list) else [recs]
        return metadata

    @staticmethod
    def _extract_json_block(text: str) -> Optional[str]:
        start = text.find("{")
        end = text.rfind("}")
        if start == -1 or end == -1 or end <= start:
            return None
        return text[start:end + 1]

    def _should_stop_by_score(self, score: Optional[int], last_score: Optional[int]) -> bool:
        """
        智能化终止条件的辅助函数
        根据分数判断是否应该停止迭代。
        停止的条件是:
        1. 当前分数和上一轮分数都已超过高分阈值 (`high_score_threshold`)。
        2. 分数变化非常小,未达到最小改进幅度 (`min_improvement`)。
        当两者同时满足时,认为已经收敛,可以停止。
        """
        if score is None or last_score is None:
            return False
        # 条件1: 分数足够高
        high_enough = score >= self.high_score_threshold and last_score >= self.high_score_threshold
        # 条件2: 改进幅度微小
        minor_change = abs(score - last_score) < self.min_improvement
        return high_enough and minor_change

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐