Tool Calling
什么是Tool Calling
工具调用(Tool Calling,Function Calling,FC)是一种将大模型与外部工具和 API 相连的关键功能,作为自然语言与信息接口之间的“翻译官”,它能够将用户的自然语言请求智能地转化为对特定工具或 API 的调用,从而高效满足用户的特定需求。
工作原理:开发者通过自然语言向模型描述工具的功能和定义,模型在对话过程中自主判断是否需要调用工具。当需要调用时,模型会返回符合要求的工具函数及入参,开发者负责实际调用工具并将结果回填给模型,模型再根据结果进行总结或继续规划子任务。
实现原理
FC特性实现主要包括前处理(serving_chat模块)、后处理模块(tool parser)以及chat_template,前处理模块通过chat_template对用户prompt进行渲染,后处理模块对模型输出进行解析。整体流程如下图所示:
- 检测到用户输入中传入工具定义,并开启了auto tool choice选项;
- 应用chat template渲染用户输入,将工具信息和用户prompt构造到模型输入中;
- 模型执行推理并完成基础的后处理流程;
- tool parser对模型输出进行解析,如果模型输出中包含工具调用信息,tool parser会将工具调用信息解析到用户响应中的tool_calls字段中。
规格说明
模型 |
优势 |
说明 |
---|---|---|
Qwen3-32B/Qwen3-30B-A3B/Qwen3-235B-A22B |
平衡性能与资源消耗,在 MMLU(通用知识)、C-Eval(中文评测)上表现优秀。 |
- |

1. 上表中的模型均经过验证,其他发布模型支持能力与社区保持一致;
2. FC不会增强模型能力,模型推理能力影响FC性能和精度。
tool choice支持模式
tool choice目前只支持auto(自动识别)和named(指定函数调用)两种模式,不支持required(必选函数调用)模式,详情如下。
模式 |
支持情况 |
说明 |
示例 |
---|---|---|---|
auto(推荐) |
√ |
模型自动识别是否需要进行工具调用 |
"tool_choice": "auto" |
named |
√ |
指定函数调用 |
"tool_choice": {"type": "function", "function": {"name": "get_weather"} |
required |
× |
提示模型必须进行函数调用 |
"tool_choice": "required" |
支持处理模式
模式 |
支持情况 |
说明 |
---|---|---|
流式输出适配 |
√ |
支持流式输出,逐步获取工具调用信息,提升响应效率。 |
多轮工具调用 |
√ |
当用户需求需要多次调用工具时,维护对话历史上下文,逐轮处理工具调用和结果回填。 |
特性兼容性
Function call与vllm已有关键特性兼容性如下表。
特性 |
兼容 |
说明 |
兼容报错行为 |
---|---|---|---|
Reasoning Outputs |
√ |
支持思维链模型输出深度思考内容,Function call场景下关闭深度思考内容输出,可以提高Function call运行效率,同时避免某些模型reasoning_content中的异常返回影响结果解析。 Deepseek R1:不支持关闭思维链 Qwen3:支持关闭思维链 |
- |
Automatic Prefix Caching |
√ |
- |
- |
Chunked Prefill |
√ |
- |
- |
投机推理 |
√ |
- |
- |
图模式 |
√ |
- |
- |

上述内容为auto模式下的兼容性说明,named模式下与Guided decoding的特性兼容性一致,详见社区特性兼容矩阵。
基本使用流程
- 环境准备
在启用工具调用的情况下启动服务器。此示例使用Qwen3模型,因此我们需要使用vLLM示例目录中的hermes工具调用聊天模板:
python -m vllm.entrypoints.openai.api_server \ --model Qwen3/ \ --chat-template=tool_chat_template_hermes.v1.jinja \ --enable-auto-tool-choice \ --tool-call-parser=hermes
- 定义工具
FC通过json格式定义 tools 字段的方式向模型提供可用工具。tools 包含工具名称、描述、参数定义等信息。具体参考 :工具参数构造规范
定义工具函数
def get_weather(location: str, unit: str): return f"Getting the weather for {location} in {unit}..."
- 假设在代码中定义了一个名为 get_weather 的工具函数,用于获取指定地点的天气信息。
- location:表示天气查询的地点,必选。
- unit:表示函数返回结果的温度单位,可选。
- 注意:此用例只是模拟的天气查询场景,实际应用中需要调用真实的天气查询 API。
定义 Tools
"tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": { "location": {"type": "string", "description": "City and state, e.g., 'San Francisco, CA'"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["location"] } } }]
- tools 列表类型,其中每个元素代表一个可调用的工具函数。这里定义了一个名为 get_weather 的工具。
- type:工具的类型,这里是固定值 function,表示这是一个可调用工具函数。
- function:函数对象,用于定义工具函数的详细信息,如名称、描述和参数。
- name:函数名称,在这里为 get_weather。
- description:函数描述,解释该函数应用信息。
- parameters:函数所需参数,这里是一个对象,包含 location 和 unit 两个属性。
- location:地点的位置信息,参数类型为string。
- unit:温度单位,参数类型为枚举string,候选值为 celsius 或 fahrenheit。
- required:指定必需的参数,这里 location是必需的。
- 假设在代码中定义了一个名为 get_weather 的工具函数,用于获取指定地点的天气信息。
- 发起请求
在请求中提供用户问题和工具,模型会根据问题自动识别并返回需要调用的工具及参数。
from openai import OpenAI import json client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy") //用户问题 messages = [{"role": "user", "content": "What's the weather like in San Francisco?"}] tools = [ { //参见步骤1中定义的tools } ] //发起模型请求 response = client.chat.completions.create( model=client.models.list().data[0].id, messages=messages , tools=tools, tool_choice="auto" )
- 调用外部工具
根据模型返回的工具和参数信息,调用对应的外部工具或 API,获取工具的实际执行结果。
# 解析模型返回的工具调和参数信息 tool_call = response.choices[0].message.tool_calls[0].function # 工具名称 tool_name = tool_call.function.name #根据工具名称执行对应工具 if tool_name == "get_weather": # 提取的用户参数 arguments = json.loads(tool_call.function.arguments) # 调用工具 tool_result = get_weather(**arguments)
- 从模型返回的 tool_calls 中获取模型调用的工具列表。
- 根据工具名称执行对应工具。如当工具名称是 get_weather 时,则提取用户参数并调用 get_weather 函数获取工具执行结果。
- 回填执行结果并生成最终回复
将工具执行结果以 role=tool 的消息形式回填给模型,模型根据结果生成最终回复。
messages.append(completion.choices[0].message) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": tool_result }) # 调用模型生成最终回复 final_response = client.chat.completions.create( model=client.models.list().data[0].id, messages=messages , tools=tools, tool_choice="auto" ) print(final_response.choices[0].message.content)
完整代码示例
from openai import OpenAI import json client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy") def get_weather(location: str, unit: str): return f"Getting the weather for {location} in {unit}..." tool_functions = {"get_weather": get_weather} tools = [{ "type": "function", "function": { "name": "get_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": { "location": {"type": "string", "description": "City and state, e.g., 'San Francisco, CA'"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} }, "required": ["location", "unit"] } } }] response = client.chat.completions.create( model=client.models.list().data[0].id, messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}], tools=tools, tool_choice="auto" ) tool_call = response.choices[0].message.tool_calls[0].function print(f"Function called: {tool_call.name}") print(f"Arguments: {tool_call.arguments}") print(f"Result: {get_weather(**json.loads(tool_call.arguments))}")
Example output:
Function called: get_weather Arguments: {"location": "San Francisco, CA", "unit": "fahrenheit"} Result: Getting the weather for San Francisco, CA in fahrenheit...
Prompt最佳实践
Function call的性能很大程度上依赖于所使用模型本身的推理能力,用户需要通过合理的任务定义prompt配合清晰明确的工具函数定义实现高效的工具调用,使用时应该遵从以下原则:
- 任务定义简单直接,避免输入和任务无关的多余信息,避免造成对模型的信息干扰;
- 模型推理具有随机性,能用代码完成的任务就不要调用大模型;
以下是一些典型的错误示例和修正示范:
类别 |
问题 |
错误示例 |
改正后示例 |
---|---|---|---|
函数定义 |
函数命名不规范,功能描述不清晰 |
{ "type": "function", "function": { "name": "func1", "description": "功能函数" } } |
{ "type": "function", "function": { "name": "CreateTask", "description": "当需要为用户新建工作项时,此工具将创建工作项,并返回工作项ID" } } |
参数定义 |
格式定义冗余,包含重复信息 |
{ "time": { "type": "object", "description": "城市", "properties": { "city": { "description": "城市" } } } } |
{ "time": { "type": "string", "description": "城市" } } |
包含非必要入参(包含固定值等) |
{ "time": { "type": "object", "description": "城市", "properties": { "city": { "description": "固定传杭州即可" } } } } |
如果函数入参非必要,比如为固定值。这种情况应该移除相关入参,直接由代码处理。 |
|
prompt |
任务描述复杂,导致无意义增加工具调用轮次 |
System prompt: 你正在与用户Marvin沟通,你需要先查询用户ID,再通过ID为用户创建工作项…… |
System prompt: 你正在与用户Marvin(ID=123)沟通,你可以通过用户ID为用户创建工作项…… |
任务定义包含模糊信息,模型无法区分 |
System prompt: 可以通过ID查找用户,并获得用户的任务ID 此处两个ID无法明确区分,导致模型可能混用。 |
System prompt: 每个用户具有唯一的用户ID;每个工作项有对应的工作项ID。可以通过用户ID查找用户信息,并获取用户的所有工作项ID |
|
任务定义与工具函数无法match |
查询天气工具函数入参要求传入查询地点和指定日期。 prompt: 查询北京的天气 任务定义缺失日期信息,会导致模型无法调用函数或者输入日期为缺省值导致调用结果异常。 |
prompt: 查询北京2025年7月30日的天气 |
|
格式冲突 |
system prompt定义的某种返回格式与Function call要求的格式冲突,导致工具函数调用失败。 |
去除导致函数调用异常的格式内容。 |
工具函数定义最佳实践
为确保模型能正确调用工具功能,工具函数定义需遵循 JSON Schema 标准,按照如下规范构造 tools 对象。
tools 整体结构
"tools": [ { "type": "function", "function": { "name": "...", // 函数名称(小写+下划线) "description": "...", // 函数描述 "parameters": { ... } // 函数参数(JSON Schema格式) } } ]
- type:工具的类型,这里是固定值 function,表示这是一个可调用工具函数。
- function:函数对象,用于定义工具函数的名称、描述和参数等详细配置。
字段解释
function
字段 |
类型 |
是否必填 |
说明 |
---|---|---|---|
name |
string |
是 |
函数名称,唯一标识,建议使用小写加下划线 |
description |
string |
是 |
函数描述,解释函数应用信息 |
parameters |
object |
是 |
函数所需参数,需遵循 JSON Schema 格式 |
parameters
parameters 需为遵循JSON Schema格式的对象:
"parameters": { { "type": "object", "properties": { "name": { "type": "string | number | boolean | object | array | integer", "description": "属性说明" } }, "required": [ "必填参数" ] } }
- type:必须为"object";
- properties:列出支持的所有属性名及其类型;
- name:参数名,须为英文字符串,且不能重复;
- type:需遵循JSON Schema规范,支持类型包括string、number、boolean、integer、object、array;
- required:指定函数中必填的参数名;
- 其它参数根据type类型不同稍有区别,配置方式请参见下表。
type类型 |
示例 |
---|---|
string、integer、number、boolean |
略 |
object (对象)
|
|
array (列表)
|
|
完整示例
"tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Get weather information for a specified location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "City and state, e.g., 'San Francisco, CA'" } }, "required": [ "location" ] } } } ]
注意事项
- 大小写敏感:所有字段名、参数名严格区分大小写(建议统一用小写)。
- 中英文:字段名建议使用英文, description 中可以使用中文(如location 可以描述为“城市”)。
- Schema 合规性:定义方式必须遵循 JSON Schema ,可通过JSON Schema 校验工具验证。
最佳实践
- 工具描述核心准则
- 详细阐述工具能力、参数含义与影响、适用场景(或禁用场景)、限制条件(如输入长度限制)。单工具描述建议3-4句。
- 优先完善功能、参数等基础描述,示例仅作为补充(推理模型需谨慎添加)。
- 函数设计要点
- 命名与参数:函数名直观(如parse_product_info),参数说明包含格式(如city: string)和业务含义(如“目标城市拼音全称”),明确输出定义(如“返回JSON格式天气数据”)。
- 系统提示:通过提示指定调用条件(如“用户询问商品详情时触发get_product_detail”)。
- 工程化设计:
- 最小惊讶原则:使用枚举类型(如StatusEnum)避免无效参数,确保逻辑直观。
- 简洁明了原则:提示词需表述清晰,达到人类可凭直觉进行判断的效果。
- 调用优化:
- 已知参数通过代码隐式传递(如submit_order无需重复声明user_id)。
- 合并固定流程函数(如query_location与mark_location整合为query_and_mark_location)。
- 数量与性能:控制函数数量≤20个,通过调试工具迭代函数模式(Schema),复杂场景可使用微调能力提升准确率。
请求实践
- 工具调用
请求示例:
{ "model": "deepseek", "messages": [ { "role": "user", "content": "获取北京天气" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "查询天气", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "城市" }, "unit": { "type": "string", "enum": [ "celsius", "fahrenheit" ] } }, "required": [ "location", "unit" ] } } }, { "type": "function", "function": { "name": "send_email", "description": "发送邮件", "parameters": { "type": "object", "properties": { "userInput": { "type": "string", "description": "邮件内容" } }, "required": [ "userInput" ] } } } ], "tool_choice": "auto", "temperature": 0, "stream": false }
请求结果:
{ "id": "1530/chat-c7277abfbc724677a570c03c7541edd7", "object": "chat.completion", "created": 1753423691, "model": "deepseek", "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "reasoning_content": null, "tool_calls": [ { "id": "chatcmpl-tool-6714630cc3fc4551a156aa48715d5139", "type": "function", "function": { "name": "get_weather", "arguments": "{\"location\":\"北京\",\"unit\":\"celsius\"}" } } ] }, "logprobs": null, "finish_reason": "tool_calls", "stop_reason": null } ], "usage": { "prompt_tokens": 309, "total_tokens": 359, "completion_tokens": 50 }, "prompt_logprobs": null }
- 工具总结
{ "model": "deepseek", "messages": [ { "role": "user", "content": "获取北京的天气" }, { "role": "assistant", "tool_calls": [ { "id": "chatcmpl-tool-fc6986a3dc014e80a5d3e091c60648d9", "type": "function", "function": { "name": "get_weather", "arguments": "{\"location\": \"Beijing\", \"unit\": \"celsius\"}" } } ]}, { "role": "tool", "tool_call_id": "chatcmpl-tool-fc6986a3dc014e80a5d3e091c60648d9", "content": "北京今天20到50度", "name": "get_weather" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "查询天气", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "城市" }, "unit": { "type": "string", "enum": [ "celsius", "fahrenheit" ] } }, "required": [ "location", "unit" ] } } }, { "type": "function", "function": { "name": "send_email", "description": "发送邮件", "parameters": { "type": "object", "properties": { "userInput": { "type": "string", "description": "邮件内容" } }, "required": [ "userInput" ] } } } ], "tool_choice": "auto", "temperature": 0, "stream": false }
请求结果:
{ "id": "1530/chat-2966628beae0430b872b994f7ef0f9b4", "object": "chat.completion", "created": 1753423849, "model": "deepseek", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "北京今天的天气是20到50度。", "reasoning_content": null, "tool_calls": [] }, "logprobs": null, "finish_reason": "stop", "stop_reason": null } ], "usage": { "prompt_tokens": 387, "total_tokens": 398, "completion_tokens": 11 }, "prompt_logprobs": null }
异常处理
JSON 格式容错机制
对于轻微不合法的 JSON 格式,可尝试使用 json-repair 库进行容错修复。
import json_repair invalid_json = '{"location": "北京", "unit": "摄氏度"}' valid_json = json_repair.loads(invalid_json)
工具调用异常
因prompt输入和工具函数定义导致模型无法正确调用工具函数的场景,建议按照最佳实践部分的内容进行prompt调优和函数定义优化。
模型返回异常
Function call功能依赖模型能力实现,因大模型幻觉等原因,可能出现模型返回结果不符合预期,导致一定的工具调用失败概率。
如果某场景下调用失败率较低,可以通过设置重试机制进行可靠性加固。
Q&A
Q:Deepseek-R1-0528为什么在非流式处理模式下content中会返回<result>标签?
A:模型能力缺陷,模型自行输出标签,不影响Function call功能正常使用,用户无需关注。
Q:Deepseek-R1等思维链模型开启深度思考情况下,reasoning_content中为什么概率性出现</think>标签?
A:Deepseek-R1模型能力缺陷,存在概率性多输出</think>标签,导致思维链内容被截断。目前无法规避,建议增加重试。
Q:Deepseek-R1等思维链模型开启深度思考情况下,reasoning_content返回中为什么包含<tool_calls_begin>标签?
A:Funtion call预置提示词模版引入特殊字符,不影响功能正常使用,用户无需关注。
Q:使用Function call功能时,只调用1个函数,为什么会出现返回多个函数调用的情况?
A:模型自主判断调用函数次数,通常与prompt语义不明确或工具函数定义模糊有关,建议参考最佳实践部分内容优化prompt输入和工具函数定义。