智谱AI-FunctionCall
编写FuncationCall大模型的函数调用,先直观的感受一下的感受下FunctionCall的魅力
1-参考网址
- 智谱AI-FunctionCall-代码仓库:https://gitee.com/enzoism/python_zhipu_funcationcall
- FunctionCall大模型的函数调用参考
- 智谱API-大模型调用博客记录
- 智谱API-官网地址
- 智谱API-KEY地址
2-思路整理
- 1)先测试API-KEY是否可用-main01_zhipu_ai.py
- 2)再验证FunctionCall是否可用-main02_functioncall.py
- 3)解读FunctionCall的请求逻辑
3-代码拆件
1-[非核心]两个业务函数
定义两个业务函数,用于查询航班号和查询票价(这个不是FunctionCall的核心功能,只是为了测试)
# 定义一个函数,用于根据日期、出发地和目的地查询航班号
def get_flight_number(date: str, departure: str, destination: str):
"""
查询航班号
:param date: 日期
:param departure: 出发地
:param destination: 目的地
:return: 航班号
"""
# 定义一个嵌套字典,存储不同出发地和目的地对应的航班号
flight_number = {
"北京": {
"上海": "1234",
"广州": "8321",
},
"上海": {
"北京": "1233",
"广州": "8123",
}
}
# 返回查询到的航班号-方法的核心逻辑
destination_data = flight_number[departure][destination]
return {
"flight_number": destination_data}
# 定义一个函数,用于根据日期和航班号查询票价
def get_ticket_price(date: str, flight_number: str):
"""
查询票价
:param date: 日期
:param flight_number: 航班号
:return: 票价
"""
# 目前代码中票价是固定的,返回一个固定的票价值
return {
"ticket_price": "1000"}
2-[非核心]业务函数的JsonSchema定义
就是当前的这个JSON说明把【大模型】和【FunctionCall】结合在一起,告诉了大模型有什么工具可以被调用;可以通过大模型针对我们的函数直接帮我们生成对应的JSON说明,如果chat模型不可以,就创建一个专家Prompt来解决
# 定义一个列表,存储工具函数的定义
tools = [
{
"type": "function",
"function": {
"name": "get_flight_number",
"description": "根据始发地、目的地和日期,查询对应日期的航班号",
"parameters": {
"type": "object",
"properties": {
"departure": {
"description": "出发地",
"type": "string"
},
"destination": {
"description": "目的地",
"type": "string"
},
"date": {
"description": "日期",
"type": "string",
}
},
"required": ["departure", "destination", "date"]
},
}
},
{
"type": "function",
"function": {
"name": "get_ticket_price",
"description": "查询某航班在某日的票价",
"parameters": {
"type": "object",
"properties": {
"flight_number": {
"description": "航班号",
"type": "string"
},
"date": {
"description": "日期",
"type": "string",
}
},
"required": ["flight_number", "date"]
},
}
},
]
3-[核心]FunctionCall的调用
调用FunctionCall的核心代码,主要是调用API接口,获取到返回的结果,然后根据返回的结果,生成对应的JSON数据,返回给chat模型
# 初始化智谱AI客户端,填写自己的APIKey
client = ZhipuAI(api_key="59572aa940214acba740ecb818e4c271.ELxoeOci9Cpmh0es")
# 定义一个函数,用于解析模型的函数调用结果
def parse_function_call(model_response, messages):
"""
解析模型的函数调用结果
:param model_response: 模型返回的响应
:param messages: 消息列表
"""
# 判断模型是否进行了函数调用
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_flight_number":
# 调用get_flight_number函数,并将结果存储到function_result中
function_result = get_flight_number(**json.loads(args))
if tool_call.function.name == "get_ticket_price":
# 调用get_ticket_price函数,并将结果存储到function_result中
function_result = get_ticket_price(**json.loads(args))
# 构造tool message,将函数调用结果添加到消息列表中
messages.append({
"role": "tool",
"content": f"{json.dumps(function_result)}",
"tool_call_id": tool_call.id
})
# 再次调用模型,将函数调用结果输入模型
response = client.chat.completions.create(
model="glm-4-plus", # 填写需要调用的模型名称
messages=messages,
tools=tools,
)
# 打印最终模型的回答结果
print("------>第二次调用模型的回答结果:", response.choices[0].message)
# 将最终模型的回答结果添加到消息列表中
messages.append(response.choices[0].message.model_dump())
# 清空对话消息列表
messages = []
# 拼接第一次对话,添加系统消息和用户消息
messages.append(
{"role": "system", "content": "不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息"})
messages.append({"role": "user", "content": "帮我查询1月23日,北京到广州的航班"})
# 调用模型处理用户消息
response = client.chat.completions.create(
model="glm-4-plus", # 填写需要调用的模型名称
messages=messages,
tools=tools,
)
# 打印模型的响应
print("------>第一次调用模型的回答结果:", response.choices[0].message)
# 将模型的响应添加到消息列表中
messages.append(response.choices[0].message.model_dump())
# 调用parse_function_call函数,解析函数调用结果
parse_function_call(response, messages)
1-打印的结果长什么样子
------>第一次调用模型的请求参数: [{"role": "system", "content": "不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息"}, {"role": "user", "content": "帮我查询1月23日,北京到广州的航班"}]
------>第一次调用模型的回答结果: {"content":null,"role":"assistant","tool_calls":[{"id":"call_-8929800266402085722","function":{"arguments":"{\"date\": \"2024-01-23\", \"departure\": \"北京\", \"destination\": \"广州\"}","name":"get_flight_number"},"type":"function","index":0}]}
------>第二次调用模型的请求参数: [{"role": "system", "content": "不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息"}, {"role": "user", "content": "帮我查询1月23日,北京到广州的航班"}, {"content": null, "role": "assistant", "tool_calls": [{"id": "call_-8929800266402085722", "function": {"arguments": "{\"date\": \"2024-01-23\", \"departure\": \"北京\", \"destination\": \"广州\"}", "name": "get_flight_number"}, "type": "function", "index": 0}]}, {"role": "tool", "content": "{\"flight_number\": \"8321\"}", "tool_call_id": "call_-8929800266402085722"}]
------>第二次调用模型的回答结果: {"content":"1月23日从北京飞往广州的航班号为8321。如果需要查询该航班的票价,请告诉我。","role":"assistant","tool_calls":null}
2-FunctionCall的调用流程
- 1)调用智谱AI的API接口,获取到模型的响应
- 2)解析模型的响应,获取到函数调用信息
- 3)根据函数名称调用对应的函数,获取到函数调用结果
- 4)构造tool message,将函数调用结果添加到消息列表中
- 5)再次调用模型,将函数调用结果输入模型
- 6)解析模型的响应,获取到最终的回答结果