GPT 的能力很强,但是很多人不知道如何去使用,如何去落地到自己的业务系统
现在 OpenAI 开发了两个能力 Actions,Function Calling。
GPT 通过这两个能力与外部世界打通。
本文主要介绍 Function Calling
1 .业务系统先拿到用户的输入
2.应用系统构建一个 prompt, 以及一个 function 的定义喂给大模型
3.大模型判断是否需要调用函数,
3.1 不需要调用函数,大模型直接回答问题了
3.2 需要调用函数,就返回一个调用说明,里面包含调用的参数给应用系统
4. 应用系统拿到大模型返回的函数调用说明,调用函数获取到结果
5. 应用系统将调用结果构建一个 prompt 给大模型
6. 大模型输出自然语言经过应用系统返回给用户
整体的过程如下图所示:
先定义几个工具方法
print_json 是为了打印参数用于调试
get_completion:定义了几个函数,供大模型判断是否需要调用
fbnq:是用户自己定义的一个函数
from openai import OpenAI
import json
client = OpenAI(api_key="YOUR KEY")
def print_json(data):
"""
打印参数。如果参数是有结构的(如字典或列表),则以格式化的 JSON 形式打印;
否则,直接打印该值。
"""
if hasattr(data, 'model_dump_json'):
data = json.loads(data.model_dump_json())
if isinstance(data, list):
for item in data:
print_json(item)
elif isinstance(data, dict):
print(json.dumps(
data,
indent=4,
ensure_ascii=False
))
else:
print(data)
def get_comletion(messages, model="gpt-3.5-turbo"):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0.7,
tools=[ # 用 JSON 描述函数,可以定义多个,由大模型决定调用或者不调用
{
"type": "function",
"function": {
"name": "sum",
"description": "加法器,计算一组数据的和",
"parameters": {
"type": "array",
"items": {
"type": "number"
}
}
}
},
{
"type": "function",
"function": {
"name": "abs",
"description": "绝对值,计算一个数字对应的绝对值",
"parameters": {
"type": "number"
}
}
},
{
"type": "function",
"function": {
"name": "fbnq",
"description": "计算斐波那契数列的值",
"parameters": {
"type": "number"
}
}
}
]
)
return response.choices[0].message
def fbnq(n):
if n <= 2:
return 1
return fbnq(n - 1) + fbnq(n - 2)
开始调用大模型,看看大模型会不会调用我们提供的一些方法
def call_gpt(user_input):
print("用户输入:", user_input)
messages = [
{"role": "system", "content": "你是一个数学家"},
{"role": "user", "content": user_input}
]
print("prompt:")
print_json(messages)
response = get_completion(messages)
print("大模型:")
print_json(response)
# 将大模型的回复加入到对话历史
messages.append(response)
if response.tool_calls:
tool_call = response.tool_calls[0]
if tool_call.function.name == "sum":
args = json.loads(tool_call.function.arguments)
result = sum(args['numbers'])
if tool_call.function.name == "abs":
args = json.loads(tool_call.function.arguments)
result = abs(args['number'])
if tool_call.function.name == "fbnq":
args = json.loads(tool_call.function.arguments)
result = fbnq(args['number'])
fun_res = {
"tool_call_id": tool_call.id, # 用于标识函数调用的 ID
"role": "tool",
"name": "sum",
"content": str(result) # 数值 result 必须转成字符串
}
# 把调用结果加入到对话历史中
messages.append(fun_res)
print("函数调用结果:")
print_json(fun_res)
# 再次调用大模型
print("=====最终 GPT 回复=====")
print(get_completion(messages).content)
if __name__ == "__main__":
call_gpt("计算一下斐波那契数列第10位是几?")
输出结果:
用户输入: 计算一下斐波那契数列第10位是几?
prompt:
{
"role": "system",
"content": "你是一个数学家"
}
{
"role": "user",
"content": "计算一下斐波那契数列第10位是几?"
}
大模型:
{
"content": null,
"role": "assistant",
"function_call": null,
"tool_calls": [
{
"id": "call_naVIx2li3mJuOAtzXag9mUcZ",
"function": {
"arguments": "{\"number\":10}",
"name": "fbnq"
},
"type": "function"
}
]
}
函数调用结果:
{
"tool_call_id": "call_naVIx2li3mJuOAtzXag9mUcZ",
"role": "tool",
"name": "sum",
"content": "55"
}
=====最终 GPT 回复=====
斐波那契数列的第10位是55。
从结果可以看出,GPT 是调用了前面定义的 fbnq 方法。
上面的代码无法处理下面这样的任务
计算一下斐波那契数列第10位和第11位,并计算这两个数的和
这个任务应该是分解成两步,第一步计算第10位和11位的数值,第二步再将上一步的结果加和
将代码稍加修改
def call_gpt(user_input):
print("用户输入:", user_input)
messages = [
{"role": "system", "content": "你是一个数学家"},
{"role": "user", "content": user_input}
]
print("prompt:")
print_json(messages)
response = get_completion(messages)
print("大模型:")
print_json(response)
# 将大模型的回复加入到对话历史
messages.append(response)
if response.tool_calls:
for tool_call in response.tool_calls:# 改了这里 gpt 会将任务拆解成多个任务
if tool_call.function.name == "sum":
args = json.loads(tool_call.function.arguments)
result = sum(args['numbers'])
if tool_call.function.name == "abs":
args = json.loads(tool_call.function.arguments)
result = abs(args['number'])
if tool_call.function.name == "fbnq":
args = json.loads(tool_call.function.arguments)
result = fbnq(args['number'])
fun_res = {
"tool_call_id": tool_call.id, # 用于标识函数调用的 ID
"role": "tool",
"name": "sum",
"content": str(result) # 数值 result 必须转成字符串
}
# 把调用结果加入到对话历史中
messages.append(fun_res)
print("函数调用结果:")
print_json(fun_res)
# 再次调用大模型
print("=====最终 GPT 回复=====")
print(get_completion(messages).content)
输出:
用户输入: 计算一下斐波那契数列第10位和第11位,并计算这两个数的和
prompt:
{
"role": "system",
"content": "你是一个数学家"
}
{
"role": "user",
"content": "计算一下斐波那契数列第10位和第11位,并计算这两个数的和"
}
大模型:
{
"content": null,
"role": "assistant",
"function_call": null,
"tool_calls": [
{
"id": "call_GbbKxqjBn6lv0JSYY7UBeNLg",
"function": {
"arguments": "{\"number\": 10}",
"name": "fbnq"
},
"type": "function"
},
{
"id": "call_zO1khQ64ERobcHqqkAf27afv",
"function": {
"arguments": "{\"number\": 11}",
"name": "fbnq"
},
"type": "function"
}
]
}
函数调用结果:
{
"tool_call_id": "call_GbbKxqjBn6lv0JSYY7UBeNLg",
"role": "tool",
"name": "sum",
"content": "55"
}
函数调用结果:
{
"tool_call_id": "call_zO1khQ64ERobcHqqkAf27afv",
"role": "tool",
"name": "sum",
"content": "89"
}
=====最终 GPT 回复=====
None
Process finished with exit code 0
从结果看,gpt 确实将任务做到了拆解,但是最后一步的任务却拆不出来,其实大模型已经给出步骤了,还需要进一步处理才能得到最后结果
def call_gpt(user_input):
print("用户输入:", user_input)
messages = [
{"role": "system", "content": "你是一个数学家"},
{"role": "user", "content": user_input}
]
print("prompt:")
print_json(messages)
response = get_completion(messages)
print("大模型:")
print_json(response)
# 将大模型的回复加入到对话历史
messages.append(response)
while response.tool_calls:
for tool_call in response.tool_calls:
if tool_call.function.name == "sum":
args = json.loads(tool_call.function.arguments)
result = sum(args['numbers'])
if tool_call.function.name == "abs":
args = json.loads(tool_call.function.arguments)
result = abs(args['number'])
if tool_call.function.name == "fbnq":
args = json.loads(tool_call.function.arguments)
result = fbnq(args['number'])
fun_res = {
"tool_call_id": tool_call.id, # 用于标识函数调用的 ID
"role": "tool",
"name": "sum",
"content": str(result) # 数值 result 必须转成字符串
}
# 把调用结果加入到对话历史中
messages.append(fun_res)
print("函数调用结果:")
print_json(fun_res)
# 再次调用大模型
response = get_completion(messages)
messages.append(response) # 把大模型的回复加入到对话中
print("=====最终回复=====")
print(response.content)
用户输入: 计算一下斐波那契数列第10位和第11位,并计算这两个数的和
prompt:
{
"role": "system",
"content": "你是一个数学家"
}
{
"role": "user",
"content": "计算一下斐波那契数列第10位和第11位,并计算这两个数的和"
}
大模型:
{
"content": null,
"role": "assistant",
"function_call": null,
"tool_calls": [
{
"id": "call_hAVFeLjeegHSE4ZlCrMVCNpc",
"function": {
"arguments": "{\"number\": 10}",
"name": "fbnq"
},
"type": "function"
},
{
"id": "call_R5jEoh0cdTO2j1oo1z7wDq1j",
"function": {
"arguments": "{\"number\": 11}",
"name": "fbnq"
},
"type": "function"
}
]
}
函数调用结果:
{
"tool_call_id": "call_hAVFeLjeegHSE4ZlCrMVCNpc",
"role": "tool",
"name": "sum",
"content": "55"
}
函数调用结果:
{
"tool_call_id": "call_R5jEoh0cdTO2j1oo1z7wDq1j",
"role": "tool",
"name": "sum",
"content": "89"
}
函数调用结果:
{
"tool_call_id": "call_l7zDPFvIwYEzZIB8XQ6B9vjk",
"role": "tool",
"name": "sum",
"content": "144"
}
=====最终回复=====
斐波那契数列的第10位是55,第11位是89,它们的和是144。
至此,大模型的任务拆解就完成了