☰
LangGraph工具调用实战:从聊天机器人到智能体的核心机制
2026/10/6 9:47:55 网站建设 项目流程

之前在做智能体开发时,我反复卡在一个问题上:大模型“只会说,不会做”。你问它“厦门今天天气怎么样”,它能给出非常流畅的回复,但它并不知道真实天气,也不会主动去查天气接口。后来在项目中接入 LangGraph 的工具调用(Tool Calling)机制后,模型才真正从“聊天机器人”变成了“能干活的智能体”。

这篇文章围绕《AI编程与智能体开发》课程中 LangGraph 工具调用这一主题,整理了一份完整的实战笔记。文章会覆盖工具调用的核心概念、环境准备、工具定义、模型绑定、ToolNode 节点、ReAct 智能体搭建,以及高频报错排查和工程落地建议。无论你是刚开始接触 LangGraph 的初学者,还是准备把智能体接入业务系统的开发者,都可以直接参考本文的代码和排错思路。

1. 工具调用是什么,为什么智能体离不开它

1.1 从“只会聊天”到“能干活”

大模型的本质是一个文本生成模型,它的所有知识都来自训练数据。这就带来两个天然限制:

  • 它不知道训练数据截止之后的实时信息,比如今天的天气、最新的股票价格。
  • 它只能输出文字,不能直接查数据库、调接口、执行代码。

工具调用就是为了解决这两个问题而设计的。它的核心思想是:模型不负责执行动作,只负责“决定要调用哪个工具、传什么参数”,真正执行动作的是你的代码。

整个流程可以拆成四步:

  1. 你提前定义好一批工具,例如“查天气”“算乘法”“查订单”。
  2. 调用模型时,把工具的描述、参数结构一起发给模型。
  3. 模型根据用户问题,判断是否需要调用工具。如果需要,就返回一个结构化的“工具调用请求”,里面包含工具名和参数。
  4. 你的程序执行这个工具,把结果返回给模型。模型基于结果生成最终回答。

在 LangGraph 中,这四步被封装成了图(Graph)上的节点和边。模型节点负责“思考”,工具节点负责“执行”,两者通过条件边形成循环,直到模型认为任务完成。

1.2 LangGraph 与 LangChain 的关系

很多初学者会把 LangGraph 和 LangChain 搞混,这里先做一个简单区分。

LangChain 是一个组件库,提供了模型封装、提示词模板、向量存储、文档加载器等能力。你可以用 LangChain 快速调用 OpenAI、DeepSeek、通义千问等模型,也可以用它提供的@tool装饰器来定义工具。

LangGraph 则是一个编排引擎,它把智能体流程建模成一张有向图。图的每个节点是一个函数或逻辑单元,每条边定义节点之间的流转关系。LangGraph 的重点是状态管理、循环控制、条件路由和持久化,这些正是 LangChain 早期版本最薄弱的地方。

在实际项目中,两者通常是配合使用的:

  • 工具定义用 LangChain 的@tool。
  • 模型调用用 LangChain 的ChatOpenAI等封装。
  • 流程编排用 LangGraph 的StateGraph、ToolNode、create_react_agent。

简单说,LangChain 提供“零件”,LangGraph 负责“组装和调度”。

1.3 工具调用的典型应用场景

工具调用的应用场景非常广,常见的有下面几类:

  • 实时数据查询:天气、新闻、股票、航班信息。
  • 企业内部系统对接:查订单、查库存、创建工单、查询员工信息。
  • 计算与数据处理:数学计算、SQL 查询、文件格式转换。
  • 操作类任务:代发邮件、创建日历日程、提交审批。
  • 知识库检索:在 RAG 流程中,把检索器封装成工具,让模型按需检索。

可以说,只要你的智能体需要“接触外部世界”,就离不开工具调用。这也是 LangGraph 工具调用成为智能体开发核心技能的原因。

2. 环境准备与版本说明

2.1 Python 环境与依赖安装

LangGraph 是基于 Python 的框架,建议使用 Python 3.9 及以上版本。为了不影响系统全局环境,推荐创建独立的虚拟环境。

python -m venv .venv source .venv/bin/activate

Windows 系统激活命令为:

.venv\Scripts\activate

本文需要安装以下核心依赖:

pip install langgraph langchain-core langchain-openai python-dotenv

各包的作用:

  • langgraph:负责图的构建、状态管理和节点调度。
  • langchain-core:提供@tool装饰器、消息类型等基础抽象。
  • langchain-openai:提供 OpenAI 兼容接口的模型封装。
  • python-dotenv:用于读取.env文件中的环境变量。

LangGraph 目前还处于 0.x 快速迭代阶段,API 在不同小版本之间可能有细微差异。本文代码以常见稳定写法为例,安装时建议使用最新发布版本。如果你的项目已经存在其他版本的 LangGraph,升级前务必先阅读官方更新日志。

2.2 模型 API 的配置

工具调用依赖模型的原生 Function Calling 能力。目前主流的 OpenAI 兼容接口都支持这一能力,包括 OpenAI 官方模型、DeepSeek、通义千问、智谱等。

推荐把 API Key 写入.env文件,避免硬编码在代码中。

# 文件路径:.env OPENAI_API_KEY=你的密钥 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_MODEL=gpt-4o-mini

如果你的项目使用的是国内大模型厂商提供的 OpenAI 兼容接口,只需要把OPENAI_BASE_URL和OPENAI_MODEL换成对应的值即可。不同厂商的兼容地址和模型名不同,请以官方文档为准。

在代码中通过下面的方式加载配置:

import os from dotenv import load_dotenv load_dotenv() api_key = os.getenv("OPENAI_API_KEY") base_url = os.getenv("OPENAI_BASE_URL") model_name = os.getenv("OPENAI_MODEL")

需要注意,OPENAI_API_KEY属于敏感信息,不要提交到 Git 仓库。生产环境中建议使用密钥管理服务或者 CI/CD 的 Secrets 配置。

2.3 示例项目结构

为了便于后续实战,我们先规划好项目结构:

langgraph-tool-demo/ ├── .env ├── requirements.txt └── src/ ├── tools.py ├── agent.py └── run.py
  • tools.py:所有自定义工具函数。
  • agent.py:LangGraph 图的构建与编译。
  • run.py:入口脚本,接收用户问题并运行智能体。

requirements.txt内容如下:

langgraph langchain-core langchain-openai python-dotenv

3. LangGraph 工具调用的核心机制

在动手写代码之前,有必要先理解 LangGraph 工具调用的四个核心概念:工具本身、模型绑定、工具节点、条件路由。

3.1 工具的本质:函数 + 描述 + 参数结构

在 LangChain / LangGraph 中,一个工具就是一个普通 Python 函数,加上名称、描述和参数结构三部分元信息。

最常用的定义方式是@tool装饰器:

from langchain_core.tools import tool @tool def get_weather(city: str) -> str: """查询指定城市的当前天气情况。 Args: city: 城市名称,例如“厦门” """ return f"{city}:晴,气温 22~28 摄氏度,东南风 3 级"

这里的关键点是:

  • 函数名get_weather就是工具名。
  • 函数的 docstring 就是工具描述,模型会据此判断何时调用这个工具。
  • 参数city: str会被解析成 JSON Schema,模型会按照这个结构生成参数。

如果你想知道模型看到的工具结构是什么样,可以打印get_weather.name、get_weather.description和get_weather.args来查看。这就是模型在请求中收到的全部工具信息。

3.2 用 bind_tools 让模型“看到”工具

定义好工具后,需要把工具列表绑定到模型上,这一步通过bind_tools完成。

from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o-mini", api_key=api_key, base_url=base_url, temperature=0 ) tools = [get_weather] llm_with_tools = llm.bind_tools(tools)

需要特别注意的是,bind_tools只是把工具定义附加到模型的请求参数中,并不会执行任何工具。它改变的是模型的“能力边界”:模型现在知道存在get_weather这个工具,并且知道它的参数格式。

调用绑定了工具的模型后,如果模型认为需要查天气,它会返回一个tool_calls字段。这个字段是结构化的调用请求,而不是自然语言。

from langchain_core.messages import HumanMessage response = llm_with_tools.invoke([HumanMessage(content="厦门今天天气怎么样?")]) print(response.tool_calls)

输出大致如下:

[{'name': 'get_weather', 'args': {'city': '厦门'}, 'id': 'call_abc123', 'type': 'tool_call'}]

其中name是工具名,args是模型生成的参数,id是本次调用请求的唯一标识,后续工具执行结果的回传需要用到它。

3.3 工具节点 ToolNode 与条件路由 tools_condition

在 LangGraph 中,真正执行工具的不是模型,而是ToolNode。它接收模型返回的tool_calls,逐个调用对应工具,并把结果包装成ToolMessage写回图的状态。

from langgraph.prebuilt import ToolNode tool_node = ToolNode(tools)

ToolNode内部会根据tool_calls里的name找到对应的工具函数,用args作为参数调用,然后把结果封装成消息。

那么图怎么知道“什么时候该调用工具,什么时候该结束”呢?答案是tools_condition,它是 LangGraph 预置的一个条件路由函数。

from langgraph.prebuilt import tools_condition

tools_condition的逻辑很简单:检查图中最后一条 AIMessage 是否包含tool_calls。

  • 如果包含,返回字符串"tools",表示下一步应该进入工具节点。
  • 如果不包含,返回END,表示模型已经可以直接给出最终回答,流程结束。

3.4 完整的执行链路

把上面几个概念组合起来,就是一个标准的工具调用循环。

用一个最简单的图来说明:

用户输入 --> agent 节点 --> tools_condition 判断 | 有 tool_calls ----> tools 节点(执行工具) 没有 tool_calls ---> 结束,输出最终回答

当tools节点执行完工具后,结果会追加到消息列表里,流程再次回到agent节点,让模型基于工具结果继续推理。这个“思考 -> 调用工具 -> 观察结果 -> 再思考”的循环,就是 ReAct 模式的核心,也是智能体能够完成多步任务的原因。

这里需要理解一个关键点:图中的状态是消息列表的累积,而不是覆盖。每一轮模型输出、工具结果都被追加到messages中,模型因此能记住之前发生过什么。

4. 从零开始:手写第一个工具调用

为了彻底理解工具调用的执行过程,我们先不急着搭建完整图,而是手动模拟一遍“模型调用工具 -> 执行工具 -> 返回结果给模型”的流程。

4.1 安装依赖并创建项目

先创建项目目录并激活虚拟环境:

mkdir langgraph-tool-demo && cd langgraph-tool-demo python -m venv .venv source .venv/bin/activate pip install langgraph langchain-core langchain-openai python-dotenv

创建.env文件并填入你的模型配置,然后创建src目录。

4.2 定义工具函数

在src/tools.py中写入第一个工具:

# 文件路径:src/tools.py from langchain_core.tools import tool @tool def get_weather(city: str) -> str: """查询指定城市的当前天气情况。 Args: city: 城市名称,例如“厦门” """ # 生产环境中应替换为真实天气 API,例如和风天气、高德天气等 return f"{city}:晴,气温 22~28 摄氏度,东南风 3 级" @tool def multiply(first: float, second: float) -> float: """计算两个数字的乘积。 Args: first: 第一个乘数 second: 第二个乘数 """ return first * second

这里定义了两个工具:一个查天气,一个做乘法。multiply是为了后面演示多工具场景准备的。

4.3 绑定模型并查看工具调用请求

在src/manual_test.py中手动触发一次工具调用:

# 文件路径:src/manual_test.py import os from dotenv import load_dotenv from langchain_core.messages import HumanMessage, ToolMessage from langchain_openai import ChatOpenAI from tools import get_weather load_dotenv() llm = ChatOpenAI( model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"), api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"), temperature=0 ) llm_with_tools = llm.bind_tools([get_weather]) # 第一步:发送用户问题 messages = [HumanMessage(content="厦门今天天气怎么样?适合出门吗?")] ai_msg = llm_with_tools.invoke(messages) print("模型返回的工具调用请求:") print(ai_msg.tool_calls)

运行脚本:

cd src python manual_test.py

如果一切正常,你会看到模型输出了一个tool_calls列表,其中包含工具名get_weather和参数{"city": "厦门"}。

4.4 手动执行工具并回传结果

接下来手动执行这个工具调用,把结果封装成ToolMessage送回模型:

# 继续在上面的文件中追加 if ai_msg.tool_calls: messages.append(ai_msg) for tool_call in ai_msg.tool_calls: tool_name = tool_call["name"] tool_args = tool_call["args"] if tool_name == "get_weather": result = get_weather.invoke(tool_args) messages.append(ToolMessage(content=result, tool_call_id=tool_call["id"])) # 第二步:把工具结果发回模型,让模型生成最终回答 final_msg = llm_with_tools.invoke(messages) print("最终回答:") print(final_msg.content)

这里有两个容易忽略的细节:

  1. 我们需要把ai_msg本身也追加到messages,因为模型需要看到自己刚才的调用请求。
  2. ToolMessage必须携带tool_call_id,并且这个 id 要和tool_calls里的id一一对应。否则模型无法把工具结果和调用请求关联起来。

运行后,期望的输出类似:

最终回答: 根据查询结果,厦门今天晴,气温 22~28 摄氏度,东南风 3 级。天气不错,适合出门。

到这里,你已经手动完成了一次完整的工具调用流程。这个流程虽然能用,但存在几个问题:循环要靠自己写、分支逻辑要自己维护、消息状态要自己管理。如果任务涉及多轮工具调用,代码会迅速变得混乱。这正是下一步引入 LangGraph 图结构的原因。

5. 用 LangGraph 实现完整的 ReAct 智能体

5.1 为什么需要图结构

手动流程适合理解原理,但不适合工程落地。真实场景中的智能体往往需要:

  • 根据用户问题决定是否调用工具。
  • 一次调用多个工具。
  • 根据工具结果决定是否继续调用其他工具。
  • 在工具调用失败时重试或换一种方式。

这些需求本质上是一个带循环和条件分支的状态机。LangGraph 用图来建模,把“模型调用”“工具执行”抽象成节点,用边和条件函数控制流转,状态管理也由框架自动完成。

5.2 基于 StateGraph 搭建工具调度图

在src/agent.py中基于StateGraph搭建完整的工具调度图:

# 文件路径:src/agent.py import os from dotenv import load_dotenv from langchain_core.messages import HumanMessage from langchain_openai import ChatOpenAI from langgraph.graph import MessagesState, StateGraph, START, END from langgraph.prebuilt import ToolNode, tools_condition from tools import get_weather, multiply load_dotenv() def create_agent(): llm = ChatOpenAI( model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"), api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"), temperature=0 ) tools = [get_weather, multiply] llm_with_tools = llm.bind_tools(tools) # 模型节点:调用模型,返回新的消息 def call_model(state: MessagesState): response = llm_with_tools.invoke(state["messages"]) return {"messages": [response]} # 构建图 graph = StateGraph(MessagesState) graph.add_node("agent", call_model) graph.add_node("tools", ToolNode(tools)) graph.add_edge(START, "agent") graph.add_conditional_edges("agent", tools_condition) graph.add_edge("tools", "agent") return graph.compile() if __name__ == "__main__": app = create_agent() result = app.invoke({ "messages": [HumanMessage(content="厦门和北京今天的天气怎么样?")] }) for message in result["messages"]: message.pretty_print()

这段代码有几个关键点:

  • MessagesState是 LangGraph 预置的状态类型,内部使用add_messages归约器管理消息列表。你不需要手动维护消息累积逻辑。
  • call_model是 agent 节点,它从状态中取出全部消息,调用绑定工具的模型,并返回新的消息。
  • ToolNode(tools)接收工具列表,自动执行模型返回的tool_calls。
  • tools_condition是预置条件函数,负责在“结束”和“进入 tools 节点”之间做选择。

运行脚本:

cd src python agent.py

你会看到类似下面的输出(具体内容取决于模型返回):

================================ Human Message ================================= 厦门和北京今天的天气怎么样? ================================== AI Message ================================== Tool Calls: get_weather (call_xxx) Args: city: 厦门 get_weather (call_yyy) Args: city: 北京 ================================= Tool Message ================================= 厦门:晴,气温 22~28 摄氏度,东南风 3 级 ================================= Tool Message ================================= 北京:晴,气温 18~26 摄氏度,西北风 2 级 ================================== AI Message ================================== 厦门今天晴,气温 22~28 摄氏度;北京今天也是晴天,气温 18~26 摄氏度。

可以看到,模型自动并行发起了两个get_weather调用请求,ToolNode分别执行并返回结果,最终模型基于两个工具结果生成了汇总回答。这就是 LangGraph 处理多工具并行的能力。

5.3 使用 create_react_agent 快速搭建

如果你不想手动定义节点和边,LangGraph 提供了一个更高级的封装create_react_agent,它内部已经实现了标准的 ReAct 循环。

# 文件路径:src/quick_agent.py import os from dotenv import load_dotenv from langchain_core.messages import HumanMessage from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent from tools import get_weather, multiply load_dotenv() llm = ChatOpenAI( model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"), api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"), temperature=0 ) tools = [get_weather, multiply] agent = create_react_agent(model=llm, tools=tools) result = agent.invoke({ "messages": [HumanMessage(content="厦门天气怎么样?顺便算一下 12 乘以 8 等于多少。")] }) for message in result["messages"]: message.pretty_print()

create_react_agent内部做了几件重要的事情:

  • 自动调用bind_tools把工具绑定到模型。
  • 自动创建 agent 节点和ToolNode。
  • 自动添加tools_condition条件路由。
  • 内部处理了循环、状态和消息累积。

对于标准工具调用场景,create_react_agent是最省事的方案。对于需要自定义流程、添加人工审批节点、插入条件分支的复杂业务,则建议使用StateGraph手动构建。

5.4 多工具场景的执行逻辑

上面的例子同时用到了get_weather和multiply两个工具。模型会根据用户问题的语义自动选择调用哪个工具。

用户问“厦门天气怎么样”,模型只调用get_weather。用户问“12 乘以 8”,模型只调用multiply。用户同时问两件事,模型可能并行发起两个工具调用。

这个“自主决策”能力来自模型本身。在实际项目中需要注意,模型选择工具的结果并不总是符合预期,因此工具的设计是否清晰直接影响到调用准确率。

5.5 运行与验证

确保当前在项目虚拟环境中,执行:

cd src python quick_agent.py

如果输出里同时出现了天气查询结果和96.0的乘法结果,说明多工具智能体已经正常运行。

6. 常见问题与排查思路

工具调用的开发过程中,最常见的问题集中在“模型不调用工具”“参数解析失败”“图循环异常”几个方面。下面按问题现象、可能原因、解决思路三个维度整理。

问题现象常见原因解决思路
模型始终不调用工具,直接文字回答模型不支持 Function Calling,或未调用 bind_tools确认模型支持工具调用,检查是否执行了 bind_tools
工具参数解析报错,缺少必填参数工具参数名对模型不友好,或 docstring 描述不清晰简化参数名,在 docstring 中说明每个参数含义
图进入死循环,工具被反复调用工具返回内容让模型误以为需要继续调用,或工具状态异常让工具返回明确结果,检查是否触发了不必要的循环
工具返回内容过长,耗尽上下文工具返回了整张表或大段日志精简工具返回内容,只返回核心字段
ToolMessage 关联失败tool_call_id 未正确传递使用 ToolNode,它自动处理 id 关联
导入 ToolNode 报错langgraph 版本过旧升级 langgraph 到最新稳定版

6.1 模型始终不调用工具

这是最常见的问题。首先确认你使用的模型是否支持原生的 Function Calling / Tool Calling 能力。老版本的模型或部分轻量模型不支持这个功能,模型只能把工具调用要求当作普通文字生成,导致永远不返回tool_calls。

排查步骤:

  1. 确认已经执行了llm.bind_tools(tools)。
  2. 打印最终发给模型的请求,确认tools字段是否出现在请求中。
  3. 确认模型名称正确,部分模型需要特定的开关参数才能启用工具调用。
  4. 检查temperature是否过高,建议机器类任务设置为 0。

6.2 工具参数解析失败

模型生成参数时偶尔会出现格式问题,比如缺少必填字段、类型错误、字段名拼写错误。

解决方案:

  • 在工具函数的 docstring 里写清楚每个参数的用途和示例值。
  • 参数名尽量用完整单词,不要用c、x这种无意义缩写。
  • 工具内部做好参数校验,对异常参数返回友好的错误信息,而不是直接抛异常。

工具内部建议这样处理:

@tool def get_weather(city: str) -> str: """查询指定城市的当前天气情况。 Args: city: 城市名称,例如“厦门” """ if not city or not city.strip(): return "参数错误:city 不能为空" # 正常查询逻辑 return f"{city}:晴,气温 22~28 摄氏度"

6.3 图循环卡死或无限调用工具

LangGraph 默认有递归限制,超过限制会抛出GraphRecursionError。发生这种情况,通常意味着智能体陷入了“调用工具 -> 观察结果 -> 再次调用工具”的死循环。

排查方向:

  • 工具返回内容是否足够明确?如果工具总是返回空字符串,模型可能反复尝试调用。
  • 工具内部是否有异常导致每次返回相同错误?应该让模型感知到失败并停止继续调用。
  • 是否某些工具真的可能被调用无限次?可以手动设置recursion_limit作为兜底。
result = app.invoke( {"messages": [HumanMessage(content="厦门天气怎么样?")]}, config={"recursion_limit": 20} )

6.4 工具返回内容太大导致上下文溢出

有些工具会返回数据库全表、大段日志或完整文件内容,这些内容会迅速占满上下文窗口。

解决方案是限流和精简:

  • 在工具内部做数据截断,只返回前 N 条记录。
  • 返回摘要而非原文。
  • 把大数据写入临时文件或对象存储,工具只返回文件地址。

工具设计的黄金原则是:返回给模型的内容越精炼,模型的理解越准确,上下文消耗也越少。

7. 最佳实践与工程建议

7.1 工具设计原则

工具的质量直接决定智能体的上限。在定义工具时,建议遵循以下原则:

  • 单一职责:一个工具只做一件事。把“查天气”和“发邮件”拆成两个工具,而不是放在一个工具里按参数分支。
  • 参数尽量少:工具参数越多,模型生成参数的出错概率越高。能合并的参数尽量合并。
  • 描述要清晰:docstring 要写明工具用途、每个参数的含义和单位、返回内容的格式。
  • 返回结构化数据:在可能的情况下,返回 JSON 字符串或字典,方便模型解读。

一个反面例子是工具描述写成“处理数据”,模型根本不知道何时调用它。正面例子应该写清楚触发条件、输入和输出。

7.2 错误处理与超时控制

工具执行是智能体流程中最容易出错的环节,因为外部接口不稳定、参数可能非法、服务可能超时。工具内部必须做异常兜底。

import time @tool def query_order(order_id: str) -> str: """根据订单号查询订单状态。 Args: order_id: 订单号 """ try: # 模拟外部 API 调用 time.sleep(0.5) return f"订单 {order_id} 状态:已发货" except Exception as e: return f"订单查询失败:{str(e)}"

注意这里的关键设计:工具出错时返回一条描述失败原因的消息,而不是抛异常让整个图崩溃。模型可以基于这条错误信息决定是重试、更换工具还是直接告知用户失败。

对于超时类的外部调用,建议在工具内部设置超时时间。需要特别注意,工具的返回结果不要包含敏感信息,比如完整密钥、数据库连接串等,防止这些信息被回传给模型。

7.3 安全边界与权限控制

这是工具调用工程化中最重要的一点。工具一旦暴露给模型,模型就拥有了执行真实操作的能力。必须遵守最小权限原则:

  • 只注册当前场景确实需要的工具,不要把所有函数都暴露给模型。
  • 涉及删除、修改、转账、审批等敏感操作,添加人工确认环节。例如在工具调用前插入一个human_approval节点,人工确认后才执行。
  • 所有外部调用都要做参数校验,防止模型生成恶意参数。
  • 在生产环境使用真实工具前,先在测试环境验证一遍完整的调用链。

如果你在@tool里使用了eval、exec、直接执行 shell 命令等能力,务必意识到这相当于给了模型代码执行权限,安全风险极高,生产环境要格外谨慎。

7.4 日志与可观测性

智能体的运行过程很难调试,因为涉及模型、工具、状态多轮交互。建议在关键节点埋点:

  • 记录模型每次返回的tool_calls内容。
  • 记录每个工具的入参、耗时和返回摘要。
  • 记录图执行的最大深度和总轮次。

在call_model和工具节点中加日志是常见的做法:

def call_model(state: MessagesState): response = llm_with_tools.invoke(state["messages"]) if response.tool_calls: print(f"[agent] 模型发起工具调用: {response.tool_calls}") return {"messages": [response]}

线上系统建议接入成熟的日志系统,并给单次智能体运行生成一个trace_id,便于把一次完整交互链路串起来排查问题。

8. 总结与后续学习路线

到这里,你已经完整走通了 LangGraph 工具调用的全流程:理解了工具调用的背景和原理,掌握了@tool定义工具、bind_tools绑定模型、ToolNode执行工具、tools_condition条件路由这几个核心概念,并且用StateGraph和create_react_agent分别实现了可运行的 ReAct 智能体。

接下来的学习建议按下面的顺序推进:

  1. 自己动手添加一个真实工具,比如对接一个公开天气 API 或数据库查询接口,体验真实环境下的参数解析和异常处理。
  2. 学习 LangGraph 的状态定义和自定义 State,理解add_messages归约器之外的消息管理模式。
  3. 研究条件路由的高级用法,比如根据工具结果决定是否结束流程或进入人工审核节点。
  4. 学习子图(Subgraph)与并行分支,把复杂任务拆解成多个子智能体。
  5. 尝试接入 LangGraph 的持久化能力,实现多轮对话的长期记忆。

工具调用是智能体开发的第一个门槛,迈过这道门槛后,你会发现真正复杂的不是“调用工具”,而是设计一套稳定、安全、可观测的工具调用体系。建议你在学习过程中多打印模型返回的原始请求和tool_calls结构,这对理解模型的行为方式非常有帮助。如果本文对你有帮助,可以先收藏备用,后续实战中遇到问题时随时回来对照排查。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询