Back

Building Your First C# AI Agent with Semantic Kernel

An AI agent is a software program that acts autonomously to achieve goals by perceiving its environment, making decisions, and taking actions. It can be thought of as a digital entity that can sense, reason, and act based on programmed objectives. AI agents can range from simple to complex and can be used in various applications, from customer service to software development

Semantic Kernel is a powerful open-source SDK from Microsoft that allows you to easily integrate large language models (LLMs) into your C# applications. In this post, we'll walk through building a simple, yet functional, AI agent that can perform tasks by calling native C# code.

Prerequisites

  • .NET 8 SDK or later installed.
  • An API key for a large language model, such as the Gemini API. You will need to set this as an environment variable named GOOGLE_API_KEY.
  • A code editor like Visual Studio or Visual Studio Code.

Project Setup

First, create a new console application and add the necessary NuGet packages.

dotnet new console -n SemanticKernelAgent
cd SemanticKernelAgent
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.Connectors.Google

Next, update the `Program.cs` file with the code below.

The C# Agent Code

This code demonstrates a simple AI agent that can perform two tasks: getting the current date and generating a motivational quote. Notice how we use C# attributes to define functions that the AI can understand and call.


using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using System.ComponentModel;

// IMPORTANT: This class contains the native functions (C# code) that the AI agent can call.
// This is how you give your AI agent access to real-world tools and data.
// We use the [KernelFunction] and [Description] attributes to make these methods
// discoverable and understandable by the AI.
public class AgentTools
{
    [KernelFunction, Description("Gets the current date and time.")]
    public string GetCurrentDate()
    {
        return DateTime.Now.ToLongDateString();
    }

    [KernelFunction, Description("Generates a short, positive, and inspirational quote.")]
    [return: Description("A motivational quote")]
    public async Task<string> GenerateMotivationalQuoteAsync(IKernel kernel, string userInput)
    {
        var motivationalQuotePrompt = @"
        You are an upbeat and friendly motivational speaker.
        When the user asks for a quote, generate a short, positive, and inspirational quote.
        If the user asks for anything else, just respond with 'I can only provide motivational quotes right now.'

        User input: {{user_input}}
        ";

        var motivationalQuoteFunction = kernel.CreateFunctionFromPrompt(motivationalQuotePrompt);
        
        var response = await kernel.InvokeAsync(motivationalQuoteFunction, new KernelArguments()
        {
            ["user_input"] = userInput
        });
        
        return response.GetValue<string>() ?? "I am sorry, I could not generate a quote at this time.";
    }
}

class Program
{
    static async Task Main(string[] args)
    {
        // 1. Initialize the Semantic Kernel with a Large Language Model (LLM)
        // We use the Gemini API for this example.
        // The API key is automatically provided by the Canvas environment.
        string? apiKey = Environment.GetEnvironmentVariable("GOOGLE_API_KEY");
        if (string.IsNullOrEmpty(apiKey))
        {
            Console.WriteLine("API key not found. Please set the GOOGLE_API_KEY environment variable.");
            return;
        }

        var builder = Kernel.CreateBuilder();
        builder.AddGoogleGenerativeAI(
            modelId: "gemini-1.5-flash-latest",
            apiKey: apiKey);

        var kernel = builder.Build();

        // 2. Import the native function plugin
        // The agent can now use the "GetCurrentDate" and "GenerateMotivationalQuoteAsync" methods
        // from the AgentTools class.
        kernel.ImportPluginFromObject(new AgentTools(), "AgentTools");

        Console.WriteLine("Hello! I am a simple AI agent. I can get the current date or give you a motivational quote. Ask me something!");

        // 3. Start the conversation loop.
        while (true)
        {
            Console.Write("User: ");
            var userInput = Console.ReadLine();
            
            if (string.IsNullOrWhiteSpace(userInput))
            {
                continue;
            }

            // 4. Use simple keyword-based intent routing (a basic form of a planner)
            // In a real-world scenario, you would use a 'Planner' to automatically decide
            // which plugin or prompt to use based on the user's intent.
            // This keyword approach is for demonstration purposes.
            if (userInput.ToLower().Contains("date"))
            {
                // Invoke the native function directly
                var response = await kernel.InvokeAsync("AgentTools", "GetCurrentDate");
                Console.WriteLine($"Agent: The current date is {response.GetValue<string>()}");
            }
            else if (userInput.ToLower().Contains("quote") || userInput.ToLower().Contains("motivational"))
            {
                // Invoke the semantic function (which is now part of the AgentTools plugin)
                var response = await kernel.InvokeAsync("AgentTools", "GenerateMotivationalQuoteAsync", new KernelArguments()
                {
                    ["userInput"] = userInput,
                    ["kernel"] = kernel // We need to pass the kernel instance to the function
                });
                Console.WriteLine($"Agent: {response.GetValue<string>()}");
            }
            else
            {
                Console.WriteLine("Agent: I can only provide the current date or a motivational quote right now. Please try asking for one of those.");
            }
        }
    }
}

Conclusion & Next Steps

This simple example shows how to build a basic AI agent in C# using Semantic Kernel. You've created a kernel, defined a plugin with native functions, and built a conversational loop that uses these functions to respond to user input. From here, you can expand your agent by adding more complex plugins, connecting to external APIs, or implementing a more sophisticated planner to handle multi-step tasks.

Comments - Beta - WIP

Leave a Comment