尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

构建具备自我反思能力的智能体:从原理到SDK实现

构建具备自我反思能力的智能体:从原理到SDK实现 1. 项目概述为什么我们需要一个会“自我反思”的Agent在构建智能体Agent系统的过程中我们常常会遇到一个瓶颈当Agent执行一个复杂任务链时一旦某个环节出错或结果偏离预期整个流程就可能卡住或产生无意义的输出。传统的“执行-反馈”模式依赖于外部比如用户来指出错误并重新规划这既不智能也严重限制了Agent的自主性和可靠性。这就好比一个程序员写代码如果编译器不报错他自己也不回头检查那么代码里的逻辑缺陷可能永远发现不了。“自我反思循环”Self-Reflection Loop正是为了解决这个问题而生。它赋予Agent一种内省能力让其能够像人类一样在执行动作后停下来审视自己的输出目标达成了吗结果符合要求吗推理过程有没有漏洞如果发现问题就主动调整策略重新尝试。ReflectionAgent的核心就是将这个“执行-观察-反思-再规划”的循环机制内化到SDK的设计中使其成为一个可复用、可配置的基础组件。这不仅仅是给Agent加一个“后处理”步骤而是从根本上改变其工作模式从单向的线性执行升级为带有负反馈调节的闭环系统。对于需要高可靠性、多步骤推理的应用场景如复杂数据分析、自动化流程编排、动态决策支持等具备自我反思能力的Agent将成为不可或缺的基石。接下来我将拆解如何从零开始在SDK中实现这样一个ReflectionAgent。2. ReflectionAgent 的核心设计思路与架构拆解实现一个有效的自我反思循环关键在于明确三个核心问题反思什么如何评估怎样改进这决定了整个Agent的架构设计。2.1 反思循环的基本工作流程一个标准的ReflectionAgent工作流程可以抽象为以下四个阶段构成一个循环执行ActAgent根据当前计划Plan和上下文Context调用工具或生成内容产生一个输出Action Output。观察ObserveAgent收集执行后的结果包括工具调用的返回结果、环境状态的变化、或生成文本本身。反思Reflect这是核心环节。Agent基于初始目标、历史动作和当前观察结果启动一个反思过程。这个过程通常由一个专门的“反思器”Reflector模块完成其任务是批判性地分析执行是否成功结果质量如何哪里可以做得更好再规划Re-plan根据反思得出的结论Agent调整后续策略。如果反思认为结果完美则循环终止输出最终结果。如果发现错误或不足则生成新的、改进后的计划并跳回“执行”阶段开始新一轮尝试。这个循环可能会进行多次直到达到预设的成功标准或最大迭代次数。设计时我们必须避免无限循环因此需要设置清晰的终止条件。2.2 架构组件设计基于上述流程我们可以将ReflectionAgent拆解为几个核心组件在SDK中以类或模块的形式实现主代理ReflectionAgent统筹全局持有上下文、记忆和历史管理整个反思循环的运转。执行器Executor负责具体的任务执行可以是调用一个语言模型生成文本也可以是调用一个外部工具或函数。反思器Reflector这是实现“智能”反思的关键。它通常本身也是一个轻量级的Agent或一个提示工程Prompt Engineering模块。其输入是目标、历史记录和当前结果输出是一段结构化的反思文本和改进建议。评判器Evaluator可选但推荐用于将反思器的文本输出转化为可量化的决策。例如判断本次执行是“成功”、“部分成功”还是“失败”或者计算一个置信度分数。这可以让循环的决策逻辑是否继续、如何调整更加清晰和可编程。规划器Planner根据反思结论制定或修改下一步的行动计划。在简单场景中规划器可能只是根据反思结论重新生成提示词在复杂场景中它可能需要调整任务分解结构。在SDK设计中我们应该追求高度的模块化和可插拔性。例如用户可以选择使用基于规则Rule-based的简单反思器也可以接入一个强大的LLM作为反思器评判器的阈值可以自定义规划策略也可以替换。2.3 与记忆Memory系统的集成反思离不开记忆。Agent需要记住最初的任务是什么工作记忆我已经尝试过哪些步骤短期记忆从过去的错误中学到了什么长期记忆。因此ReflectionAgent必须与一个健壮的记忆系统紧密集成。工作记忆存储当前循环的上下文包括原始查询、当前目标、已执行步骤列表及其结果。短期记忆存储最近几次反思循环的完整记录用于发现模式性错误。长期记忆可选将成功的反思结论和修正策略向量化存储在未来遇到类似任务时快速调用实现“经验学习”。这能显著提升Agent随使用次数增加而表现出的智能水平。注意记忆的实现需要谨慎避免上下文Context过长导致LLM调用成本剧增或性能下降。通常需要对记忆进行摘要Summarization或选择性检索Retrieval。3. 核心细节解析如何实现“有效”的反思反思环节是整个设计的灵魂。一个流于形式的反思比如只是问“我做得对吗”是无效的。我们必须设计出能够引导深度分析的反思机制。3.1 反思提示词Reflection Prompt的设计技巧如果使用LLM作为反思器提示词的设计至关重要。一个好的反思提示词应该包含以下几个部分角色设定明确告诉模型它现在是一个“严厉的审核员”或“经验丰富的导师”任务是挑刺和改进。任务回顾清晰复述最初的任务目标和要求。执行历史提供之前所有步骤的详细记录做了什么得到了什么结果。反思焦点提出具体、引导性的问题而不是开放式的“你觉得怎么样”。例如“最终输出是否直接、完整地回答了最初的问题”“在推理过程中是否存在逻辑跳跃或未经证实的假设”“所使用的工具或方法是否最适合这个任务有没有更优的选择”“结果的格式、结构是否符合要求”“有没有遗漏任何重要的边界条件或细节”输出格式要求模型以结构化格式输出例如反思结论: [成功/部分成功/失败] 主要问题: 1. ... 2. ... 改进建议: 1. ... 2. ... 下一步行动计划: ...结构化的输出便于后续的评判器解析和自动化决策。实操心得在调试初期可以将反思环节的输出即模型对自己的批判也打印出来这对于我们优化提示词和理解Agent的“思考过程”有巨大帮助。你经常会发现模型能指出一些你都没意识到的潜在问题。3.2 评判器的实现策略评判器的作用是将文本反思转化为动作。有几种实现方式基于规则的评判器解析反思文本中的关键词。例如如果反思文本中出现“错误”、“遗漏”、“不符合”等词则判定为“失败”如果出现“可以优化”、“建议”等词则判定为“部分成功”。这种方式简单快速但不够灵活。基于LLM的评判器用一个小型的、专门的提示词让LLM对本次执行进行评分或分类。例如“基于以下反思给本次任务执行打分1-10分并判断是否需要重新执行。”这种方式更智能但会增加一次API调用和延迟。混合模式先尝试用规则快速判断如果规则无法明确判定如置信度低再fallback到LLM进行评判。这是在成本和效果之间取得平衡的常见做法。在SDK中我们可以提供一个默认的基于简单规则的评判器同时开放接口让用户传入自定义的评判函数以满足不同场景的灵敏度要求。3.3 终止条件与循环控制没有终止条件的循环是危险的。必须设计明确的退出机制成功条件评判器输出“成功”或置信度分数超过某个阈值如0.9。失败条件达到最大迭代次数如5次。这是必须有的安全阀。反思多次后改进建议陷入重复表明Agent可能无法自行解决此问题。执行过程中出现不可恢复的错误如工具调用异常。用户中断SDK应提供在循环过程中接收外部信号如用户输入“停止”的机制。在代码实现中循环控制逻辑通常是一个while循环内部包含act,observe,reflect,evaluate,re-plan的调用并根据评判结果和终止条件决定是break还是continue。4. 实操过程从零编写ReflectionAgent核心代码下面我将以一个相对完整的代码示例展示如何用Python构建一个简化但功能核心的ReflectionAgent类。假设我们已经有一个基础的LLM客户端和一个简单的工具调用框架。4.1 定义核心类与初始化首先我们定义主类并初始化必要的组件。class ReflectionAgent: 一个具备自我反思循环的智能体。 def __init__(self, llm_client, toolsNone, max_iterations3, reflection_prompt_templateNone): 初始化ReflectionAgent。 Args: llm_client: 配置好的LLM客户端对象。 tools: 可用的工具列表每个工具应有 name 和 run 方法。 max_iterations: 最大反思循环次数。 reflection_prompt_template: 自定义的反思提示词模板。 self.llm llm_client self.tools tools or [] self.max_iterations max_iterations # 工作记忆 self.context { original_goal: , history: [], # 记录每一步{step:, action:, observation:, reflection:} current_plan: } # 使用默认或自定义的反思提示词模板 self.reflection_prompt_template reflection_prompt_template or self._get_default_reflection_prompt() def _get_default_reflection_prompt(self): 返回默认的反思提示词模板。 return 你是一个严格的质量评估员。请根据以下信息进行评估 原始任务和目标 {goal} 已执行的历史步骤和结果 {history} 当前轮次的执行动作和输出 {action_output} 请从以下角度进行批判性反思 1. 当前输出是否直接、完整、准确地满足了原始任务目标 2. 在执行过程中是否存在逻辑错误、信息缺失或偏离主题的情况 3. 是否有更高效、更精确的方法来完成这个任务 请以如下格式输出你的反思 反思结论: [成功/部分成功/失败] 主要问题: 1. ... 2. ... (如果没有问题写“无”) 改进建议: 1. ... 2. ... (如果成功写“无”) 下一步行动计划建议: ... 4.2 实现单步执行与反思循环接下来我们实现核心的run方法它封装了整个反思循环。def run(self, goal): 执行给定目标并启动反思循环。 self.context[original_goal] goal self.context[current_plan] f尝试直接完成目标{goal} # 初始简单计划 iteration 0 final_output None while iteration self.max_iterations: iteration 1 print(f\n 反思循环迭代第 {iteration} 次 ) # 1. 执行 (Act) action_output self._act(self.context[current_plan]) print(f执行输出: {action_output}) # 2. 观察 (Observe) - 这里简单记录 observation action_output # 3. 反思 (Reflect) reflection_text self._reflect(goal, self.context[history], observation) print(f反思结果: {reflection_text}) # 解析反思结果这里简化处理实际应用可能需要更复杂的解析 reflection_result self._parse_reflection(reflection_text) # 4. 评估与决策 (Evaluate Decide) if reflection_result.get(conclusion) 成功: print(反思认为任务成功循环终止。) final_output observation break else: print(f反思发现问题: {reflection_result.get(problems)}) # 5. 再规划 (Re-plan) - 基于改进建议生成新计划 new_plan self._replan(reflection_result, self.context[history]) self.context[current_plan] new_plan print(f新计划: {new_plan}) # 将本轮记录存入历史 self.context[history].append({ iteration: iteration, plan: self.context[current_plan], action: action_output, reflection: reflection_result }) if final_output is None: final_output f经过 {self.max_iterations} 次尝试仍未成功。最后输出{action_output} print(达到最大迭代次数循环终止。) return final_output def _act(self, plan): 根据计划执行动作。这里简化为例直接让LLM根据计划生成内容。 # 在实际中这里可能包含工具调用、代码执行等复杂逻辑 prompt f请根据以下计划执行任务{plan} response self.llm.generate(prompt) return response.strip() def _reflect(self, goal, history, action_output): 调用反思器进行反思。 # 格式化历史记录 history_str for h in history: history_str f第{h[iteration]}轮 - 计划{h[plan]}\\n输出{h[action]}\\n反思{h[reflection]}\\n\\n # 填充反思提示词模板 prompt self.reflection_prompt_template.format( goalgoal, historyhistory_str, action_outputaction_output ) reflection self.llm.generate(prompt) return reflection.strip() def _parse_reflection(self, reflection_text): 简单解析反思文本提取结论、问题和建议。 # 这是一个非常简单的基于关键词的解析器实际应用中可能需要正则表达式或LLM再次提取。 result {conclusion: 部分成功, problems: [], suggestions: [], next_plan: } lines reflection_text.split(\\n) for line in lines: if line.startswith(反思结论:): if 成功 in line and 部分 not in line: result[conclusion] 成功 elif 失败 in line: result[conclusion] 失败 elif line.startswith(主要问题:): # 简单提取实际应更健壮 result[problems] [p.strip() for p in line.replace(主要问题:, ).split(;) if p.strip()] elif line.startswith(改进建议:): result[suggestions] [s.strip() for s in line.replace(改进建议:, ).split(;) if s.strip()] elif line.startswith(下一步行动计划建议:): result[next_plan] line.replace(下一步行动计划建议:, ).strip() return result def _replan(self, reflection_result, history): 基于反思结果生成新的计划。 # 如果反思结果中有具体的下一步建议优先使用 if reflection_result[next_plan]: return reflection_result[next_plan] # 否则结合问题和建议让LLM生成新计划 problems_str ; .join(reflection_result[problems]) suggestions_str ; .join(reflection_result[suggestions]) replan_prompt f 之前的尝试遇到了问题{problems_str} 改进建议是{suggestions_str} 原始目标是{self.context[original_goal]} 请基于以上信息制定一个全新的、更有可能成功的行动计划。 行动计划应具体、可执行。 new_plan self.llm.generate(replan_prompt) return new_plan.strip()4.3 使用示例最后我们可以这样使用这个ReflectionAgent# 假设有一个简单的LLM客户端这里用伪代码 class MockLLM: def generate(self, prompt): # 模拟LLM的响应实际中替换为OpenAI、Anthropic等API调用 # 这里为了演示返回一个简单响应 if 反思 in prompt: return 反思结论: 部分成功 主要问题: 1. 输出过于笼统缺乏具体数据支撑2. 未考虑最新的市场变化。 改进建议: 1. 在分析中加入近三年的具体营收增长率2. 提及当前行业的主要挑战。 下一步行动计划建议: 重新生成分析报告重点补充2019-2021年的财务数据对比并加入对供应链挑战的讨论。 else: return 这是一份关于某公司竞争力的分析报告该公司在行业内具有品牌优势。 # 初始化并运行Agent llm MockLLM() agent ReflectionAgent(llm_clientllm, max_iterations3) goal 生成一份关于XYZ科技公司当前市场竞争力的详细分析报告。 result agent.run(goal) print(f\\n最终结果:\\n{result})在这个示例中Agent会在第一次输出较笼统的报告后通过反思发现“缺乏具体数据”和“未考虑最新变化”的问题然后根据改进建议生成一个新的、更具体的计划“补充财务数据讨论供应链挑战”并在下一次循环中执行。如果第二次反思成功则输出最终报告。5. 常见问题与排查技巧实录在实际开发和调试ReflectionAgent的过程中你肯定会遇到各种问题。下面是我总结的一些典型场景和解决思路。5.1 反思循环陷入死循环或无效循环现象Agent反复在相似的问题上打转每次反思都提出类似的小修小补但始终无法达到“成功”标准或者一直在“成功”和“部分成功”之间摇摆。排查与解决检查反思提示词反思提示词是否足够“严厉”和具体如果问题太宽泛如“输出好吗”模型可能只会给出泛泛而谈的肯定。尝试让反思聚焦于可验证的、客观的标准如“是否包含A、B、C三个要素”。审查评判器逻辑评判“成功”的标准是否过于严苛或模糊可以考虑引入量化评分如1-10分并设定一个合理的成功阈值如8分。同时检查解析反思文本的代码是否可靠是否存在误判。引入多样性在再规划阶段如果反思建议不明确可以尝试让LLM生成多个不同的备选计划然后选择一个与历史尝试差异最大的以跳出局部循环。设置差异检测在历史记录中检查最近N次的行动计划或输出是否高度相似。如果相似度超过阈值则强制终止循环或引入一个随机的“探索性”动作。5.2 反思过程显著增加延迟和成本现象每个任务都进行多次LLM调用执行反思导致响应时间变长API费用增加。排查与解决分层反思不是每次执行后都进行“深度反思”。可以设计一个“快速检查”环节使用更短的提示词或启发式规则先判断是否有明显错误。只有快速检查不通过时才触发完整的、耗时的深度反思。缓存反思结果对于常见任务或错误模式可以将成功的反思结论和改进方案缓存起来。当遇到类似任务时直接应用缓存的经验无需再次调用LLM反思。使用更小/更快的模型进行反思反思不一定需要和使用最强大模型来执行任务。可以尝试用更小、更快的模型如GPT-3.5 Turbo相比GPT-4来承担反思工作虽然可能深度稍欠但能极大降低成本。限制最大迭代次数根据业务场景合理设置max_iterations通常2-3次迭代在效果和成本间就能取得较好平衡。5.3 反思结果质量不稳定现象同样的任务有时反思能精准指出问题有时却给出无关或错误的建议。排查与解决提供更丰富的上下文确保在反思提示词中提供给模型的“执行历史”是清晰、完整的。包括每一步的意图、具体动作和原始结果。信息缺失会导致模型“猜”错。结构化输出与后处理要求反思输出严格遵循指定格式如JSON。在代码中增加对输出格式的校验和修复逻辑。如果解析失败可以尝试让模型重试一次或降级到基于规则的简单判断。温度Temperature参数执行任务时可能希望创造性温度稍高但进行反思时更需要确定性、批判性的思维。尝试将反思调用的温度参数设置为0或一个较低的值如0.2。人工反馈回路在关键任务或调试阶段可以将反思结论和改进建议展示给用户确认再将确认后的结果反馈给Agent作为其学习样本。这能逐步提升反思的准确性。5.4 记忆管理导致上下文过长现象随着循环次数增加携带的历史记录越来越长最终可能超出LLM的上下文窗口限制或者导致处理速度变慢、成本升高。排查与解决选择性记忆不要将每一步的完整原始输出都塞进上下文。只存储关键信息步骤的摘要、结果的核心结论、反思的要点。可以为ReflectionAgent实现一个summarize_history方法在每轮结束后对当前历史进行摘要。滑动窗口只保留最近N次循环的详细记录更早的记录则用高度概括的摘要代替。向量化检索如果实现了长期记忆当需要历史参考时不要传入全部历史而是将当前情况向量化从记忆库中检索最相关的几条过去经验即可。一个实用的调试技巧在开发初期实现一个详细的日志系统记录每一轮循环的计划、执行输出、完整反思文本、解析后的反思结果和新计划。将这些日志可视化或保存下来是优化提示词、调整评判逻辑最直接的依据。你会发现很多问题不是出在算法上而是出在给模型的“指令”是否清晰无歧义上。
返回列表