Edit

Share via


Use chat completion configuration in a .NET console app

In this guide, you build an AI chat application and iterate on the prompt using chat completion configuration dynamically loaded from Azure App Configuration.

Prerequisites

Create a console app

  1. Create a new folder for your project. In the new folder, run the following command to create a new .NET console app project:

    dotnet new console
    
  2. Install the following NuGet packages in your project:

    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. Open the Program.cs file, and add the following namespaces at the top of the file:

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    using Azure.Identity;
    using Azure.AI.OpenAI;
    using OpenAI.Chat;
    
  4. Connect to your App Configuration store by calling the AddAzureAppConfiguration method in the Program.cs file.

    You can connect to App Configuration using either Microsoft Entra ID (recommended) or a connection string. In this example, you use Microsoft Entra ID with DefaultAzureCredential to authenticate to your App Configuration store. Follow these instructions to assign the App Configuration Data Reader role to the identity represented by DefaultAzureCredential. Be sure to allow sufficient time for the permission to propagate before running your application.

    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. Create an instance of the AzureOpenAIClient to connect to your Azure OpenAI resource. You can use either Microsoft Entra ID or API key for authentication.

    To access your Azure OpenAI resource with Microsoft Entra ID, you use DefaultAzureCredential. Assign the Cognitive Services OpenAI User role to the identity represented by DefaultAzureCredential. For detailed steps, refer to the Role-based access control for Azure OpenAI service guide. Be sure to allow sufficient time for the permission to propagate before running your application.

    // 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);
    

    To access your Azure OpenAI resource with an API key, add the following code:

    // Initialize the AzureOpenAIClient
    var apiKey = configuration["ChatApp:AzureOpenAI:ApiKey"];
    AzureOpenAIClient client = new(openAIEndpoint, new AzureKeyCredential(apiKey));
    

    If the key ChatApp:AzureOpenAI:ApiKey is a Key Vault reference in App Configuration, make sure to add the following code snippet to the AddAzureAppConfiguration call and grant your app access to Key Vault.

    options.ConfigureKeyVault(keyVaultOptions =>
    {
        keyVaultOptions.SetCredential(credential);
    });
    
  6. Define the ModelConfiguration class in Program.cs file:

    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. Update the Program.cs file to add a helper method GetChatMessages to process chat messages:

    // 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. Next, update the existing code in the Program.cs file to refresh the configuration from Azure App Configuration, apply the latest AI configuration values to the chat completion settings, and retrieve a response from the AI model.

    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. After completing the previous steps, your Program.cs file should now contain the complete implementation as shown below:

    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; }
    }
    

Build and run the app

  1. Set the environment variable named AZURE_APPCONFIGURATION_ENDPOINT to the endpoint of your App Configuration store found under the Overview of your store in the Azure portal.

    If you use the Windows command prompt, run the following command and restart the command prompt to allow the change to take effect:

    setx AZURE_APPCONFIGURATION_ENDPOINT "<endpoint-of-your-app-configuration-store>"
    

    If you use PowerShell, run the following command:

    $Env:AZURE_APPCONFIGURATION_ENDPOINT = "<endpoint-of-your-app-configuration-store>"
    

    If you use macOS or Linux run the following command:

    export AZURE_APPCONFIGURATION_ENDPOINT ='<endpoint-of-your-app-configuration-store>'
    
  2. After the environment variable is properly set, run the following command to build and run your app.

    dotnet run
    

    You should see the following output:

    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. In Azure portal, select the App Configuration store instance that you created. From the Operations menu, select Configuration explorer and select the ChatApp:Model key. Update the value of the Messages property:

    • Role: system
    • Content: "You are a cheerful tour guide".
  4. Wait a few moments for the refresh interval to elapse, and then press the Enter key to see the updated AI response in the output.

    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...