智能体构建的三种经典套路:从零开始理解ReAct、Plan-and-Solve和Reflection

智能体构建的三种经典套路:从零开始理解ReAct、Plan-and-Solve和Reflection

学完大语言模型的基础后,下一步就是让模型"动"起来,也就是构建智能体。智能体的核心很简单:让大模型能调用外部工具(比如搜索引擎、计算器、API),从而完成它自己做不到的事。但怎么组织它的"思考"和"行动"呢?这就像不同的人有不同的做事风格。第四章介绍了三种最经典的构建套路,亲手实现它们,比直接用现成框架更能理解背后的门道。

一、 基础准备:让模型能使用工具

在开始任何一种套路之前,我们得先解决一个基本问题:如何告诉并允许大模型去使用工具?

这主要靠两部分:

  1. 定义工具:就像给模型一个工具箱。每个工具要有明确的名字、用途描述(这个描述至关重要,模型就靠它来判断什么时候用哪个工具)和具体的执行函数。

  2. 设计交互格式 :我们需要和模型约定一个"暗号"。通常让模型的输出包含两部分:Thought (内心独白,解释它为什么这么做)和Action (具体行动指令,比如 Search[关键词])。然后,我们的程序会解析这个Action,调用对应工具,并把工具返回的结果整理成一段清晰的Observation(观察),塞回给模型进行下一步思考。

有了这个基础,三种不同的"做事风格"就可以登场了。


二、 套路一:ReAct ------ 边想边做的"侦探"

核心思想 :模仿人类解决未知问题的过程,采用 思考(Reason)-行动(Act)-观察(Observe) 的循环。模型不会在一开始就定死所有步骤,而是走一步看一步,根据上一步的结果动态调整下一步计划。

工作流程

  1. 接到问题(比如"华为最新手机是什么?")。
  2. 思考:分析问题,决定下一步做什么("我需要搜索最新信息")。
  3. 行动 :执行行动(调用 Search["华为最新手机"])。
  4. 观察:获得搜索结果,并总结成文本。
  5. 带着这个新观察,回到第2步继续思考,直到它认为可以给出最终答案。

好比一个侦探破案:他不会有一个完美的预设剧本,而是根据每一条新线索(观察)来推理(思考)下一步该问谁、查哪里(行动)。

  • 优点:非常灵活,能适应需要探索和外部信息输入的任务(如查天气、搜新闻)。整个过程透明,能看到它的"心路历程"。
  • 缺点:一步步串行进行,可能比较慢;如果模型某一步"想歪了",可能陷入死循环或错误路径。

三、 套路二:Plan-and-Solve ------ 先规划后执行的"建筑师"

核心思想:把"规划"和"执行"彻底分开。先花时间制定一个详细的计划蓝图,然后严格按蓝图执行。

工作流程

  1. 规划阶段 :模型只做一件事------把复杂任务分解成一步步清晰的子任务列表。例如,对于问题"三天共卖出多少苹果?",计划可能是:["计算周二销量", "计算周三销量", "计算总销量"]
  2. 执行阶段:另一个专门的模块,严格按照上面的计划列表,一步步执行。执行每一步时,都知道整体计划和之前步骤的结果。

好比建筑师盖楼:必须先画出完整的设计图纸(规划),然后施工队才能按图施工(执行),不会中途随意改结构。

  • 优点:对于逻辑清晰、可分解的任务(如数学应用题、写报告),结构稳定,目标不容易跑偏。
  • 缺点:计划是静态的,如果执行中发现计划有误或环境变了,难以中途调整。另外,需要为"规划"单独调用一次模型,有额外开销。

四、 套路三:Reflection ------ 反复打磨的"作家"

核心思想 :为智能体加上 "自我反思和修改" 的能力。先出一个初稿,然后自我批判,不断优化。

工作流程

  1. 执行:用任何一种方法(比如ReAct或Plan-and-Solve)生成一个初始结果或方案(比如一段代码、一个答案)。
  2. 反思:让模型(或另一个评审角色)审查这个初稿,找出其中的错误、逻辑漏洞或可改进点,生成具体的"反馈意见"。
  3. 优化:根据初稿和反馈意见,让模型重新生成一个更好的版本。
  4. 可以重复2-3步多次,进行多轮迭代优化。

好比作家写文章:先快速完成初稿,然后通读反思(这里表述不清,那里论据不足),最后修改润色,甚至重写某些段落,直到满意。

  • 优点:能显著提升最终成果的质量,尤其适合对正确性、优雅性要求高的任务(如代码生成、报告撰写)。
  • 缺点:迭代过程耗时更长,计算成本更高。

五、 小结:怎么选?

这三种套路没有绝对的好坏,关键看你的任务是什么:

任务特点 推荐套路 类比
需要查资料、与外部交互,路径不确定 ReAct 侦探查案
逻辑清晰、步骤分明,侧重内部推理 Plan-and-Solve 建筑师施工
对结果质量要求极高,不怕多花时间打磨 Reflection 作家改稿

当然,你也可以组合使用它们。比如,用 Plan-and-Solve 来制定总体策略,用 ReAct 来完成其中需要探索的步骤,最后用 Reflection 来优化整个方案。

亲手实现一遍这些套路,最大的收获不是代码本身,而是真正理解了不同智能体设计背后的权衡:是追求灵活还是稳定?是看重速度还是质量?想清楚这些问题,你就不再只是框架的使用者,而能成为智能体应用的设计者了。

习题


第四章习题 第一题解答

1. 三种范式在"思考"与"行动"的组织方式上的本质区别

这三种范式的核心区别在于如何处理"规划"(思考)与"执行"(行动)的时序关系和反馈机制。

  • ReAct (Reasoning and Acting)

    其本质是 "边想边做,动态调整" 。它将思考与行动紧密耦合在一个循环中(Thought → Action → Observation)。在每个时间步,智能体基于当前所有历史信息进行即时思考,并执行单个行动,然后立即根据行动结果调整下一步的思考。这种范式强调环境适应性和动态纠错能力,规划是渐进式、反应式的。
    形式化表达 : ( t h t , a t ) = π ( q , ( a 1 , o 1 ) , ... , ( a t − 1 , o t − 1 ) ) (th_t, a_t) = \pi(q, (a_1, o_1), \ldots, (a_{t-1}, o_{t-1})) (tht,at)=π(q,(a1,o1),...,(at−1,ot−1))。

  • Plan-and-Solve

    其本质是 "先谋后动,严格执行" 。它将流程明确解耦为两个串行阶段:规划阶段和执行阶段。在规划阶段,智能体一次性生成一个完整的、静态的行动计划 P = π plan ( q ) P = \pi_{\text{plan}}(q) P=πplan(q)。在执行阶段,智能体严格按计划步骤逐一执行 s i = π solve ( q , P , ( s 1 , ... , s i − 1 ) ) s_i = \pi_{\text{solve}}(q, P, (s_1, \dots, s_{i-1})) si=πsolve(q,P,(s1,...,si−1)),每一步的思考主要关注如何完成当前步骤,而非修改全局计划。这种范式强调结构性和目标一致性,规划是前瞻性、一次性的。

  • Reflection

    其本质是 "事后反思,迭代优化" 。它在一次完整的"执行"之后,引入了一个独立的"反思-优化"循环。智能体首先通过某种方法生成一个初始输出("初稿"),然后由一个反思模型对其进行评审,生成结构化反馈 F i = π reflect ( Task , O i ) F_i = \pi_{\text{reflect}}(\text{Task}, O_i) Fi=πreflect(Task,Oi),最后优化模型根据反馈生成改进版输出 O i + 1 = π refine ( Task , O i , F i ) O_{i+1} = \pi_{\text{refine}}(\text{Task}, O_i, F_i) Oi+1=πrefine(Task,Oi,Fi)。这种范式不直接改变"思考-行动"的组织方式,而是为其增加了一个质量提升回路,核心价值在于通过自我批判和迭代来显著提升解决方案的最终质量。


2. 智能家居控制助手的基础架构选择

我会选择 以 ReAct 范式为基础架构,并融合 Reflection 机制

为什么以 ReAct 为基础:

智能家居环境是典型的动态、部分可观察、序贯的环境。用户习惯的"自动调节"意味着智能体需要持续感知环境状态(如时间、温度、光照、人体传感器信号),并根据这些实时观察进行决策。

  • 动态性与实时响应:ReAct 的步进式"感知-思考-行动"循环非常适合处理持续变化的环境。例如,当传感器检测到有人离开房间,智能体需要立即思考并执行关灯、调节空调等动作,这种"边想边做"的模式能保证低延迟响应。
  • 处理不确定性:传感器数据可能有噪声或延迟,用户行为也可能有例外。ReAct 的机制允许智能体根据每一次行动后的新观察来动态调整后续行动,具备很强的环境适应和纠错能力。
  • 多工具协同:控制灯光、空调、窗帘等涉及调用多个不同的工具(设备API)。ReAct 范式天然支持在思考过程中进行工具选择,可以根据复杂的上下文决定调用一个组合动作。

为什么需要融合 Reflection:

"根据用户习惯自动调节"是一个需要长期学习和优化的任务。单纯的 ReAct 擅长即时反应,但缺乏对长期策略的优化能力。

  • 优化习惯模型:可以定期(例如每天深夜)启动一个 Reflection 循环,回顾一天内的所有控制决策、用户手动干预记录以及环境数据。反思模型可以分析这些数据,评估当前习惯学习算法的有效性,并提出优化建议。然后优化模型据此更新内部的习惯模型或策略。
  • 提升决策质量:对于复杂的场景(如"举办聚会"模式),Reflection 可以帮助生成和优化更精细、更节能或更舒适的控制方案,而不仅仅是即时反应。

因此,ReAct 负责日常的实时感知与控制,Reflection 负责周期性的策略与模型优化,两者结合可以构建一个既灵敏又智能的助手。


3. 三种范式的组合使用与混合架构设计

可以。这三种范式并非互斥,它们解决的是智能体工作流中不同层面的问题,可以有机组合。

混合范式架构设计:一个"高级研究与报告生成智能体"

适用场景:需要完成复杂、开放域的研究任务并生成高质量报告,例如"分析量子计算对金融风险管理领域的潜在影响与挑战"。

架构设计:

顶层:Plan-and-Solve 作为总指挥
  • 角色:接收用户复杂任务,进行高层、宏观的任务分解。
  • 输出 :生成一个结构化研究计划,例如:
    1. 阶段一:理解量子计算基本原理与当前发展水平
    2. 阶段二:调研金融风险管理现有技术与痛点
    3. 阶段三:交叉分析量子计算在金融风控的具体应用场景与可行性
    4. 阶段四:识别主要挑战(技术、伦理、监管)
    5. 阶段五:撰写综合分析报告
  • 作用:确保整个复杂任务不偏离主线,有清晰的阶段性目标。
中层:ReAct 作为每个阶段的执行引擎
  • 角色:被分配去执行计划中的每一个具体阶段(子任务)。
  • 工作模式:对于每个子任务,启动一个 ReAct 循环。它会自主思考,调用各种工具(如学术搜索引擎、文献数据库、专业术语解释工具),收集和整合信息,直到完成该阶段的调研目标,输出阶段摘要。
  • 作用:提供探索性、自适应的问题解决能力,灵活获取和整合外部知识。
底层:Reflection 作为每个阶段和最终输出的质量优化器
  • 角色
    • 阶段内反思:在每个 ReAct 阶段执行过程中或结束后,对收集到的信息、初步结论进行反思,评估其相关性、可信度和完整性,可能触发 ReAct 进行补充搜索或修正推理。
    • 阶段间反思:在一个阶段完成后,反思该阶段成果是否充分满足了计划的要求,为进入下一阶段做好准备。
    • 终稿反思:在所有阶段完成后,对初步生成的完整报告进行多维度反思(逻辑连贯性、论据充分性、语言专业性、格式规范性),驱动多轮优化,产生最终的高质量报告。
  • 作用:确保每一个中间步骤和最终输出的深度、准确性和严谨性,克服单一范式的幻觉或浅层问题。

总结

在这个混合架构中,Plan-and-Solve 提供了骨架(规划),ReAct 填充了血肉(执行),Reflection 打磨了品质(优化)。它适用于任何需要系统性规划、深度探索和高质量产出的复杂知识工作场景,如战略咨询、学术研究、复杂技术方案设计等。

习题

习题1:三种范式的本质区别与选择

  1. 三种范式在"思考"与"行动"的组织方式上有什么本质区别?
    • ReAct(思考-行动-观察循环):它的核心是 "交织"。思考和行动在每一步都紧密耦合,像一个实时策略游戏。模型每轮都先"想"一下(分析现状、规划下一步),然后立刻"做",并根据"做"的结果(观察)来调整下一轮的"想"。这是一个动态、适应性的循环。
    • Plan-and-Solve(先规划后执行):它的核心是 "分离"。把"思考"(制定完整计划)和"行动"(执行计划)彻底分成两个阶段,像瀑布流开发模型。先集中所有精力做顶层设计,生成一个步骤清单,然后几乎不带思考地、机械地按清单执行。
    • Reflection(执行-反思-优化):它的核心是 "迭代"。它把"思考"升级为"批判性思考",把"行动"升级为"版本迭代"。首先生成一个版本(执行),然后以一个评审员的视角挑毛病(反思),最后根据反馈生成改进版(优化)。思考服务于质量的递进,而非单步的决策。
  2. 设计"智能家居控制助手",你会选择哪种范式?为什么?
    我会选择 以ReAct为基础,融合Reflection机制。
    • 为什么不是纯Plan-and-Solve? 家居环境是动态、部分可观察的。用户习惯会变,传感器数据(如温度、光照)实时变化,一个预先制定的静态计划很难适应。比如计划"晚上7点开灯",但今天阴天,6点天就黑了,计划就失效了。
    • 为什么ReAct更合适? 它能很好地处理动态环境。例如:
    • Thought: "当前光照传感器显示很暗,但时间才下午6点,比平常早。我需要检查用户是否有'根据光照开灯'的偏好。"
    • Action: 查询用户偏好["光照触发开灯"]
    • Observation: "用户设置了'光照低于50lux自动开灯'。"
    • Thought: "符合条件,执行开灯。"
    • Action: 控制灯具["打开"]
    这种边感知、边判断、边执行的方式非常适合家居场景。
    • 为什么加入Reflection? 用于长期优化。例如,助手可以定期(比如每周)反思自己的控制记录:"过去一周,每次下雨天用户都会手动调高空调温度,我是否应该学习这个模式,自动关联'下雨'和'提高设定温度'?" 通过反思来优化未来的决策策略。
  3. 是否可以将这三种范式进行组合使用?请设计一个混合范式架构。
    完全可以,而且强大的智能体系统往往是混合的。我设计一个 "分层-循环-迭代" 架构:
    • 顶层 (Plan-and-Solve):负责接收宏大、复杂的任务(如"为我规划一个健康的周末"),并进行高层分解。输出一个粗粒度计划:["制定健身计划", "安排饮食", "推荐放松活动"]。
    • 中层 (ReAct):每个高层计划项由一个专门的ReAct子智能体执行。例如"制定健身计划"子智能体,会循环进行:思考用户体能历史 -> 调用健身知识库工具 -> 生成初步方案 -> 思考方案合理性 -> 调整... 直到完成一个具体的健身计划。
    • 底层 (Reflection):每个子智能体在输出结果前,进行自我反思优化。同时,在顶层计划全部执行完毕后,一个全局Reflection模块会回顾整个周末规划的质量,评估用户满意度(可通过后续反馈或传感器数据),生成改进报告,用于优化未来类似任务的规划逻辑。
    适用场景:复杂的个人生活助理、项目管理系统、多阶段研发流程自动化。这些任务既有需要宏观规划的顶层设计,又有需要灵活执行的具体步骤,还需要持续的经验积累和优化。
    习题2:ReAct输出解析的脆弱性与改进
  4. 当前正则表达式解析方法的潜在脆弱性?
    • 格式偏离:如果LLM没有严格按照 Thought: ... 和 Action: ... 的格式输出,比如写成 想法: 或 动作:,或者忘记换行,正则表达式就会匹配失败。
    • 内容嵌套:如果 Thought 或 Action 的内容中本身包含了"Thought:"或"Action:"这样的字符串,或者 Action 的参数里包含了复杂的、不配对的括号 ],正则表达式可能会错误地截断或匹配。
    • 模型"废话":LLM可能在格式化的输出前后加上一些自然语言描述,如"好的,我将按照要求输出:",这会干扰解析。
    • 多Action或缺失:理论上,模型可能输出多个Action,或只输出Thought没有Action,简单的正则可能无法处理这些边缘情况。
  5. 除了正则表达式,还有哪些更鲁棒的输出解析方案?
    • 结构化输出(JSON模式):这是最鲁棒的方法。在提示词中明确要求LLM输出一个严格的JSON对象,例如 {"thought": "...", "action": "..."}。然后使用 json.loads() 解析。现代LLM的API(如OpenAI)甚至原生支持请求 response_format={ "type": "json_object" },强制模型输出合法JSON。
    • 使用解析库(如Pydantic):定义严格的Pydantic模型来描述输出结构,结合验证逻辑。这不仅能解析,还能进行数据类型验证。
    • 文法解析器:对于非常复杂的、接近自然语言的指令,可以使用更高级的解析器,但杀鸡用牛刀。
    • LLM二次解析:用一个轻量、快速的模型(或同一个模型的新调用)专门来解析前一个模型的非结构化输出,将其转换为结构化数据。成本高,但容错性也高。
  6. 尝试修改代码,使用一种更可靠的输出格式。
    方案:采用 JSON模式 替代原有的文本模板。
    修改提示词模板:
    REACT_JSON_PROMPT_TEMPLATE = """
    你是一个有能力调用外部工具的智能助手。
    可用工具如下:
    {tools}

你必须以严格的JSON格式回应,包含且仅包含两个键:"thought" 和 "action"。

  • "thought": 字符串,你的思考过程。
  • "action": 字符串,必须是以下格式之一:
    • {``{tool_name}}[{``{tool_input}}] 表示调用工具。
    • Finish[最终答案] 表示任务完成。

示例:{"thought": "我需要搜索...", "action": "Search[华为手机]"}

现在,请解决以下问题:

问题: {question}

历史: {history}

"""

修改解析方法:

import json

def _parse_output(self, text: str):

"""解析LLM的JSON输出"""

try: # 1. 尝试从文本中提取JSON块(更安全)

start = text.find('{')

end = text.rfind('}') + 1

if start == -1 or end == 0:

raise ValueError("未找到JSON结构")

json_str = text[start:end]

data = json.loads(json_str)

thought = data.get("thought")

action = data.get("action")

return thought, action

except (json.JSONDecodeError, ValueError, KeyError) as e:

print(f"JSON解析失败: {e}, 原始文本: {text[:100]}...") # 可以在这里加入fallback逻辑,例如尝试用旧的正则方法

return None, None

优缺点对比:

• 优点:稳定性极大提升。JSON是标准格式,解析库成熟,边界情况少。模型遵循JSON格式的能力通常很强。

• 缺点:提示词稍复杂,需要提供示例。对于极老的或非主流的模型,JSON支持可能不佳。输出内容中如果包含未转义的特殊字符(如引号、换行),仍可能导致JSON解析失败,但概率远低于正则匹配失败。

习题3:工具调用扩展与实践

  1. 为ReAct智能体添加"计算器"工具。
    步骤:
  2. 实现计算器函数:使用Python的eval需极度谨慎(安全风险),应使用安全的数学表达式解析库(如asteval)或自己实现一个简单的四则运算解析器。
  3. 注册到ToolExecutor。
    import ast
    import operator

class SafeCalculator:

"""一个安全的计算器工具"""

_allowed_operators = {

ast.Add: operator.add,

ast.Sub: operator.sub,

ast.Mult: operator.mul,

ast.Div: operator.truediv,

ast.Pow: operator.pow,

ast.USub: operator.neg,

}

复制代码
@staticmethod
def calculate(expression: str) -> str:
    """计算数学表达式,仅支持基本算术和幂运算"""
    try:
        # 使用ast解析,确保安全
        tree = ast.parse(expression, mode='eval')
        result = SafeCalculator._eval_node(tree.body)
        return str(result)
    except (SyntaxError, TypeError, ZeroDivisionError, KeyError) as e:
        return f"计算错误: {e}"

@staticmethod
def _eval_node(node):
    if isinstance(node, ast.Constant): # Python 3.8+ 使用ast.Constant
        return node.value
    elif isinstance(node, ast.Num): # Python 3.7及以下
        return node.n
    elif isinstance(node, ast.BinOp):
        left = SafeCalculator._eval_node(node.left)
        right = SafeCalculator._eval_node(node.right)
        op_type = type(node.op)
        if op_type not in SafeCalculator._allowed_operators:
            raise TypeError(f"不允许的操作符: {node.op}")
        return SafeCalculator._allowed_operators[op_type](left, right)
    elif isinstance(node, ast.UnaryOp):
        operand = SafeCalculator._eval_node(node.operand)
        op_type = type(node.op)
        if op_type not in SafeCalculator._allowed_operators:
            raise TypeError(f"不允许的操作符: {node.op}")
        return SafeCalculator._allowed_operators[op_type](operand)
    else:
        raise TypeError(f"不支持的表达式节点: {node}")

注册工具

tool_executor.registerTool(

name="Calculator",

description="用于计算数学表达式,支持加减乘除和幂运算。输入应为一个字符串表达式,如'(123 + 456) * 789 / 12'。",

func=SafeCalculator.calculate

) 2. 设计"工具选择失败"的处理机制。

可以在ReActAgent.run的循环中加入失败计数和引导逻辑:

class ReActAgent:

def init (self, ...):

...

self.consecutive_failures = 0 # 连续失败计数器

self.max_failures = 3 # 最大容忍失败次数

复制代码
def run(self, question: str):
    ...
    while current_step < self.max_steps:
        ...
        # 在执行Action并得到observation后
        if "错误" in observation or "未找到" in observation:
            self.consecutive_failures += 1
            print(f"⚠️ 行动失败,连续失败次数: {self.consecutive_failures}")
            if self.consecutive_failures >= self.max_failures:
                # 引导机制:在历史中插入一条明确的系统提示
                guidance = "\n系统提示:你似乎在选择工具或参数上遇到了困难。请仔细阅读可用工具的描述,确保你调用的工具名称完全匹配,并且输入参数是工具所期望的格式。"
                self.history.append(f"Observation: {observation}{guidance}")
                self.consecutive_failures = 0 # 重置计数器,给予新机会
            else:
                self.history.append(f"Observation: {observation}")
        else:
            self.consecutive_failures = 0 # 成功则重置
            self.history.append(f"Observation: {observation}")

更高级的机制可以是:在达到失败阈值时,触发一个专门的"纠错"子流程,让另一个LLM(或同一个模型用不同的提示词)分析失败历史,并给出具体的调整建议,然后将建议作为强化的Observation反馈给主智能体。3. 工具数量大增(50-100个)时的工程优化。

当工具数量爆炸式增长时,直接把所有工具描述塞进提示词会导致上下文过长、成本剧增,且LLM选择工具的性能会下降。

优化方案:

• 动态工具检索:不要一次性提供所有工具。维护一个工具向量数据库。当智能体需要行动时,先根据当前的Thought内容,用嵌入模型(Embedding)检索最相关的Top K(例如3-5个)工具,只把这几个工具的描述放入提示词。这类似于RAG(检索增强生成)在工具选择上的应用。

• 分层工具目录:对工具进行分类(如"搜索类"、"计算类"、"数据查询类"、"系统控制类")。智能体先决定大类,再在大类下选择具体工具。这可以减少单次决策的选项数量。

• 工具描述优化:工具描述需要高度精炼、标准化,包含明确的关键词,便于检索。可以设计工具描述模板,如"功能:[一句话],输入格式:[示例],输出格式:[示例]"。

• 元工具(Meta-Tool):提供一个ListTools或SearchTools的工具,当智能体不确定时,可以先用这个工具查询可用工具列表,然后再调用。这相当于把工具发现过程也纳入了循环。

习题4:Plan-and-Solve的动态重规划与对比

  1. 如何设计"动态重规划"机制?

    静态计划的致命弱点是无法应对执行时的意外。动态重规划需要让执行器具备反馈能力,并能触发规划器的重新运行。

    设计:

  2. 在执行器Executor.execute的每一步,不仅执行,还要进行结果验证。验证可以是简单的(如检查结果是否为数字),也可以复杂(用另一个LLM调用判断结果是否合理)。

  3. 如果验证失败,或工具调用返回错误,执行器将当前步骤标记为"阻塞",并收集阻塞上下文(问题、原计划、执行到哪一步、发生了什么错误)。

  4. 触发重规划器。重规划器接收阻塞上下文,其提示词调整为:"原始计划在执行步骤X时失败,原因是Y。请基于当前情况(已完成步骤A、B、C的结果分别为...),重新生成一个从步骤X开始的新计划,以规避该问题。"

  5. 用新计划替换旧计划中未完成的部分,继续执行。

    class DynamicPlanAndSolveAgent:

    def run(self, question: str):

    plan = self.planner.plan(question)

    attempt = 0

    max_replan_attempts = 2

    复制代码
        while attempt < max_replan_attempts:
            result, success, failure_step, failure_reason = self.executor.execute_with_monitoring(question, plan)
            if success:
                return result
            else:
                print(f"计划在步骤{failure_step}失败: {failure_reason},尝试重规划...")
                # 获取已成功步骤的历史
                partial_history = self.executor.get_history_up_to(failure_step)
                # 重规划
                new_plan = self.replanner.replan(question, plan, failure_step, failure_reason, partial_history)
                if new_plan:
                    plan = new_plan # 用新计划继续
                    attempt += 1
                else:
                    break
        return "任务失败,经过多次重规划仍无法解决。"
  6. 对比Plan-and-Solve与ReAct:处理"预订商务旅行"任务。

    "预订商务旅行"任务特点:多步骤(机票、酒店、租车)、步骤间有依赖(先有日期才能订酒店)、需要查询外部API(比价、库存)、有明确约束(预算、时间、偏好)。这是一个半结构化任务。

    • Plan-and-Solve更合适。

    • 理由:任务虽复杂,但步骤逻辑相对清晰,可以预先规划出一个主干流程:[确定出差日期 -> 查询并选择航班 -> 根据航班到达时间选择酒店 -> 根据酒店位置选择租车点]。先规划能确保不遗漏关键环节,并且可以一次性收集所有必要参数(如日期、城市),避免在循环中反复向用户确认。执行阶段可以严格按此流程调用各预订API,效率高,不易跑偏。

    • ReAct的劣势:在探索中可能会陷入细节循环,比如在比较多个航班选项时来回搜索,或者忘记预订的后续环节。对于这种目标明确、路径相对固定的任务,ReAct的灵活性反而可能成为效率的负担。

  7. 设计"分层规划"系统及其优势。

    设计:

    • 高层规划器:接收模糊目标(如"开发一个手机App")。输出抽象阶段:["需求分析与设计", "前端开发", "后端开发", "测试与部署"]。每个阶段是一个目标,而非具体动作。

    • 中层规划器/执行器:每个高层阶段由一个专门的智能体负责。例如"前端开发"智能体接收到目标后,会进行自己的规划:["搭建React Native环境", "实现登录页面UI", "集成状态管理"...],然后执行。它可能内部采用ReAct范式来调用代码生成、UI审查等工具。

    • 优势:

  8. 管理复杂性:将巨型任务分解为模块,分而治之,符合人类项目管理思维。

  9. 关注点分离:不同层次的智能体可以专精于不同领域(产品经理、前端工程师、后端工程师)。

  10. 灵活性:高层规划可以较稳定,而底层执行可以很灵活。例如,"测试与部署"阶段可以根据"前端开发"和"后端开发"的实际产出,动态生成具体的测试用例和部署脚本。

  11. 并行与协作:在高层规划确定后,某些阶段(如前端、后端开发)理论上可以并行执行,由不同的智能体团队协作,并通过共享记忆或消息总线同步信息。

    习题5:Reflection机制的深入思考

  12. 使用不同模型进行反思与执行的影响。

    • 反思用更强模型,执行用更快/更便宜模型:

    • 积极影响:反思(评审)是要求更高的任务,需要深度分析、批判性思维和广博知识。更强的模型(如GPT-4)能提供更精准、深刻的反馈,从而引导优化方向更正确。执行(生成)任务相对直接,用更快更便宜的模型(如Claude Haiku、本地小模型)可以大幅降低成本、提高响应速度。这是一种性价比优化策略。

    • 潜在风险:如果两个模型的知识、风格差异太大,执行模型可能无法完全理解或有效落实反思模型提出的"高级"建议,导致优化效果打折扣。需要确保它们对任务的基本理解一致。

  13. 反思终止条件的合理性及更智能的设计。

    当前条件("反馈包含'无需改进'"或"达到最大迭代次数")是基础但粗糙的。

    • 问题:"无需改进"是模型的主观判断,可能误判。最大迭代次数是硬性限制,可能没优化够就停了,或浪费资源空转。

    更智能的终止条件设计:

  14. 量化评估阈值:在每次优化后,不仅让模型反思,还让一个"评估器"对当前版本进行量化评分(例如,代码的效率、可读性、正确性各打1-5分)。设定一个目标总分阈值(如12分),达到即终止。也可以设定连续两次迭代分数提升小于某个增量(如0.5分)时终止,表明收敛。

  15. 多维度投票:让反思从多个角度进行(如"算法专家"、"安全专家"、"用户体验专家"),如果多数专家认为"无需改进",则终止。这比单视角更可靠。

  16. 资源预算管理:综合考量已消耗的API费用、时间和迭代次数,设定一个综合预算。当任何一项接近预算时,选择当前最优版本输出并终止。

  17. 设计"学术论文写作助手"的多维度Reflection。

    这个Reflection机制需要一个评审委员会,而非单个评审员。

    • 执行:LLM根据主题生成论文初稿(包括标题、摘要、引言、方法、实验、结论)。

    • 多维度反思(并行或串行调用不同角色的反思提示词):

  18. 逻辑连贯性评审员:检查各部分是否逻辑自洽,引言是否引出问题,方法是否解决问题,实验是否验证方法,结论是否总结成果。

  19. 方法创新性评审员:批判方法部分,是否足够新颖,与现有工作对比是否清晰,技术细节是否扎实。

  20. 学术语言与表达评审员:检查语言是否正式、准确,术语使用是否规范,句式是否多样,有无语法错误。

  21. 引用与格式评审员:检查参考文献引用是否完整、恰当,格式是否符合目标会议/期刊要求。

  22. 实验严谨性评审员(如果涉及):检查实验设计是否合理,数据是否充分,分析是否深入,图表是否清晰。

    • 优化:将来自多个评审员的反馈汇总,可能需要对冲突的反馈进行权衡(例如,创新性评审员建议增加一个复杂模块,但语言评审员建议简化表达)。优化提示词需要指导模型综合处理这些反馈,生成修订稿。

    • 迭代:可以设定每一轮只聚焦解决1-2个最严重的问题(根据评审员给出的严重等级),逐轮细化,避免单轮修改过多导致文章风格撕裂。

    习题6:提示词工程分析

  23. 对比ReAct和Plan-and-Solve提示词的结构差异。

    • ReAct提示词:像一个实时操作手册。它强调"格式规约"(必须输出Thought/Action)和"动态上下文"(注入History)。结构是循环式的,旨在引导模型在单步内完成"感知->决策->输出指令"的完整动作。它的核心是控制输出格式和维持会话状态。

    • Plan-and-Solve提示词:像一个项目任务书。它强调"角色设定"(规划专家)和"输出格式约束"(必须是Python列表)。它不关心动态历史,因为规划是一次性的。它的核心是激发分解思维和强制结构化输出,以便后续程序能稳定解析和执行。

    • 差异服务于核心逻辑:ReAct的提示词设计是为了适配其循环、交互的本质;Plan-and-Solve的提示词设计是为了适配其阶段化、管道化的本质。

  24. 修改Reflection提示词角色设定的影响。

    • 原设定("极其严格的代码评审专家"):引导模型聚焦于正确性、性能、算法效率等硬核技术指标。反馈可能严厉,倾向于推荐根本性的算法变更。

    • 新设定("注重代码可读性的开源项目维护者"):引导模型聚焦于命名清晰度、函数拆分、注释完整性、代码风格统一等可维护性指标。反馈可能更温和,倾向于重构和美化,而不是重写算法。

    • 总结:角色设定是提示词的"灵魂",它直接定义了模型的视角、价值观和评估标准。改变角色设定,会显著改变反思的侧重点和最终优化方向。这说明了在Reflection范式中,设计一个与最终目标对齐的"评审角色"至关重要。

  25. 为智能体添加Few-shot示例的效果。

    以ReAct的Action解析为例,在提示词中加入一个完整的成功示例:

    示例:

    用户:华为最新手机是什么?

    Thought: 用户询问的产品信息可能已更新,我需要搜索最新资料。

    Action: Search[华为最新手机型号]

    Observation: 根据搜索结果,华为最新旗舰手机是Mate 60 Pro...

    Thought: 已获得信息,可以给出答案。

    Action: Finish[华为目前最新旗舰手机是Mate 60 Pro,其主要卖点包括...]

    效果:

    • 显著提升格式遵循能力:模型会模仿示例的结构、用词和节奏来输出,大大降低格式错乱的概率。

    • 明确工具使用范例:展示了如何正确调用Search工具和Finish动作。

    • 降低歧义:展示了从问题到最终答案的完整推理链条,帮助模型理解任务的全貌。

    • 潜在缺点:占用上下文令牌,增加成本。如果示例不够典型或存在偏差,也可能将模型引入特定的思维定式。

    习题7:综合场景设计------"客服智能体"

  26. 选择哪种范式(或组合)作为核心架构?

    我会选择 以Plan-and-Solve为主干,嵌入ReAct和Reflection模块 的混合架构。

    • 主干用Plan-and-Solve:因为客服退款流程有相对固定的阶段,符合"先规划后执行"。规划阶段能确保不遗漏关键环节:[理解用户理由 -> 查询订单与物流 -> 根据政策判断 -> 生成回复 -> 发送邮件]。

    • 关键环节嵌入ReAct:在"理解用户理由"和"根据政策判断"环节,问题可能复杂,需要探索。例如,用户理由描述模糊,智能体可能需要通过ReAct循环,主动提问澄清(调用一个"向用户提问"的工具),或搜索知识库来理解特定术语。

    • 关键环节嵌入Reflection:在"生成回复"之后,发送邮件之前,必须进行Reflection。反思重点是:回复语气是否得体(避免激怒用户)?逻辑是否清晰?是否涵盖了所有已查询到的信息?是否严格遵守了公司政策?根据反思结果优化邮件措辞。同时,整个流程结束后,可以进行一次全局Reflection,用于优化未来的决策策略(如发现某类情况总是判断失误)。

  27. 这个系统需要哪些工具?

    至少需要以下工具:

  28. 订单查询工具:连接公司内部数据库或订单系统API,根据用户ID或订单号查询订单详情、支付状态、购买时间。

  29. 物流状态查询工具:连接物流系统API,查询该订单的当前物流轨迹和签收状态。

  30. 公司政策知识库工具:一个RAG系统,向量化存储公司的所有退款、售后政策文档。智能体可以自然语言提问(如"商品已拆封但损坏如何处理?"),工具返回相关的政策条款。

  31. 邮件发送工具:连接邮件服务器API(如SMTP),能够发送格式化的邮件。

  32. (可选) 用户历史交互查询工具:查询该用户过去的客诉、退款记录,辅助判断信用。

  33. 如何设计提示词确保决策既符合公司利益,又能保持用户友好?

    提示词需要植入双重约束:

    • 系统角色设定:"你是XX公司的智能客服专员,你的首要职责是公平、准确地执行公司的售后政策,维护公司利益。同时,你必须以专业、友善、共情的方式与用户沟通,维护客户关系。"

    • 在规划器和执行器的提示词中具体化:

    • 对于政策判断步骤:"请严格依据提供的政策条款进行判断。如果政策存在模糊地带,请采取对公司风险较低且对用户相对公平的保守解释。"

    • 对于邮件生成步骤:"邮件开头应表达对用户问题的理解和关怀。然后清晰、有条理地说明你的调查结果(订单信息、物流状态)和政策依据。最后明确告知决策结果。即使结果是拒绝退款,也要表达歉意并提供替代解决方案(如维修、折扣券等),保持语气诚恳、坚定。"

  34. 产品上线后可能面临的风险和挑战及技术应对手段?

    • 风险1:决策错误或不一致。智能体可能误解政策或用户描述,做出错误退款决定。

    • 应对:建立 "置信度-人工复核"流水线。智能体输出决策时,必须同时输出一个自我评估的置信度分数。低于阈值的case自动流转给人工客服复核。所有决策和邮件内容记录在案,便于审计和后续模型训练。

    • 风险2:生成不当或敏感回复。模型可能生成带有偏见、冒犯性或泄露内部信息的回复。

    • 应对:在Reflection环节之后,邮件发送之前,增加一个 "安全与合规过滤器"。这可以是一个专门训练的分类模型或规则集,检查邮件内容是否包含敏感词、负面情绪过激、泄露隐私等,拦截不合格的邮件。

    • 风险3:被恶意用户利用或攻击。用户可能用精心构造的描述来欺骗智能体,绕过政策。

    • 应对:在工具层面,严格验证输入(如订单号格式、用户身份)。在流程层面,对于高频或高金额的退款申请,自动触发更严格的检查流程(如要求上传凭证图片,并调用图像识别工具进行初步审核)。

    • 风险4:系统可解释性差。当出现纠纷时,无法说清AI为何做出某个决定。

    • 应对:系统必须完整记录整个Plan-and-Solve-ReAct-Reflection的完整轨迹,包括每一步的Thought、调用的工具及原始返回结果、反思的反馈。这个"决策日志"是解释和调试的根本。

    • 挑战:与现有系统集成。工具需要对接多个内部系统(订单、物流、邮件),接口稳定性、数据格式统一是工程挑战。

    • 应对:为每个内部系统开发稳定、有容错机制的API客户端,并在工具层做好异常处理和日志记录。

项目地址:hello-agents

相关推荐
骇客野人2 小时前
用python实现一个查询当天天气的MCP服务器
服务器·开发语言·python
天空属于哈夫克32 小时前
拒绝被动响应:企业微信主动调用接口高阶方案
开发语言·python
belldeep2 小时前
python:spaCy 工业级 NLP 库
python·自然语言处理·nlp·spacy
Flittly2 小时前
【从零手写 ClaudeCode:learn-claude-code 项目实战笔记】(11)Autonomous Agents (自治智能体)
笔记·python·ai·ai编程
2301_776508722 小时前
使用PyQt5创建现代化的桌面应用程序
jvm·数据库·python
dmlcq2 小时前
一文读懂 PageQueryUtil:分页查询的优雅打开方式
开发语言·windows·python
今儿敲了吗2 小时前
python基础学习笔记第八章——异常
笔记·python·学习
umeelove352 小时前
【Flask】四、flask连接并操作数据库
数据库·python·flask
ProgramHan2 小时前
十大排行榜——后端语言及要介绍
java·c++·python·php