langGraph从入门到精通(九)——基于LangGraph构建具备多工具调用与自动化摘要能力的智能 Agent

《基于LangGraph构建具备多工具调用与自动化摘要能力的智能 Agent 》

1 导语

在构建复杂的 AI 代理时,如何让 Agent 不仅能"听懂"需求,还能"协调"多个工具并最终"专业"地汇总结果?本文将基于 LangGraph 实战案例,深度拆解一个具备实时联网搜索、天气查询、数据库入库以及最终结果自动化摘要能力的完整智能体闭环。

本文所有步骤亲测可复现,适配环境:Windows/macOS/Linux,Python >= 3.9。

2 技术栈清单

  • Python == 3.11.x
  • langgraph == 1.0.5
  • langchain-openai == 1.1.7
  • python-dotenv == 1.2.1
  • Model: qwen-plus (DashScope API)

3 项目核心原理

本项目通过 StateGraph 构建了一个闭环工作流:

  1. 决策层 :由大模型判定是否需要调用工具(chat_with_model)。
  2. 执行层 :手动实现工具执行节点(execute_function),处理并行的 tool_calls
  3. 分流逻辑:利用条件边(Conditional Edges)实现"执行工具"与"直接回复"的动态切换。
  4. 汇总层 :所有路径最终汇聚于 natural_response 节点,利用系统 Prompt 对多源信息进行专业化中文总结。

4 实战步骤

4.1 环境准备

前置条件:已配置 .env 文件,包含 DASHSCOPE_API_KEY

bash 复制代码
# 安装必要依赖
pip install langgraph==1.0.5 langchain-openai==1.1.7 pydantic==2.10.0
# 验证环境
python -c "import langgraph; print(langgraph.__version__)"
# 成功标识:输出 1.0.5

4.2 代码实现

4.2.1 状态定义与工具 Schema

使用 Pydantic 定义工具的参数约束,确保 LLM 输出的准确性。

python 复制代码
from typing import TypedDict, Annotated, Optional
import operator
from pydantic import BaseModel, Field
from langchain_core.messages import AnyMessage

# 定义状态:使用 Annotated 和 operator.add 实现消息自动追加
class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]

# 定义工具参数模型
class UserInfo(BaseModel):
    name: str = Field(description="用户姓名")
    age: Optional[int] = Field(description="用户年龄")
    email: str = Field(description="邮箱地址")
    phone: Optional[str] = Field(description="电话号码")
@tool(args_schema = UserInfo)
def insert_db(name, age, email, phone):
    """Insert user information into the database, The required parameters are name, age, email, phone"""
    session = Session()  # 确保为每次操作创建新的会话
    try:
        # 创建用户实例
        user = User(name=name, age=age, email=email, phone=phone)
        # 添加到会话
        session.add(user)
        # 提交事务
        session.commit()
        return {"messages": [f"数据已成功存储至Mysql数据库。"]}
    except Exception as e:
        session.rollback()  # 出错时回滚
        return {"messages": [f"数据存储失败,错误原因:{e}"]}
    finally:
        session.close()  # 关闭会话
4.2.2 核心节点与路由逻辑

手动实现工具执行逻辑,深入理解 ToolMessage 的构造。

python 复制代码
def execute_function(state: AgentState):
    # 获取模型生成的工具调用指令
    tool_calls = state['messages'][-1].tool_calls
    results = []
    # 建立工具映射表
    tools_map = {"insert_db": insert_db, "fetch_real_time_info": fetch_real_time_info, "get_weather": get_weather}
    
    for t in tool_calls:
        # 执行工具并将结果封装为 ToolMessage
        result = tools_map[t['name']].invoke(t['args'])
        results.append(ToolMessage(tool_call_id=t['id'], name=t['name'], content=str(result)))
    return {'messages': results}

def exists_function_calling(state: AgentState):
    # 判定是否存在工具调用请求
    return len(state['messages'][-1].tool_calls) > 0
4.2.3 图编排与编译
python 复制代码
graph = StateGraph(AgentState)
graph.add_node("chat_with_model", chat_with_model)
graph.add_node("execute_function", execute_function)
graph.add_node("natural_response", natural_response)

graph.set_entry_point("chat_with_model")
graph.add_conditional_edges(
    "chat_with_model",
    exists_function_calling,
    {True: "execute_function", False: "final_answer"} # 条件分流
)
graph.add_edge("execute_function", "natural_response")
graph.set_finish_point("natural_response")
app = graph.compile()

4.3 功能测试

测试用户信息的自动入库与专业回复:

  • 启动命令python ./07-tool-05.py
  • 预期输出 :输入用户信息后,控制台应先打印 SQL 执行语句(若配置了 echo=True),最后输出中文专业总结。

5 核心代码深度解析

5.1 原始代码展示

python 复制代码
# 行号 139-148
graph.add_conditional_edges(
    "chat_with_model",
    exists_function_calling,
    {True: "execute_function", False: "final_answer"}
)

graph.add_edge("execute_function", "natural_response")
graph.add_edge("final_answer", "natural_response")
graph.set_finish_point("natural_response")

5.2 关联知识点讲解

  • 知识点 1:ToolMessage 的手动构造
    execute_function 中,我们没有使用预构建的 ToolNode语法/知识点名称ToolMessage(tool_call_id=...)核心作用 :它必须携带 tool_call_id 才能让模型知道这条结果对应的是哪个请求,否则在多工具并行场景下会逻辑混乱。
  • 知识点 2:Annotated 状态归并
    语法/知识点名称Annotated[list, operator.add]新手易错 :如果漏写了 operator.add,后续节点返回的 {"messages": [...]} 会直接覆盖之前的消息,导致 Agent 丢失上下文记忆。

5.3 代码逻辑解析

  1. exists_function_calling :作为"分流器",它通过检查 AIMessage 中的 tool_calls 列表长度。如果模型觉得需要查外部信息(如天气),则返回 True 强制流向执行节点。
  2. natural_response :这是系统的"润色员"。它不直接返回工具执行的原始字符串(通常很乱),而是通过一个 SYSTEM_PROMPT 指令:"基于现有信息,生成专业中文回复"。这种设计保证了最终用户看到的输出具有统一的语气和格式。

6 效果验证

6.1 案例1

python 复制代码
query="你好,请你介绍一下你自己"
input_message = {"messages": [HumanMessage(content=query)]}

result = graph.invoke(input_message)
result

6.2 案例2

python 复制代码
query="小米汽车"
input_message = {"messages": [HumanMessage(content=query)]}

result = graph.invoke(input_message)
result

6.3 案例3

python 复制代码
query="北京的天气怎么样?"
input_message = {"messages": [HumanMessage(content=query)]}

result = graph.invoke(input_message)
result

7 踩坑记录

7.1 Pydantic 模型描述缺失

  • 错误现象:模型总是乱填参数,或者不调用工具。
  • 根因分析UserInfoFielddescription 写得太简略,模型不理解什么时候该采集电话。
  • 解决方案 :在 Field 中明确标注"如果用户没有提供则不填"等引导语。

7.2 异步调用下的状态冲突

  • 错误现象:数据库插入成功但回复里说失败。
  • 根因分析 :由于 operator.add 的原子性,在并发执行工具时,如果节点逻辑编写不当可能导致消息顺序错乱。
  • 解决方案 :在 execute_function 中使用列表收集所有 ToolMessage 后一次性返回。

7.3 环境配置导致的导入错误

  • 错误现象ModuleNotFoundError: No module named 'langgraph'
  • 根因分析:在虚拟环境外执行或未正确安装。
  • 解决方案 :执行 pip install langgraph==1.0.5 并确认 which python 指向正确环境。

8 总结与扩展

本文通过手动实现 ToolNode 的逻辑,带大家深入理解了 LangGraph 内部的消息交换机制。复现关键点在于:

  1. Schema 描述:给 LLM 的"说明书"必须精准。
  2. 状态追加 :必须使用 operator.add 保证记忆连续。
  3. 结果润色:最后加入一个汇总节点,极大提升用户体验。

欢迎评论区留言讨论核心主题相关的问题,若复现失败可留言你的系统版本+报错日志,我会及时回复~

相关推荐
七月稻草人1 小时前
CANN ops-nn:AIGC底层神经网络算力的核心优化引擎
人工智能·神经网络·aigc·cann
种时光的人1 小时前
CANN仓库核心解读:ops-nn打造AIGC模型的神经网络算子核心支撑
人工智能·神经网络·aigc
晚霞的不甘1 小时前
守护智能边界:CANN 的 AI 安全机制深度解析
人工智能·安全·语言模型·自然语言处理·前端框架
谢璞2 小时前
中国AI最疯狂的一周:50亿金元肉搏,争夺未来的突围之战
人工智能
池央2 小时前
CANN 算子生态的深度演进:稀疏计算支持与 PyPTO 范式的抽象层级
运维·人工智能·信号处理
方见华Richard2 小时前
世毫九实验室(Shardy Lab)研究成果清单(2025版)
人工智能·经验分享·交互·原型模式·空间计算
Maynor9962 小时前
OpenClaw 玩家必备:用 AI 自动追踪社区最新动态
java·服务器·人工智能
aini_lovee2 小时前
MATLAB基于小波技术的图像融合实现
开发语言·人工智能·matlab
ujainu2 小时前
CANN仓库中的AIGC多模态统一抽象工程:昇腾AI软件栈如何用一套接口驾驭图文音视
人工智能·aigc
少云清2 小时前
【金融项目实战】7_接口测试 _代码实现接口测试(重点)
python·金融项目实战