Function Call
什么是Function Call
工具调用(Tool Calling,Function Call,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字段中。
支持模型
当前支持Function Call的模型请参见文本生成支持能力。
规格说明
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已有关键特性兼容性如下表。
|
特性 |
兼容 |
说明 |
兼容报错行为 |
|---|---|---|---|
|
Reasoning Outputs |
√ |
支持思维链模型输出深度思考内容,Function Call场景下关闭深度思考内容输出,可以提高Function Call运行效率,同时避免某些模型reasoning_content中的异常返回影响结果解析。 Qwen3:支持关闭思维链。 |
- |
基本使用流程
- 定义工具
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 httpx import json client = OpenAI(base_url="https://api.modelarts-maas.com/openai/v1", api_key="MAAS_API_KEY", http_client=httpx.Client(verify=False)) # 把MAAS_API_KEY替换成已获取的API Key messages = [{"role": "user", "content": "What's the weather like in San Francisco?"}] tools = [ { //参见步骤1中定义的tools } ] response = client.chat.completions.create( model="deepseek-v3.2", 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 "name": tool_name }) # 调用模型生成最终回复 final_response = client.chat.completions.create( model="deepseek-v3.2", messages=messages , tools=tools, tool_choice="auto" ) print(final_response.choices[0].message.content)
完整代码示例
from openai import OpenAI
import httpx
import json
api_key = "MAAS_API_KEY" # 把MAAS_API_KEY替换成已获取的API Key
client = OpenAI(base_url="https://api.modelarts-maas.com/openai/v1", api_key=api_key, http_client=httpx.Client(verify=False))
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="deepseek-v3.2",
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格式容错机制
对于轻微不合法的JSON格式,可尝试使用json-repair库进行容错修复。
import json_repair
invalid_json = '{"location": "北京", "unit": "摄氏度"}'
valid_json = json_repair.loads(invalid_json)
工具调用异常
因prompt输入和工具函数定义导致模型无法正确调用工具函数的场景,建议按照最佳实践部分的内容进行prompt调优和函数定义优化。
模型返回异常
Function Call功能依赖模型能力实现,因大模型幻觉等原因,可能出现模型返回结果不符合预期,导致一定的工具调用失败概率。
如果某场景下调用失败率较低,可以通过设置重试机制进行可靠性加固。
常见问题
- 使用Function Call功能时,只调用1个函数,为什么会出现返回多个函数调用的情况?
模型自主判断调用函数次数,通常与prompt语义不明确或工具函数定义模糊有关,建议参考最佳实践部分内容优化prompt输入和工具函数定义。
- 使用Function Call功能时,配置max_tokens后为什么无法解析tool_calls?
max_tokens配置过小可能会导致模型输出截断,无法正常解析出tool_calls内容,需要合理配置max_tokens大小。
- 如何判断模型是否需要调用函数?
模型会根据用户问题结合工具定义和tool_choice字段自主判断,若返回结果中包含tool_calls字段,则表示需要调用工具。
- 使用Function Call功能时,如果在请求中的System Prompt设置了输出格式,为什么有时会输出特殊标签token,导致无法解析tool_calls?
这一般是由于System Prompt设置的格式未遵循模型所要求的格式规范。建议参考相关最佳实践,对prompt进行优化调整。