6月14日ChatGPT刚刚更新了Function Call函数调用功能,用户可以通过自定义函数代码来扩展ChatGPT的能力,让ChatGPT可以做到除了问答以外的扩展能力,比如官方举例说可以调第三方API查询天气,还可以通过生成SQL语句帮你查数据库等等。这篇文章我们通过官方的几个例子以及我自己的一些尝试介绍一下函数调用到底怎么玩。
函数调用
根据官方文档的描述,14日新发布的两个算法版本gpt-3.5-turbo-0613
和gpt-4-0613
支持该项功能,要主要的是,自定义的函数是在你本地执行的,而不是在ChatGPT的服务器上,ChatGPT能做是理解你的问题,并且帮你决策要调用哪个函数,以及帮你生成入参,理解了后面的例子这一点就明白了。
根据官方的描述,函数调用提供了一种从ChatGPT模型获取格式化数据的能力,比如:
- 创建一个对话机器人,通过调用外部API进行问答。e.g. 定义一个函数
send_email(to: string, body: string)
或者get_current_weather(location: string, unit: 'celsius' | 'fahrenheit')
- 把自然语言转换成API调用,e.g. 把"Who are my top customers?"转换为
get_customers(min_revenue: int, created_before: string, limit: int)
然后调用外部API - 抽取结构化数据,e.g. 定义一个函数
extract_data(name: string, birthday: string)
或者sql_query(query: string)
函数调用的整体流程如下:
- 使用user query调用模型,并且模型的入参中指定一个或一组"functions"调用。
- 模型会自己选择调用哪个Function,这样的话返回内容将是一个符合自定义模式的字符串化的JSON对象(注意:模型可能生成无效的JSON或虚构参数)。
- 在您的代码中将字符串解析为JSON,并根据提供的参数调用您的函数(如果存在)。
- 通过将函数响应作为新消息附加,并让模型将结果总结给用户,再次调用模型。
示例:查询IP信誉
这个例子我们先定义一个简单的函数调用微步在线API,然后把这个函数传给ChatGPT,最后向它花式提问让它帮我们查这个IP的信誉,相当于一个智能助手(有点大炮打蚊子的赶脚=.=)
下面这段代码传入IP参数,调用微步API查询IP信誉
import requests
def query_ip_reputation(ip):
# 获取一个微步APIkey,不会玩的去问ChatGPT
api_key = "<apikey>"
url = f"https://api.threatbook.cn/v3/scene/ip_reputation?apikey={api_key}&resource={ip}"
resp = requests.get(url)
if resp.status_code == 200:
print(resp.text)
return resp.text
else:
raise Exception(resp.text)
#ip_address = "8.8.8.8"
输出
{"data":{"8.8.8.8":{"severity":"info","judgments":["IDC","Whitelist","CDN"],"tags_classes":[{"tags":["GoogleCloud"],"tags_type":"public_info"}],"basic":{"carrier":"Google LLC","location":{"country":"United States","province":"","city":"","lng":"-101.407912","lat":"39.765054","country_code":"US"}},"asn":{"rank":4,"info":"GOOGLE, US","number":15169},"scene":"Cloud Provider","confidence_level":"high","is_malicious":false,"update_time":"2023-06-01 08:29:11"}},"response_code":0,"verbose_msg":"OK"}
接下来我们看看如何调用ChatGPT,当然你可以用request
调用openai的url,但是这里我们选择使用它的SDK,先安装:
pip install openai
下面这段代码可以用来测试你的ChatGPT api_key
是否有效(没有的自己想办法吧)
import openai
openai.api_key = "sk-<apikey>"
# confirm authentication was successful
openai.Engine.list()['data'][0]
下面这段相当于是我们前面定义python函数的一个Schema,这个格式基本是固定的,包含函数名、描述、参数以及参数类型和描述,这里的描述一定要尽可能准确,因为这段描述是ChatGPT做决策的依据,ChatGPT会根据它理解的语义选择调用或不调用这个函数,总之决策权在它不在你。
query_ip_reputation_func = {
"name": "ip_reputation",
"description": "Query the reputation of IP address",
"parameters": {
"type": "object",
"properties": {
"ip": {
"type": "string",
"description": "The target IP address that you need to query for the reputation"
}
},
"required": ["ip"]
}
}
最后,我们调用对话接口用自然语言让他查某个IP的信誉,效果如下
import json
prompt = "给我查询这个IP 8.8.8.8的信誉"
res = openai.ChatCompletion.create(
model='gpt-3.5-turbo-0613', # swap for gpt-3.5-turbo-0613 if needed
messages=[{"role": "user", "content": prompt}],
functions=[query_ip_reputation_func]
)
if res['choices'][0]["finish_reason"] == "function_call":
print("We should call a function!")
name = res['choices'][0]['message']['function_call']['name']
params = json.loads(res['choices'][0]['message']['function_call']['arguments'])
name, params
print(query_ip_reputation(**params))
输出
We should call a function!
{"data":{"8.8.8.8":{"severity":"info","judgments":["IDC","Whitelist","CDN"],"tags_classes":[{"tags":["GoogleCloud"],"tags_type":"public_info"}],"basic":{"carrier":"Google LLC","location":{"country":"United States","province":"","city":"","lng":"-101.407912","lat":"39.765054","country_code":"US"}},"asn":{"rank":4,"info":"GOOGLE, US","number":15169},"scene":"Cloud Provider","confidence_level":"high","is_malicious":false,"update_time":"2023-06-01 08:29:11"}},"response_code":0,"verbose_msg":"OK"}
可以看到ChatGPT理解了我们的问题,也理解了这个函数的作用,并最终选择调用我们定义的函数。当然,我们可以定义一系列Function用来完成不同的工作,然后在调用对话接口的时候把所有的Function都绑定进去,让ChatGPT自己决定
总结
官方还提供了一个让CHatGPT生成SQL并借助函数查询本地数据库的一个例子传送门。总的来讲还是蛮有创意的,通过本地执行函数即保证了数据安全性又能方便的使用线上的生成式大语言模型,只是如果函数全都自己写还是感觉有点费劲,毕竟来使用AI的都是想偷懒的人,不过据说Langchain
在openai发布新版本后十分钟你内就立即宣布支持Function Call,相信有了专业人士的加持,Function call会孵化出很多千奇百怪的玩法。