在 绑定工具Ⅱ中,我们通过 model.bind_tools(tools) 得到了一个 Runnable 实例 model_with_tools。这个实例就像一个普通的聊天模型,可以接受消息并给出回复,但它多了一个能力:在需要的时候,回复中会包含工具调用的请求。
本篇文章会聚焦在一个完整的调用流程上:定义工具 → 绑定模型 → 用 .invoke() 触发调用 → 解读返回的 AIMessage。
1、准备工具:用 @tool 装饰器定义函数
python
from langchain_openai import ChatDeepSeek
from langchain.core.messages import HumanMessage
from langchain.core.tools import tool
from typing_extensions import Annotated
# 定义大模型
model = ChatDeepSeek(model="deepseek-chat")
@tool
def add(
a: Annotated[int, "First integer"],
b: Annotated[int, "Second integer"]
) -> int:
"""Add two integers."""
return a + b
@tool
def multiply(
a: Annotated[int, "First integer"],
b: Annotated[int, "Second integer"]
) -> int:
"""Multiply two integers."""
return a * b
关于
Annotated
Annotated[int, "First integer"]这种写法告诉 LangChain 这个参数的类型是int,并且附加了人类可读的描述"First integer"。这样在生成工具调用的 JSON Schema 时,模型就能更准确地理解每个参数的含义。
现在,add 和 multiply 已是两个标准的 LangChain 工具对象,可以被 bind_tools() 识别。
2、绑定并调用
python
tools = [add, multiply]
model_with_tools = model.bind_tools(tools)
# 调用工具
result = model_with_tools.invoke("9乘6等于多少?")
print(result)
这里的关键是 .invoke()。我们直接传了一个中文问题 "9乘6等于多少?",模型需要判断:
-
这个问题是否需要工具?
-
如果需要,选哪个工具?
-
调用该工具时需要什么参数?
结果 result 是一个 AIMessage 对象:
python
AIMessage(
content='',
additional_kwargs={
'tool_calls': [{
'id': 'call_mbNxNYVfA0rExEETcdECG1',
'function': {'name': 'multiply', 'arguments': {'a': 9, 'b': 6}},
'type': 'function'
}],
'refusal': None
},
response_metadata={
'token_usage': { ... },
'model_name': 'deepseek-chat',
'finish_reason': 'tool_calls',
...
},
id='run--1f43e942-d5bb-46dd-8df3-f45b75ed0836-0',
tool_calls=[{
'name': 'multiply',
'args': {'a': 9, 'b': 6},
'id': 'call_mbNxNYVfA0rExEETcdECG1',
'type': 'tool_call'
}],
usage_metadata={'input_tokens': 86, 'output_tokens': 17, 'total_tokens': 103}
)
content(消息正文)
值为空字符串
''。表示模型这次没有生成文本回复 ,而是直接选择调用工具。如果模型想同时给出文字说明,
content中就会包含那段话。
additional_kwargs
这是附加的有效负载数据,通常由模型提供程序直接编码。
其中的
tool_calls是一个列表,包含了模型计划调用的工具信息:
id:这次工具调用的唯一标识。
function:{'name': 'multiply', 'arguments': {'a': 9, 'b': 6}},指出要调用的函数名及参数。
type:'function',固定表示函数调用。
response_metadata
存放响应的元数据,例如:
token_usage:本次请求消耗的 token 数。
model_name:实际作答的模型版本。
finish_reason:结束原因,这里是'tool_calls',说明模型因要调用工具而停止生成。这也是我们判断是否需要进行工具调用的一个重要标志。
tool_calls(最常用)
LangChain 为了方便开发者,直接解析了
additional_kwargs中的工具调用信息,放在了顶层的tool_calls属性里。它是一个列表,每个元素是一个字典,包含:
name:工具名('multiply')。
args:参数字典({'a': 9, 'b': 6})。
id:调用唯一 ID。
type:类型。实战中我们通常直接使用
result.tool_calls来获取工具调用请求 ,而不必手动钻入additional_kwargs。
usage_metadata
- 统计了本次调用的 token 使用情况,方便计费和性能监控。
| 字段 | 含义 | 关键作用 |
|---|---|---|
content |
模型的文本回复 | 为空字符串 '' 表示模型这次没有生成文本回复,而是直接选择调用工具。如果模型想同时给出文字说明,这里会包含对应的文本。 |
additional_kwargs |
附加的有效负载数据 | 由模型提供程序直接编码,其中的 tool_calls 列表包含了模型计划调用的工具信息。 |
tool_calls |
LangChain 解析后的工具调用信息 | 最常用的字段,直接包含了工具名、参数和调用 ID,实战中通常用 result.tool_calls 获取调用请求。 |
response_metadata |
响应的元数据 | 包含 token_usage(本次请求消耗的 token 数)、model_name(实际作答的模型版本)、finish_reason(结束原因)。其中 finish_reason='tool_calls' 是关键标志,说明模型因要调用工具而停止生成。 |
usage_metadata |
token 使用统计 | 方便计费和性能监控,和 response_metadata 中的 token_usage 信息一致。 |
3、小结
通过 .bind_tools() + .invoke(),我们让模型从"纯聊天"升级为"能主动提出工具调用需求"的智能体。返回的 AIMessage 中,tool_calls 是核心字段,它明确指出了要调用的函数名和参数。