《Agentic Design Patterns:构建智能系统的实战指南》- 第四章 反思

书籍名称:Agentic Design Patterns: A Hands-On Guide to Building Intelligent Systems
本书作者:Antonio Gulli
链接地址:https://docs.google.com/document/d/1rsaK53T3Lg5KoGwvf8ukOUvbELRtH-V0LnOIFDxBryE
内容摘要:本文是对《智能体设计模式》一书第四章节的翻译,此章节主要介绍了反思(Reflection)模式。
翻译:煤矿工厂

摘要

反思模式是什么

一个智能体的初始输出往往不是最好的,可能存在不准确、不完整,或者未能满足复杂需求的缺陷。基础的智能体工作流通常没有内置的机制让智能体自己识别并修正其错误。通过让智能体评估自身的工作,或者更为稳妥地引入一个独立的逻辑智能体作为批评者,可以解决这个问题,从而避免初始输出即为最终结果。

为什么要用反思

反思(Reflection) 模式通过引入自我修正和完善的机制,建立了一个反馈循环。在这个循环中,生成智能体首先生成输出,然后批评智能体(或生成者本身)根据预定标准对其进行评估。评估的结果将用于生成改进版的回答。这个生成、评估和完善的迭代过程,逐步提升了最终结果的质量,从而产生更准确、更连贯、更可靠的输出。

经验法则

当最终输出的质量准确性细节速度成本更为重要时,可以使用反思模式。它特别适用于生成精细的长篇内容编写和调试代码、以及创建详细计划等任务。在任务需要高度客观专业评估时,使用独立的批评者会更有效,因为普通的生成智能体可能会遗漏这些细节。

《Agentic Design Patterns:构建智能系统的实战指南》- 第四章 反思
图1:使用生成智能体的自反思模式示意图
《Agentic Design Patterns:构建智能系统的实战指南》- 第四章 反思
图2:使用生成智能体和批评智能体的完整反思模式示意图

反思模式概述

在前几章中,我们探讨了几个基础的智能体模式:提示链(Chaining) 用于顺序执行,路由(Routing) 用于动态路径选择,并行化(Parallelization) 用于并发任务执行。这些模式使得智能体能够更高效、灵活地执行复杂任务。然而,即使是在非常复杂的工作流设计下,一个智能体的初始输出或计划也可能并不完美、准确或完整。这时,反思模式(Reflection) 便起到了至关重要的作用。

反思模式是智能体评估自身的工作、输出或内部状态,并利用这一评估来提升其表现或精炼回应的步骤。这是一种自我修正自我提升的过程,允许智能体基于反馈、自我批评或与期望标准的对比,逐步改进输出、调整方法。反思步骤有时可以通过一个专门的智能体来实现。

与简单的顺序链式执行(输出直接传递到下一个步骤)或路由(选择路径)不同,反思引入了一个反馈循环。智能体不仅仅是生成输出,它还会检查该输出或生成该输出的过程,识别潜在问题和改进点,并基于这些洞察生成更好的结果或修改未来的行动。

反思过程通常包括以下步骤:

1. 执行(Execution):智能体执行任务或生成初步输出。

2. 评估/批评(Evaluation/Critique):智能体(通常使用另一个 LLM 或另一组规则)分析上一阶段的结果。这个评估可能检查事实准确性、一致性、风格、完整性、是否遵循指令或其他相关标准。

3. 反思/精炼(Reflection/Refinement):根据评估结果,智能体决定如何改进。这可能涉及生成精炼后的输出、调整下一步的参数,甚至修改整体计划。

4. 迭代(Iteration)(常见选项):重新运用改进后的输出或调整后的方法,重复反思过程,直到得到满意的结果或满足停止条件为之。

生产者与批评者模型

反思模式的一个重要且高效的实现方式是将过程分为两个独立的逻辑角色:生成者(Producer)批评者(Critic)。这通常被称为生成器-批评者(Generator-Critic) 或 生产者-审阅者(Producer-Reviewer) 模型。虽然单个智能体也可以执行自我反思,但使用两个专门的智能体(或两个具有不同系统提示的 LLM 调用)通常能产生更强健、无偏差的结果。

1. 生成智能体:该智能体的主要职责是执行任务的初步操作。它专注于生成内容,比如编写代码、撰写博客文章、制定计划。它接受初步提示并生成输出的第一版本。

2. 批评智能体:该智能体的唯一任务是评估生产者生成的输出。它会接受一组不同的指令,通常具有与生产者不同的角色设定(例如:“你是高级软件工程师”,“你是严谨的事实检查员”)。批评者的指令引导它根据特定标准分析生产者的工作,如事实准确性、代码质量、风格要求或完整性。它旨在找出缺陷、提出改进意见,并提供结构化反馈。

这种角色分离设计的很重要,因为它避免了智能体在审阅自己工作时可能存在的认知偏差。批评者智能体能够以全新的视角审视输出,专注于寻找错误和改进点。批评者的反馈随后会传递给生产者智能体,生产者智能体根据这些反馈生成新的、更精炼的版本。

LangChain 和 ADK 的代码示例都实现了这一双智能体模型:LangChain 示例使用了特定的reflector_prompt来创建批评者角色,而 ADK 示例则明确地定义了生产者和审阅者智能体。

实现反思通常需要将智能体的工作流结构化以包含这些反馈循环。这可以通过代码中的迭代循环实现,或者使用支持状态管理基于评估结果的条件转换的框架。虽然 LangChain/LangGraph、ADK 或 Crew.AI 中可以实现单步的评估与精炼,但真正的迭代反思通常需要更复杂的协调和流程管理。

反思模式对于构建能够产生高质量输出、可以处理复杂任务、包含一定自我意识与适应性的智能体至关重要。它将智能体从单纯执行指令推向更为复杂的问题解决和内容生成形式。

值得注意的是,反思与目标设定和过程监控(参见第11章)之间存在着密切的联系。目标为智能体的自我评估提供了最终的参照标准,而监控则用于跟踪其执行过程中的进展。在许多实际场景中,反思机制利用监控反馈来分析偏差,并据此调整策略,从而充当了校正引擎的角色。通过这种协同作用,智能体从一个被动执行指令的系统,转变为一个能够主动调整、灵活适应、并有目的地朝着目标前进的智能系统。

此外,当 LLM 保持对话的记忆时(详见第八章),反思模式的效果会显著增强。这种对话历史为评估阶段提供了重要的上下文,使得智能体可以不仅仅从孤立的角度去评估输出,可以进一步结合以往的互动、用户反馈和不断发展的目标。它使得智能体能够从过去的批评中学习,避免重复错误。如果没有记忆,每次反思都是一次独立的事件;而有了记忆,反思便成为一个累积的过程,每个循环都建立在上一个循环之上,带来更智能和更具上下文意识的精炼。

实践代码

要实现一个完整的、可迭代的反思过程,必须具备状态管理循环执行的机制。这些机制可以通过图结构框架(如 LangGraph)原生支持,或通过自定义的过程式代码实现。不过,即使不依赖复杂框架,单次反思循环的基本原理也可以使用 LCEL(LangChain Expression Language) 的组合语法清晰地演示出来。

LangChain

下面的示例展示了如何使用 LangChain 库和 OpenAI 的 GPT-4o 模型 实现一个反思循环: 智能体会迭代地生成并优化一个用于计算阶乘的 Python 函数,整个流程如下:

  1. 从任务提示开始,生成初始代码。
  2. 然后通过一个模拟的“高级软件工程师”角色进行代码审查(批评阶段)。
  3. 根据批评意见,智能体对代码进行改进。
  4. 这个生成—反思—改进的循环会持续执行,直到审查阶段认为代码已经完美,或者达到预设的最大迭代次数为止。
  5. 最终输出经过多次优化的函数代码。

在开始前,请确保安装以下必要的依赖库:

pip install langchain langchain-community langchain-openai

此外,你还需要为所选语言模型(如 OpenAIGoogle Gemini 或 Anthropic)设置环境变量以配置 API 密钥。

代码示例:

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

# --- 配置部分 ---
# 从 .env 文件中加载环境变量(用于 OPENAI_API_KEY)
load_dotenv()

# 检查 API 密钥是否已设置
ifnot os.getenv("OPENAI_API_KEY"):
   raise ValueError("在 .env 文件中未找到 OPENAI_API_KEY,请添加。")

# 初始化 Chat LLM。这里使用 gpt-4o 模型以获得更好的推理能力。
# 设置较低的 temperature 以使输出更具确定性。
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)

def run_reflection_loop():
   """
   演示一个多步骤的 AI 反思循环,用于逐步改进一个 Python 函数。
   """
   # --- 核心任务 ---
   task_prompt = """
   你的任务是创建一个名为 `calculate_factorial` 的 Python 函数。
   该函数应满足以下要求:
   1. 接受一个整数参数 `n`。
   2. 计算它的阶乘(n!)。
   3. 包含一个清晰的文档字符串,说明函数的功能。
   4. 处理边界情况:0 的阶乘应为 1。
   5. 处理无效输入:若输入为负数,应抛出 ValueError。
   """
   # --- 反思循环 ---
   max_iterations = 3
   current_code = ""
   # 构建消息历史,以便在每一步提供上下文信息
   message_history = [HumanMessage(content=task_prompt)]

   for i in range(max_iterations):
       print("\n" + "="*25 + f" 反思循环:第 {i + 1} 次迭代 " + "="*25)

       # --- 1. 生成 / 优化阶段 ---
       # 第一次迭代生成代码,之后的迭代基于反馈进行优化
       if i == 0:
           print("\n>>> 阶段 1:生成初始代码...")
           # 第一次只需要任务提示
           response = llm.invoke(message_history)
           current_code = response.content
       else:
           print("\n>>> 阶段 1:根据上次批评意见改进代码...")
           # 消息历史中包含任务、上次的代码及其批评
           # 我们要求模型根据批评进行改进
           message_history.append(HumanMessage(content="请根据提供的批评意见改进代码。"))
           response = llm.invoke(message_history)
           current_code = response.content

       print("\n--- 生成的代码 (版本 " + str(i + 1) + ") ---\n" + current_code)
       message_history.append(response)  # 将生成的代码加入历史记录

       # --- 2. 反思阶段 ---
       print("\n>>> 阶段 2:对生成的代码进行反思...")

       # 为“反思代理”创建专用提示
       # 模型将在此阶段扮演高级代码审查工程师
       reflector_prompt = [
           SystemMessage(content="""
               你是一名资深软件工程师,精通 Python。
               你的任务是对给定的 Python 代码进行细致的代码审查。
               请根据原始任务要求,严格检查以下内容:
               - 是否存在错误;
               - 是否符合代码风格;
               - 是否处理了边界情况;
               - 是否有改进空间。
               如果代码完全符合要求,请仅回复 "CODE_IS_PERFECT"。
               否则,请以项目符号(•)形式列出你的批评意见。
           """),
           HumanMessage(content=f"原始任务:\n{task_prompt}\n\n待审查代码:\n{current_code}")
       ]

       critique_response = llm.invoke(reflector_prompt)
       critique = critique_response.content

       # --- 3. 停止条件 ---
       if"CODE_IS_PERFECT"in critique:
           print("\n--- 批评结果 ---\n未发现进一步问题,代码已令人满意。")
           break

       print("\n--- 批评结果 ---\n" + critique)
       # 将批评内容添加到历史中,用于下一轮改进
       message_history.append(HumanMessage(content=f"上次代码的批评意见:\n{critique}"))

   print("\n" + "="*30 + " 最终结果 " + "="*30)
   print("\n反思过程结束后得到的最终优化代码:\n")
   print(current_code)

if __name__ == "__main__":
   run_reflection_loop()

代码解释:

这段代码首先进行环境配置,加载 API 密钥,并初始化一个、语言模型(GPT-4o),其温度参数被设为较低值,以获得更专注、稳定的输出结果。 核心任务由一个提示词(prompt)定义,要求生成一个用于计算数字阶乘的 Python 函数。该函数需满足特定要求,包括编写清晰的文档字符串(docstring)、正确处理边界情况(例如 0 的阶乘),以及对负数输入进行错误处理(抛出异常)。run_reflection_loop 函数负责协调整个迭代优化过程。在循环中,模型在第一次迭代时根据任务提示生成初始代码;在随后的迭代中,它会根据上一轮批评阶段的反馈对代码进行改进。

反思环节由同一个语言模型扮演不同角色来完成。在这里,GPT-4o充当“资深软件工程师”,以另一种系统提示身份对生成的代码进行审查,依据原始任务要求给出批评。反馈形式可能是一系列以项目符号列出的改进意见,或者在没有问题时,仅返回短语 “CODE_IS_PERFECT”。 循环会持续执行,直到批评结果表明代码已完美,或达到预设的最大迭代次数为止。在整个过程中,代码通过维护一份对话历史(message_history),为每一步的生成、改进与反思阶段提供上下文信息。最终,脚本会输出反思循环结束后得到的最终版本代码。

Google ADK

现在我们来看一个使用 Google ADK 实现的概念性代码示例。 该示例通过 生成者-批评者(Generator-Critic)结构 展示了这一模式:其中生成者(Generator)负责生成初始结果或计划,而批评者(Critic)则提供批评性反馈,引导生成者不断改进,最终得到更精确更完善的输出。

代码示例:

from google.adk.agents import SequentialAgent, LlmAgent

# 第一个智能体生成初稿。
generator = LlmAgent(
   name="DraftWriter",
   description="根据给定主题生成初稿内容。",
   instruction="写一段关于用户主题的简短、有信息量的段落。",
   output_key="draft_text"# 输出保存到此状态键中。
)

# 第二个智能体批评并检查第一个智能体的初稿。
reviewer = LlmAgent(
   name="FactChecker",
   description="审查给定文本的事实准确性并提供结构化的批评。",
   instruction=""" 
   你是一个细致的事实检查员。
   1. 阅读状态键'draft_text'中的文本。
   2. 仔细验证所有声明的事实准确性。
   3. 你的最终输出必须是一个包含两个键的字典:
      - "status":一个字符串,值为"ACCURATE"或"INACCURATE"。
      - "reasoning":一个字符串,提供清晰的解释,说明你的状态,若发现问题,需具体列举。
   """,
   output_key="review_output"# 结构化的字典保存到这里。
)

# SequentialAgent确保生成器在审查者之前运行。
review_pipeline = SequentialAgent(
   name="WriteAndReview_Pipeline",
   sub_agents=[generator, reviewer]
)

# 执行流程:
# 1. generator 运行 -> 将其段落保存到 state['draft_text']。
# 2. reviewer 运行 -> 读取 state['draft_text'] 并将其字典输出保存到 state['review_output']。

这段代码演示了在 Google ADK 中使用顺序智能体管道生成和审查文本的过程。它定义了两个LlmAgent实例:generator(生成器)和 reviewer(批评者)。生成器智能体的设计目的是根据给定的主题创建初步的段落草稿。它被指示写一段简短而富有信息量的文本,并将其输出保存到状态键 draft_text 中。批评者智能体充当事实检查员,负责验证生成器生成文本的事实准确性。审查者被指示从 draft_text 中读取文本并验证其准确性。审查者的输出是一个结构化的字典,包含两个键:status 和 reasoningstatus 指示文本是否为 “ACCURATE”(准确)或 “INACCURATE”(不准确),而 reasoning 提供关于该状态的解释。这个字典被保存到状态键 review_output 中。

代码随后创建了一个名为 review_pipeline 的结构SequentialAgent,用于管理这两个智能体的执行顺序。它确保先运行生成器,然后运行批评者,确保整体执行流程是:生成器生成文本,并将其保存到状态中,批评者从状态中读取该文本,进行事实检查,并将结果(状态和解释)保存回状态。这个管道允许使用独立的智能体进行结构化的内容创建和审查。

注意:也可以使用 ADK 的 LoopAgent 来实现类似的功能。

最后,需要指出的是,尽管反思模式显著提高了输出质量,但它也带来了一些重要的权衡。这个迭代过程虽然强大,但可能导致更高的成本和延迟,因为每次优化循环可能都需要新的 LLM 调用,这使得它在时间敏感的应用场景中不太理想。此外,该模式也很耗内存;随着每次迭代,聊天历史会扩展,需要包含初始输出、批评和每一步的优化记录。

本章要点

  • 反思模式的主要优势在于能够通过迭代自我修正和完善输出,从而显著提高结果的质量、准确性,并更好地遵循复杂指令。
  • 该模式使智能体能够执行自我修正,并随着时间提升其性能。
  • 它包含一个执行、评估/批评和改进的反馈循环,适用于需要高质量、精确或细致输出的任务。
  • 一种实现方式是生产者-批评者(Producer-Critic) 模型,其中独立的智能体(或同一个智能体,不同的的角色提示)对初始输出进行评估。这种职责分离增强了 客观性,并允许提供更专业、结构化的反馈。
  • 但是,这些好处伴随着更高的延迟和计算成本,存在超出模型上下文窗口或被 API 限流的风险。
  • 虽然完整的迭代反思通常需要有状态的工作流(如 LangGraph),但在 LangChain 中也可以通过 LCEL 实现单次反思步骤,将输出传递以供批评和随后的改进。Google ADK 可以通过顺序工作流支持反思,其中一个智能体的输出由另一个智能体进行批评,从而允许后续的改进步骤。

总结

反思模式为智能体工作流提供了关键的自我修正机制,使其能够超越单次执行,实现迭代改进。这是通过创建一个循环实现的:系统生成输出、基于特定标准进行评估、利用该评估生成优化的结果。评估可以由智能体自身执行(自我反思),也可以由独立的批评者智能体执行。后者往往更为高效,并构成该模式的关键架构选择。

虽然一个完全自主的多步骤反思过程需要稳健复杂的状态管理架构,但其核心原理就体现在单次“生成-批评-改进”循环中。作为一种控制结构,反思可以与其他基础模式结合,用于构建更稳健且功能更复杂的智能体系统。

参考文献

  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/

往期回顾

《Agentic Design Patterns:构建智能系统的实战指南》- 前言

《Agentic Design Patterns:构建智能系统的实战指南》- 第一章 提示链

《Agentic Design Patterns:构建智能系统的实战指南》- 第二章 路由

《Agentic Design Patterns:构建智能系统的实战指南》- 第三章 并行化

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论