摘要: ReAct 和 Plan-and-Solve 完成任务后即止,而 Reflection 范式引入了“事后修正”机制。本篇将构建一个具备“自我进化”能力的智能体,通过模拟人类的“初稿->反思->修稿”工作流,实现代码生成任务从 O ( n n ) O(n\sqrt{n}) O(nn ) O ( n log ⁡ log ⁡ n ) O(n \log \log n) O(nloglogn) 的算法级自动优化。
关键词: Reflection, Self-Correction, Iterative Refinement, Memory Module, System 2 Thinking
本文是基于Datawhale的hello-agent开源项目做的一些笔记,内容仅供参考,原PDF以及代码可以去github仓库获取https://datawhalechina.github.io/hello-agents


在前两篇中,我们构建了“边走边看”的 ReAct 和“先谋后动”的 Plan-and-Solve。它们各有千秋,但都有一个共同痛点:一旦输出,便是定局,缺乏自我纠错的能力。

4.4 Reflection (自我反思)

智能体生成的初始答案,无论是行动轨迹还是最终代码,往往存在谬误或并非最优。Reflection 机制的核心思想,是为智能体引入一种事后 (post-hoc) 的自我校正循环

4.4.1 Reflection 机制的核心思想

Reflection 灵感来源于人类的学习过程:写完文章要校对,做完题要验算。这一思想在 Noah Shinn 等人提出的 Reflexion 框架中得到了系统化0。

其核心是一个简洁的三步循环:

  1. 执行 (Execution):生成“初稿”。
  2. 反思 (Reflection):调用一个独立的 LLM 实例扮演“评审员”,审视“初稿”的事实错误、逻辑漏洞或效率问题,并生成反馈 (Feedback)
  3. 优化 (Refinement):结合“初稿”和“反馈”,生成“修订稿” 。
数学形式化表达

假设 O i O_i Oi 是第 i i i 次迭代的输出, F i F_i Fi 是反馈。
反思模型 π r e f l e c t \pi_{reflect} πreflect 生成反馈:
F i = π r e f l e c t ( T a s k , O i ) F_{i} = \pi_{reflect}(Task, O_{i}) Fi=πreflect(Task,Oi)
优化模型 π r e f i n e \pi_{refine} πrefine 生成新输出:
O i + 1 = π r e f i n e ( T a s k , O i , F i ) O_{i+1} = \pi_{refine}(Task, O_{i}, F_{i}) Oi+1=πrefine(Task,Oi,Fi)

流程可视化

Reflection Loop

Task

Initial Output O0

Feedback Fi

Optimized Output Oi+1

No improvement needed

User

Agent

Execution / Actor

Self-Reflection / Evaluator

Refinement / Optimizer

Final Answer

(图 4.3 Reflection 机制中的“执行-反思-优化”迭代循环)


4.4.2 短期记忆模块 (Memory Module)

Reflection 的核心在于迭代,而迭代的前提是“记住”之前的尝试和反馈。我们需要一个 Memory 模块来存储完整的轨迹 。

from typing import List, Dict, Any, Optional

class Memory:
    """一个简单的短期记忆模块,用于存储智能体的行动与反思轨迹。"""
    
    def __init__(self):
        # 初始化一个空列表来存储所有记录
        self.records: List[Dict[str, Any]] = []

    def add_record(self, record_type: str, content: str):
        """
        向记忆中添加一条新记录。
        :param record_type: 'execution' (执行/代码) 或 'reflection' (反思/反馈)
        :param content: 具体内容
        """
        record = {"type": record_type, "content": content}
        self.records.append(record)
        print(f"记忆已更新,新增一条 '{record_type}' 记录。")

    def get_trajectory(self) -> str:
        """将所有记忆记录格式化为一个连贯的字符串,用于构建 Prompt。"""
        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]:
        """获取最近一次的执行结果(例如最新生成的代码),供反思使用。"""
        for record in reversed(self.records):
            if record['type'] == 'execution':
                return record['content']
        return None


4.4.3 Reflection 智能体的编码实现

有了记忆模块,我们来实现 ReflectionAgent。这需要三个精心设计的 Prompt,分别对应三个角色。

1. 提示词设计 (Prompt Engineering)
  • Initial Prompt: 资深 Python 程序员。任务:直接写代码 。

  • Reflection Prompt: 极其严格的代码评审专家。任务:找出算法效率瓶颈,提出改进建议(如时间复杂度优化)。

  • Refinement Prompt: 优化者。任务:根据反馈重写代码 。

💡 深度解析 (Deep Dive)
原文中 Reflection Prompt 的设计非常关键:“你是一位极其严格的代码评审专家…专注于找出算法效率上的主要瓶颈…如果存在更优解,请提出具体的改进算法(如筛法替代试除法)” 。这种Persona (角色设定) + Specific Constraint (具体约束) 是让 LLM 输出高质量反馈的秘诀。

2. 智能体核心逻辑
# 假设 llm_client.py 和 memory.py 已定义
# from llm_client import HelloAgentsLLM
# from memory import Memory

class ReflectionAgent:
    def __init__(self, llm_client, max_iterations=3):
        self.llm_client = llm_client
        self.memory = Memory()
        self.max_iterations = max_iterations
        
        # 定义 Prompt 模板 (简化版,实际使用请参考上文描述或 GitHub 源码)
        self.INITIAL_PROMPT = "你是一位资深 Python 程序员。请根据以下要求编写函数:{task}"
        self.REFLECT_PROMPT = "你是一位严格的代码评审专家。请分析以下代码的时间复杂度并提出优化建议:\n任务:{task}\n代码:{code}"
        self.REFINE_PROMPT = "请根据评审反馈优化代码。\n任务:{task}\n上一轮代码:{last_code_attempt}\n反馈:{feedback}"

    def _get_llm_response(self, prompt: str) -> str:
        """辅助方法:调用 LLM"""
        messages = [{"role": "user", "content": prompt}]
        return self.llm_client.think(messages=messages) or ""

    def run(self, task: str):
        print(f"\n--- 开始处理任务 ---\n任务: {task}")
        
        # 1. 初始尝试 (Execution)
        print("\n--- 正在进行初始尝试 ---")
        initial_prompt = self.INITIAL_PROMPT.format(task=task)
        initial_code = self._get_llm_response(initial_prompt)
        self.memory.add_record("execution", initial_code)

        # 2. 迭代循环 (Reflection Loop)
        for i in range(self.max_iterations):
            print(f"\n--- 第 {i+1}/{self.max_iterations} 轮迭代 ---")
            
            # a. 反思 (Reflection)
            print("\n-> 正在进行反思...")
            last_code = self.memory.get_last_execution()
            reflect_prompt = self.REFLECT_PROMPT.format(task=task, code=last_code)
            feedback = self._get_llm_response(reflect_prompt)
            self.memory.add_record("reflection", feedback)
            
            # b. 检查终止条件
            if "无需改进" in feedback:
                print("\n反思认为代码已无需改进,任务完成。")
                break
                
            # c. 优化 (Refinement)
            print("\n-> 正在进行优化...")
            refine_prompt = self.REFINE_PROMPT.format(
                task=task, 
                last_code_attempt=last_code, 
                feedback=feedback
            )
            refined_code = self._get_llm_response(refine_prompt)
            self.memory.add_record("execution", refined_code)

        final_code = self.memory.get_last_execution()
        print(f"\n--- 任务完成 ---\n最终代码:\n{final_code}")
        return final_code


4.4.4 运行实例:从 到

我们将任务设定为:“编写一个 Python 函数,找出 1 到 n 之间所有的素数” 。这是一个经典的算法优化场景。

第 1 轮:初始尝试

  • LLM 输出:生成了一个标准的双重循环代码(试除法)。
def find_primes(n):
    primes = []
    for num in range(2, n + 1):
        is_prime = True
        for i in range(2, int(num ** 0.5) + 1): # 试除
            if num % i == 0:
                is_prime = False
                break
        if is_prime:
            primes.append(num)
    return primes

(注:这是典型的初学者写法,效率一般)

第 1 轮:反思

  • 评审员反馈:当前代码时间复杂度为 。当 n 很大时性能会下降。建议使用 埃拉托斯特尼筛法 (Sieve of Eratosthenes),复杂度可降为 。

第 1 轮:优化

  • LLM 输出:根据反馈重写了代码,使用了筛法。
def find_primes(n):
    if n < 2: return []
    is_prime = [True] * (n + 1)
    p = 2
    while (p * p <= n):
        if is_prime[p]:
            for i in range(p * p, n + 1, p):
                is_prime[i] = False
        p += 1
    return [p for p in range(2, n+1) if is_prime[p]]

第 2 轮:反思

  • 评审员反馈:当前代码已使用筛法,非常高效。虽然可以进一步使用“分段筛法”优化内存,但一般情况下无需改进

  • 结果:触发终止条件,任务结束。


4.4.5 成本收益分析

Reflection 是一种“以成本换质量”的高级策略。

  • 成本 (Cost)

  • Token 消耗倍增:每一轮迭代至少由于 2 次 LLM 调用(Reflect + Refine)。

  • 延迟 (Latency):串行过程,耗时显著增加 。

  • 收益 (Benefit)

  • 质量跃迁:能将“合格”方案优化为“优秀”方案(如本例中的算法复杂度降低)。

  • 鲁棒性:内部纠错回路能发现逻辑漏洞 。

适用场景:生成关键业务代码、撰写技术报告、复杂逻辑推演 。


4.5 本章小结

至此,我们完成了三种经典范式的构建。请参考下表选择适合你的架构:

范式 核心逻辑 适用场景 优势
ReAct 思考-行动-观察 需要实时搜索、API 交互、探索性任务 环境适应性强,动态纠错
Plan-and-Solve 先规划-后执行 逻辑严密、步骤清晰的复杂推理任务 结构清晰,避免中途迷失
Reflection 执行-反思-优化 代码生成、长文写作、高质量决策 质量极高,具备自我进化能力

🚀 Next Step: 现在你已经掌握了单智能体的设计。但在真实世界中,一个超级智能体往往难以独当一面。下一章,我们将进入 Multi-Agent (多智能体) 的世界,探索如何让多个 Agent 像公司团队一样协作!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐