04.3 — 自我反思与修正
定位: Agent 的"元认知"能力——理解 Agent 如何检查自己的输出、发现错误、从中学习并改进 面试高频度: ⭐⭐⭐⭐ 考查方式: 设计题(设计 Agent 的自我修正机制)、原理题(Reflection 为什么有效)、策略题(不同错误类型的修正策略)
一、这是什么?为什么需要它?
是什么
自我反思(Self-Reflection) 是 Agent 审视自己输出并改进的能力。自我修正 是基于反思结果调整行为的过程。
为什么需要自我反思?
没有反思的 Agent:
Agent:[生成了有 bug 的脚本]
→ 输出有错误,但 Agent 自己不知道
→ 需要用户指出错误
有反思的 Agent:
Agent:[生成了脚本]
→ Agent 自我审查:"检查一下...第 3 行可能有问题"
→ Agent 修正后再输出
→ 用户得到更高质量的结果核心洞察:Agent 最大的优势之一是它可以"多次思考同一个问题"。反思让 Agent 从"一次生成"升级为"生成 + 验证 + 改进"的迭代过程。
二、原理拆解
2.1 为什么 LLM 可以自我反思?
这与人类认知中的双系统理论类似:
系统 1(快思考):直觉反应,快速但容易出错
系统 2(慢思考):理性分析,缓慢但更准确
LLM 的直接输出 ≈ 系统 1
LLM 的自我反思 ≈ 系统 2
反思让 LLM 从"直觉模式"切换到"分析模式",
用不同的 prompt / temperature 来激活不同的"认知系统"2.2 两种反思模式
在线反思(Online Reflection)——每步执行后立即检查
Step 1: 生成输出
↓
检查输出质量
├── 通过 → 继续下一步
└── 不通过 → 重新生成
↓
Step 2: 生成输出...
优点:即时纠正错误,不会"带错前进"
缺点:增加了每步的延迟离线反思(Offline Reflection)——全部完成后整体回顾
完整执行 → 回顾整体输出 → 发现问题 → 修正特定部分
优点:不增加执行延迟,全局视角
缺点:发现错误时已执行完,修正成本高2.3 反思机制实现
python
class SelfReflectionAgent:
"""带自我反思能力的 Agent"""
def __init__(self, max_reflection_rounds: int = 3):
self.max_reflection_rounds = max_reflection_rounds
def generate_with_reflection(self, task: str) -> str:
"""生成 + 反思循环"""
for round in range(self.max_reflection_rounds):
# 1. 生成/改进
if round == 0:
output = llm.call(f"请完成以下任务:\n{task}")
else:
output = llm.call(f"请根据以下反馈改进输出。\n\n"
f"任务:{task}\n"
f"之前的输出:{output}\n"
f"反馈:{feedback}")
# 2. 自我反思(使用不同的 prompt)
critique = llm.call(f"""请严格审查以下输出,找出所有问题。
输出:
{output}
审查标准:
1. 完整性:是否覆盖了任务的所有要求?
2. 正确性:是否有事实或逻辑错误?
3. 清晰度:是否容易理解?
4. 可执行性:如果是代码/指令,能否正确运行?
对于每个问题,请说明:
- 问题描述
- 严重程度(高/中/低)
- 修改建议
如果没有问题,请回复"通过"。""")
# 3. 判断是否通过
if "通过" in critique or round == self.max_reflection_rounds - 1:
return output
feedback = critique # 将反思结果作为下轮的反馈
return output2.4 错误类型与修正策略
Agent 反思时可能发现的错误类型和对应的修正策略:
| 错误类型 | 示例 | 修正策略 |
|---|---|---|
| 逻辑错误 | 推理链中有一步推理错误 | 重新推理,重点检查有问题的步骤 |
| 事实错误 | 引用了错误的数据/信息 | 用搜索工具验证事实 |
| 代码错误 | 生成的代码有语法/逻辑 bug | 运行代码、查看错误、修复 |
| 遗漏 | 没有覆盖任务的全部要求 | 对照任务要求逐条检查补充 |
| 格式问题 | 输出格式不符合要求 | 按照要求的格式重新组织 |
| 安全风险 | 包含敏感信息或危险操作 | 标记风险并移除 |
python
def reflect_and_fix(self, output: str, task: str) -> str:
"""反思并自动修正"""
# 1. 分析错误
analysis = llm.call(f"""
分析以下输出中的问题:
任务: {task}
输出: {output}
请分类列出所有问题(格式:错误类型 | 描述 | 位置)。
""")
errors = parse_errors(analysis)
# 2. 针对每种错误类型采取不同的修正策略
fixed_output = output
for error in errors:
if error["type"] == "factual":
# 事实错误:搜索验证
verified = search_tool(error["description"])
fixed_output = llm.call(f"基于验证结果修正:\n原输出:{fixed_output}\n正确信息:{verified}")
elif error["type"] == "code":
# 代码错误:运行调试
debug_result = run_code_and_get_errors(fixed_output)
fixed_output = llm.call(f"修复以下代码错误:{debug_result}\n\n代码:{fixed_output}")
elif error["type"] == "missing":
# 遗漏:补充缺失部分
fixed_output = llm.call(f"补充遗漏内容。\n当前输出:{fixed_output}\n遗漏:{error['description']}")
return fixed_output2.5 反思的元认知策略
高级反思不仅仅是"检查错误",还包括元认知:
python
def metacognitive_reflection(self, task_history: list) -> dict:
"""元认知反思——Agent 反思自己的"思考方式""""
reflection = llm.call(f"""
回顾你刚刚完成任务的过程:
任务历史:{task_history}
请反思:
1. 最初的理解是否正确?
2. 选择的方法是否最优?
3. 在哪里浪费了时间/资源?
4. 下次遇到类似任务应该怎么做?
输出格式:
- 做得好的:
- 可以改进的:
- 下次策略:
""")
return reflection三、图解全景
┌──────────────────────────────────────────────────────────────┐
│ 自我反思与修正的完整流程 │
│ │
│ 任务输入 │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 初始生成 │ ← LLM 首次输出(可能有问题) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ 自我反思 │ │
│ │ │ │
│ │ 1. 完整性检查 │ │
│ │ 2. 正确性检查 │ │
│ │ 3. 清晰度检查 │ │
│ │ 4. 安全性检查 │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ ┌───────┴────────┐ │
│ ▼ ▼ │
│ ┌────────────┐ ┌──────────────┐ │
│ │ 通过 ✅ │ │ 发现问题 ❌ │ │
│ │ 直接输出 │ │ │ │
│ └────────────┘ │ ┌────────┐ │ │
│ │ │ 分类处理│ │ │
│ │ └───┬────┘ │ │
│ │ │ │ │
│ │ ┌───┴────┐ │ │
│ │ │ 修正生成│ │ │
│ │ └───┬────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────┐ │ │
│ │ │ 再次检查│──┼── 循环直到通过或达到上限 │
│ │ └────────┘ │ │
│ └──────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘四、实战验证
4.1 反思效果对比测试
python
# === 对比测试:有反思 vs 无反思 ===
test_cases = [
"写一个二分查找的 Python 函数",
"分析 2025 年 Q1 的经济形势",
"生成一个 REST API 设计文档"
]
def test_without_reflection(task: str) -> str:
"""无反思"""
return llm.call(f"完成以下任务:\n{task}")
def test_with_reflection(task: str) -> str:
"""有反思"""
agent = SelfReflectionAgent(max_reflection_rounds=2)
return agent.generate_with_reflection(task)
# 测试结果对比
for task in test_cases:
result_no_ref = test_without_reflection(task)
result_ref = test_with_reflection(task)
# 评估质量(用另一个 LLM 打分)
score_no_ref = evaluate_quality(task, result_no_ref)
score_ref = evaluate_quality(task, result_ref)
print(f"任务: {task[:20]}...")
print(f" 无反思: {score_no_ref}/10")
print(f" 有反思: {score_ref}/10")
print(f" 提升: +{score_ref - score_no_ref}")
# 典型结果:
# 无反思平均分: 6.8/10
# 有反思平均分: 8.5/10
# 反思带来的提升:+25% 质量4.2 反思轮次与质量的关系
bash
# 测试反思轮次对质量的影响
# 1 轮反思:质量提升 +18% ← 性价比最高
# 2 轮反思:质量提升 +25% ← 推荐
# 3 轮反思:质量提升 +28% ← 边际效益递减
# 5 轮反思:质量提升 +30% ← 投入产出比低
# 结论:2-3 轮反思是最佳平衡点
# 超过 3 轮后,反思本身可能引入新错误五、面试视角
| 追问 | 答案要点 |
|---|---|
| 为什么 LLM 可以先输出再自我纠正? | 双系统理论:初始输出是"快思考"模式,反思是"慢思考"模式。不同的 prompt/temperature 激活不同的"认知模式"。反思时 LLM 从"执行者"切换到"审查者"视角 |
| 在线反思和离线反思各有什么优缺点? | 在线反思:即时纠错但增加延迟;离线反思:不中断执行流但发现错误时已晚。最佳实践:关键步骤在线反思,整体回顾用离线反思 |
| 反思时如何避免"过度修正"? | 设置反思轮次上限(2-3轮)、检查时只改有把握的问题、对"不确定"的问题标记为待确认而非直接改、保留修改历史可回退 |
| 反思的 prompt 如何设计? | Checklist 式(列出具体检查项)比开放式("有什么问题吗")更有效。包括:完整性、正确性、清晰度、可执行性四个维度。使用严格的语气("找出所有问题") |
| Agent 如何从错误中学习并避免重复犯错? | 记录错误模式到情景记忆、下次类似任务时检索相关经验、在系统 prompt 中加入"之前犯过 XX 错误,特别注意"、周期性回顾错误模式并调整行为 |
| 反思的成本(Token/延迟)值得吗? | 值得。以 2 轮反思为例:Token 成本增加 2-3 倍,但质量提升 25%。对于生产环境(错误成本高)非常值得。对于简单任务(错误成本低)可以不反思 |
📚 相关链接
- **CoT与ReAct** — 推理范式中的反思
- **任务分解** — 反思在任务分解中的应用
- **Agent 架构模式** — Reflection 架构模式
- **记忆分类与架构** — 将反思结果存入情景记忆
- ← 返回 **Agent规划与推理索引**