Selaa lähdekoodia

ReAct vs Plan And Executor 作业

Daphne chen 1 kuukausi sitten
vanhempi
commit
746abd5568
6 muutettua tiedostoa jossa 342 lisäystä ja 0 poistoa
  1. 113 0
      03_work/ReAct.py
  2. 62 0
      03_work/React_tool.py
  3. 43 0
      03_work/executor.py
  4. 59 0
      03_work/main.py
  5. 49 0
      03_work/planner.py
  6. 16 0
      03_work/tools.py

+ 113 - 0
03_work/ReAct.py

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

+ 62 - 0
03_work/React_tool.py

@@ -0,0 +1,62 @@
+"""企业业务工具"""
+
+from langchain_core.tools import tool
+
+# ================================
+# 工具1:查询订单系统
+# ================================
+
+
+@tool
+def query_order(order_id: str) -> str:
+    """查询订单系统"""
+    orders = {
+        "10001": {
+            "status": "运输中",
+            "company": "顺丰",
+            "days": 2,
+        },
+        "10002": {
+            "status": "已退款",
+            "company": "",
+            "days": 0,
+        },
+    }
+
+    return orders.get(
+        order_id,
+        "没有找到订单",
+    )
+
+
+# ================================
+# 工具2:查询商品知识库
+# ================================
+
+
+@tool
+def query_product(product_name: str) -> str:
+    """查询商品知识库"""
+    products = {
+        "无线耳机": {
+            "category": "电子产品",
+            "price": "299元",
+            "warranty": "1年",
+        },
+        "机械键盘": {
+            "category": "电脑外设",
+            "price": "599元",
+            "warranty": "2年",
+        },
+    }
+
+    return products.get(
+        product_name,
+        "没有找到该商品信息",
+    )
+
+
+tools = [
+    query_order,
+    query_product
+]

+ 43 - 0
03_work/executor.py

@@ -0,0 +1,43 @@
+import sys
+from pathlib import Path
+path = Path(__file__).resolve().parent.parent
+sys.path.insert(0, str(path))
+
+from llm_client import get_llm
+from langchain.agents import create_agent
+from agent_demo.tools import tools
+
+llm = get_llm()
+
+prompt = """你是一名专业研究分析Agent。
+
+你的任务:完成用户交给你的研究任务。
+
+你拥有搜索工具。当你的知识不足,或者需要最新信息时,必须调用工具。
+
+工作流程:
+1. Thought: 分析当前需要什么信息
+2. Action: 调用工具
+3. Observation: 查看工具返回结果
+4. 继续推理,直到输出最终答案
+
+不要编造数据。
+"""
+
+agent = create_agent(llm, tools, system_prompt=prompt)
+
+
+def execute_task(task: str):
+    """执行一个Planner任务,返回Agent最终答案"""
+    result = agent.invoke({"messages": [("user", task)]})
+    return result["messages"][-1].content
+
+
+# ======================================
+# 测试 Executor
+# ======================================
+if __name__ == "__main__":
+    task = "分析2026年AI Agent市场发展趋势"
+    answer = execute_task(task)
+    print("\n最终结果:")
+    print(answer)

+ 59 - 0
03_work/main.py

@@ -0,0 +1,59 @@
+"""
+main.py — Plan-and-Execute + ReAct Agent
+
+完整流程:
+  用户目标 → Planner → 生成任务列表 → Executor (ReAct Agent) → 调用 Tool → 返回结果 → 最终输出
+"""
+
+import sys
+from pathlib import Path
+path = Path(__file__).resolve().parent.parent
+sys.path.insert(0, str(path))
+
+from agent_demo.planner import create_plan
+from agent_demo.executor import execute_task
+
+# =====================================
+# 用户需求
+# =====================================
+goal = "请分析2026年AI Agent市场发展趋势,并生成一份行业研究报告。"
+
+# =====================================
+# 第一阶段:Planner 生成计划
+# =====================================
+print("\n" + "=" * 60)
+print("Planner 开始工作")
+print("=" * 60)
+
+plan = create_plan(goal)
+print("\n生成任务计划:\n")
+for item in plan:
+    print(f"Step {item['task_id']}:{item['task']}")
+
+# =====================================
+# 第二阶段:Executor 执行任务
+# =====================================
+print("\n" + "=" * 60)
+print("Executor 开始执行")
+print("=" * 60)
+
+results = []
+for item in plan:
+    print(f"\n正在执行 Step {item['task_id']}:{item['task']}")
+    task_result = execute_task(item["task"])
+    results.append({"task": item["task"], "result": task_result})
+    print("\n执行结果:")
+    print(task_result)
+
+# =====================================
+# 第三阶段:汇总输出
+# =====================================
+print("\n" + "=" * 60)
+print("全部任务完成")
+print("=" * 60)
+
+for r in results:
+    print("\n任务:")
+    print(r["task"])
+    print("\n结果:")
+    print(r["result"])

+ 49 - 0
03_work/planner.py

@@ -0,0 +1,49 @@
+import sys
+from pathlib import Path
+path = Path(__file__).resolve().parent.parent
+sys.path.insert(0, str(path))
+
+import json
+from llm_client import get_llm
+
+llm = get_llm()
+
+
+def create_plan(goal: str) -> list:
+    """根据用户目标生成任务列表,返回 [{"task_id": 1, "task": "..."}]"""
+    prompt = f"""你是一名专业任务规划专家。
+
+用户目标:
+{goal}
+
+请将这个复杂目标拆解成多个独立任务。
+
+要求:
+1. 每个任务可以单独执行
+2. 不要执行任务,只负责规划
+3. 返回 JSON,不要 Markdown
+
+格式:
+[
+    {{
+        "task_id": 1,
+        "task": "任务描述"
+    }}
+]
+"""
+    response = llm.invoke(prompt)
+    plan = json.loads(response.content)
+    return plan
+
+
+# =====================================
+# 测试 Planner
+# =====================================
+if __name__ == "__main__":
+    goal = "分析2025年AI Agent市场,并生成行业研究报告。"
+    plan = create_plan(goal)
+    print("=" * 50)
+    print("生成计划:")
+    print("=" * 50)
+    for item in plan:
+        print(f"Step {item['task_id']}:{item['task']}")

+ 16 - 0
03_work/tools.py

@@ -0,0 +1,16 @@
+"""tools.py — Agent 工具定义,Agent 运行时 LLM 自主决定是否调用工具。"""
+
+from dotenv import load_dotenv
+load_dotenv()
+
+from langchain_tavily import TavilySearch
+
+search_tool = TavilySearch(max_results=5, topic="general")
+tools = [search_tool]
+
+# =====================================
+# 单独测试 Tool
+# =====================================
+if __name__ == "__main__":
+    result = search_tool.invoke({"query": "2026 AI Agent market trend"})
+    print(result)