使用工具扩展 OpenAI 并使用 .NET 执行本地函数

通过创建简单的 .NET 8 控制台聊天应用程序,开始使用 AI。 该应用程序将在本地运行并使用 OpenAI gpt-3.5-turbo 模型,使用工具通过调用本地 .NET 方法来扩展模型的功能。 按照以下步骤访问 OpenAI,并了解如何使用语义内核。

先决条件

  • .NET 8.0 SDK - 安装 .NET 8.0 SDK
  • OpenAI 的 API 密钥,可以用于运行此示例。
  • 在 Windows 上,必须安装 PowerShell v7+。 若要验证版本,请在终端中运行 pwsh。 它应返回当前版本。 如果返回错误,请执行以下命令 dotnet tool update --global PowerShell

通过创建简单的 .NET 8 控制台聊天应用程序,开始使用 AI。 应用程序将在本地运行,并使用部署到 Azure OpenAI 帐户的 OpenAI gpt-35-turbo 模型。 它使用工具通过调用本地 .NET 方法来扩展模型的功能。 按照以下步骤预配 Azure OpenAI,并了解如何使用语义内核。

先决条件

获取示例项目

克隆 GitHub 存储库,其中包含用于所有快速入门的示例应用:

git clone https://github.com/dotnet/ai-samples.git

创建 Azure OpenAI 服务

示例 GitHub 存储库构造为 Azure Developer CLI (azd) 模板,azd 可以使用此模板为你预配 Azure OpenAI 服务和模型。

  1. 从终端或命令提示符导航到示例存储库的 src\quickstarts\azure-openai 目录。

  2. 运行 azd up 命令来预配 Azure OpenAI 资源。 创建 Azure OpenAI 服务并部署模型可能需要几分钟。

    azd up
    

    azd 还为示例应用配置所需的用户机密,例如 OpenAI 访问密钥。

    注意

    如果在 azd up 部署期间遇到错误,请访问故障排除部分。

尝试徒步旅行者专业版示例

  1. 在终端或命令提示符下,导航到 azure-openai\04-HikerAIPro 目录。

  2. 运行以下命令,将 OpenAI API 密钥配置为示例应用的机密:

    dotnet user-secrets init
    dotnet user-secrets set OpenAIKey <your-openai-key>
    
  3. 使用 dotnet run 命令运行应用:

    dotnet run
    
  1. 在终端或命令提示符下,导航到 azure-openai\04-HikerAIPro 目录。

  2. 使用 dotnet run 命令运行应用:

    dotnet run
    

    提示

    如果收到错误消息,表明 Azure OpenAI 资源可能尚未完成部署。 等待几分钟,然后重试。

了解代码

应用程序使用 Microsoft.SemanticKernel 包向 OpenAI 服务发送和接收请求。

整个应用程序包含在 Program.cs 文件中。 前几行代码设置配置值,并获取以前使用 dotnet user-secrets 命令设置的 OpenAI 密钥。

var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
string model = "gpt-3.5-turbo";
string key = config["OpenAIKey"];

Kernel 类在 AddOpenAIChatCompletion 服务的帮助下便利了请求和响应。

// Create a Kernel containing the OpenAI Chat Completion Service
IKernelBuilder b = Kernel.CreateBuilder();

Kernel kernel = b
    .AddOpenAIChatCompletion(model, key)
    .Build();

应用程序使用 Microsoft.SemanticKernel 包向 OpenAI 服务发送和接收请求。

整个应用程序包含在 Program.cs 文件中。 前几行代码加载在应用程序预配期间在 dotnet user-secrets 中设置的机密和配置值。

var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
string endpoint = config["AZURE_OPENAI_ENDPOINT"];
string deployment = config["AZURE_OPENAI_GPT_NAME"];
string key = config["AZURE_OPENAI_KEY"];

Kernel 类在 AzureOpenAIChatCompletion 服务的帮助下便利了请求和响应。

// Create a Kernel containing the Azure OpenAI Chat Completion Service
IKernelBuilder b = Kernel.CreateBuilder();

Kernel kernel = b
    .AddAzureOpenAIChatCompletion(deployment, endpoint, key)
    .Build();

函数 ImportPluginFromFunctionsCreateFromMethod 定义模型将调用的本地函数。

// Add a new plugin with a local .NET function that should be available to the AI model
// For convenience and clarity of into the code, this standalone local method handles tool call responses. It will fake a call to a weather API and return the current weather for the specified location.
kernel.ImportPluginFromFunctions("WeatherPlugin",
[
    KernelFunctionFactory.CreateFromMethod(
        ([Description("The city, e.g. Montreal, Sidney")] string location, string unit = null) =>
    {
        // Here you would call a weather API to get the weather for the location
        return "Periods of rain or drizzle, 15 C";
    }, "get_current_weather", "Get the current weather in a given location")
]);

创建 kernel 客户端后,代码就会使用系统提示来提供上下文,并会影响补全的语气和内容。 注意系统提示中如何强调天气。

ChatHistory chatHistory = new("""
    You are a hiking enthusiast who helps people discover fun hikes in their area.
    You are upbeat and friendly. Good weather is important for a good hike. 
    Only make recommendations if the weather is good or if people insist.
    You introduce yourself when first saying hello. When helping people out,
    you always ask them for this information to inform the hiking recommendation you provide:

    1. Where they are located
    2. What hiking intensity they are looking for

    You will then provide three suggestions for nearby hikes that vary in length
    after you get that information. You will also share an interesting fact about the local
    nature on the hikes when making a recommendation.
    """);

应用还可使用 AddUserMessage 函数向模型添加用户消息。 GetChatMessageContentAsync 函数将聊天历史记录发送给模型,以根据系统和用户提示生成响应。

chatHistory.AddUserMessage("""
    Is the weather is good today for a hike?
    If yes, I live in the greater Montreal area and would like an easy hike. 
    I don't mind driving a bit to get there. I don't want the hike to be over 10 miles round trip.
    I'd consider a point-to-point hike.
    I want the hike to be as isolated as possible. I don't want to see many people.
    I would like it to be as bug free as possible.
    """);

Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

chatHistory.Add(await service.GetChatMessageContentAsync(
    chatHistory, 
    new OpenAIPromptExecutionSettings()
    { 
        MaxTokens = 400 
    }));

Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

自定义系统提示和用户消息,了解模型如何响应以帮助你找到你喜欢的徒步旅行。

清理资源

不再需要示例应用程序或资源时,请删除相应的部署和所有资源。

azd down

疑难解答

在 Windows 上,运行 azd up 后,可能会收到以下错误消息:

postprovision.ps1 未进行数字签名。 该脚本不会在系统上执行

执行脚本 postprovision.ps1 以设置应用程序中使用的 .NET 用户机密。 若要避免此错误,请运行以下 PowerShell 命令:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

然后,重新运行 azd up 命令。

另一个可能的错误:

“pwsh”没有被识别为内部或外部命令、可运行程序或批处理文件。 警告:“postprovision”挂钩失败,退出代码为“1”,路径:“.\infra\post-script\postprovision.ps1”。 :退出代码:1 执行将继续,因为 ContinueOnError 已设置为 true。

执行脚本 postprovision.ps1 以设置应用程序中使用的 .NET 用户机密。 若要避免此错误,请使用以下 PowerShell 命令手动运行脚本:

.\infra\post-script\postprovision.ps1

.NET AI 应用现已配置用户机密,可以对其进行测试。

后续步骤