第 29 期 | 项目打磨:UI 集成与最终呈现

⏱ 预计阅读 20 分钟 更新于 2026/5/7
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)

本期副标题:突破问答限制,赋予AI行动力

各位未来的 AI 架构师们,大家好!我是你们的老朋友,AI 技术导师。经过前几期的学习,我们的智能客服小助手已经能进行基础的问答,也能从知识库里检索信息了,对吧?但你有没有觉得,它还差点“意思”?这个“意思”就是——行动力

用户问:“我的订单号 XYZ-123 的配送状态是怎样的?” 小助手回答:“我不知道。” —— 这显然不够智能。

用户问:“请帮我更新一下注册手机号。” 小助手回答:“好的,请告诉我新号码。”然后呢?就没有然后了。

传统意义上的 LLM Chain,无论是直接问答还是 RAG,都像一个超级聪明的“图书馆管理员”,它能找到信息、总结信息,但它不能“走出图书馆”去为你办事情。而一个真正的“智能客服副驾驶”,它不仅要能回答,更要能解决问题

今天,我们就来给我们的客服小助手插上“翅膀”,让它学会主动思考、主动行动,从一个“问答机器人”升级为能“解决问题”的 Agent。这绝对是 LangChain 里最激动人心的部分之一,也是你打造生产级 AI 应用的必经之路!

🎯 本期学习目标

  1. 理解 Agent 的核心工作原理:掌握 Agent 如何利用 LLM 的推理能力,结合外部工具(Tools)进行规划与执行,突破传统 Chain 的问答限制。
  2. 掌握工具(Tools)的定义与集成:学会如何为 Agent 创建并注册自定义工具,让 AI 能够与外部系统(如数据库、API、CRM)进行交互。
  3. 在智能客服项目中实现 Agent 功能:赋予我们的客服小助手主动查询订单、更新用户资料、查询门店信息等能力,提升其解决实际问题的效率。
  4. 识别 Agent 的适用场景与潜在挑战:了解 Agent 在实际应用中的优势、劣势以及常见的“坑”,为未来设计更复杂的 AI 系统打下基础。

📖 原理解析

Agent:AI 的“大脑”与“双手”

想象一下,你作为一名客服,接到一个关于“订单查询”的请求。你会怎么做?

  1. 理解问题:用户想查订单状态。
  2. 规划行动:我需要一个订单号。如果用户提供了,就用它。如果没提供,就问用户要。
  3. 选择工具:我需要访问“订单管理系统”或“物流查询系统”。
  4. 执行工具:调用系统接口,传入订单号。
  5. 获取结果:系统返回订单状态。
  6. 总结并回复:将状态信息以友好的方式告诉用户。

这个过程,就是 Agent 的核心思想:LLM 不再仅仅是生成文本,它成为了一个决策者和规划者,指挥一系列“工具”来完成任务。

在 LangChain 中:

  • Agent (代理):是核心的控制器,它利用一个强大的 LLM 作为“大脑”,根据用户的输入和当前状态,决定下一步应该“思考”什么,或者“采取”什么行动。
  • Tools (工具):是 Agent 的“双手”,它们是封装了特定功能的函数或 API 接口。比如,查询数据库的工具、发送邮件的工具、调用天气 API 的工具等等。Agent 通过调用这些工具来与外部世界交互,获取信息或执行操作。
  • Agent Executor (代理执行器):是 Agent 的“心脏”,它负责驱动整个“思考-行动”循环。Agent Executor 会不断地将用户的输入、LLM 的思考(即Agent的决策)、工具的输出传递给 Agent,直到任务完成或达到某个停止条件。

Agent 的工作模式,通常遵循 ReAct (Reasoning and Acting) 模式:

  1. Observation (观察):Agent 接收用户输入和工具的执行结果。
  2. Thought (思考):LLM 根据观察到的信息,进行推理,决定下一步的行动或思考方向。
  3. Action (行动):LLM 决定调用哪个工具,以及调用工具所需的参数。
  4. Action Input (行动输入):LLM 为选定的工具提供具体的输入。
  5. Observation (新观察):工具执行后,将结果返回给 Agent,形成新的观察。

这个循环会一直持续,直到 LLM 决定生成最终答案并停止。

Mermaid 图解 Agent 工作流

graph TD
    A[用户请求] --> B{Agent Executor 启动};
    B --> C{Agent (LLM) 思考};
    C -- "Thought: 我需要查询订单状态,应该使用订单查询工具。" --> D{选择工具};
    D -- "Action: search_order_status" --> E[执行工具 (Tools)];
    E -- "Action Input: order_id=XYZ-123" --> F[外部系统 (数据库/API)];
    F --> G[工具输出结果];
    G -- "Observation: 订单 XYZ-123 状态为‘配送中’。" --> C;
    C -- "Thought: 我已获取订单状态,现在可以回复用户了。" --> H{Agent (LLM) 最终回复};
    H --> I[返回给用户];

这个流程图清晰地展示了 Agent 如何通过“思考-行动-观察”的循环,逐步解决用户的问题。LLM 不再是简单的问答机器,而是一个能够主动规划、调用外部资源的智能体。对于我们的智能客服小助手来说,这意味着它能够从一个“被动回答者”转变为一个“主动问题解决者”。

💻 实战代码演练

现在,我们把 Agent 的强大能力集成到我们的智能客服项目中。我们将创建两个自定义工具:

  1. OrderTrackerTool (订单查询工具):模拟查询用户订单状态。
  2. StoreLocatorTool (门店查询工具):模拟查询最近的门店地址。

然后,我们将创建一个 Agent,让它能够根据用户的问题,智能地选择并使用这些工具。

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent, Tool
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableSequence
from langchain_core.messages import HumanMessage, AIMessage

# 加载环境变量 (确保你的 .env 文件中有 OPENAI_API_KEY)
load_dotenv()

# --- 1. 定义我们客服小助手的专属工具 ---

# 工具一:订单查询工具
def search_order_status(order_id: str) -> str:
    """
    模拟查询订单状态的工具。
    在真实场景中,这里会调用你的电商后台API或数据库。
    Simulates a tool to query order status.
    In a real scenario, this would call your e-commerce backend API or database.
    """
    print(f"\n--- 模拟调用订单查询工具,查询订单号: {order_id} ---")
    if order_id == "XYZ-123":
        return "订单 XYZ-123 目前正在配送中,预计今天下午送达。"
    elif order_id == "ABC-456":
        return "订单 ABC-456 已签收,感谢您的购买!"
    else:
        return f"抱歉,未能找到订单号为 {order_id} 的信息,请检查后重试。"

# 工具二:门店查询工具
def find_nearest_store(location: str) -> str:
    """
    模拟查询最近门店地址的工具。
    在真实场景中,这里会调用地图API或门店数据库。
    Simulates a tool to find the nearest store.
    In a real scenario, this would call a map API or store database.
    """
    print(f"\n--- 模拟调用门店查询工具,查询地点: {location} ---")
    if "上海" in location:
        return "上海市徐汇区漕宝路123号,电话:021-88889999"
    elif "北京" in location:
        return "北京市朝阳区大望路456号,电话:010-66667777"
    else:
        return f"抱歉,我们目前在 {location} 附近没有直营门店。"

# 将工具封装成 LangChain 的 Tool 对象
tools = [
    Tool(
        name="OrderTracker", # 工具名称,Agent 会根据这个名称来调用
        func=search_order_status, # 实际执行的函数
        description="用于查询客户订单的实时配送状态。输入必须是订单号,例如 'XYZ-123'。"
                   "Useful for getting the real-time delivery status of customer orders. Input must be an order ID, e.g., 'XYZ-123'."
    ),
    Tool(
        name="StoreLocator", # 工具名称
        func=find_nearest_store, # 实际执行的函数
        description="用于查询最近的门店地址和联系方式。输入必须是城市或具体地点,例如 '上海' 或 '北京朝阳区'。"
                   "Useful for finding the nearest store's address and contact information. Input must be a city or specific location, e.g., 'Shanghai' or 'Beijing Chaoyang District'."
    )
]

# --- 2. 初始化 LLM ---
# 使用 ChatOpenAI 作为 Agent 的“大脑”
llm = ChatOpenAI(model="gpt-4o", temperature=0) # 建议使用更强的模型,如 gpt-4o 或 gpt-3.5-turbo

# --- 3. 创建 Agent 的 Prompt ---
# LangChain 提供了一些内置的 Agent 类型和 Prompt 模板,
# 这里我们使用 create_react_agent,它基于 ReAct 模式。
# ReAct Agent 需要一个包含 {tools}, {tool_names}, {input}, {agent_scratchpad} 的 Prompt。
# {agent_scratchpad} 是 Agent 记录思考过程和工具执行结果的地方。
prompt_template = PromptTemplate.from_template("""
你是一个智能客服小助手,可以帮助用户查询订单状态和门店信息。
请根据用户的问题,使用合适的工具进行查询,并给出友好的回复。
如果需要更多信息才能使用工具,请主动询问用户。

可用的工具如下:
{tools}

请使用以下格式进行回复:

Question: 用户输入问题
Thought: 我应该思考什么来回答这个问题?
Action: 我应该执行的工具 (仅当需要工具时)
Action Input: 传递给工具的输入 (仅当需要工具时)
Observation: 工具的输出结果 (这是由工具返回的,你不需要自己生成)
... (这个 Thought/Action/Action Input/Observation 循环可以重复多次)
Thought: 我已经得到了最终答案
Final Answer: 最终的答案

现在开始回答:
Question: {input}
{agent_scratchpad}
""")

# --- 4. 创建 Agent ---
# create_react_agent 会根据 LLM, tools 和 prompt_template 构建一个 Agent
agent = create_react_agent(llm, tools, prompt_template)

# --- 5. 创建 Agent Executor ---
# Agent Executor 负责运行 Agent,处理 Thought/Action/Observation 循环
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # verbose=True 可以看到 Agent 的思考过程

# --- 6. 运行 Agent 进行实战演练 ---
print("\n--- 智能客服 Agent 启动! ---")

# 场景一:查询已知订单号
print("\n--- 场景一:查询已知订单号 ---")
response1 = agent_executor.invoke({"input": "我的订单号 XYZ-123 的配送状态是怎样的?"})
print(f"\n客服小助手回复: {response1['output']}")

# 场景二:查询未知订单号
print("\n--- 场景二:查询未知订单号 ---")
response2 = agent_executor.invoke({"input": "帮我查一下订单号 999-888 的状态。"})
print(f"\n客服小助手回复: {response2['output']}")

# 场景三:查询门店信息
print("\n--- 场景三:查询门店信息 ---")
response3 = agent_executor.invoke({"input": "请问上海最近的门店在哪里?"})
print(f"\n客服小助手回复: {response3['output']}")

# 场景四:查询没有门店的地区
print("\n--- 场景四:查询没有门店的地区 ---")
response4 = agent_executor.invoke({"input": "我想知道深圳的门店地址。"})
print(f"\n客服小助手回复: {response4['output']}")

# 场景五:Agent 需要主动询问更多信息
print("\n--- 场景五:Agent 需要主动询问更多信息 ---")
response5 = agent_executor.invoke({"input": "我想查一下订单。"})
print(f"\n客服小助手回复: {response5['output']}")

# 场景六:不使用工具的通用问题
print("\n--- 场景六:不使用工具的通用问题 ---")
response6 = agent_executor.invoke({"input": "你好,请问你们的工作时间是?"})
print(f"\n客服小助手回复: {response6['output']}")

# 场景七:复杂一些的请求 (Agent 可能会多次思考和调用工具)
print("\n--- 场景七:复杂一些的请求 ---")
response7 = agent_executor.invoke({"input": "我有个订单是 ABC-456,同时想知道北京的门店地址。"})
print(f"\n客服小助手回复: {response7['output']}")

代码解析:

  1. 定义工具 (Tool):我们通过封装 Python 函数 search_order_statusfind_nearest_store,创建了两个 Tool 对象。每个 Tool 都需要一个 name (供 Agent 识别) 和一个 description (至关重要,LLM 会根据这个描述来判断何时使用该工具)。
  2. 初始化 LLMChatOpenAI 作为 Agent 的“大脑”,负责理解用户意图、规划行动。
  3. 创建 Agent Prompt:我们使用 PromptTemplate 定义了 Agent 的行为规范。这个 Prompt 非常关键,它告诉 LLM 如何思考、何时调用工具、以及如何形成最终答案。{agent_scratchpad} 是 Agent 内部记录思考过程和工具输出的占位符。
  4. 创建 Agent (create_react_agent):LangChain 提供了多种创建 Agent 的方式。create_react_agent 是一个非常常用且强大的工厂函数,它基于 ReAct 模式,能让 Agent 表现出很强的推理能力。
  5. 创建 Agent Executor (AgentExecutor):这是实际运行 Agent 的入口。verbose=True 参数非常有用,它会打印 Agent 的思考过程 (Thought) 和工具的调用 (Action/Observation),帮助我们理解 Agent 的决策逻辑,调试时必开!
  6. 运行 Agent:通过 agent_executor.invoke({"input": "..."}) 传入用户问题,Agent 就会开始它的“思考-行动”循环,最终返回结果。

运行上面的代码,你会看到 Agent 如何根据你的问题,智能地选择并执行 OrderTrackerStoreLocator 工具,并最终给出符合预期的回答。特别注意 verbose=True 打印出的详细日志,它能让你清晰地看到 Agent 的每一步思考和行动。

坑与避坑指南

Agent 虽然强大,但在实际应用中也存在不少“坑”,作为未来的架构师,你必须提前预知并做好准备:

  1. 工具描述模糊不清 (The "Blurry Tool Description" Trap)

    • 坑点:如果你给工具的 description 写得不够清晰、准确,或者与其他工具的描述有重叠,LLM 可能会误判,导致选择错误的工具,或者根本不知道何时该用哪个工具。
    • 避坑指南:工具描述是 Agent 的“说明书”。要像写 API 文档一样,力求简洁、明确、无歧义。明确指出工具的功能、输入参数的类型和预期、输出结果的含义。让 LLM 觉得这个工具就是为解决某个特定问题而生的。
  2. Prompt 工程的挑战 (The "Prompt as a Manual" Challenge)

    • 坑点:Agent 的行为高度依赖于你给它的主 Prompt。一个不好的 Prompt 可能导致 Agent 循环往复、无法停止、胡乱调用工具,或者在需要工具时却直接回答。
    • 避坑指南:Agent 的 Prompt 就像给一个新手员工的“操作手册”。它需要包含:
      • 明确的角色设定:你是谁?(智能客服小助手)
      • 明确的任务目标:你要做什么?(帮助用户解决问题)
      • 明确的工具使用规则:何时使用工具?如何使用工具?
      • 明确的回复格式:确保 Agent 知道如何组织最终答案。
      • 处理不确定情况的指令:如果信息不足怎么办?(主动询问)
    • 多尝试不同的 Prompt 措辞,观察 Agent 的行为,逐步优化。
  3. 工具的健壮性与错误处理 (The "Fragile Tool" Problem)

    • 坑点:Agent 调用的工具可能会失败(网络错误、API 限流、数据库异常)。如果工具失败了,Agent 可能会陷入困境,或者返回一个毫无意义的错误信息。
    • 避坑指南
      • 工具内部做好异常处理:你的 func 函数内部必须捕获所有可能的异常,并返回一个友好的、可供 LLM 理解的错误信息(例如:“查询订单失败,请稍后再试。”)。
      • Agent 的 Prompt 中加入错误处理指令:告知 Agent 在接收到工具错误信息时,应该如何处理(例如:向用户解释错误,建议重试,或转接人工客服)。
  4. 成本与延迟 (The "Hidden Cost" of Intelligence)

    • 坑点:Agent 模式下,LLM 可能会进行多次“思考”和“行动”循环,这意味着每次用户请求都可能触发多次 LLM API 调用和工具调用。这会显著增加 API 成本和响应延迟。
    • 避坑指南
      • 优化 Prompt:尽量让 Agent 一次思考就能做出正确决策,减少不必要的循环。
      • 精简工具:只提供 Agent 真正需要的工具,避免工具库过于庞大,增加 LLM 选择的难度。
      • 缓存策略:对于频繁查询且结果变化不大的工具,考虑引入缓存机制。
      • 模型选择:在确保效果的前提下,优先使用成本较低、速度较快的 LLM 模型。例如,很多简单的工具选择,gpt-3.5-turbo 也能做得很好。
  5. 安全与权限控制 (The "Rogue Agent" Risk)

    • 坑点:Agent 获得了调用外部系统的能力,如果设计不当,可能会导致安全漏洞(例如,Agent 调用了敏感的删除数据接口,或者获取了不该获取的用户信息)。
    • 避坑指南
      • 最小权限原则:为 Agent 提供的工具,其后端接口应只具备完成任务所需的最小权限。
      • 严格的输入校验:工具函数内部必须对所有输入参数进行严格的合法性校验,防止注入攻击或其他恶意输入。
      • 审计与监控:对 Agent 的所有工具调用和操作进行详细的日志记录和监控,及时发现异常行为。
      • 人工审核 (Human-in-the-Loop):对于一些高风险的操作(如修改关键数据),可以引入人工审核机制。

📝 本期小结

恭喜你!在本期课程中,我们成功地为智能客服小助手赋予了“行动力”,将它从一个被动的问答机器升级为能够主动解决问题的 Agent。我们深入理解了 Agent 的核心原理、ReAct 模式,并通过实战代码演示了如何定义工具、创建 Agent,并让它在客服场景中发挥作用。

你现在应该掌握了:

  • Agent 如何利用 LLM 的推理能力和外部工具来执行复杂任务。
  • 如何创建自定义的 Tool 对象,并将其集成到 Agent 中。
  • AgentExecutor 的作用以及 verbose 参数在调试中的重要性。

同时,我们也探讨了 Agent 在实际应用中可能遇到的各种“坑”,并提供了详细的避坑指南。记住,Agent 的强大伴随着复杂性,需要你在工具设计、Prompt 工程、错误处理和安全方面投入更多思考。

Agent 是构建真正智能、有用的 AI 应用的关键。下一期,我们将继续深入,探讨如何为 Agent 添加“记忆”,让它在多轮对话中保持上下文,更好地服务用户!敬请期待!