相信作为编程人员或AI应用的每一位关注者,都苦于ChatGPT之前的知识只能到2021年,而且我们作为开发者大多数人其实都希望能通过给ChatGPT写更多的通用能力,非常眼馋ChatGPT的插件能力。
终于OpenAI后来发布会宣布可以通过API来实现插件能力了,无疑给ChatGPT的应用插上了翅膀。
实现插件能力的基础就是本次的主角-Function Call,让我们一起揭开其神秘面纱吧!
什么是Function Call
Function Call是GPT API中的一项新能力。
它可以让开发者在调用GPT-4和GPT-3.5-turbo模型时,通过描述函数能让模型智能的输出包含调用这些函数所需参数的JSON对象。这是一种更可靠地将 GPT 的功能与外部工具和 API 相连接的新方法。函数调用使开发者能够更可靠地从模型中获得结构化数据。通俗点讲,能把自然语言的世界和现在的机器世界打通了,虽然整个世界最终的走向将会是自然语言的世界,但现在所有的计算机系统都还是代码的世界,Function Call将两个世界完美的搭配了起来。
通过插件体系的建立,ChatGPT不仅可以获取最新的新闻,还可以查询天气、酒店等信息,规划旅行及电商下单等,使得ChatGPT在更多领域发挥有更多的用武之地。
Function Call本质
Function Call的本质就是把原来ChatGPT API中completetions的调用,从原来只支持messages(三种角色:system、user、assistant),扩展到了还可以提供functions。ChatGPT会根据functions里面每个单独的function描述的意思,进行简单的逻辑判断用户的问题用某个函数回答是否合适。如果可以它将会把用户的问题中间可以作为参数的部分提出出来,并返回一个结构化的函数调用数据结构。代码世界再通过严格的JSON格式定义的函数调用方法调用函数,将最终结果返回给ChatGPT,ChatGPT根据返回的信息继续回答用户的问题,我们可以实现所有的计算机函数接口都有了人类语言的能力!
举个例子
- 开发者可以利用调用外部工具创建聊天机器人(如 ChatGPT 插件)来回答问题
将查询如“今天的天气如何?”转换为像 getCurrentWeather(location: string)
这样的函数调用
- 将自然语言转换为 API 调用或数据库查询
将“某段时间前十位客户是谁?”转换为内部 API 调用,如 get_customers(start_date: string, end_date: string, limit: int)
,或者将“公司上个月下了多少订单?”转换为使用 sql_query(query: string) 的 SQL 查询。
- 从文本中提取结构化数据
定义一个extract_user_data(name: string, birthday: string)
的函数,提取在维基百科文章中提到的所有人物。
这些例子通过我们的 /v1/chat/completions 端点中的新 API 参数 functions 和 function_call 得以实现,开发者可以通过 JSON Schema 描述函数,并可选择要求模型调用特定函数。
一句话解释就是:我们可以把自己的函数集成到GPT里了
Function Calling帮我们能解决什么问题
Function Calling本质上就是插件!插件功能相当于给OpenAI增加了一个武器库,开发者可以随意给它安装武器提升它的能力。
- 数据实时性问题
问他langchain是什么?由于训练集是截止2021年(目前最新版的已更新至2023年04月)的,他会回答不知道。但是有了Function Callling,我们就可以写一个函数集成谷歌/百度搜索API,给GPT加上联网能力,这样就借助搜索引擎的能力支持了数据的动态更新。
- 跟已有应用系统集成问题
问他今天天气如何?由于ChatGPT数据集是离线的,无法满足获取实时天气的需求。但是有了Function Calling,我们可以编写一个函数来调用天气获取的API,从而获取实时天气信息,然后再与大模型的对话能力进行自然语言交互。
Function Calling如何使用
与普通chat对话的区别是增加了两个额外参数
- functions: 声明自定义函数库
- funcion_call: 控制大模型什么时机使用通Function Calling 功能
# 普通代码
# 注意新版的python SDK中openai函数已经发生了更新
# 历史版本
messages = [
{"role": "user", "content": "Hello stone!"}
]
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages
)
# 新版中
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "Hello stone!"}
],
)
# Function calling
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages,
# 增加额外两个参数
functions=functions,
function_call="auto", # auto is default, but we'll be explicit
)
实时天气查询实践
调用流程
1.定义函数
定义本地函数get_current_weather实现从API拉取,这里直接写一个简单对参数输出进行模拟。
然后按照OpenAI的文档要求格式定义get_current_weather的接口函数的json参数。
代码语言:python代码运行次数:0复制# 1.1 定义模拟获取天气的本地函数
def get_current_weather(location, unit):
# 可以对接第三方应用系统的API
return f"It's 0 {unit} in {location}"
- 第一次调用接口
返回大模型分析出的函数名称和参数。
代码语言:python代码运行次数:0复制 ChatCompletion(
id='chatcmpl-8K54AkuSdoiwk8Jw2B8zcPs5VibAZ',
choices=[
Choice(
finish_reason='function_call',
index=0,
message=ChatCompletionMessage(
content=None, role='assistant',
function_call=FunctionCall(
arguments='{n "location": "Xian",n "unit": "celsius"n}',
name='get_current_weather'
),
tool_calls=None
))
],
created=1699796726,
model='gpt-3.5-turbo-0613',
object='chat.completion',
system_fingerprint=None,
usage=CompletionUsage(
completion_tokens=25,
prompt_tokens=89,
total_tokens=114
)
)
- 调用本地函数
获取返回值,进行本地python方法调用
- 第二次调用接口
将第一次接口的返回值message与本地函数调用的接口拼装起来,然后再次调用接口。
代码语言:python代码运行次数:0复制ChatCompletionMessage(
content='The weather in Xian today is 0 degrees Celsius.',
role='assistant',
function_call=None,
tool_calls=None
)
代码语言:python代码运行次数:0复制# function_calling.py
import openai
import json
openai.api_key = 'sk-xxxxxxxx' # 密钥
# 1. 定义函数
# 1.1 定义模拟获取天气的本地函数
def get_current_weather(location, unit):
# Call the weather API
return f"It's 0 {unit} in {location}"
# 1.2 定义函数字典方便调用
function_dict = {
"get_current_weather": get_current_weather,
}
# 1.3 定义chat接口需要的函数
functions = [
{
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. ShaanXi, Xian",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
}
]
# 2. 第一次调用chat接口,返回的是函数调用的提示
messages = [
{"role": "user", "content": "What's the weather like in Xian today with celsius?"}]
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
functions=functions,
function_call="auto", # auto is default, but we'll be explicit
)
print(completion)
# 3. 从结果接口的结果中获取函数调用的参数 进行本地函数调用
# 3.1 获取函数调用的参数
response_message = completion.choices[0].message
function_name = response_message.function_call.name
function_args = json.loads(response_message.function_call.arguments)
# 3.2 调用本地函数
function_response = function_dict.get(function_name)(**function_args)
# 3.3 将本地函数的结果作为chat接口的输入
messages.append(response_message)
messages.append({
"role": "function",
"name": function_name,
"content": function_response,
})
# 4. 第二次调用chat接口,返回的是chat的最终结果
completion_final = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages,
)
print(completion_final.choices[0].message)
参考文献
- OpenAI Chat API官方文档
- Function Calling
准备工作
- 准备自己的ChatGPT账号