
# Tool Calling
#### 什么是Tool Calling
工具调用（Tool Calling，Function Calling，FC）是一种将大模型与外部工具和 API 相连的关键功能，作为自然语言与信息接口之间的"翻译官"，它能够将用户的自然语言请求智能地转化为对特定工具或 API 的调用，从而高效满足用户的特定需求。
**工作原理**：开发者通过自然语言向模型描述工具的功能和定义，模型在对话过程中自主判断是否需要调用工具。当需要调用时，模型会返回符合要求的工具函数及入参，开发者负责实际调用工具并将结果回填给模型，模型再根据结果进行总结或继续规划子任务。
#### 实现原理
FC特性实现主要包括前处理（serving_chat模块）、后处理模块（tool parser）以及chat_template，前处理模块通过chat_template对用户prompt进行渲染，后处理模块对模型输出进行解析。整体流程如下图所示：
![](https://support.huaweicloud.com/bestpractice-modelarts/figure/zh-cn_image_0000002451298494.png "点击放大")
1. 检测到用户输入中传入工具定义，并开启了auto tool choice选项；
2. 应用chat template渲染用户输入，将工具信息和用户prompt构造到模型输入中；
3. 模型执行推理并完成基础的后处理流程；
4. tool parser对模型输出进行解析，如果模型输出中包含工具调用信息，tool parser会将工具调用信息解析到用户响应中的tool_calls字段中。
 
#### 规格说明
**Qwen3-32B**模型的Tool Calling功能经过Ascend适配和验证，其他模型支持能力与社区保持一致。
说明：Qwen3-32B流式场景下，如果需要Tool Calling，则不能关闭思维链，否则会导致工具无法正常调用。
**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：支持关闭思维链 | -      |
| Prefix Caching    | √  | -                                                                                                                                                                                                                                                                                                   | -      |
| Chunked Prefill   | √  | -                                                                                                                                                                                                                                                                                                   | -      |
| 投机推理              | √  | -                                                                                                                                                                                                                                                                                                   | -      |
| 图模式               | √  | -                                                                                                                                                                                                                                                                                                   | -      |
| Guided Decoding   | ×  | -                                                                                                                                                                                                                                                                                                   | -      |
   
#### 基本使用流程
1. 环境准备 Qwen3-32B启动推理服务时需要增加Tool Calling相关参数，具体示例命令如下。
   ```
   python -m vllm.entrypoints.openai.api_server \
   --model Qwen3/ \
   --chat-template={jinja文件在容器中的路径} \
   --enable-auto-tool-choice \
   --tool-call-parser=ascend_hermes \
   --tool-parser-plugin={tool_parser文件在容器中的路径}
   ```
   - tool_parser文件：ascend_hermes_tool_parser.py，已经预置在推理框架代码包中，路径是/home/ma-user/AscendCloud/AscendCloud-LLM/llm_inference/ascend_vllm/ascend_vllm/tool_parsers/ascend_hermes_tool_parser.py
   
   - jinja文件：tool_chat_template_hermes.v2.jinja，jinja文件请提工单联系技术支持获取。
    
2. 定义工具 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*是必需的。
        
      
    
3. 发起请求 在请求中提供用户问题和工具，模型会根据问题自动识别并返回需要调用的工具及参数。
   ```
   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"
   )
   ```
   
   
4. 调用外部工具 根据模型返回的工具和参数信息，调用对应的外部工具或 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* 函数获取工具执行结果。
    
5. 回填执行结果并生成最终回复 将工具执行结果以 *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配合清晰明确的工具函数定义实现高效的工具调用，使用时应该遵从以下原则：
1. 任务定义简单直接，避免输入和任务无关的多余信息，避免造成对模型的信息干扰；
2. 模型推理具有随机性，能用代码完成的任务就不要调用大模型；
以下是一些典型的错误示例和修正示范：
| 类别     | 问题                   | 错误示例                                                                                                                                                                                                                                              | 改正后示例                                                                                                                                                       |
|:---|:---|:---|:---|
| 函数定义   | 函数命名不规范，功能描述不清晰      | ``` { "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为用户创建工作项…… ```               |
| prompt | 任务定义包含模糊信息，模型无法区分    | System prompt: ``` 可以通过ID查找用户，并获得用户的任务ID ``` 此处两个ID无法明确区分，导致模型可能混用。                                                                                                     | System prompt: ``` 每个用户具有唯一的用户ID；每个工作项有对应的工作项ID。可以通过用户ID查找用户信息，并获取用户的所有工作项ID ``` |
| prompt | 任务定义与工具函数无法match     | 查询天气工具函数入参要求传入查询地点和指定日期。 prompt: ``` 查询北京的天气 ``` 任务定义缺失日期信息，会导致模型无法调用函数或者输入日期为缺省值导致调用结果异常。 | prompt: ``` 查询北京2025年7月30日的天气 ```                                               |
| prompt | 格式冲突                 | system prompt定义的某种返回格式与Function call要求的格式冲突，导致工具函数调用失败。                                                                                                                                                                                           | 去除导致函数调用异常的格式内容。                                                                                                                                            |
   
 #### 工具函数定义最佳实践
为确保模型能正确调用工具功能，工具函数定义需遵循 [JSON Schema](https://json-schema.org/docs) 标准，按照如下规范构造 *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](https://json-schema.org/docs)格式的对象：
```
"parameters": {
    {
        "type": "object",
        "properties": {
            "name": {
                "type": "string | number | boolean | object | array | integer",
                "description": "属性说明"
            }
        },
        "required": [
            "必填参数"
        ]
    }
}
```
- *type* ：必须为*"object"*；
- *properties* ：列出支持的所有属性名及其类型；
  - name：参数名，须为英文字符串，且不能重复；
  
  - *type* ：需遵循[JSON Schema规范](https://json-schema.org/docs)，支持类型包括string、number、boolean、integer、object、array；
  
  - *required*：指定函数中必填的参数名；
  
  - **其它参数** 根据*type*类型不同稍有区别，配置方式请参见下表。
   
| type类型                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | 示例                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
|:---|:---|
| string、integer、number、boolean                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | 略                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| object （对象） - *description*：说明  - *properties*： 描述对象涉及属性  - *required ：*描述必填属性   | - 示例1: 查询学生个人信息 ``` "parameters": { "type": "object", "description": "学生信息", "properties": { "age": { "type": "integer", "description": "年龄" }, "gender": { "type": "string", "description": "性别" }, "married": { "type": "boolean", "description": "是否党员" } }, "required": [ "age" ], } ```                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| array （列表） - *description*：说明  - *"items": {"type": ITEM_TYPE}* ：用于表达数组元素的数据类型                                                                                                                                                          | - 示例1：定义文本数组 ``` "parameters": { "type": "array", "description": "任意数量文本", "items": { "type": "string" } } ```     - 示例2： 定义二维数组 ``` "parameters": { "type": "array", "description": "二维矩阵", "items": { "type": "array", "items": { "type": "number" } }, } ```     - 示例3: 通过array来实现多选数组 ``` "parameters": { "description": "爱好, 支持多选", "type": "array", "items": { "type": "string", "description": """枚举值有 "游泳", "跑步", "爬山", "健身", "羽毛球", "篮球"。 """, }, } ```     |
   
**完整示例**
```
"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"
                ]
            }
        }
    }
]
```
**注意事项**
1. **大小写敏感**：所有字段名、参数名严格区分大小写（建议统一用小写）。
2. **中英文** ：字段名建议使用英文， *description* 中可以使用中文（如*location* 可以描述为"城市"）。
3. **Schema 合规性**：定义方式必须遵循 JSON Schema ，可通过JSON Schema 校验工具验证。
**最佳实践**
1. **工具描述核心准则**
   - 详细阐述工具能力、参数含义与影响、适用场景（或禁用场景）、限制条件（如输入长度限制）。单工具描述建议3-4句。
   
   - 优先完善功能、参数等基础描述，示例仅作为补充（推理模型需谨慎添加）。
    
2. **函数设计要点**
   - **命名与参数** ：函数名直观（如*parse_product_info* ），参数说明包含格式（如*city: string*）和业务含义（如"目标城市拼音全称"），明确输出定义（如"返回JSON格式天气数据"）。
   
   - **系统提示** ：通过提示指定调用条件（如"用户询问商品详情时触发*get_product_detail*"）。
   
   - **工程化设计** ：
     - 最小惊讶原则：使用枚举类型（如*StatusEnum*）避免无效参数，确保逻辑直观。
     
     - 简洁明了原则：提示词需表述清晰，达到人类可凭直觉进行判断的效果。
      
   
   - **调用优化** ：
     - 已知参数通过代码隐式传递（如*submit_order* 无需重复声明*user_id*）。
     
     - 合并固定流程函数（如*query_location* 与*mark_location* 整合为*query_and_mark_location*）。
      
   
   - **数量与性能**：控制函数数量≤20个，通过调试工具迭代函数模式（Schema），复杂场景可使用微调能力提升准确率。
    
**请求实践**
1. 工具调用
   请求示例：
   ```
   {
       "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
   }
   ```
   
2. 工具总结 请求示例：
   ```
   {
       "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：使用Function call功能时，为什么会出现调用函数个数不对的情况?**
A：模型自主判断调用函数次数，通常与prompt语义不明确或工具函数定义模糊有关，建议参考最佳实践部分内容优化prompt输入和工具函数定义。
**Q：使用Function call功能时，配置max_tokens后为什么无法解析tool_calls?**
A：max_tokens配置过小可能会导致模型输出截断，无法正常调用工具，需要合理配置max_tokens大小。
