大模型函数调用(Function Calling)
·
在大模型应用开发中,函数调用(Function Calling)是突破纯文本交互、实现模型与外部工具协同的核心能力。它让大模型不再只做 “语言翻译官”,更能成为 “任务指挥官”—— 识别需要调用的工具、传递正确参数、接收执行结果并给出最终答案。本文将以阿里通义千问(qwen-plus)为例,从基础加法器实现到复杂场景的水果计数,一步步拆解大模型函数调用的完整流程。
一、函数调用核心原理
函数调用的本质是:开发者预先定义工具(函数)的描述(名称、用途、参数格式),大模型接收用户问题后,先判断是否需要调用工具;若需要,则按照预设格式生成调用指令(指定函数名、传入参数);开发者解析指令后执行函数,再将结果返回给大模型,最终由大模型整合结果给出自然语言回答。
核心流程:
- 定义工具函数的 JSON 描述(告诉大模型 “有什么工具、怎么用”)
- 用户提问,大模型判断是否调用工具并生成调用指令
- 解析调用指令,执行本地函数并获取结果
- 将函数结果回传给大模型,生成最终回答
二、加法器函数调用
1.定义函数调用的核心函数
封装get_completion函数,包含模型调用逻辑和工具描述定义(重点是tools参数)
def get_completion(messages, model="qwen-plus"):
"""
调用大模型,支持工具函数调用
:param messages: 对话历史(system+user+工具调用结果等)
:param model: 调用的模型,默认qwen-plus
:return: 大模型的回复对象
"""
response = client.chat.completions.create(
model=model,
messages=messages,
tools=[ # 定义工具函数的JSON描述(可定义多个)
{
"type": "function",
"function": {
"name": "sum", # 函数名
"description": "加法器,计算一组数的和,只能运用于加法操作", # 函数用途(大模型据此判断是否调用)
"parameters": { # 参数定义(JSON Schema格式)
"type": "object",
"properties": {
"numbers": {"type": "array", "items": {"type": "number"}} # 数组类型,元素为数字
},
"required": ["numbers"] # 必传参数(建议显式声明,提升稳定性)
},
},
}
],
)
return response.choices[0].message
2.测试基础加法场景
调用函数计算 1 到 10 的和,验证工具调用逻辑:
# 测试1:计算1-10的和
prompt = "Tell me the sum of 1, 2, 3, 4, 5, 6, 7, 8, 9, 10."
messages = [
{"role": "system", "content": "你是一个数学家,当需要进行加法操作时调用sum工具"},
{"role": "user", "content": prompt},
]
# 第一步:获取大模型的工具调用指令
response = get_completion(messages)
messages.append(response) # 将模型回复加入对话历史
print("=====大模型工具调用指令=====")
print(response)
# 第二步:解析指令并执行sum函数
if response.tool_calls is not None:
tool_call = response.tool_calls[0]
if tool_call.function.name == "sum":
# 解析参数(JSON字符串转字典)
args = json.loads(tool_call.function.arguments)
result = sum(args["numbers"]) # 执行加法
print("=====函数执行结果=====")
print(result)
# 第三步:将函数结果回传给大模型
messages.append(
{
"tool_call_id": tool_call.id, # 关联工具调用ID
"role": "tool",
"name": "sum",
"content": str(result), # 工具返回结果必须是字符串
}
)
# 第四步:获取大模型的最终自然语言回答
final_response = get_completion(messages)
print("=====最终回答=====")
print(final_response.content)
3.解析
-
tools参数是核心:通过 JSON Schema 定义函数的名称、描述、参数,大模型会根据用户问题和描述判断是否调用该函数 -
tool_calls是模型返回的调用指令:若不为空,说明模型决定调用工具,需解析其中的function.name和function.arguments -
对话历史需完整:每一步的模型回复、工具执行结果都要加入
messages,保证模型上下文连贯
三、智能水果计数
加法场景是纯数字输入,而实际场景中用户问题往往是自然语言(如 “2 个苹果、4 个桃子、3 本书,一共有几个水果?”),需要大模型先识别 “水果类别”、提取数字,再调用加法函数。
1.代码实现
import json
from openai import OpenAI
# 初始化客户端
client = OpenAI(
api_key="sk-0b717f29b6ee4852a2331cf1ffa30d4f",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
def get_completion(messages, model="qwen-plus"):
response = client.chat.completions.create(
model=model,
messages=messages,
tools=[
{
"type": "function",
"function": {
"name": "sum",
"description": "加法器,计算一组数的和,只能运用于加法操作",
"parameters": {
"type": "object",
"properties": {
"numbers": {"type": "array", "items": {"type": "number"}}
},
"required": ["numbers"]
},
},
}
],
)
return response.choices[0].message
# 进阶测试:水果计数(需先筛选水果类别,再求和)
prompt = "桌上有 2 个苹果,四个桃子和 3 本书,一共有几个水果?"
messages = [
{"role": "system", "content": "你是一个数学家,先识别用户问题中的水果类别,提取对应数量,再调用sum工具计算水果总数;非水果类物品忽略"},
{"role": "user", "content": prompt},
]
# 第一步:获取模型的工具调用指令(模型会自动筛选水果数量)
response = get_completion(messages)
messages.append(response)
print("=====大模型回复(工具调用指令)=====")
print(response)
# 第二步:兼容处理(模型可能直接回答,也可能调用工具)
if response.tool_calls is not None:
tool_call = response.tool_calls[0]
if tool_call.function.name == "sum":
# 解析参数并执行加法
args = json.loads(tool_call.function.arguments)
result = sum(args["numbers"])
print("=====sum函数执行结果=====")
print(result)
# 第三步:回传工具结果给模型
messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": "sum",
"content": str(result),
}
)
# 第四步:获取最终自然语言回答
final_response = get_completion(messages)
print("=====最终回答=====")
print(final_response.content)
else:
# 模型未调用工具,直接返回回答
print("=====最终回答=====")
print(response.content)
更多推荐
所有评论(0)