1. 背景
大模型的函数调用功能能够提升模型的推理能力,并支持执行多种外部操作场景,如信息检索、数据库查询、知识图谱搜索与推理,以及调用操作系统工具等。这一功能实现了模型与外部函数库的联动。函数调用依赖于内容生成API中的一个可选参数 tools
,用于向模型提供函数定义。通过 tools
参数,模型可以根据提供的规范生成相应的函数调用参数。然而,API本身并不实际执行这些函数调用,而是返回供调用所需的参数。开发者可根据模型输出的参数,在具体应用中完成函数调用的执行。我们将会使用chat completion接口向模型描述外部函数,并与模型交互,触发模型对函数的调用,进而使用模型生成的结果调用外部函数。
特别关注:chat.completions
提供了一种支持模型推理与外部功能交互的能力。通过指定functions
参数,开发者可以定义一组函数接口,包括函数的名称、输入参数和规范。模型根据上下文生成符合这些定义的参数,chat.completions
本身并不实际执行这些函数,而是返回所需的调用参数。
2. 描述外部函数
假设需要创建一个具备查询学生信息的机器人,定义两个外部函数供模型选择调用:
查询班级中身高最高的同学姓名:get_student_num(class_id:str, feature:str)
查询某学生的某门课程期末成绩:get_student_grade(student_id:str, course:str)
为了向模型描述外部函数库,需要向 tools 字段传入可以调用的函数列表。参数如下表:
description :说明函数方法的用途。
type :定义 JSON 数据的数据类型约束。
properties:一个Object,其中的每个属性代表要定义的 JSON 数据中的一个键。
required:指定哪些属性在数据中必须被包含。
enum:如果一个属性是枚举类型,则此字段应当设置为枚举值的数组。
完整的tools字段设置为:
tools = [ { "type": "function", "function": { "name": "get_student_num", "description": "根据班级id和特征描述,查找对应信息的学生姓名", "parameters": { "type": "object", "properties": { "class_id": { "description": "班级id", "type": "string" }, "feature": { "description": "学生特征", "type": "string" } }, "required": ["class_id", "feature"] }, } }, { "type": "function", "function": { "name": "get_student_grade", "description": "根据学生id和对应课程信息,查找该生对应课程的成绩", "parameters": { "type": "object", "properties": { "student_id": { "description": "学生id", "type": "string" }, "course": { "description": "课程", "type": "string" } }, "required": ["student_id", "course"] }, } }, ]
在 tools 参数中,如果填写了 functions 参数,则默认情况下模型将决定何时使用其中一个函数。
3. Function Call 流程实践
以具备查询学生信息功能的聊天机器人完成函数调用。
初始化函数定义和client:
from zhipuai import ZhipuAI
client = ZhipuAI(api_key="") # 替换成你自己的api_key
messages = []
tools = [
{
"type": "function",
"function": {
"name": "get_student_num",
"description": "根据班级id和特征描述,查找对应信息的学生姓名",
"parameters": {
"type": "object",
"properties": {
"class_id": {
"description": "班级id",
"type": "string"
},
"feature": {
"description": "学生特征",
"type": "string"
}
},
"required": ["class_id", "feature"]
},
}
},
{
"type": "function",
"function": {
"name": "get_student_grade",
"description": "根据学生id和对应课程信息,查找该生对应课程的成绩",
"parameters": {
"type": "object",
"properties": {
"student_id": {
"description": "学生id",
"type": "string"
},
"course": {
"description": "课程",
"type": "string"
}
},
"required": ["student_id", "course"]
},
}
},
]
查询班级id为12345的班级女生的数量。向模型提供这个信息:
messages = []
messages.append({"role": "user", "content": "帮我查询班级id为12345的班级中女生的数量"})
response = client.chat.completions.create(
model="glm-4", # 填写需要调用的模型名称
messages=messages,
tools=tools,)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
查询学生id为s58523的语文成绩:
messages.append({"role": "user", "content": "帮我查询学生id为s58523的语文成绩"})
response = client.chat.completions.create(
model="glm-4", # 填写需要调用的模型名称
messages=messages,
tools=tools,
)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
定义parse_function_call(response, messages)
def get_student_num(class_id:str, feature:str):
class_student_info = {
"12345":{
"女生" : "28",
"男生" : "22",
},
"254313":{
"女生" : "20",
"男生" : "30",
}
}
return { "student":class_student_info[class_id][feature] }
def get_student_grade(student_id:str , course:str):
course_grade_info = {
"s58292":{
"数学" : "149",
"语文" : "125",
},
"s58523":{
"数学" : "123",
"语文" : "140",
}
}
return { "grade":course_grade_info[student_id][course] }
def parse_function_call(model_response,messages):
# 处理函数调用结果,根据模型返回参数,调用对应的函数。
# 调用函数返回结果后构造tool message,再次调用模型,将函数结果输入模型
# 模型会将函数调用结果以自然语言格式返回给用户。
if model_response.choices[0].message.tool_calls:
tool_call = model_response.choices[0].message.tool_calls[0]
args = tool_call.function.arguments
function_result = {}
if tool_call.function.name == "get_student_num":
function_result = get_student_num(**json.loads(args))
if tool_call.function.name == "get_student_grade":
function_result = get_student_grade(**json.loads(args))
messages.append({
"role": "tool",
"content": f"{json.dumps(function_result)}",
"tool_call_id":tool_call.id
})
response = client.chat.completions.create(
model="glm-4", # 填写需要调用的模型名称
messages=messages,
tools=tools,
)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
完整代码:
from zhipuai import ZhipuAI
import json
def get_student_num(class_id:str, feature:str):
class_student_info = {
"12345":{
"女生" : "28",
"男生" : "22",
},
"254313":{
"女生" : "20",
"男生" : "30",
}
}
return { "student":class_student_info[class_id][feature] }
def get_student_grade(student_id:str , course:str):
course_grade_info = {
"s58292":{
"数学" : "149",
"语文" : "125",
},
"s58523":{
"数学" : "123",
"语文" : "140",
}
}
return { "grade":course_grade_info[student_id][course] }
def parse_function_call(model_response,messages):
# 处理函数调用结果,根据模型返回参数,调用对应的函数。
# 调用函数返回结果后构造tool message,再次调用模型,将函数结果输入模型
# 模型会将函数调用结果以自然语言格式返回给用户。
if model_response.choices[0].message.tool_calls:
tool_call = model_response.choices[0].message.tool_calls[0]
args = tool_call.function.arguments
function_result = {}
if tool_call.function.name == "get_student_num":
function_result = get_student_num(**json.loads(args))
if tool_call.function.name == "get_student_grade":
function_result = get_student_grade(**json.loads(args))
messages.append({
"role": "tool",
"content": f"{json.dumps(function_result)}",
"tool_call_id":tool_call.id
})
response = client.chat.completions.create(
model="glm-4", # 填写需要调用的模型名称
messages=messages,
tools=tools,
)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
client = ZhipuAI(api_key="")
tools = [
{
"type": "function",
"function": {
"name": "get_student_num",
"description": "根据班级id和特征描述,查找对应的学生数量",
"parameters": {
"type": "object",
"properties": {
"class_id": {
"description": "班级id",
"type": "string"
},
"feature": {
"description": "学生特征",
"type": "string"
}
},
"required": ["class_id", "feature"]
},
}
},
{
"type": "function",
"function": {
"name": "get_student_grade",
"description": "根据学生id和对应课程信息,查找该生对应课程的成绩",
"parameters": {
"type": "object",
"properties": {
"student_id": {
"description": "学生id",
"type": "string"
},
"course": {
"description": "课程",
"type": "string"
}
},
"required": ["student_id", "course"]
},
}
},
]
messages = []
messages.append({"role": "user", "content": "帮我查询班级id为12345的班级中女生的数量"})
response = client.chat.completions.create(
model="glm-4",
messages=messages,
tools=tools,)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
parse_function_call(response, messages)
messages.append({"role": "user", "content": "帮我查询学生id为s58523的语文成绩"})
response = client.chat.completions.create(
model="glm-4",
messages=messages,
tools=tools,
)
print(response.choices[0].message)
messages.append(response.choices[0].message.model_dump())
parse_function_call(response, messages)
输出结果:
扩展阅读:
《全方位解读大模型》