跳到主要内容

Azure函数示例

nbviewer

注意:openai库有更新版本可用。请参阅 https://github.com/openai/openai-python/discussions/742

这个笔记本展示了如何使用Azure OpenAI服务的函数调用功能。函数允许聊天完成的调用者定义模型可以使用的功能,以扩展其功能到外部工具和数据源。

您可以在OpenAI的博客上阅读更多关于聊天函数的内容:https://openai.com/blog/function-calling-and-other-api-updates

注意:聊天函数要求模型版本以gpt-4和gpt-35-turbo的-0613标签开头。它们不受旧版本模型的支持。

设置

首先,我们安装必要的依赖项。

! pip install "openai>=0.28.1,<1.0.0"
# (可选)如果您希望使用Microsoft Active Directory,
! pip install azure-identity

import os
import openai

另外,为了正确访问Azure OpenAI服务,我们需要在Azure门户上创建适当的资源(您可以在Microsoft Docs上查看如何执行此操作的详细指南)

资源创建完成后,我们首先需要使用的是其终结点。您可以在“资源管理”部分的“密钥和终结点”部分找到终结点。有了这个信息,我们将使用这些信息设置SDK:

openai.api_base = "" # 在此添加您的端点

# 函数仅在2023-07-01-preview API版本中受支持。
openai.api_version = "2023-07-01-preview"

认证

Azure OpenAI 服务支持多种认证机制,包括 API 密钥和 Azure 凭据。

use_azure_active_directory = False

使用API密钥进行身份验证

要设置OpenAI SDK以使用Azure API密钥,我们需要将api_type设置为azure,并将api_key设置为与您的终端关联的密钥(您可以在Azure门户的*“资源管理”下的“密钥和终结点”*中找到此密钥)。

if not use_azure_active_directory:
openai.api_type = "azure"
openai.api_key = os.environ["OPENAI_API_KEY"]

注意:在这个示例中,我们通过在代码中设置变量来配置库以使用Azure API。对于开发环境,考虑设置环境变量而不是在代码中设置:

OPENAI_API_BASE
OPENAI_API_KEY
OPENAI_API_TYPE
OPENAI_API_VERSION

使用Microsoft Active Directory进行身份验证

现在让我们看看如何通过Microsoft Active Directory身份验证获取密钥。

from azure.identity import DefaultAzureCredential

if use_azure_active_directory:
default_credential = DefaultAzureCredential()
token = default_credential.get_token("https://cognitiveservices.azure.com/.default")

openai.api_type = "azure_ad"
openai.api_key = token.token

令牌在一段时间内有效,之后将会过期。为了确保每个请求都携带一个有效的令牌,您可以通过连接到requests.auth来刷新即将过期的令牌:

import typing
import time
import requests

if typing.TYPE_CHECKING:
from azure.core.credentials import TokenCredential

class TokenRefresh(requests.auth.AuthBase):

def __init__(self, credential: "TokenCredential", scopes: typing.List[str]) -> None:
self.credential = credential
self.scopes = scopes
self.cached_token: typing.Optional[str] = None

def __call__(self, req):
if not self.cached_token or self.cached_token.expires_on - time.time() < 300:
self.cached_token = self.credential.get_token(*self.scopes)
req.headers["Authorization"] = f"Bearer {self.cached_token.token}"
return req

if use_azure_active_directory:
session = requests.Session()
session.auth = TokenRefresh(default_credential, ["https://cognitiveservices.azure.com/.default"])

openai.requestssession = session

函数

完成设置和身份验证后,现在可以使用Azure OpenAI服务中的函数。这将分为几个步骤:

  1. 定义函数
  2. 将函数定义传递到聊天完成API
  3. 使用响应中的参数调用函数
  4. 将函数响应反馈到聊天完成API

1. 定义函数

可以定义一系列函数,每个函数包含函数名称、可选描述以及函数接受的参数(描述为一个JSON模式)。

functions = [
{
"name": "get_current_weather",
"description": "Get the current weather",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"format": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit to use. Infer this from the users location.",
},
},
"required": ["location"],
},
}
]

2. 将函数定义传递给聊天完成API

现在我们可以将函数传递给聊天完成API。如果模型确定应该调用该函数,选择项上将填充一个”function_call”的finish_reason,并且message中将包含要调用的函数及其参数的详细信息。可选地,您可以将function_call关键字参数设置为强制模型调用特定函数(例如function_call={"name": get_current_weather})。默认情况下,这被设置为auto,允许模型选择是否调用该函数。

messages = [
{"role": "system", "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."},
{"role": "user", "content": "What's the weather like today in Seattle?"}
]

chat_completion = openai.ChatCompletion.create(
deployment_id="gpt-35-turbo-0613",
messages=messages,
functions=functions,
)
print(chat_completion)

{
"choices": [
{
"content_filter_results": {},
"finish_reason": "function_call",
"index": 0,
"message": {
"function_call": {
"arguments": "{\n \"location\": \"Seattle, WA\"\n}",
"name": "get_current_weather"
},
"role": "assistant"
}
}
],
"created": 1689702512,
"id": "chatcmpl-7dj6GkYdM7Vw9eGn02bc2qqjN70Ps",
"model": "gpt-4",
"object": "chat.completion",
"prompt_annotations": [
{
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
},
"prompt_index": 0
}
],
"usage": {
"completion_tokens": 18,
"prompt_tokens": 115,
"total_tokens": 133
}
}

3. 使用响应中的参数调用函数

函数调用的名称将是最初提供的名称,参数将包括与函数定义中包含的模式匹配的JSON数据。

import json

def get_current_weather(request):
"""
此功能仅供说明之用。
应根据位置和单位来确定天气情况,而非返回硬编码的响应。
"""
location = request.get("location")
unit = request.get("unit")
return {"temperature": "22", "unit": "celsius", "description": "Sunny"}

function_call = chat_completion.choices[0].message.function_call
print(function_call.name)
print(function_call.arguments)

if function_call.name == "get_current_weather":
response = get_current_weather(json.loads(function_call.arguments))

get_current_weather
{
"location": "Seattle, WA"
}

4. 将函数的响应反馈到聊天完成API中

函数的响应应该被序列化为一个角色设置为“function”的新消息。现在模型将使用响应数据来制定其答案。

messages.append(
{
"role": "function",
"name": "get_current_weather",
"content": json.dumps(response)
}
)

function_completion = openai.ChatCompletion.create(
deployment_id="gpt-35-turbo-0613",
messages=messages,
functions=functions,
)

print(function_completion.choices[0].message.content.strip())

Today in Seattle, the weather is sunny with a temperature of 22 degrees celsius.