基于 Chat Completions API 实现外部函数调用
2023年6月20日,OpenAI 官方在 Chat Completions API 原有的三种不同角色设定(System, Assistant, User)基础上,新增了 Function Calling 功能。
详见OpenAI Blog
functions
是 Chat Completion API 中的可选参数,用于提供函数定义。其目的是使 GPT 模型能够生成符合所提供定义的函数参数。请注意,API不会实际执行任何函数调用。开发人员需要使用GPT 模型输出来执行函数调用。
如果提供了functions
参数,默认情况下,GPT 模型将决定在何时适当地使用其中一个函数。
可以通过将function_call
参数设置为{"name": "<insert-function-name>"}
来强制 API 使用指定函数。
同时,也支持通过将function_call
参数设置为"none"
来强制API不使用任何函数。
如果使用了某个函数,则响应中的输出将包含"finish_reason": "function_call"
,以及一个具有该函数名称和生成的函数参数的function_call
对象。
概述
本 Notebook 介绍了如何将 Chat Completions API 与外部函数结合使用,以扩展 GPT 模型的功能。包含以下2个部分:
- 如何使用
functions
参数 - 如何使用
function_call
参数 - 使用 GPT 模型生成函数和参数
- 实际执行 GPT 模型生成的函数(以 SQL 查询为例)
注意:本示例直接构造 HTTP 请求访问 OpenAI API,因此无需使用 openai Python SDK。
安装依赖包
!pip install scipy tenacity tiktoken termcolor openai requests
import json
import requests
import os
from tenacity import retry, wait_random_exponential, stop_after_attempt
from termcolor import coloredGPT_MODEL = "gpt-3.5-turbo"
定义工具函数
首先,让我们定义一些用于调用聊天完成 API 的实用工具,并维护和跟踪对话状态。
# 使用了retry库,指定在请求失败时的重试策略。
# 这里设定的是指数等待(wait_random_exponential),时间间隔的最大值为40秒,并且最多重试3次(stop_after_attempt(3))。
# 定义一个函数chat_completion_request,主要用于发送 聊天补全 请求到OpenAI服务器
@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3))
def chat_completion_request(messages, functions=None, function_call=None, model=GPT_MODEL):# 设定请求的header信息,包括 API_KEYheaders = {"Content-Type": "application/json","Authorization": "Bearer " + os.getenv("OPENAI_API_KEY"),}# 设定请求的JSON数据,包括GPT 模型名和要进行补全的消息json_data = {"model": model, "messages": messages}# 如果传入了functions,将其加入到json_data中if functions is not None:json_data.update({"functions": functions})# 如果传入了function_call,将其加入到json_data中if function_call is not None:json_data.update({"function_call": function_call})# 尝试发送POST请求到OpenAI服务器的chat/completions接口try:response = requests.post("https://api.openai.com/v1/chat/completions",headers=headers,json=json_data,)# 返回服务器的响应return response# 如果发送请求或处理响应时出现异常,打印异常信息并返回except Exception as e:print("Unable to generate ChatCompletion response")print(f"Exception: {e}")return e
# 定义一个函数pretty_print_conversation,用于打印消息对话内容
def pretty_print_conversation(messages):# 为不同角色设置不同的颜色role_to_color = {"system": "red","user": "green","assistant": "blue","function": "magenta",}# 遍历消息列表for message in messages:# 如果消息的角色是"system",则用红色打印“content”if message["role"] == "system":print(colored(f"system: {message['content']}\n", role_to_color[message["role"]]))# 如果消息的角色是"user",则用绿色打印“content”elif message["role"] == "user":print(colored(f"user: {message['content']}\n", role_to_color[message["role"]]))# 如果消息的角色是"assistant",并且消息中包含"function_call",则用蓝色打印"function_call"elif message["role"] == "assistant" and message.get("function_call"):print(colored(f"assistant[function_call]: {message['function_call']}\n", role_to_color[message["role"]]))# 如果消息的角色是"assistant",但是消息中不包含"function_call",则用蓝色打印“content”elif message["role"] == "assistant" and not message.get("function_call"):print(colored(f"assistant[content]: {message['content']}\n", role_to_color[message["role"]]))# 如果消息的角色是"function",则用品红色打印“function”elif message["role"] == "function":print(colored(f"function ({message['name']}