Creating a Conversational App with Amazon Bedrock and .NET

Introduction

In this article, you'll learn how to create a .NET console application that uses the Amazon Bedrock Converse API to interact with the Anthropic Claude 3 Sonnet model. The application will start a conversation by asking the model to create a list of songs and then continue the conversation by asking that the songs be by artists from India.

Prerequisites

  1. Create an AWS account and log in. Ensure the IAM user you use has sufficient permissions to make necessary AWS service calls and manage AWS resources.
  2. Download and install the AWS Command Line Interface (CLI).
  3. Configure the AWS CLI.
  4. Download and install Visual Studio or Visual Studio Code.
  5. Download and install .NET 8.0 SDK
  6. Access to Amazon Bedrock foundation model

Tools

  1. Visual Studio 2022

Steps Involved

Perform the following steps to create a .NET console application in Visual Studio 2022 to send input text, inference parameters, and additional model-specific parameters.

  1. Open Visual Studio 2022.
  2. Click File -> New -> Project.
  3. Select the Console App template. Click Next.
  4. Enter the project name and click Next.
  5. Select the .NET 8.0 framework. Click Create.
  6. Add the following NuGet packages.
    AWSSDK.BedrockRuntime
  7. Open Program.cs and replace the code with the following.
    using Amazon;
    using Amazon.BedrockRuntime;
    using Amazon.BedrockRuntime.Model;
    using Amazon.Runtime.Documents;
    namespace AmazonBedrockConverseApp
    {
        internal class Program
        {
            // Constants for the model ID and input messages
            private const string ModelId = "anthropic.claude-3-sonnet-20240229-v1:0";
    
            // System prompts
            private static readonly List<string> SystemPrompts = new()
            {
                "You are an app that creates playlists for a radio station that plays rock and pop music. Only return song names and the artist."
            };
    
            // Initial messages
            private static readonly Message Message1 = new()
            {
                Role = "user",
                Content = new List<ContentBlock>
                {
                    new() { Text = "Create a list of 3 pop songs." }
                }
            };
    
            private static readonly Message Message2 = new()
            {
                Role = "user",
                Content = new List<ContentBlock>
                {
                    new() { Text = "Make sure the songs are by artists from India." }
                }
            };
    
            static async Task Main(string[] args)
            {
                // Configure the Amazon Bedrock Runtime client
                var config = new AmazonBedrockRuntimeConfig
                {
                    RegionEndpoint = RegionEndpoint.USEast1 // Use your region
                };
    
                using var bedrockClient = new AmazonBedrockRuntimeClient(config);
    
                try
                {
                    // Start the conversation with the first message
                    var messages = new List<Message> { Message1 };
                    var response = await GenerateConversationAsync(bedrockClient, ModelId, SystemPrompts, messages);
    
                    // Add the response message if it is not null
                    if (response.Output?.Message != null)
                    {
                        messages.Add(response.Output.Message);
                    }
    
                    // Continue the conversation with the second message
                    messages.Add(Message2);
                    response = await GenerateConversationAsync(bedrockClient, ModelId, SystemPrompts, messages);
    
                    // Add the response message if it is not null
                    if (response.Output?.Message != null)
                    {
                        messages.Add(response.Output.Message);
                    }
    
                    // Print the entire conversation
                    PrintConversation(messages);
                }
                catch (AmazonBedrockRuntimeException ex)
                {
                    // Log the Amazon Bedrock Runtime exception message
                    Console.WriteLine($"Error: {ex.Message}");
                    // TODO: Add more descriptive error handling and logging
                }
                catch (Exception ex)
                {
                    // Log any unexpected exception message
                    Console.WriteLine($"Unexpected error occurred: {ex.Message}");
                    // TODO: Add error logging
                }
            }
    
            /// <summary>
            /// Generates a conversation by sending messages to the Amazon Bedrock model.
            /// </summary>
            /// <param name="bedrockClient">The Bedrock Runtime client.</param>
            /// <param name="modelId">The model ID to use.</param>
            /// <param name="systemPrompts">The system prompts to send to the model.</param>
            /// <param name="messages">The messages to send to the model.</param>
            /// <returns>The response from the Bedrock Runtime.</returns>
            private static async Task<ConverseResponse> GenerateConversationAsync(IAmazonBedrockRuntime bedrockClient, string modelId, List<string> systemPrompts, List<Message> messages)
            {
                // Set inference configuration
                var inferenceConfig = new InferenceConfiguration
                {
                    Temperature = 0.5f
                };
    
                // Additional model fields as a document
                var additionalModelFields = new Document(new Dictionary<string, Document>
                {
                    { "top_k", new Document(200) }
                });
    
                // Prepare system content blocks
                var systemContentBlocks = systemPrompts.Select(prompt => new SystemContentBlock { Text = prompt }).ToList();
    
                // Prepare additional model response field paths
                var additionalModelResponseFieldPaths = new List<string> { "/top_k" };
    
                // Create the request
                var request = new ConverseRequest
                {
                    ModelId = modelId,
                    Messages = messages,
                    System = systemContentBlocks,
                    InferenceConfig = inferenceConfig,
                    AdditionalModelResponseFieldPaths = additionalModelResponseFieldPaths,
                    AdditionalModelRequestFields = additionalModelFields
                };
    
                // Send the request and return the response
                return await bedrockClient.ConverseAsync(request);
            }
    
            /// <summary>
            /// Prints the conversation to the console.
            /// </summary>
            /// <param name="messages">The list of messages in the conversation.</param>
            private static void PrintConversation(IEnumerable<Message> messages)
            {
                foreach (var message in messages)
                {
                    Console.WriteLine($"Role: {message.Role}");
                    foreach (var content in message.Content)
                    {
                        Console.WriteLine($"Text: {content.Text}");
                    }
                    Console.WriteLine();
                }
            }
        }
    }
  8. Press F5 to run the application. You should see the conversation output, including the list of pop songs and the subsequent message ensuring the songs are by artists from India.
    Subsequent message

Summary

This article describes how to create a .NET console application that uses the Amazon Bedrock Converse API to interact with the Anthropic Claude 3 Sonnet model.


Similar Articles