ReAct.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. """
  2. ReAct vs Plan-and-Execute
  3. ReAct(Reasoning + Acting): 边想边做 —— 每一步都「推理 → 行动 → 观察 → 再推理」
  4. 适合: 简单任务,不需要提前规划
  5. 缺点:由于缺乏全局规划,它像个"近视眼",极易在步骤繁多的复杂任务中迷失方向,
  6. 甚至在出错时陷入工具调用的无限死循环。
  7. Plan-and-Execute: 先计划再执行 —— 先制定完整计划,再逐步执行
  8. 适合: 复杂任务,需要全局规划
  9. 缺点:由于强依赖前期的静态规划,它显得过于笨重且延迟较高,一旦中间步骤执行出错
  10. 或现实情况发生突变,就必须频繁重新规划,缺乏像 ReAct 那样快速、灵活的即时反应能力。
  11. 本文件演示 ReAct 模式的 Agent:
  12. 每轮循环:LLM 推理当前状况 → 决定调用哪个工具 → 工具返回结果 → LLM 观察结果继续推理
  13. 直到 LLM 认为问题已解决,输出最终答案。
  14. """
  15. import sys
  16. from pathlib import Path
  17. # 将项目根目录加入 sys.path,确保能 import llm_client 和 agent_demo 等模块
  18. path = Path(__file__).resolve().parent.parent
  19. sys.path.insert(0, str(path))
  20. """企业需求:智能客服售后分析 Agent(ReAct 模式)"""
  21. # ================================================================
  22. # 1. 初始化大模型(LLM)
  23. # get_llm() 返回 ChatOpenAI 单例,自动读取 .env 中的 API Key / base_url / model
  24. # LLM 是 ReAct 循环中的「推理引擎」,负责理解问题 + 决定调用哪个工具
  25. # ================================================================
  26. from llm_client import get_llm
  27. llm = get_llm()
  28. # ================================================================
  29. # 2. 加载工具(Tools)
  30. # ReAct 中的 "Act" 环节 —— Agent 通过调用这些工具与外部系统交互
  31. # - query_order: 查询订单系统(订单状态、物流等)
  32. # - query_product: 查询商品知识库(商品信息、价格等)
  33. # tools 列表会在创建 Agent 时注入,LLM 可以自主决定调用哪个
  34. # ================================================================
  35. from langchain.agents import create_agent
  36. from agent_demo.React_tool import query_order, query_product
  37. tools = [query_order, query_product]
  38. # ================================================================
  39. # 3. 系统提示词(System Prompt)
  40. # 定义 Agent 的角色、行为规范和输出要求
  41. # 这段 prompt 会作为 SystemMessage 拼接在每轮 LLM 调用的最前面
  42. # ReAct 的 "Reasoning" 质量很大程度上取决于 prompt 写得是否清晰
  43. # ================================================================
  44. prompt = """你是企业售后智能客服Agent。
  45. 你的任务:
  46. 1. 理解用户问题
  47. 2. 判断是否需要调用工具
  48. 3. 获取业务数据
  49. 4. 根据结果分析
  50. 5. 给出准确解决方案
  51. 你不能编造订单信息。
  52. 如果缺少信息,需要主动询问。
  53. """
  54. # ================================================================
  55. # 4. 创建 ReAct Agent
  56. # create_agent 内部封装了完整的 ReAct 循环:
  57. #
  58. # ┌──────────┐ 有工具调用 ┌──────────┐
  59. # │ LLM │ ───────────────→ │ 工具执行 │
  60. # │ (推理) │ ←─────────────── │ (行动) │
  61. # └──────────┘ 返回观察结果 └──────────┘
  62. # │
  63. # │ 无工具调用,直接输出
  64. # ↓
  65. # 最终答案
  66. #
  67. # 参数说明:
  68. # - llm: 负责推理的 LLM
  69. # - tools: 可调用的工具列表(ReAct 中的 Action 来源)
  70. # - system_prompt: 系统提示词,定义 Agent 的角色和行为规范
  71. # ================================================================
  72. agent = create_agent(
  73. llm,
  74. tools,
  75. system_prompt=prompt,
  76. )
  77. # ================================================================
  78. # 5. 运行 Agent
  79. # agent.invoke() 启动 ReAct 循环,输入 messages 列表
  80. # 返回的 result['messages'] 包含完整的对话历史:
  81. # HumanMessage → 用户输入
  82. # AIMessage → LLM 推理(可能包含 tool_calls)
  83. # ToolMessage → 工具执行结果
  84. # ...(重复上述过程直到 LLM 输出最终答案)
  85. # AIMessage → 最终回答(不含 tool_calls)
  86. # ================================================================
  87. if __name__ == '__main__':
  88. # 用户问题:查询订单 10001 的状态
  89. result = agent.invoke(
  90. {"messages": [("user", "我的订单10001为什么还没有收到?")]}
  91. )
  92. # 取最后一条消息的 content 作为最终回答
  93. print(f"\n最终回答:{result['messages'][-1].content}")