大模型 Function Call 的实现步骤及示例详解
Function Call(函数调用)是大模型与外部工具/函数交互的核心机制,其核心逻辑是:让大模型根据用户需求判断是否需要调用预设工具,若需要则生成标准化的调用指令(包含工具名、参数等),执行工具后将结果返回给模型,最终由模型整合结果生成自然语言回答。
一、Function Call的核心流程拆解
Function Call的完整流程可分为5个关键步骤,每个步骤对应具体的逻辑和目标:
定义工具(Tool Definition)
提前告诉大模型“有哪些工具可用”“工具的功能是什么”“需要传入哪些参数”,通常以结构化格式(如JSON Schema)描述,确保模型能精准理解工具的调用规则。用户提问与初始判断
接收用户输入后,大模型结合问题和工具定义,判断“是否需要调用工具”:- 若问题可直接回答(如“1+1等于几”),则直接返回结果;
- 若问题需要外部信息(如“现在几点了”“北京天气如何”),则生成工具调用指令。
生成工具调用指令
若需要调用工具,大模型会生成标准化的调用指令(包含工具名、参数等),格式需严格匹配工具定义,确保后续能被正确解析执行。执行工具并返回结果
解析模型生成的调用指令,调用对应的工具函数,执行逻辑(如查询数据库、API调用等),并将结果以固定格式(如“tool角色”消息)返回给模型。整合结果生成最终回答
大模型接收工具返回的结果后,结合问题和结果,生成自然语言回答,完成交互。
二、结合代码详解Function Call实现
下面结合完整的代码,逐步骤解析每个环节的具体实现,示例代码来自大模型服务平台百炼 Function Calling:
点击展开代码from openai import OpenAI
from datetime import datetime
import json
import os
import random
client = OpenAI(
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", # 填写DashScope SDK的base_url
)
# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
# 工具1 获取当前时刻的时间
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
# 因为获取当前时间无需输入参数,因此parameters为空字典
"parameters": {},
},
},
# 工具2 获取指定城市的天气
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
# 查询天气时需要提供位置,因此参数设置为location
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。",
}
},
"required": ["location"],
},
},
},
]
# 模拟天气查询工具。返回结果示例:“北京今天是雨天。”
def get_current_weather(arguments):
# 定义备选的天气条件列表
weather_conditions = ["晴天", "多云", "雨天"]
# 随机选择一个天气条件
random_weather = random.choice(weather_conditions)
# 从 JSON 中提取位置信息
location = arguments["location"]
# 返回格式化的天气信息
return f"{location}今天是{random_weather}。"
# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
# 获取当前日期和时间
current_datetime = datetime.now()
# 格式化当前日期和时间
formatted_time = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
# 返回格式化后的当前时间
return f"当前时间:{formatted_time}。"
# 封装模型响应函数
def get_response(messages):
completion = client.chat.completions.create(
model="qwen-plus", # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages=messages,
tools=tools,
)
return completion
def call_with_messages():
print("\n")
messages = [
{
"content": input(
"请输入:"
), # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
"role": "user",
}
]
print("-" * 60)
# 模型的第一轮调用
i = 1
first_response = get_response(messages)
assistant_output = first_response.choices[0].message
print(f"\n第{i}轮大模型输出信息:{first_response}\n")
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
# 如果不需要调用工具,则直接返回最终答案
if (
assistant_output.tool_calls == None
): # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
print(f"无需调用工具,我可以直接回复:{assistant_output.content}")
return
# 如果需要调用工具,则进行模型的多轮调用,直到模型判断无需调用工具
while assistant_output.tool_calls != None:
# 如果判断需要调用查询天气工具,则运行查询天气工具
tool_info = {
"content": "",
"role": "tool",
"tool_call_id": assistant_output.tool_calls[0].id,
}
if assistant_output.tool_calls[0].function.name == "get_current_weather":
# 提取位置参数信息
argumens = json.loads(assistant_output.tool_calls[0].function.arguments)
tool_info["content"] = get_current_weather(argumens)
# 如果判断需要调用查询时间工具,则运行查询时间工具
elif assistant_output.tool_calls[0].function.name == "get_current_time":
tool_info["content"] = get_current_time()
tool_output = tool_info["content"]
print(f"工具输出信息:{tool_output}\n")
print("-" * 60)
messages.append(tool_info)
assistant_output = get_response(messages).choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
messages.append(assistant_output)
i += 1
print(f"第{i}轮大模型输出信息:{assistant_output}\n")
print(f"最终答案:{assistant_output.content}")
if __name__ == "__main__":
call_with_messages()
步骤1:定义工具(对应代码中的tools
列表)
代码中通过tools
列表定义了两个工具,这是大模型判断“是否调用工具”和“如何调用”的依据。每个工具的定义包含3个核心要素:
name
:工具函数的唯一标识(需与实际函数名一致,如get_current_weather
);description
:工具的功能描述(帮助模型判断何时该用这个工具,如“查询指定城市的天气时使用”);parameters
:工具所需参数的结构化定义(包含参数名、类型、描述、是否必填等,确保模型传入正确参数)。
示例解析:
tools = [
# 工具1:获取当前时间(无参数)
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "当你想知道现在的时间时非常有用。",
"parameters": {} # 无参数,因此为空字典
},
},
# 工具2:获取指定城市天气(需location参数)
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
"location": { # 参数名:location
"type": "string", # 参数类型:字符串
"description": "城市或县区,比如北京市、杭州市" # 参数描述
}
},
"required": ["location"] # 该参数为必填项
}
},
}
]
作用:大模型会读取tools
中的信息,例如当用户问“北京天气如何”时,模型会匹配到get_current_weather
的description
,并根据parameters
知道需要传入location="北京"
。
步骤2:实现工具函数(对应代码中的get_current_weather
和get_current_time
)
工具函数是实际执行逻辑的“执行者”,接收模型传入的参数,返回具体结果。代码中这两个函数是模拟实现(实际场景可能是调用天气API、时间接口等)。
get_current_time
:无参数,返回当前格式化时间(如“2025-07-19 15:30:00”);get_current_weather
:接收location
参数,随机返回天气结果(如“北京今天是晴天”)。
示例解析:
def get_current_weather(arguments):
weather_conditions = ["晴天", "多云", "雨天"]
random_weather = random.choice(weather_conditions)
location = arguments["location"] # 从参数中提取城市
return f"{location}今天是{random_weather}。" # 返回工具结果
步骤3:模型交互与工具调用判断(对应call_with_messages
函数)
这是Function Call的核心流程,负责协调用户输入、模型判断、工具执行和结果整合,具体分为以下子步骤:
子步骤3.1:初始化对话消息
用户输入作为初始消息(role="user"
),存入messages
列表,用于传递给模型。
messages = [
{
"content": input("请输入:"), # 例如用户输入“杭州天气如何?”
"role": "user",
}
]
子步骤3.2:首次调用模型,判断是否需要调用工具
通过get_response
函数调用大模型(这里对接的是阿里云DashScope的千问模型),传入messages
(用户问题)和tools
(工具列表),模型会返回判断结果:
- 若无需调用工具:
assistant_output.tool_calls
为None
,直接返回回答; - 若需要调用工具:
assistant_output.tool_calls
包含调用指令(工具名、参数等)。
示例解析:
first_response = get_response(messages) # 调用模型
assistant_output = first_response.choices[0].message # 获取模型输出
if assistant_output.tool_calls is None: # 无需调用工具
print(f"无需调用工具,我可以直接回复:{assistant_output.content}")
return
子步骤3.3:解析工具调用指令并执行工具
若模型返回tool_calls
,则需解析指令并执行对应工具:
- 从
tool_calls
中提取工具名(function.name
)和参数(function.arguments
); - 调用对应的工具函数(如
get_current_weather
),传入参数,获取工具返回结果; - 将工具结果以
role="tool"
的格式存入messages
,并关联tool_call_id
(确保模型知道结果对应哪个调用)。
示例解析:
# 循环处理工具调用(可能多轮,直到模型无需调用)
while assistant_output.tool_calls is not None:
tool_call = assistant_output.tool_calls[0] # 获取第一个工具调用指令
tool_info = {
"role": "tool",
"tool_call_id": tool_call.id, # 关联调用ID
"content": "" # 存储工具返回结果
}
# 若调用的是天气工具
if tool_call.function.name == "get_current_weather":
arguments = json.loads(tool_call.function.arguments) # 解析参数(如{"location":"杭州"})
tool_info["content"] = get_current_weather(arguments) # 执行工具,获取结果
# 若调用的是时间工具
elif tool_call.function.name == "get_current_time":
tool_info["content"] = get_current_time() # 执行工具
messages.append(tool_info) # 将工具结果加入对话历史
子步骤3.4:多轮调用模型,整合工具结果生成最终回答
工具结果存入messages
后,再次调用模型,模型会基于“用户问题+工具结果”生成最终回答。若仍需进一步调用工具(如参数缺失),则重复“解析→执行→返回”流程,直到模型判断无需调用工具,输出最终结果。
示例解析:
# 再次调用模型,传入工具结果
assistant_output = get_response(messages).choices[0].message
messages.append(assistant_output) # 更新对话历史
# 直到模型不再返回tool_calls,输出最终结果
print(f"最终答案:{assistant_output.content}") # 例如“杭州今天是晴天。”
三、总结:代码如何实现Function Call的核心逻辑
- 工具定义:通过
tools
列表让模型“认识”可用工具及调用规则; - 模型判断:大模型结合用户问题和工具定义,决定是否调用工具;
- 指令解析与执行:解析模型生成的
tool_calls
,调用对应工具函数并获取结果; - 多轮交互:将工具结果反馈给模型,反复迭代直到生成最终回答。
这种机制让大模型突破“仅依赖内部知识”的限制,能通过外部工具获取实时信息(如时间、天气)、执行复杂计算等,极大扩展了应用场景。