在本指南中,你将生成一个 AI 聊天应用程序,并使用从 Azure 应用程序配置动态加载的聊天补全配置来循环访问提示。
Azure 应用配置 GitHub 存储库中提供了完整的示例源代码。
先决条件
- 完成本教程以创建聊天补全配置。
- 最新的 .NET SDK
创建控制台应用
- 为项目新建一个文件夹。 在新文件夹中,运行以下命令以创建新的 .NET 控制台应用项目: - dotnet new console
- 在项目中安装以下 NuGet 包: - dotnet add package Microsoft.Extensions.Configuration.AzureAppConfiguration dotnet add package Microsoft.Extensions.Configuration.Binder dotnet add package Azure.Identity dotnet add package Azure.AI.OpenAI
- 打开 Program.cs 文件,并在文件顶部添加以下命名空间: - using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.AzureAppConfiguration; using Azure.Identity; using Azure.AI.OpenAI; using OpenAI.Chat;
- 通过调用 - AddAzureAppConfigurationProgram.cs 文件中的方法连接到应用配置存储。- 可以使用 Microsoft Entra ID(建议)或连接字符串连接到应用程序配置。 在此示例中,会使用 Microsoft Entra ID 和 - DefaultAzureCredential对应用程序配置存储区进行身份验证。 按照以下 说明 将 应用配置数据读取者 角色分配给由- DefaultAzureCredential表示的标识。 运行应用程序前,请务必留出足够的时间让权限生效。- TokenCredential credential = new DefaultAzureCredential(); IConfigurationRefresher refresher = null; // Load configuration from Azure App Configuration IConfiguration configuration = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { Uri endpoint = new(Environment.GetEnvironmentVariable("AZURE_APPCONFIGURATION_ENDPOINT") ?? throw new InvalidOperationException("The environment variable 'AZURE_APPCONFIGURATION_ENDPOINT' is not set or is empty.")); options.Connect(endpoint, credential) // Load all keys that start with "ChatApp:" and have no label. .Select("ChatApp:*") // Reload configuration if any selected key-values have changed. // Use the default refresh interval of 30 seconds. It can be overridden via refreshOptions.SetRefreshInterval. .ConfigureRefresh(refreshOptions => { refreshOptions.RegisterAll(); }); refresher = options.GetRefresher(); }) .Build();
- 创建连接到 Azure OpenAI 资源的实例 - AzureOpenAIClient。 可以使用 Microsoft Entra ID 或 API 密钥进行身份验证。- 若要使用 Microsoft Entra ID 访问 Azure OpenAI 资源,请使用 - DefaultAzureCredential。 将“认知服务 OpenAI 用户”角色分配给- DefaultAzureCredential所表示的标识。 有关详细步骤,请参阅 Azure OpenAI 服务指南的基于角色的访问控制 。 运行应用程序前,请务必留出足够的时间让权限生效。- // Retrieve the OpenAI connection information from the configuration Uri openaiEndpoint = new(configuration["ChatApp:AzureOpenAI:Endpoint"]); string deploymentName = configuration["ChatApp:AzureOpenAI:DeploymentName"]; // Initialize the AzureOpenAIClient AzureOpenAIClient azureClient = new(openaiEndpoint, credential); // Create a chat client ChatClient chatClient = azureClient.GetChatClient(deploymentName);- 若要使用 API 密钥访问 Azure OpenAI 资源,请添加以下代码: - // Initialize the AzureOpenAIClient var apiKey = configuration["ChatApp:AzureOpenAI:ApiKey"]; AzureOpenAIClient client = new(openAIEndpoint, new AzureKeyCredential(apiKey));- 如果密钥 ChatApp:AzureOpenAI:ApiKey 是应用配置中的 Key Vault 引用,请确保将以下代码片段添加到 - AddAzureAppConfiguration调用中,并向 应用授予对 Key Vault 的访问权限。- options.ConfigureKeyVault(keyVaultOptions => { keyVaultOptions.SetCredential(credential); });
- 在 - ChatCompletionConfiguration文件中定义类。- internal class ChatCompletionConfiguration { [ConfigurationKeyName("model")] public string? Model { get; set; } [ConfigurationKeyName("messages")] public List<Message>? Messages { get; set; } [ConfigurationKeyName("max_tokens")] public int MaxTokens { get; set; } [ConfigurationKeyName("temperature")] public float Temperature { get; set; } [ConfigurationKeyName("top_p")] public float TopP { get; set; } } internal class Message { [ConfigurationKeyName("role")] public required string Role { get; set; } [ConfigurationKeyName("content")] public string? Content { get; set; } }
- 更新 Program.cs 文件以添加帮助程序方法来 - GetChatMessages处理聊天消息:- // Helper method to convert configuration messages to ChatMessage objects static IEnumerable<ChatMessage> GetChatMessages(ChatCompletionConfiguration chatCompletionConfiguration) { return chatCompletionConfiguration.Messages.Select<Message, ChatMessage>(message => message.Role switch { "system" => ChatMessage.CreateSystemMessage(message.Content), "user" => ChatMessage.CreateUserMessage(message.Content), "assistant" => ChatMessage.CreateAssistantMessage(message.Content), _ => throw new ArgumentException($"Unknown role: {message.Role}", nameof(message.Role)) }); }
- 接下来,更新 Program.cs 文件中的现有代码以从 Azure 应用配置刷新配置,将最新的 AI 配置值应用于聊天完成设置,并从 AI 模型检索响应。 - // Initialize chat conversation var chatConversation = new List<ChatMessage>(); Console.WriteLine("Chat started! What's on your mind?"); while (true) { // Get user input Console.Write("You: "); string? userInput = Console.ReadLine(); // Exit if user input is empty if (string.IsNullOrEmpty(userInput)) { Console.WriteLine("Exiting chat. Goodbye!"); break; } chatConversation.Add(ChatMessage.CreateUserMessage(userInput)); // Refresh the configuration from Azure App Configuration await refresher.RefreshAsync(); // Configure chat completion with AI configuration var chatCompletionConfiguration = configuration.GetSection("ChatApp:ChatCompletion").Get<ChatCompletionConfiguration>(); var requestOptions = new ChatCompletionOptions() { MaxOutputTokenCount = chatCompletionConfiguration.MaxTokens, Temperature = chatCompletionConfiguration.Temperature, TopP = chatCompletionConfiguration.TopP }; // Get latest system message from AI configuration var chatMessages = new List<ChatMessage>(GetChatMessages(chatCompletionConfiguration)); chatMessages.AddRange(chatConversation); // Get AI response and add it to chat conversation var response = await chatClient.CompleteChatAsync(chatMessages, requestOptions); string aiResponse = response.Value.Content[0].Text; Console.WriteLine($"AI: {aiResponse}"); chatConversation.Add(ChatMessage.CreateAssistantMessage(aiResponse)); Console.WriteLine(); }
- 完成前面的步骤后, Program.cs 文件现在应包含完整的实现,如下所示: - using Azure.AI.OpenAI; using Azure.Identity; using Azure.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.AzureAppConfiguration; using OpenAI.Chat; TokenCredential credential = new DefaultAzureCredential(); IConfigurationRefresher refresher = null; // Load configuration from Azure App Configuration IConfiguration configuration = new ConfigurationBuilder() .AddAzureAppConfiguration(options => { Uri endpoint = new(Environment.GetEnvironmentVariable("AZURE_APPCONFIGURATION_ENDPOINT") ?? throw new InvalidOperationException("The environment variable 'AZURE_APPCONFIGURATION_ENDPOINT' is not set or is empty.")); options.Connect(endpoint, credential) // Load all keys that start with "ChatApp:" and have no label. .Select("ChatApp:*") // Reload configuration if any selected key-values have changed. // Use the default refresh interval of 30 seconds. It can be overridden via refreshOptions.SetRefreshInterval. .ConfigureRefresh(refreshOptions => { refreshOptions.RegisterAll(); }); refresher = options.GetRefresher(); }) .Build(); // Retrieve the OpenAI connection information from the configuration Uri openaiEndpoint = new(configuration["ChatApp:AzureOpenAI:Endpoint"]); string deploymentName = configuration["ChatApp:AzureOpenAI:DeploymentName"]; // Create a chat client AzureOpenAIClient azureClient = new(openaiEndpoint, credential); ChatClient chatClient = azureClient.GetChatClient(deploymentName); // Initialize chat conversation var chatConversation = new List<ChatMessage>(); Console.WriteLine("Chat started! What's on your mind?"); while (true) { // Get user input Console.Write("You: "); string? userInput = Console.ReadLine(); // Exit if user input is empty if (string.IsNullOrEmpty(userInput)) { Console.WriteLine("Exiting chat. Goodbye!"); break; } chatConversation.Add(ChatMessage.CreateUserMessage(userInput)); // Refresh the configuration from Azure App Configuration await refresher.RefreshAsync(); // Configure chat completion with AI configuration var chatCompletionConfiguration = configuration.GetSection("ChatApp:ChatCompletion").Get<ChatCompletionConfiguration>(); var requestOptions = new ChatCompletionOptions() { MaxOutputTokenCount = chatCompletionConfiguration.MaxTokens, Temperature = chatCompletionConfiguration.Temperature, TopP = chatCompletionConfiguration.TopP }; // Get latest system message from AI configuration var chatMessages = new List<ChatMessage>(GetChatMessages(chatCompletionConfiguration)); chatMessages.AddRange(chatConversation); // Get AI response and add it to chat conversation var response = await chatClient.CompleteChatAsync(chatMessages, requestOptions); string aiResponse = response.Value.Content[0].Text; Console.WriteLine($"AI: {aiResponse}"); chatConversation.Add(ChatMessage.CreateAssistantMessage(aiResponse)); Console.WriteLine(); } // Helper method to convert configuration messages to ChatMessage objects static IEnumerable<ChatMessage> GetChatMessages(ChatCompletionConfiguration chatCompletionConfiguration) { return chatCompletionConfiguration.Messages.Select<Message, ChatMessage>(message => message.Role switch { "system" => ChatMessage.CreateSystemMessage(message.Content), "user" => ChatMessage.CreateUserMessage(message.Content), "assistant" => ChatMessage.CreateAssistantMessage(message.Content), _ => throw new ArgumentException($"Unknown role: {message.Role}", nameof(message.Role)) }); } internal class ChatCompletionConfiguration { [ConfigurationKeyName("model")] public string? Model { get; set; } [ConfigurationKeyName("messages")] public List<Message>? Messages { get; set; } [ConfigurationKeyName("max_tokens")] public int MaxTokens { get; set; } [ConfigurationKeyName("temperature")] public float Temperature { get; set; } [ConfigurationKeyName("top_p")] public float TopP { get; set; } } internal class Message { [ConfigurationKeyName("role")] public required string Role { get; set; } [ConfigurationKeyName("content")] public string? Content { get; set; } }
生成并运行应用
- 将名为 “AZURE_APPCONFIGURATION_ENDPOINT ”的环境变量设置为 Azure 门户中应用商店 “概述 ”下找到的应用配置存储的终结点。 - 如果使用 Windows 命令提示符,则请运行以下命令并重启命令提示符,这样更改才会生效: - setx AZURE_APPCONFIGURATION_ENDPOINT "<endpoint-of-your-app-configuration-store>"- 如果使用 PowerShell,请运行以下命令: - $Env:AZURE_APPCONFIGURATION_ENDPOINT = "<endpoint-of-your-app-configuration-store>"- 如果使用 macOS 或 Linux,请运行以下命令: - export AZURE_APPCONFIGURATION_ENDPOINT ='<endpoint-of-your-app-configuration-store>'
- 正确设置环境变量后,运行以下命令以生成并运行应用。 - dotnet run
- 当系统提示输入“You:”时,键入消息“你的姓名是什么?”,然后按 Enter 键。 - Chat started! What's on your mind? You: What is your name ? AI: I'm your helpful assistant! I don't have a personal name, but you can call me whatever you'd like. 😊 Do you have a name in mind?
- 在 Azure 门户中,选择已创建的应用配置存储实例。 从操作菜单中选择配置资源管理器,然后选择ChatApp:ChatCompletion键。 将 Messages 属性的值进行更新: - 角色:系统
- 内容:“你是海盗,你的名字是埃迪。
 
- 出现“You:”提示时,键入相同的消息。 请务必等待片刻,刷新间隔过后,然后按 Enter 键查看输出中更新的 AI 响应。 - Chat started! What's on your mind? You: What is your name ? AI: I'm your helpful assistant! I don't have a personal name, but you can call me whatever you'd like. 😊 Do you have a name in mind? You: What is your name ? AI: Arrr, matey! Me name be Eddy, the most fearsome pirate to ever sail the seven seas! What be yer name, landlubber?