你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 .NET 控制台应用中使用聊天补全配置

在本指南中,你将生成一个 AI 聊天应用程序,并使用从 Azure 应用程序配置动态加载的聊天补全配置来循环访问提示。

先决条件

创建控制台应用

  1. 为项目新建一个文件夹。 在新文件夹中,运行以下命令以创建新的 .NET 控制台应用项目:

    dotnet new console
    
  2. 在项目中安装以下 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
    
  3. 打开 Program.cs 文件,并在文件顶部添加以下命名空间:

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    using Azure.Identity;
    using Azure.AI.OpenAI;
    using OpenAI.Chat;
    
  4. 通过调用 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();
    
  5. 创建连接到 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);
    });
    
  6. ModelConfiguration 文件中定义类。

    internal class ModelConfiguration
    {
        [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; }
    }
    
  7. 更新 Program.cs 文件以添加帮助程序方法来 GetChatMessages 处理聊天消息:

    // Helper method to convert configuration messages to chat API format
    static IEnumerable<ChatMessage> GetChatMessages(ModelConfiguration modelConfiguration)
    {
        return modelConfiguration.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))
        });
    }
    
  8. 接下来,更新 Program.cs 文件中的现有代码以从 Azure 应用配置刷新配置,将最新的 AI 配置值应用于聊天完成设置,并从 AI 模型检索响应。

    while (true)
    {
        // Refresh the configuration from Azure App Configuration
        await refresher.RefreshAsync();
    
        // Configure chat completion with AI configuration
        var modelConfiguration = configuration.GetSection("ChatApp:Model").Get<ModelConfiguration>();
        var requestOptions = new ChatCompletionOptions()
        {
            MaxOutputTokenCount = modelConfiguration.MaxTokens,
            Temperature = modelConfiguration.Temperature,
            TopP = modelConfiguration.TopP
        };
    
        foreach (var message in modelConfiguration.Messages)
        {
            Console.WriteLine($"{message.Role}: {message.Content}");
        }
    
        // Get chat response from AI
        var response = await chatClient.CompleteChatAsync(GetChatMessages(modelConfiguration), requestOptions);
        Console.WriteLine($"AI response: {response.Value.Content[0].Text}");
    
        Console.WriteLine("Press Enter to continue...");
        Console.ReadLine();
    }
    
  9. 完成前面的步骤后, 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);
    
    while (true)
    {
        // Refresh the configuration from Azure App Configuration
        await refresher.RefreshAsync();
    
        // Configure chat completion with AI configuration
        var modelConfiguration = configuration.GetSection("ChatApp:Model").Get<ModelConfiguration>();
        var requestOptions = new ChatCompletionOptions()
        {
            MaxOutputTokenCount = modelConfiguration.MaxTokens,
            Temperature = modelConfiguration.Temperature,
            TopP = modelConfiguration.TopP
        };
    
        foreach (var message in modelConfiguration.Messages)
        {
            Console.WriteLine($"{message.Role}: {message.Content}");
        }
    
        // Get chat response from AI
        var response = await chatClient.CompleteChatAsync(GetChatMessages(modelConfiguration), requestOptions);
        Console.WriteLine($"AI response: {response.Value.Content[0].Text}");
    
        Console.WriteLine("Press Enter to continue...");
        Console.ReadLine();
    
    }
    
    static IEnumerable<ChatMessage> GetChatMessages(ModelConfiguration modelConfiguration)
    {
        return modelConfiguration.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 ModelConfiguration
    {
        [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; }
    }
    

生成并运行应用

  1. 将名为 “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>'
    
  2. 正确设置环境变量后,运行以下命令以生成并运行应用。

    dotnet run
    

    应会看到以下输出:

    system: You are a helpful assistant.
    user: What is the capital of France ?
    AI response: The capital of France is **Paris**.
    Press Enter to continue...
    
    
  3. 在 Azure 门户中,选择已创建的应用配置存储实例。 从“操作”菜单中选择“配置资源管理器”,然后选择ChatApp:Model键。 将 Messages 属性的值进行更新:

    • 角色:系统
    • 内容:“你是一个欢快的导游”。
  4. 等待片刻,刷新间隔过后,然后按 Enter 键查看输出中更新的 AI 响应。

    system: You are a cheerful tour guide
    user: What is the capital of France ?
    AI response: Oh là là! The capital of France is the magnificent **Paris**!
    Known as the "City of Light" (*La Ville Lumière*), it's famous for its romantic ambiance,
    iconic landmarks like the Eiffel Tower, the Louvre Museum, and Notre-Dame Cathedral,
    as well as its delicious pastries and charming cafés.
    Have you ever been, or is it on your travel bucket list? 😊✨
    Press Enter to continue...