Transformers 聊天模型的 Tool Use 完全指南:从 Python 函数到 JSON Schema 的工具调用实现原理
本文以 Transformers 官方的 Tool use(工具调用)文档 docs/source/en/chat_extras.md 为主体,系统讲解聊天模型的函数调用(function-calling)能力:如何定义工具、如何把工具传入 apply_chat_template、如何处理模型的 tool call 请求,以及底层 get_json_schema 的 schema 生成机制。读完本文,你将能够独立搭建一个带工具调用回环(tool loop)的本地聊天应用,并理解 Transformers 是如何把你的 Python 函数自动转成 JSON schema 的。
一、什么是 Tool Use
聊天模型(chat model)通常都在"function-calling"或"tool-use"场景上做过训练。所谓 Tool,就是由用户(开发者)提供的函数,模型可以在生成回复的过程中选择性地"调用"它。例如:给模型一个计算器工具,它就可以完成算术运算而不必在内部硬算;给一个天气查询工具,它就能获取实时温度。
官方文档将工具使用流程归纳为三个环节,也是本文的结构主线:
- 定义工具——用带类型注解和 Google 风格 docstring 的 Python 函数,或手写 JSON schema;
- 传入工具——通过
apply_chat_template的tools参数交给模型; - 处理工具调用——模型只"请求"调用,真正执行工具、把结果写回对话历史的是你的代码。
二、定义并传入工具(Passing tools)
当模型支持 tool-use 时,把函数传给 PreTrainedTokenizerBase.apply_chat_template 的 tools 参数即可。工具有两种传法:
- JSON schema(dict 形式);
- Python 函数:解析器会自动解析函数的参数名、参数类型和 docstring,生成 JSON schema。
2.1 函数式工具的标准写法
虽然直接传 Python 函数非常方便,但解析器只能处理 Google 风格 的 docstring(这一点在仓库中可证实:get_json_schema 内部用一组正则匹配 Args: / Returns: 块,见 chat_template_utils.py#L55-L69)。官方文档给出的两个工具示例如下,可直接复制使用:
def get_current_temperature(location: str, unit: str):
"""
Get the current temperature at a location.
Args:
location: The location to get the temperature for, in the format "City, Country"
unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
"""
return 22. # A real function should probably actually get the temperature!
def get_current_wind_speed(location: str):
"""
Get the current wind speed in km/h at a given location.
Args:
location: The location to get the wind speed for, in the format "City, Country"
"""
return 6. # A real function should probably actually get the wind speed!
tools = [get_current_temperature, get_current_wind_speed]
对函数格式的几条关键要求(均由 get_json_schema 的实现印证):
| 要求 | 说明 |
|---|---|
| 必须有 docstring | 缺少 docstring 会直接抛出 DocstringParsingException(chat_template_utils.py#L357-L358) |
每个参数必须在 docstring 的 Args: 块中有描述 |
缺失参数描述会抛出 DocstringParsingException(chat_template_utils.py#L366-L370) |
| 每个参数必须有类型注解 | 缺少类型注解会抛出 TypeHintParsingException(chat_template_utils.py#L195-L196) |
Returns: 块和返回类型是可选的 |
可以添加,但多数模型的 chat template 根本不使用这些信息 |
| 函数体代码被完全忽略 | 解析器只看签名和 docstring,不看实际实现 |
docstring 中还有一个隐藏特性:参数描述行尾的 (choices: [...]) 会被解析成 schema 里的 enum 字段。文档示例中的 unit: ... (choices: ["celsius", "fahrenheit"]) 就是典型用法,对应实现位于 chat_template_utils.py#L372-L375。
真正决定模型"是否调用该工具、如何填充参数"的"签名"是:函数名、参数名、参数类型、以及描述函数与参数用途的 docstring。
三、完整工具调用示例(Tool-calling Example)
3.1 加载支持 tool-use 的模型
文档推荐加载如 NousResearch/Hermes-2-Pro-Llama-3-8B 这类支持工具调用的 checkpoint;如果硬件允许,也可以考虑 Command-R、Mixtral-8x22B 等大一些、工具调用能力更强的模型。
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")
3.2 构造对话历史
messages = [
{"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
{"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
]
注意 system 消息中的提示"回复时使用查询地点所在国家常用的温度单位"——这是让模型自己推断出 celsius 的关键上下文。
3.3 传入 tools 并生成响应
把 messages 和工具列表一起传给 apply_chat_template,然后 tokenize 并生成:
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=128)
print(tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):]))
模型的实际输出:
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00