# 2.4 反思与自我修正

如果说 ReAct 解决的是“边做边看、根据观察即时调整”，那么本节讨论的反思机制解决的是“做完一轮之后，如何基于反馈在下一轮做得更好”。广义上，反思（reflection）指模型审视并修正自身输出的能力；狭义上，Reflexion 通常特指一套带语言记忆的试错学习框架。本节先讲狭义的 Reflexion，再把它放回更宽的“测试时自我改进”谱系中，与 Self-Refine、CRITIC 区分开。

> **说明（术语说明）** 在智能体 AI 领域，**Reflexion** 通常特指 Noah Shinn 等人提出的“基于语言反馈的强化学习”框架（Reflexion framework）；而通用英语单词 **reflection** 指的是更广泛的“反思”认知能力。后文若说“狭义 Reflexion”，指的是前者；若说“广义反思”，则指所有基于反馈改进输出的方法族。

## 2.4.1 什么是反思

狭义的 Reflexion 框架由 Noah Shinn 等人在论文 [Reflexion: Language Agents with Verbal Reinforcement Learning](https://arxiv.org/abs/2303.11366) 中提出。它的关键假设是：任务失败后，不先盲目重试，而是先分析“为什么失败、下次如何避免”，再把这段语言化经验写入记忆，注入下一轮尝试。也就是说，Reflexion 的本质是 **把失败经验转化为可复用的语言形式知识，而不是更新模型权重**。

```
尝试 → 失败 → 反思（为什么失败？）→ 总结（学到了什么？）→ 将语言记忆注入下一次尝试
```

## 2.4.2 与人类学习的类比

| 阶段 | 人类学习         | 反思智能体   |
| -- | ------------ | ------- |
| 尝试 | 做数学题         | 执行任务    |
| 反馈 | 发现答案错误       | 收到失败信号  |
| 反思 | “我是在哪一步算错了？” | 分析错误原因  |
| 总结 | “以后要注意检查符号”  | 生成经验总结  |
| 改进 | 下次做题更仔细      | 更新策略/记忆 |

## 2.4.3 反思的三要素

### 执行者

负责执行任务的智能体，通常采用 ReAct 模式：

```python
class Actor:
    def act(self, task: str, memory: List[str]) -> Trajectory:
        """
        执行任务，返回执行轨迹
        memory: 之前反思得到的经验
        """
        prompt = f"""
        任务：{task}

        之前的经验教训：
        {format_memories(memory)}

        请执行任务...
        """
        return execute_with_react(prompt)
```

### 评估者

判断任务是否成功：

```python
class Evaluator:
    def evaluate(self, trajectory: Trajectory, ground_truth: Any) -> Tuple[bool, str]:
        """
        评估执行结果
        返回：(是否成功, 反馈信息)
        """
        result = trajectory.final_result

        if matches(result, ground_truth):
            return True, "任务完成"
        else:
            return False, f"结果不正确，预期 {ground_truth}，实际 {result}"
```

### 反思者

从失败中提取经验：

```python
class SelfReflection:
    def reflect(self, task: str, trajectory: Trajectory, feedback: str) -> str:
        """
        分析失败原因，生成经验总结
        """
        prompt = f"""
        任务：{task}

        执行轨迹：
        {format_trajectory(trajectory)}

        失败反馈：{feedback}

        请分析：
        1. 在哪个步骤出了问题？
        2. 为什么会出这个问题？
        3. 下次应该如何避免？

        请用一句话总结这次的经验教训：
        """
        return model.generate(prompt)
```

## 2.4.4 完整的 Reflexion 循环

```python
def reflexion_loop(task: str, max_trials: int = 3):
    memory = []  # 存储反思经验
    for trial in range(max_trials):
        # 1. 执行任务（带着记忆）
        trajectory = actor.act(task, memory)
        # 2. 评估结果
        success, feedback = evaluator.evaluate(trajectory)
        # 3. 如果成功，返回结果
        if success:
            return trajectory.final_result
        # 4. 如果失败，进行反思
        reflection = self_reflection.reflect(task, trajectory, feedback)
        memory.append(reflection)
        print(f"Trial {trial + 1} 失败，反思结果：{reflection}")
    return "达到最大尝试次数，任务失败"
```

**任务**：编写一个函数计算斐波那契数列第 n 项

**第一次尝试**：

```python
def fibonacci(n):
    return fibonacci(n-1) + fibonacci(n-2)  # ❌ 缺少终止条件
```

**评估结果**：`RecursionError: maximum recursion depth exceeded`

**反思**：

> “这次失败是因为递归函数没有设置终止条件（base case），导致无限递归。下次编写递归函数时，必须首先定义 base case。”

**第二次尝试**（带着反思记忆）：

```python
def fibonacci(n):
    if n <= 1:  # ✅ 添加了 base case
        return n
    return fibonacci(n-1) + fibonacci(n-2)
```

**评估结果**：`通过！`

到这里讨论的仍然是“狭义 Reflexion”：它有明确的 trial、评估信号，以及跨轮次保留的语言记忆。理解了这个基准形态之后，再看其它常被并列讨论、但机制并不相同的方法会更清楚。

## 2.4.5 记忆管理策略

### 短期记忆（滑动窗口）

只保留最近 k 次反思：

```python
class ShortTermMemory:
    def __init__(self, max_size: int = 5):
        self.memories = deque(maxlen=max_size)

    def add(self, reflection: str):
        self.memories.append(reflection)
```

### 长期记忆（持久化存储）

将反思结果存入向量数据库进行持久化存储，以便在未来的任务中复用：

```python
class LongTermMemory:
    def __init__(self, vector_store):
        self.store = vector_store

    def add(self, reflection: str, task_type: str):
        embedding = embed(reflection)
        self.store.add(embedding, metadata={"text": reflection, "type": task_type})

    def retrieve(self, current_task: str, k: int = 3) -> List[str]:
        """检索与当前任务相关的历史经验"""
        return self.store.search(embed(current_task), top_k=k)
```

### 经验泛化

从具体经验中提取通用规则，并注入到系统提示词中作为全局准则：

```
具体经验：
- "计算阶乘时忘了处理 n=0 的情况"
- "递归求和时没有设置终止条件"
- "链表遍历时没有检查空指针"

泛化规则：
→ "处理递归或循环结构时，始终先确定边界条件和终止条件"
```

**实现方式**：

```python
def consolidate_memories(memory_store):
    """定期执行的内存整理任务"""
    # 1. 聚类相似的错误记录

    clusters = cluster_similar_errors(memory_store.fetch_all())

    for cluster in clusters:
        # 2. 提取通用规则

        rule = model.generate(f"基于以下失败案例总结一条通用原则：\n{cluster}")

        # 3. 注入到系统提示词中作为全局准则

        agent.update_system_prompt(add_rule=rule)
```

## 2.4.6 与其他技术的结合

### Reflexion + ReAct

ReAct 提供行动能力，Reflexion 提供学习能力。

```python
class ReflexiveReActAgent:
    def run(self, task):
        for trial in range(max_trials):
            # ReAct 风格的执行
            trajectory = self.react_loop(task)
            if self.is_success(trajectory):
                return trajectory.result
            # Reflexion 风格的学习
            reflection = self.reflect(trajectory)
            self.memory.add(reflection)
```

### Reflexion + Tool Learning

从工具使用失败中学习，并更新工具使用知识库。

```
反思："调用 search API 时参数格式错误，应该用 {'q': query} 而不是 {'query': query}"
→ 更新工具使用知识库
```

## 2.4.7 Reflexion、Self-Refine 与 CRITIC 的边界

工程实践里，很多方法都会被口语化地称作“反思”。更稳妥的说法是：它们都属于“基于反馈改进输出”的相关方法，但不是同一个桶。三者在**反馈来自哪里**、**是否跨 trial 保留记忆**、**是否依赖外部工具校验**这三个维度上都不同。

### 1. Reflexion：失败后复盘并写入语言记忆

这是 Noah Shinn 等人在 *Reflexion: Language Agents with Verbal Reinforcement Learning* 中提出的框架。任务失败后，系统基于轨迹和反馈生成一条可复用的经验教训，并把它注入下一轮尝试。

```
失败：递归函数没有终止条件
反思：下次编写递归逻辑时，必须先确认 base case
下一轮：带着这条经验重新生成代码
```

### 2. Self-Refine：同一模型给自己提反馈并迭代改写

Self-Refine 通常指 Aman Madaan 等人在论文 [Self-Refine: Iterative Refinement with Self-Feedback](https://arxiv.org/abs/2303.17651) 中提出的方法。它不一定依赖明确的“失败”信号，而是在得到初稿后，由同一个模型继续扮演反馈者和改写者，主动做一轮或多轮自我审查，再迭代修改。

```
初稿：解释过于笼统
自评：缺少具体例子，抽象概念太多
改写：增加案例、对比和边界条件
```

它特别适合文案、报告、方案设计这类“没有唯一标准答案，但可以持续优化质量”的任务。与 Reflexion 相比，它更强调**当前样本内的连续打磨**，而不是“失败一次 - 总结经验 - 下一轮重试”的跨 trial 学习。

### 3. CRITIC：借助外部工具做客观校验后再修正

CRITIC 通常指 Zhibin Gou 等人在论文 [CRITIC: Large Language Models Can Self-Correct with Tool-Interactive Critiquing](https://arxiv.org/abs/2305.11738) 中提出的框架。它的关键不是“只靠自己想”，而是“先验证，再修正”。模型会调用搜索、代码执行器、数据库或其它校验工具，获得更客观的反馈后再修正输出。

```
初稿：这个 API 会返回 status 字段
校验：实际接口返回中没有 status
反思：我混淆了旧版和新版接口定义
修正：按真实返回结构更新说明
```

相比纯内部反思，这种模式更适合高风险场景，因为它把“自我感觉良好”的空间压缩到了最小。与 Self-Refine 相比，CRITIC 的关键增量不是自反馈本身，而是**把外部工具校验作为批判依据**。

可以把三者的边界收束成下表：

| 方法          | 原始论文                 | 核心反馈来源        | 是否保留跨 trial 记忆 | 典型用途                |
| ----------- | -------------------- | ------------- | -------------- | ------------------- |
| Reflexion   | Shinn et al. (2023)  | 任务成败信号 + 语言反思 | 是              | 失败后总结经验，再次尝试        |
| Self-Refine | Madaan et al. (2023) | 模型自生成的反馈      | 通常否            | 对单个初稿反复润色与改写        |
| CRITIC      | Gou et al. (2023)    | 外部工具校验结果      | 不一定，重点不在记忆     | 事实核验、代码检查、风险较高的输出修正 |

## 2.4.8 反思作为增强层，而不是独立系统

很多团队第一次接触 reflection 时，容易把它理解成一个独立 Agent。更准确的理解是：**广义反思通常是附着在 ReAct 或 Plan-and-Execute 之上的增强层**。同时也要注意，不是每一次读取 Observation、调整下一步动作都算“反思”；只有当系统显式地产生批判、总结或修正规则，并把它带入后续生成时，才进入这一层。

两种常见组合方式：

1. **ReAct + 反思层** 在若干步执行或一次 trial 结束后，额外生成复盘总结，并把结论注入后续决策。
2. **Plan-and-Execute + 反思层** 每完成一个计划节点或整个计划后做阶段复盘，决定是继续执行、局部修正，还是整体重规划。

可以把它理解为：

| 基础范式                 | 负责什么      | 广义反思额外提供什么      |
| -------------------- | --------- | --------------- |
| **ReAct**            | 边想边做、动态试探 | 对失败原因做语言化总结     |
| **Plan-and-Execute** | 全局规划、按步推进 | 发现计划漏洞并触发重规划    |
| **Multi-Agent**      | 分工协作      | 对团队协作失误做复盘与规则沉淀 |

如果没有显式的反思层，系统往往只能“重试”；有了反思层，系统才开始真正“学习”。

## 2.4.9 评估 Reflexion 的效果

### 最小实验

为了准确评估反思机制的效果，工程上应当建立对齐原论文精神的测试基准。以下是一个针对代码生成任务（如 HumanEval 基准）的最小复现实验设定：

* **评估任务**：HumanEval（如 Python 函数补全）。
* **核心指标**：`pass@1`（无反思的单次通过率）对比引入 Reflexion 循环后的最终通过率。
* **最大尝试次数（Max Trials）**：通常严格设置为 3 至 5 次（超过此阈值容易产生幻觉累积或成本衰减）。
* **反馈来源（Feedback Type）**：
  * 代码执行反馈：沙箱执行模型生成的单元测试或真实测试用例（包括通过/失败状态及报错堆栈追踪）。
  * 裁判模型反馈：由另一个隔离的 LLM 实例作为客观裁判，对初步答案给出判定和缺陷描述。
* **记忆结构与注入策略**：将失败输出、报错日志和反思总结组装为结构化数据包（参考 [第3章](/agentic_ai_guide/di-yi-bu-fen-dan-ti-zhi-neng-jia-gou/03_memory.md) 的统一上下文结构），在下一次尝试时强置于编排提示词的末尾。

### 关键评估指标

| 指标    | 说明                  |
| ----- | ------------------- |
| 成功率提升 | 第 n 次尝试的成功率与第 1 次对比 |
| 尝试次数  | 平均需要多少次才能成功         |
| 反思质量  | 反思是否正确定位问题          |
| 知识迁移  | 一个任务的经验是否帮助另一个      |

### 实验结果（参考论文）

部分研究在代码生成等任务上报告：引入 Reflexion 循环（多次尝试 + 反馈 + 经验总结）后，整体通过率会有明显提升。需要注意：不同模型、提示词、评测脚本与尝试次数都会显著影响数值，文中不固定引用具体百分比。

## 2.4.10 局限性与注意事项

* **评估信号的质量**：反思依赖准确的评估信号。如果评估不准确，反思也会出错。
* **反思的准确性**：模型可能错误归因失败原因，导致“错误的经验教训”。
* **计算成本**：多次尝试意味着多次模型调用，成本较高。
* **适用场景**：最适合有明确成功标准的任务（如代码、数学题），对于开放性任务效果有限。

***

**下一节**: [智能体提示词工程](/agentic_ai_guide/di-yi-bu-fen-dan-ti-zhi-neng-jia-gou/02_reasoning/2.5_prompt_engineering.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yeasy.gitbook.io/agentic_ai_guide/di-yi-bu-fen-dan-ti-zhi-neng-jia-gou/02_reasoning/2.4_reflexion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
