Skip to main content
章节15 min read

第4章:Reflection

第4章:Reflection Reflection 模式概述 在前面的章节中,我们探讨了基本的 agentic 模式:用于顺序执行的 Chaining、用于动态路径选择的 Routing,以及用于并发任务执行的 Parallelization。这些模式使 agent 能够更高效、更灵活地执行复杂任务。然而,即使拥有复杂...

第4章:Reflection

Reflection 模式概述

在前面的章节中,我们探讨了基本的 agentic 模式:用于顺序执行的 Chaining、用于动态路径选择的 Routing,以及用于并发任务执行的 Parallelization。这些模式使 agent 能够更高效、更灵活地执行复杂任务。然而,即使拥有复杂的工作流,agent 的初始输出或计划可能也不是最优的、准确的或完整的。这就是 Reflection 模式发挥作用的地方。

Reflection 模式涉及 agent 评估自身的工作、输出或内部状态,并利用该评估来改进其性能或优化其响应。这是一种自我纠正或自我改进的形式,允许 agent 根据反馈、内部批评或与期望标准的比较来迭代优化其输出或调整其方法。Reflection 有时可以由一个单独的 agent 来促成,该 agent 的特定职责是分析初始 agent 的输出。

与简单地直接将输出传递给下一步的顺序链,或者选择一条路径的 Routing 不同,Reflection 引入了一个反馈循环。agent 不仅生成输出;它还会检查该输出(或生成它的过程),识别潜在的问题或改进空间,并利用这些洞察来生成更好的版本或修改其未来的行动。

该过程通常包括:

  1. 执行:agent 执行任务或生成初始输出。
  2. 评估/批评:agent(通常使用另一次 LLM 调用或一组规则)分析上一步的结果。此评估可能会检查事实准确性、连贯性、风格、完整性、对指令的遵循程度或其他相关标准。
  3. 反思/优化:基于批评,agent 确定如何改进。这可能包括生成优化后的输出、为后续步骤调整参数,甚至修改整体计划。
  4. 迭代(可选但常见):优化后的输出或调整后的方法随后可以被执行,并且 Reflection 过程可以重复,直到达到满意的结果或满足停止条件。

Reflection 模式的一个关键且高效的实现方式是将过程分为两个不同的逻辑角色:Producer(生产者)和 Critic(批评者)。这通常被称为"Generator-Critic"或"Producer-Reviewer"模型。虽然单个 agent 可以执行自我反思,但使用两个专门的 agent(或两个具有不同系统提示的独立 LLM 调用)通常会产生更稳健和无偏见的结果。

  1. Producer Agent:该 agent 的主要职责是执行任务的初始执行。它完全专注于生成内容,无论是编写代码、起草博客文章还是创建计划。它接收初始提示并生成输出的第一个版本。
  2. Critic Agent:该 agent 的唯一目的是评估 Producer 生成的输出。它被赋予一组不同的指令,通常是一个不同的人设(例如,"你是一位高级软件工程师","你是一位一丝不苟的事实核查员")。Critic 的指令指导它根据特定标准(如事实准确性、代码质量、风格要求或完整性)来分析 Producer 的工作。它被设计用来发现缺陷、提出改进建议,并提供结构化的反馈。

这种关注点分离非常强大,因为它避免了 agent 审查自己工作时的"认知偏见"。Critic agent 以全新的视角审视输出,完全专注于发现错误和改进空间。来自 Critic 的反馈随后被传递回 Producer agent,Producer 将其作为指南来生成新的、优化后的输出版本。所提供的 LangChain 和 ADK 代码示例都实现了这种双 agent 模型:LangChain 示例使用特定的"reflector_prompt"来创建 critic 人设,而 ADK 示例明确定义了 producer 和 reviewer agent。

实现 Reflection 通常需要构建 agent 的工作流以包含这些反馈循环。这可以通过代码中的迭代循环来实现,或者使用支持状态管理和基于评估结果进行条件转换的框架。虽然单步评估和优化可以在 LangChain/LangGraph、ADK 或 Crew.AI 链中实现,但真正的迭代 Reflection 通常需要更复杂的编排。

Reflection 模式对于构建能够产生高质量输出、处理细微任务并展现出一定程度自我意识和适应性的 agent 至关重要。它将 agent 从仅仅执行指令推向了更复杂的问题解决和内容生成形式。

Reflection 与目标设定和监控(见第11章)的交汇点值得关注。目标为 agent 的自我评估提供了终极基准,而监控则跟踪其进展。在许多实际案例中,Reflection 可以作为纠正引擎,利用监控到的反馈来分析偏差并调整其策略。这种协同作用将 agent 从被动的执行者转变为有目的的系统,能够自适应地努力实现其目标。

此外,当 LLM 保留对话记忆(见第8章)时,Reflection 模式的效果会显著增强。对话历史为评估阶段提供了关键的上下文,使 agent 不仅能够孤立地评估其输出,还能在之前交互、用户反馈和不断演变的目标背景下进行评估。它使 agent 能够从过去的批评中学习并避免重复错误。没有记忆,每次 Reflection 都是一个独立的事件;有了记忆,Reflection 成为一个累积过程,每个循环都建立在上一个循环的基础上,从而实现更智能和更具上下文感知的优化。

实际应用与用例

Reflection 模式在输出质量、准确性或对复杂约束的遵循至关重要的场景中非常有价值:

1. 创意写作与内容生成:

优化生成的文本、故事、诗歌或营销文案。

  • 用例:一个撰写博客文章的 agent。
    • Reflection:生成初稿,对其流畅性、语气和清晰度进行批评,然后根据批评进行重写。重复直到文章达到质量标准。
    • 优势:产生更精炼、更有效的内容。

2. 代码生成与调试:

编写代码,识别错误并修复它们。

  • 用例:一个编写 Python 函数的 agent。
    • Reflection:编写初始代码,运行测试或静态分析,识别错误或低效之处,然后根据发现的问题修改代码。
    • 优势:生成更健壮、更功能完善的代码。

3. 复杂问题解决:

在多步推理任务中评估中间步骤或提出的解决方案。

  • 用例:一个解决逻辑谜题的 agent。
    • Reflection:提出一个步骤,评估它是否更接近解决方案或引入矛盾,如有需要则回溯或选择不同的步骤。
    • 优势:提高 agent 在复杂问题空间中导航的能力。

4. 摘要与信息综合:

优化摘要的准确性、完整性和简洁性。

  • 用例:一个总结长文档的 agent。
    • Reflection:生成初始摘要,将其与原始文档中的要点进行比较,优化摘要以包含缺失的信息或提高准确性。
    • 优势:创建更准确、更全面的摘要。

5. 规划与策略:

评估提出的计划并识别潜在的缺陷或改进空间。

  • 用例:一个为达成目标而规划一系列行动的 agent。
    • Reflection:生成计划,模拟其执行或根据约束条件评估其可行性,根据评估修改计划。
    • 优势:制定更有效、更现实的计划。

6. 对话式 agent:

审查对话中的先前轮次以保持上下文、纠正误解或提高响应质量。

  • 用例:一个客户支持聊天机器人。
    • Reflection:在用户回复后,审查对话历史和最后生成的消息,以确保连贯性并准确回应用户的最新输入。
    • 优势:实现更自然、更有效的对话。

Reflection 为 agentic 系统增加了一层元认知能力,使它们能够从自身的输出和过程中学习,从而产生更智能、更可靠、更高质量的结果。

实战代码示例(LangChain)

实现一个完整的迭代 Reflection 过程需要状态管理和循环执行的机制。虽然这些在基于图的框架(如 LangGraph)中通过自定义程序代码原生处理,但单次 Reflection 循环的基本原理可以使用 LCEL(LangChain Expression Language)的组合语法来有效演示。本示例使用 Langchain 库和 OpenAI 的 GPT-4o 模型实现了一个 Reflection 循环,以迭代生成和优化一个计算数字阶乘的 Python 函数。该过程从任务提示开始,生成初始代码,然后根据模拟高级软件工程师角色的批评反复对代码进行反思,在每次迭代中优化代码,直到批评阶段确定代码完美或达到最大迭代次数。最后,它打印最终优化后的代码。

首先,确保你已安装必要的库:

bash
pip install langchain langchain-community langchain-openai

你还需要为所选的语言模型(例如 OpenAI、Google Gemini、Anthropic)设置环境变量中的 API key。

python
import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.messages import SystemMessage, HumanMessage # --- Configuration --- # Load environment variables from .env file (for OPENAI_API_KEY) load_dotenv() # Check if the API key is set if not os.getenv("OPENAI_API_KEY"): raise ValueError("OPENAI_API_KEY not found in .env file. Please add it.") # Initialize the Chat LLM. We use gpt-4o for better reasoning. # A lower temperature is used for more deterministic outputs. llm = ChatOpenAI(model="gpt-4o", temperature=0.1) def run_reflection_loop(): """ Demonstrates a multi-step AI reflection loop to progressively improve a Python function. """ # --- The Core Task --- task_prompt = """ Your task is to create a Python function named `calculate_factorial`. This function should do the following: 1. Accept a single integer `n` as input. 2. Calculate its factorial (n!). 3. Include a clear docstring explaining what the function does. 4. Handle edge cases: The factorial of 0 is 1. 5. Handle invalid input: Raise a ValueError if the input is a negative number. """ # --- The Reflection Loop --- max_iterations = 3 current_code = "" # We will build a conversation history to provide context in each step. message_history = [HumanMessage(content=task_prompt)] for i in range(max_iterations): print("\n" + "="*25 + f" REFLECTION LOOP: ITERATION {i + 1} " + "="*25) # --- 1. GENERATE / REFINE STAGE --- # In the first iteration, it generates. In subsequent iterations, it refines. if i == 0: print("\n>>> STAGE 1: GENERATING initial code...") # The first message is just the task prompt. response = llm.invoke(message_history) current_code = response.content else: print("\n>>> STAGE 1: REFINING code based on previous critique...") # The message history now contains the task, # the last code, and the last critique. # We instruct the model to apply the critiques. message_history.append(HumanMessage(content="Please refine the code using the critiques provided.")) response = llm.invoke(message_history) current_code = response.content print("\n--- Generated Code (v" + str(i + 1) + ") ---\n" + current_code) message_history.append(response) # Add the generated code to history # --- 2. REFLECT STAGE --- print("\n>>> STAGE 2: REFLECTING on the generated code...") # Create a specific prompt for the reflector agent. # This asks the model to act as a senior code reviewer. reflector_prompt = [ SystemMessage(content=""" You are a senior software engineer and an expert in Python. Your role is to perform a meticulous code review. Critically evaluate the provided Python code based on the original task requirements. Look for bugs, style issues, missing edge cases, and areas for improvement. If the code is perfect and meets all requirements, respond with the single phrase 'CODE_IS_PERFECT'. Otherwise, provide a bulleted list of your critiques. """), HumanMessage(content=f"Original Task:\n{task_prompt}\n\nCode to Review:\n{current_code}") ] critique_response = llm.invoke(reflector_prompt) critique = critique_response.content # --- 3. STOPPING CONDITION --- if "CODE_IS_PERFECT" in critique: print("\n--- Critique ---\nNo further critiques found. The code is satisfactory.") break print("\n--- Critique ---\n" + critique) # Add the critique to the history for the next refinement loop. message_history.append(HumanMessage(content=f"Critique of the previous code:\n{critique}")) print("\n" + "="*30 + " FINAL RESULT " + "="*30) print("\nFinal refined code after the reflection process:\n") print(current_code) if __name__ == "__main__": run_reflection_loop()

代码首先设置环境、加载 API key,并初始化一个强大的语言模型(如 GPT-4o),使用较低的温度以获得更聚焦的输出。核心任务由一个提示定义,要求创建一个计算数字阶乘的 Python 函数,包括对 docstring、边缘情况(0的阶乘)和负数输入错误处理的具体要求。run_reflection_loop 函数编排迭代优化过程。在循环中,第一次迭代时语言模型根据任务提示生成初始代码。在后续迭代中,它根据上一步的批评来优化代码。一个单独的"reflector"角色(也由语言模型扮演,但使用不同的系统提示)充当高级软件工程师,根据原始任务要求对生成的代码进行批评。此批评以问题列表的形式提供,或者如果未发现问题则使用短语 'CODE_IS_PERFECT'。循环持续进行,直到批评表明代码完美或达到最大迭代次数。对话历史在每一步中被维护并传递给语言模型,为生成/优化和反思阶段提供上下文。最后,脚本在循环结束后打印最后生成的代码版本。

实战代码示例(ADK)

现在让我们看一个使用 Google ADK 实现的概念性代码示例。具体来说,该代码通过采用 Generator-Critic 结构来展示这一点,其中一个组件(Generator)生成初始结果或计划,另一个组件(Critic)提供关键反馈或批评,引导 Generator 生成更优化或更准确的最终输出。

python
from google.adk.agents import SequentialAgent, LlmAgent # The first agent generates the initial draft. generator = LlmAgent( name="DraftWriter", description="Generates initial draft content on a given subject.", instruction="Write a short, informative paragraph about the user's subject.", output_key="draft_text" # The output is saved to this state key. ) # The second agent critiques the draft from the first agent. reviewer = LlmAgent( name="FactChecker", description="Reviews a given text for factual accuracy and provides a structured critique.", instruction=""" You are a meticulous fact-checker. 1. Read the text provided in the state key 'draft_text'. 2. Carefully verify the factual accuracy of all claims. 3. Your final output must be a dictionary containing two keys: - "status": A string, either "ACCURATE" or "INACCURATE". - "reasoning": A string providing a clear explanation for your status, citing specific issues if any are found. """, output_key="review_output" # The structured dictionary is saved here. ) # The SequentialAgent ensures the generator runs before the reviewer. review_pipeline = SequentialAgent( name="WriteAndReview_Pipeline", sub_agents=[generator, reviewer] ) # Execution Flow: # 1. generator runs -> saves its paragraph to state['draft_text']. # 2. reviewer runs -> reads state['draft_text'] and saves its dictionary output to state['review_output'].

这段代码演示了在 Google ADK 中使用顺序 agent 管道来生成和审查文本。它定义了两个 LlmAgent 实例:generator 和 reviewer。generator agent 被设计为在给定主题上创建初始草稿段落。它被指示编写一段简短且信息丰富的文本,并将其输出保存到状态键 draft_text。reviewer agent 充当 generator 生成文本的事实核查员。它被指示从 draft_text 中读取文本并验证其事实准确性。reviewer 的输出是一个包含两个键的结构化字典:statusreasoningstatus 指示文本是"ACCURATE"还是"INACCURATE",而 reasoning 为该状态提供解释。此字典被保存到状态键 review_output。创建了一个名为 review_pipeline 的 SequentialAgent 来管理两个 agent 的执行顺序。它确保 generator 首先运行,然后是 reviewer。整体执行流程是 generator 生成文本,然后将其保存到状态中。随后,reviewer 从状态中读取该文本,执行事实核查,并将其发现(状态和推理)保存回状态中。此管道允许使用单独的 agent 进行结构化的内容创建和审查流程。

注意:对于感兴趣的用户,也可以使用 ADK 的 LoopAgent 进行替代实现。

在结束之前,需要考虑的是,虽然 Reflection 模式显著提高了输出质量,但它也伴随着重要的权衡。迭代过程虽然强大,但会导致更高的成本和延迟,因为每次优化循环可能需要一次新的 LLM 调用,使其不适合对时间敏感的应用。此外,该模式对内存的需求很大;随着每次迭代,对话历史不断扩展,包括初始输出、批评和后续的优化。

一览

是什么:agent 的初始输出往往不是最优的,可能存在不准确、不完整或未能满足复杂要求的问题。基本的 agentic 工作流缺乏一个内置机制让 agent 识别和纠正自身错误。解决方案是让 agent 评估自己的工作,或者更稳健地引入一个单独的逻辑 agent 充当批评者,防止初始响应无论质量如何都成为最终输出。

为什么:Reflection 模式通过引入自我纠正和优化机制来提供解决方案。它建立了一个反馈循环,其中"producer"agent 生成输出,然后"critic"agent(或 producer 自身)根据预定义标准对其进行评估。然后使用该批评来生成改进的版本。这种生成、评估和优化的迭代过程逐步提高最终结果的质量,从而产生更准确、更连贯、更可靠的输出。

经验法则:当最终输出的质量、准确性和细节比速度和成本更重要时,使用 Reflection 模式。它特别适用于生成精炼的长篇内容、编写和调试代码以及创建详细计划等任务。当任务需要高客观性或专业化评估(而通用 producer agent 可能会遗漏这些评估)时,使用单独的 critic agent。

视觉总结

Reflection 设计模式,自我反思

Reflection 设计模式,producer 和 critique agent

关键要点

  • Reflection 模式的主要优势是能够迭代地自我纠正和优化输出,从而显著提高质量、准确性以及对复杂指令的遵循程度。
  • 它涉及一个执行、评估/批评和优化的反馈循环。Reflection 对于需要高质量、准确或细微输出的任务至关重要。
  • 一种强大的实现方式是 Producer-Critic 模型,其中一个单独的 agent(或通过提示定义的角色)评估初始输出。这种关注点分离增强了客观性,并允许更专业化、结构化的反馈。
  • 然而,这些好处是以增加延迟和计算开销为代价的,同时还有超出模型上下文窗口或被 API 服务限流的高风险。
  • 虽然完整的迭代 Reflection 通常需要有状态的工作流(如 LangGraph),但单步 Reflection 可以使用 LangChain 中的 LCEL 来实现,将输出传递给批评和后续优化。
  • Google ADK 可以通过顺序工作流来促进 Reflection,其中一个 agent 的输出由另一个 agent 进行批评,从而允许后续的优化步骤。
  • 该模式使 agent 能够执行自我纠正并随时间提高其性能。

结论

Reflection 模式为 agent 工作流中的自我纠正提供了一个关键机制,使迭代改进超越单次执行。这是通过创建一个循环来实现的,在该循环中系统生成输出,根据特定标准对其进行评估,然后使用该评估产生优化后的结果。此评估可以由 agent 自身执行(自我反思),或者通常更有效的是由一个独立的 critic agent 执行,这代表了该模式中的一个关键架构选择。

虽然完全自主的多步 Reflection 过程需要一个健壮的状态管理架构,但其核心原理在一个生成-批评-优化循环中得到了有效展示。作为一种控制结构,Reflection 可以与其他基础模式相结合,构建更健壮和功能更复杂的 agentic 系统。

参考资料

以下是一些关于 Reflection 模式和相关概念的进一步阅读资源:

  1. Training Language Models to Self-Correct via Reinforcement Learning, https://arxiv.org/abs/2409.12917
  2. LangChain Expression Language (LCEL) Documentation: https://python.langchain.com/docs/introduction/
  3. LangGraph Documentation: https://www.langchain.com/langgraph
  4. Google Agent Developer Kit (ADK) Documentation (Multi-Agent Systems): https://google.github.io/adk-docs/agents/multi-agents/