📌 核心结论(TL;DR)
-
本质揭秘:大模型不能直接执行本地代码。Tool Call 本质上是模型返回的一段特殊的"结构化输出"(JSON),告诉开发者需要调用什么函数、传什么参数。
-
执行闭环 :完整的工具调用需要三步:① 模型决策并返回
tool_calls;② 开发者在本地执行对应函数,封装为ToolMessage;③ 将ToolMessage追加到历史消息中再次发给模型。 -
定义规范 :使用
@tool装饰器定义工具,函数名、类型提示和文档字符串(Docstring)极其重要,它们构成了模型是否调用该工具的判断依据(Schema)。
🔍 一、 原理图解与核心概念
1. 为什么需要工具?
大模型有知识截止日期,无法获取实时数据,也无法直接操作数据库。工具(Tools)允许大模型与外部世界交互,突破自身能力的边界。
2. 底层流程:"思考-行动-观察"
-
思考:用户提问,大模型分析意图。
-
行动 :如果需调用工具,模型返回带有
tool_calls的AIMessage。注意,此时模型并未给出最终答案。 -
执行 :开发者根据
tool_calls中的函数名和参数,在本地执行真实函数。 -
观察 :将执行结果包装成
ToolMessage返还给模型,模型再据此生成最终自然语言答复。
💻 二、 精选核心代码片段
1. 定义工具(@tool 装饰器)
python
from langchain_core.tools import tool
from typing_extensions import Annotated
@tool
def multiply(
a: Annotated[int, ..., "第一个整数"],
b: Annotated[int, ..., "第二个整数"]
) -> int:
"""两数相乘。当用户询问乘法计算时使用此工具。"""
return a * b
2. 工具绑定与调用闭环
python
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(model="deepseek-chat", ...)
# 1. 绑定工具
model_with_tools = model.bind_tools([multiply])
messages = [HumanMessage(content="9乘6等于多少?")]
# 2. 模型决策
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)
# 3. 本地执行(必须通过 tool_calls 获取参数)
for tool_call in ai_msg.tool_calls:
tool_msg = multiply.invoke(tool_call) # 自动生成 ToolMessage
messages.append(tool_msg)
# 4. 将执行结果交回模型生成回答
final_result = model.invoke(messages)
print(final_result.content)
3. 进阶:StructuredTool 与内容分离(content_and_artifact)
除了 @tool 装饰器,当我们需要包装第三方函数,或者需要将给大模型看的内容和给代码看的数据分离时,StructuredTool 是最佳选择。
python
from typing import Tuple
from langchain_core.tools import StructuredTool
# 假设这是一个查询天气的复杂函数
def get_weather(city: str) -> Tuple[str, dict]:
# 模拟调用第三方 API 返回了庞大的数据
raw_data = {"city": city, "temp": 25, "aqi": 45, "details": "..."}
# 但大模型只需要看一句话总结(节省 Token)
summary = f"{city}今天晴,气温25度。"
return summary, raw_data
weather_tool = StructuredTool.from_function(
func=get_weather,
name="Get_Weather",
description="查询指定城市的天气",
response_format="content_and_artifact" # 核心配置!
)
# 执行后:
# content = "西安今天晴,气温25度。" (大模型看这个)
# artifact = {"city": "西安", ...} (你的后端代码用这个)

(完整的包含多工具调用的代码已上传至 Gitee 仓库)
⚠️ 三、 踩坑排查排雷
大模型不调用工具,直接回答:
- 排查 :检查工具的
Docstring是否清晰描述了"什么时候该用它"。工具名不能太抽象(比如叫calc,不如叫multiply_numbers)。
报错 Invalid tool_call_id 或模型陷入死循环:
- 排查 :在将本地执行结果返回给模型时,必须使用
ToolMessage且带上tool_call_id。如果使用HumanMessage传递结果,模型会不知道这是工具的执行反馈,导致逻辑混乱。
类型提示缺失导致大模型解析参数失败:
- 排查 :一定要加上 Python 的类型提示(如
a: int),并在文档字符串中说明参数含义,LangChain 会自动生成 JSON Schema,缺少类型提示会导致模型乱传参数。

