函数调用
在API调用中,你可以向 gpt-3.5-turbo-0613
和 gpt-4-0613
描述函数,并让模型智能地选择输出一个包含调用这些函数的参数的 JSON 对象。聊天完成 API 不会调用函数;相反,模型生成的JSON可以在你的代码中用来调用函数。
最新模型(gpt-3.5-turbo-0613
和 gpt-4-0613
)已经微调过,既可以检测何时应该调用一个函数(取决于输入),也可以用遵循函数签名的JSON进行响应。随之而来的还有潜在的风险。我们强烈建议在代表用户执行影响世界的操作之前(发送电子邮件、在线发布内容、进行购买等),建立用户确认流程。
在底层,函数以模型经过训练的语法注入系统消息中。这意味着函数计入模型的上下文限制,并作为输入标记进行计费。如果遇到上下文限制,我们建议限制函数的数量或缩短你为函数参数提供的文档长度。
函数调用使你能够更可靠地从模型获取结构化数据。例如,你可以:
- 创建通过调用外部API来回答问题的聊天机器人(例如像 ChatGPT 插件)
- 例如定义函数像
send_email(to: string, body: string)
, 或get_current_weather(location: string, unit: 'celsius' | 'fahrenheit')
- 例如定义函数像
- 将自然语言转换为API调用
- 例如把“谁是我的顶级客户?”转换为
get_customers(min_revenue: int, created_before: string, limit: int)
并调用你的内部API
- 例如把“谁是我的顶级客户?”转换为
- 从文本中提取结构化数据
- 例如定义一个名为
extract_data(name: string, birthday: string)
的函数,或sql_query(query: string)
- 例如定义一个名为
等等!
函数调用的基本步骤如下:
- 使用用户查询和一组在 functions 参数中定义的函数调用模型。
- 模型可以选择调用一个函数;如果是这样,内容将是一个遵循你的自定义模式的字符串化 JSON 对象(注意:模型可能会生成无效的 JSON 或幻想参数)。
- 在你的代码中解析字符串为 JSON,如果存在提供的参数,使用提供的参数调用你的函数。
- 通过将函数响应作为新消息追加来再次调用模型,并让模型将结果汇总回用户。
你可以通过下面的例子看到这些步骤的实际操作:
import openai
import json
# 示例假函数硬编码为返回相同的天气
# 在生产环境中,这可以是你的后端 API 或外部 API
def get_current_weather(location, unit="fahrenheit"):
"""获取某个位置的当前天气"""
weather_info = {
"location": location,
"temperature": "72",
"unit": unit,
"forecast": ["sunny", "windy"],
}
return json.dumps(weather_info)
def run_conversation():
# 第1步:将对话和可用函数发送给GPT
messages = [{"role": "user", "content": "波士顿的天气怎么样?"}]
functions = [
{
"name": "get_current_weather",
"description": "获取某个位置的当前天气",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市和州,例如旧金山,加州",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
}
]
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=messages,
functions=functions,
function_call="auto", # 默认为auto,但我们会明确声明
)
response_message = response["choices"][0]["message"]
# 第2步:检查GPT是否想要调用一个函数
if response_message.get("function_call"):
# 第3步:调用函数
# 注意:JSON响应可能并不总是有效的;一定要处理错误
available_functions = {
"get_current_weather": get_current_weather,
} # 本例中只有一个函数,但你可以有多个
function_name = response_message["function_call"]["name"]
fuction_to_call = available_functions[function_name]
function_args = json.loads(response_message["function_call"]["arguments"])
function_response = fuction_to_call(
location=function_args.get("location"),
unit=function_args.get("unit"),
)
# 第4步:将函数调用和函数响应的信息发送给GPT
messages.append(response_message) # 用助手的回复扩展对话
messages.append(
{
"role": "function",
"name": function_name,
"content": function_response,
}
) # 用函数响应扩展对话
second_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=messages,
) # 在GPT可以看到函数响应的地方获取新的GPT响应
return second_response
print(run_conversation())
函数调用中的虚构输出(幻觉)通常可以通过系统消息进行缓解。例如,如果你发现模型正在生成未向其提供的函数的函数调用,请尝试使用这样的系统消息:“只使用你已经被提供的函数”。
在上面的例子中,我们将函数响应发送回模型,并让它决定下一步。它以告知用户波士顿的温度的面向用户的消息做出响应,但根据查询,它可能会再次选择调用一个函数。
例如,如果你问模型“查找这个周末波士顿的天气,为两人订餐厅,并更新我的日历”,并为这些查询提供相应的函数,它可以依次调用它们,只在最后创建一个面向用户的消息。
如果你想强制模型调用一个特定的函数,你可以通过设置 function_call: {"name": "<insert-function-name>"}
来实现。你也可以通过设置 function_call: "none"
强制模型生成一个面向用户的消息。请注意,默认行为(function_call: "auto"
)是让模型自己决定是否调用函数以及调用哪个函数。
你可以在 OpenAI cookbook 中找到更多函数调用的例子: 更多 demo 演示函数调用