Skip to content

Semantic Kernel Chat with Agents

This sample demonstrates how to use the Semantic Kernel Chat API with streaming in a C# console application.

Program.cs

How to generate this sample
Command
ai dev new sk-chat-with-agents --csharp
Output
AI - Azure AI CLI, Version 1.0.0
Copyright (c) 2024 Microsoft Corporation. All Rights Reserved.

This PUBLIC PREVIEW version may change at any time.
See: https://aka.ms/azure-ai-cli-public-preview

Generating 'sk-chat-with-agents' in 'sk-chat-with-agents-cs' (5 files)...

Program.cs
README.md
SemanticKernelChatWithAgents.csproj

Generating 'sk-chat-with-agents' in 'sk-chat-with-agents-cs' (5 files)... DONE!

Program.cs

STEP 1: Read the configuration settings from environment variables.

Program.cs
var AZURE_OPENAI_API_KEY = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY") ?? "<insert your Azure OpenAI API key here>";
var AZURE_OPENAI_ENDPOINT = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? "<insert your Azure OpenAI endpoint here>";
var AZURE_OPENAI_CHAT_DEPLOYMENT = Environment.GetEnvironmentVariable("AZURE_OPENAI_CHAT_DEPLOYMENT") ?? "<insert your Azure OpenAI chat deployment name here>";
var AZURE_OPENAI_SYSTEM_PROMPT = Environment.GetEnvironmentVariable("AZURE_OPENAI_SYSTEM_PROMPT") ?? "You are a helpful AI assistant.";

STEP 2: Check if the required environment variables are set.

Program.cs
var azureOk = 
    AZURE_OPENAI_API_KEY != null && !AZURE_OPENAI_API_KEY.StartsWith("<insert") &&
    AZURE_OPENAI_CHAT_DEPLOYMENT != null && !AZURE_OPENAI_CHAT_DEPLOYMENT.StartsWith("<insert") &&
    AZURE_OPENAI_ENDPOINT != null && !AZURE_OPENAI_ENDPOINT.StartsWith("<insert");

var ok = azureOk &&
    AZURE_OPENAI_SYSTEM_PROMPT != null && !AZURE_OPENAI_SYSTEM_PROMPT.StartsWith("<insert");

if (!ok)
{
    Console.WriteLine(
        "To use Azure OpenAI, set the following environment variables:\n" +
        "\n  AZURE_OPENAI_SYSTEM_PROMPT" +
        "\n  AZURE_OPENAI_API_KEY" +
        "\n  AZURE_OPENAI_CHAT_DEPLOYMENT" +
        "\n  AZURE_OPENAI_ENDPOINT"
    );
    Console.WriteLine(
        "\nYou can easily do that using the Azure AI CLI by doing one of the following:\n" +
        "\n  ai init" +
        "\n  ai dev shell" +
        "\n  dotnet run" +
        "\n" +
        "\n  or" +
        "\n" +
        "\n  ai init" +
        "\n  ai dev shell --run \"dotnet run\""
    );

    return 1;
}

STEP 3: Initialize the kernel with the configuration settings.

Program.cs
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(AZURE_OPENAI_CHAT_DEPLOYMENT!, AZURE_OPENAI_ENDPOINT!, AZURE_OPENAI_API_KEY!);
var newKernel = new Func<Kernel>(() => builder.Build());

STEP 4: Create the writer and reviewer agents.

Program.cs
ChatCompletionAgent writer = new()
{
    Instructions = WriterInstructions,
    Name = WriterName,
    Kernel = newKernel(),
};

ChatCompletionAgent reviewer = new()
{
    Instructions = ReviewerInstructions,
    Name = ReviewerName,
    Kernel = newKernel(),
};

STEP 5: Define selection and termination strategies for the chat.

Program.cs
KernelFunction pickNextAgentFunction = KernelFunctionFactory.CreateFromPrompt(PickNextAgentPromptTemplate);
KernelFunctionSelectionStrategy selectionStrategy = new KernelFunctionSelectionStrategy(pickNextAgentFunction, newKernel())
{
    ResultParser = (result) => result.GetValue<string>() ?? WriterName,
    HistoryVariableName = "history",
    AgentsVariableName = "agents",
};

KernelFunction isChatDoneFunction = KernelFunctionFactory.CreateFromPrompt(IsChatDonePromptTemplate);
KernelFunctionTerminationStrategy terminationStrategy = new KernelFunctionTerminationStrategy(isChatDoneFunction, newKernel())
{
    Agents = [reviewer],
    ResultParser = (result) => result.GetValue<string>()?.Contains("yes", StringComparison.OrdinalIgnoreCase) ?? false,
    HistoryVariableName = "history",
    MaximumIterations = 10,
};

STEP 6: Get user input in a loop and call the chat message processing function.

Program.cs
while (true)
{
    Console.Write("User: ");
    var userPrompt = Console.ReadLine();
    if (string.IsNullOrEmpty(userPrompt) || userPrompt == "exit") break;

    Console.Write("\nAssistant: ");
    await GetChatMessageContentsAsync(userPrompt, newKernel);
    Console.WriteLine("\n");
}

STEP 7: Create a group chat with the writer and reviewer agents, and the custom termination and selection strategies.

Program.cs
var agents = new[] { writer, reviewer };
AgentGroupChat chat = new(agents)
{
    ExecutionSettings = new()
    {
        SelectionStrategy = selectionStrategy,
        TerminationStrategy = terminationStrategy
    }
};

STEP 8: Start the chat by adding the initial user input.

Program.cs
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, input));

STEP 9: Process the chat messages and output the responses as they arrive.

Program.cs
await foreach (var content in chat.InvokeAsync())
{
    var hasAuthor = !string.IsNullOrEmpty(content.AuthorName);
    var output = hasAuthor
        ? $"{content.Role}-{content.AuthorName}: {content.Content}\n"
        : $"{content.Role}: {content.Content}\n";

    Console.ForegroundColor = ConsoleColor.DarkGray;
    Console.WriteLine($"\r{output}");
    responseContent.AppendLine(output);

    Console.ForegroundColor = ConsoleColor.White;
    Console.Write("Assistant: ");
}