使用 .NET 生成 Azure AI 聊天应用

通过创建简单的 .NET 8 控制台聊天应用程序,开始使用 Semantic Kernel。 应用程序将在本地运行,并使用部署到 Azure OpenAI 帐户的 OpenAI gpt-35-turbo 模型。 按照以下步骤预配 Azure OpenAI,并了解如何使用 Semantic Kernel。

通过创建简单的 .NET 8 控制台聊天应用程序,开始使用 .NET Azure OpenAI SDK。 应用程序将在本地运行,并使用部署到 Azure OpenAI 帐户的 OpenAI gpt-35-turbo 模型。 按照以下步骤预配 Azure OpenAI,并了解如何使用 .NET Azure OpenAI SDK。

先决条件

部署 Azure 资源

确保遵循先决条件以访问 Azure OpenAI 服务以及 Azure Developer CLI,然后按照以下指南设置并开始使用示例应用程序。

  1. 克隆存储库:dotnet/ai-samples

  2. 在终端或命令提示符下,导航到 quickstarts 目录。

  3. 这会预配 Azure OpenAI 资源。 创建 Azure OpenAI 服务并部署模型可能需要几分钟时间。

    azd up
    

注意

如果已有可用的 Azure OpenAI 服务,则可跳过部署并在 Program.cs 中使用该值(最好是从 IConfiguration 中使用)

疑难解答

在 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 应用现已配置了用户机密,可以对其进行测试。

尝试使用 HikerAI 示例

  1. 在终端或命令提示符下,导航到 semantic-kernel\02-HikerAI 目录。
  1. 在终端或命令提示符下,导航到 azure-openai-sdk\02-HikerAI 目录。
  1. 现在可试用控制台应用程序了。 键入以下内容以运行应用:

    dotnet run
    

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

了解代码

我们的应用程序使用 NuGet 上提供的 Microsoft.SemanticKernel 包向 Azure 中部署的 Azure OpenAI 服务发送和接收请求。

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

// == Retrieve the local secrets saved during the Azure deployment ==========
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"];

AzureOpenAIChatCompletionService 服务便利了请求和响应。

// == Create the Azure OpenAI Chat Completion Service  ==========
AzureOpenAIChatCompletionService service = new(deployment, endpoint, key);

创建 AzureOpenAIChatCompletionService 服务后,我们通过添加系统提示向模型提供更多上下文。 这会指示模型在对话期间的行为方式。

// Start the conversation with context for the AI model
ChatHistory chatHistory = new("""
    You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly. 
    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 函数。


// Add user message to chat history
chatHistory.AddUserMessage("Hi! Apparently you can help me find a hike that I will like?");

// Print User Message to console
Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

// Get response
var response = await service.GetChatMessageContentAsync(chatHistory, new OpenAIPromptExecutionSettings() { MaxTokens = 400 });

若要维护聊天历史记录,请确保添加来自模型的响应。

// Add response to chat history
chatHistory.Add(response);

// Print Response to console
Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

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

了解代码

应用程序使用 NuGet 上提供的 Azure.AI.OpenAI 客户端 SDK 向 Azure 中部署的 Azure OpenAI 服务发送和接收请求。

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

// == Retrieve the local secrets saved during the Azure deployment ==========
var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
string openAIEndpoint = config["AZURE_OPENAI_ENDPOINT"];
string openAIDeploymentName = config["AZURE_OPENAI_GPT_NAME"];
string openAiKey = config["AZURE_OPENAI_KEY"];

// == Creating the AIClient ==========
var endpoint = new Uri(openAIEndpoint);
var credentials = new AzureKeyCredential(openAiKey);

OpenAIClient 类有助于请求和响应。 ChatCompletionOptions 指定模型响应方式的参数。

var openAIClient = new OpenAIClient(endpoint, credentials);

var completionOptions = new ChatCompletionsOptions
{
    MaxTokens = 400,
    Temperature = 1f,
    FrequencyPenalty = 0.0f,
    PresencePenalty = 0.0f,
    NucleusSamplingFactor = 0.95f, // Top P
    DeploymentName = openAIDeploymentName
};

创建 OpenAIClient 客户端后,我们通过添加系统提示向模型提供更多上下文。 这会指示模型在对话期间的行为方式。

var systemPrompt = 
"""
You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly. 
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.
""";

completionOptions.Messages.Add(new ChatRequestSystemMessage(systemPrompt));

然后,可使用 ChatRequestUserMessage 类将用户消息添加到模型。

若要让模型根据系统提示和用户请求生成响应,请使用 GetChatCompletionsAsync 函数。

string userGreeting = """
Hi! 
Apparently you can help me find a hike that I will like?
""";

completionOptions.Messages.Add(new ChatRequestUserMessage(userGreeting));
Console.WriteLine($"\n\nUser >>> {userGreeting}");

ChatCompletions response = await openAIClient.GetChatCompletionsAsync(completionOptions);
ChatResponseMessage assistantResponse = response.Choices[0].Message;
Console.WriteLine($"\n\nAI >>> {assistantResponse.Content}");
completionOptions.Messages.Add(new ChatRequestAssisstantMessage(assistantResponse.Content)); 

若要维护聊天历史记录或上下文,请确保将模型中的响应添加为 ChatRequestAssistantMessage

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

清理资源

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

azd down

后续步骤