Skip to main content

AI Agents in C# with Semantic Kernel: Full Tutorial

Learn how to build AI agents in C# using Semantic Kernel. Step-by-step tutorial with runnable code, best practices, and pitfalls. Start building today!

Building AI agents in C# used to mean wiring up raw HTTP calls to a large language model and parsing JSON by hand. Today, Microsoft's Semantic Kernel gives .NET developers a production-ready framework for creating autonomous task-solving agents that can reason, call your code, and chain multiple steps together to complete real work. In this tutorial you'll learn how to build AI agents in C# from scratch using the Semantic Kernel Agent Framework, with runnable code examples, best practices, and the common pitfalls to avoid.

Whether you're a beginner searching for "how to build an AI agent in C#," an intermediate developer looking for Semantic Kernel best practices, or a senior engineer designing advanced agent architectures in .NET, this guide covers the full picture — and explains why each piece matters, not just how to type it.

What Are AI Agents in C#?

An AI agent is more than a chatbot. A chatbot answers a question; an agent achieves a goal. Given an objective like "find the cheapest flight and book it," an agent uses a language model as its reasoning engine, decides which tools (functions) to call, observes the results, and loops until the task is done. This pattern is often called the reason–act loop (ReAct).

The three core capabilities that make AI agents in C# useful are:

  • Reasoning — the LLM plans which step to take next.
  • Tool use (function calling) — the agent invokes your C# methods to fetch data or perform actions.
  • Memory — the agent keeps conversation state so multi-step tasks stay coherent.

Semantic Kernel is Microsoft's open-source SDK that packages all three. It is model-agnostic (Azure OpenAI, OpenAI, and others), integrates cleanly with .NET dependency injection, and is the recommended path for adding agentic AI to enterprise C# applications.

Setting Up Semantic Kernel in a .NET Project

Start with a console app on .NET 8 or later and add the Semantic Kernel NuGet packages. The Agent Framework lives in its own package.

// Terminal commands
// dotnet new console -n AgentDemo
// cd AgentDemo
// dotnet add package Microsoft.SemanticKernel
// dotnet add package Microsoft.SemanticKernel.Agents.Core

Next, create a Kernel — the central object that holds your AI service connections and plugins. Never hard-code API keys; read them from environment variables or user secrets.

using Microsoft.SemanticKernel;

var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
    ?? throw new InvalidOperationException("Set OPENAI_API_KEY first.");

var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(
    modelId: "gpt-4o-mini",
    apiKey: apiKey);

Kernel kernel = builder.Build();

That's the foundation. The Kernel is intentionally lightweight — think of it as a service container for AI. Everything else (plugins, agents, planners) plugs into it.

How to Build Your First AI Agent in C#

The key insight behind autonomous agents is function calling: you expose ordinary C# methods to the model, and the model decides when to call them. In Semantic Kernel these methods are grouped into plugins and marked with the [KernelFunction] attribute. The [Description] attributes are not decoration — the model reads them to decide which function fits the user's intent, so write them carefully.

using System.ComponentModel;
using Microsoft.SemanticKernel;

public class WeatherPlugin
{
    [KernelFunction]
    [Description("Gets the current weather for a given city.")]
    public string GetWeather(
        [Description("The city name, e.g. London")] string city)
    {
        // In production, call a real weather API here.
        return city.ToLower() switch
        {
            "london"   => "15°C, light rain",
            "sydney"   => "26°C, sunny",
            "toronto"  => "8°C, cloudy",
            _          => "20°C, clear skies"
        };
    }
}

Now register the plugin and create an agent. A ChatCompletionAgent wraps the kernel with instructions (its "system prompt") and a name. The critical setting is FunctionChoiceBehavior.Auto(), which tells the model it is allowed to call your functions automatically — this is what turns a passive model into an active agent.

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;

kernel.Plugins.AddFromType<WeatherPlugin>();

var settings = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};

ChatCompletionAgent agent = new()
{
    Name = "TravelAssistant",
    Instructions = "You are a helpful travel assistant. " +
                   "Use the available tools to answer questions about weather. " +
                   "Be concise and friendly.",
    Kernel = kernel,
    Arguments = new KernelArguments(settings)
};

Finally, run the agent. The agent maintains a chat history (its short-term memory), so each turn builds on the last.

ChatHistoryAgentThread thread = new();

await foreach (var response in agent.InvokeAsync(
    "I'm flying to Sydney tomorrow. What should I pack?",
    thread))
{
    Console.WriteLine(response.Message.Content);
}

Behind the scenes the agent reasons ("I need the weather for Sydney"), calls GetWeather("Sydney"), reads the result ("26°C, sunny"), and composes a packing recommendation. You wrote the tool; the model orchestrated it. That is an autonomous AI agent in C#.

Building Multi-Step Autonomous Task-Solving Agents

Single-tool demos are easy. Real value comes when an agent chains several tools to solve a multi-step task. Suppose you want an agent that researches a topic and saves a summary. Give it two functions and let it sequence them itself.

using System.ComponentModel;
using Microsoft.SemanticKernel;

public class ResearchPlugin
{
    [KernelFunction, Description("Searches the knowledge base for a topic.")]
    public string Search([Description("The search query")] string query)
    {
        // Replace with a real search/RAG call.
        return $"Top results for '{query}': .NET 9 improves Native AOT and agent tooling.";
    }

    [KernelFunction, Description("Saves a text note to disk and returns the file path.")]
    public string SaveNote(
        [Description("The note content")] string content,
        [Description("A short file name without extension")] string name)
    {
        var path = Path.Combine(Path.GetTempPath(), $"{name}.txt");
        File.WriteAllText(path, content);
        return $"Saved to {path}";
    }
}

With both functions registered and FunctionChoiceBehavior.Auto() enabled, a single instruction triggers a full reason–act loop:

kernel.Plugins.AddFromType<ResearchPlugin>();

await foreach (var response in agent.InvokeAsync(
    "Research what's new in .NET 9 and save a one-paragraph summary as 'dotnet9'.",
    thread))
{
    Console.WriteLine(response.Message.Content);
}

The agent will call Search("what's new in .NET 9"), summarize the result, then call SaveNote(...) with the summary and the name dotnet9 — all without you writing the control flow. The model is the control flow. This is the defining trait of autonomous agents and the reason Semantic Kernel is gaining traction for building LLM agents in .NET.

Why Function Descriptions Make or Break Your Agent

The single most common reason an agent "doesn't work" is vague metadata. The model never sees your method bodies — only the function name, parameter names, and [Description] text. If two functions sound similar, or a description is missing, the model guesses and calls the wrong one. Treat descriptions as part of your API contract: specific, action-oriented, and unambiguous.

Best Practices for AI Agents in C#

Once you move past a prototype, these Semantic Kernel best practices keep your agents reliable, secure, and affordable.

  • Scope tool permissions tightly. An agent that can call DeleteFile will eventually call it. Only expose functions the agent genuinely needs, and validate every argument inside the function as if it came from an untrusted user — because effectively it did.
  • Use the cheapest model that works. Start with a small, fast model like gpt-4o-mini for tool routing and reserve larger models for complex reasoning. Function calling rarely needs your most expensive model.
  • Set a max iteration limit. Autonomous loops can run away, calling tools repeatedly. Cap retries and total turns so a confused agent can't burn your token budget.
  • Make functions idempotent where possible. If the agent retries a step, a well-designed function shouldn't double-charge a card or send two emails.
  • Add observability. Log every function call, its arguments, and its result. When an agent misbehaves, the call trace tells you whether the problem is the prompt, the model, or your tool.
  • Use dependency injection. Register the Kernel and plugins through Microsoft.Extensions.DependencyInjection so your agent code is testable and your services (HTTP clients, databases) are properly managed.
  • Stream responses with InvokeStreamingAsync for a responsive UX in web and desktop apps instead of making users wait for the full answer.

Common Pitfalls When Building Autonomous Agents

Even experienced .NET developers hit these traps when building AI agents in C# for the first time:

  • Forgetting FunctionChoiceBehavior.Auto(). Without it, the model can describe what it would do but never actually calls your functions. This is the number-one "my agent won't use my tools" bug.
  • Blocking on synchronous I/O. Tool functions should be async when they hit the network or disk; blocking calls inside an agent loop kill throughput.
  • Ignoring token costs. Every tool result is fed back into the model. Returning a 50,000-character JSON blob from a function inflates cost and can blow the context window — return only what the agent needs.
  • Trusting model output blindly. Agents hallucinate. If a function performs a consequential action (payment, deletion, email), add a human-in-the-loop confirmation step rather than letting the agent act unsupervised.
  • Leaking secrets into prompts. Never put API keys or connection strings in instructions or chat history — they become part of the data sent to the model provider.

Advanced: Multi-Agent Systems in C#

For senior engineers searching for advanced agent patterns in C#, Semantic Kernel supports multi-agent orchestration, where specialized agents collaborate. A common design uses a "writer" agent and a "reviewer" agent that pass work back and forth until quality criteria are met. Each agent has its own instructions and tools, and an orchestration strategy decides whose turn it is.

var writer = new ChatCompletionAgent
{
    Name = "Writer",
    Instructions = "Draft concise, accurate technical content.",
    Kernel = kernel
};

var reviewer = new ChatCompletionAgent
{
    Name = "Reviewer",
    Instructions = "Critique the draft for accuracy. Reply 'APPROVED' when it meets the bar.",
    Kernel = kernel
};

// Orchestrate writer ↔ reviewer until the reviewer approves,
// using a group chat or your own loop with a termination condition.

This separation of concerns mirrors good software architecture: small, focused agents are easier to test, debug, and reason about than one monolithic mega-agent trying to do everything. As your system grows, prefer composition of specialized agents over ever-longer instruction prompts.

Conclusion: Start Building AI Agents in C# Today

You now have a complete picture of how to build AI agents in C# with Semantic Kernel — from a single-tool assistant to multi-step autonomous task-solving agents and multi-agent systems. The framework turns a language model into an active participant in your .NET application: it reasons about a goal, calls your C# functions, and chains steps until the work is done.

Key takeaways:

  • AI agents in C# combine LLM reasoning, function calling, and memory — Semantic Kernel packages all three for .NET.
  • Expose C# methods as plugins with precise [Description] metadata; the model uses that text to choose tools.
  • FunctionChoiceBehavior.Auto() is what makes an agent autonomous — don't forget it.
  • Apply best practices: scope tools tightly, cap iterations, log every call, and keep a human in the loop for risky actions.
  • Scale up with multi-agent orchestration rather than one oversized prompt.

The best way to learn is to run the code. Spin up a console project, drop in a plugin, and watch your first autonomous agent call your own functions. Once you see the reason–act loop work end to end, you'll have the foundation to build production-grade agentic AI in C# and .NET.

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Send an Email via SMTP with MailKit Using .NET 6

How to Send an Email in .NET Core This tutorial show you how to send an email in .NET 6.0 using the MailKit email client library. Install MailKit via NuGet Visual Studio Package Manager Console: Install-Package MailKit How to Send an HTML Email in .NET 6.0 This code sends a simple HTML email using the Gmail SMTP service. There are instructions further below on how to use a few other popular SMTP providers - Gmail, Hotmail, Office 365. // create email message var email = new MimeMessage(); email.From.Add(MailboxAddress.Parse("from_address@example.com")); email.To.Add(MailboxAddress.Parse("to_address@example.com")); email.Subject = "Email Subject"; email.Body = new TextPart(TextFormat.Html) { Text = "<h1>Test HTML Message Body</h1>" }; // send email using var smtp = new SmtpClient(); smtp.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls); smtp.Authenticate("[Username]", "[Password]"); smtp.Se...