Agent skill

dotnet-semantic-kernel

Build AI-enabled .NET applications with Semantic Kernel using services, plugins, prompts, and function-calling patterns that remain testable and maintainable.

Stars 302
Forks 22

Install this agent skill to your Project

npx add-skill https://github.com/managedcode/dotnet-skills/tree/main/catalog/Frameworks/Semantic-Kernel/skills/dotnet-semantic-kernel

SKILL.md

Semantic Kernel for .NET

Trigger On

  • adding AI-driven prompts, plugins, or orchestration to a .NET app
  • reviewing kernel construction, service registration, or plugin usage
  • building function-calling patterns with LLMs
  • migrating older Semantic Kernel code to current APIs

Documentation

References

  • patterns.md - Plugin patterns, function calling patterns, multi-agent patterns, prompt templates, and RAG patterns
  • anti-patterns.md - Common Semantic Kernel mistakes and how to avoid them

Core Concepts

Concept Description
Kernel Central orchestrator for AI services and plugins
Plugin Collection of functions exposed to the LLM
Function Native C# method or prompt template
Chat Completion LLM service for generating responses
Memory Vector storage for semantic search

Workflow

  1. Build the Kernel with required services
  2. Create Plugins with well-described functions
  3. Configure Function Calling for automatic tool use
  4. Handle Responses and manage conversation state
  5. Test and Observe AI behavior with logging

Kernel Setup

Basic Configuration

csharp
var builder = Kernel.CreateBuilder();

builder.AddAzureOpenAIChatCompletion(
    deploymentName: "gpt-4",
    endpoint: config["AzureOpenAI:Endpoint"]!,
    apiKey: config["AzureOpenAI:ApiKey"]!);

// Or OpenAI
builder.AddOpenAIChatCompletion(
    modelId: "gpt-4",
    apiKey: config["OpenAI:ApiKey"]!);

var kernel = builder.Build();

With Dependency Injection

csharp
builder.Services.AddKernel()
    .AddAzureOpenAIChatCompletion(
        deploymentName: "gpt-4",
        endpoint: config["AzureOpenAI:Endpoint"]!,
        apiKey: config["AzureOpenAI:ApiKey"]!);

// Register plugins
builder.Services.AddSingleton<WeatherPlugin>();
builder.Services.AddSingleton<OrderPlugin>();

// In your service
public class AiService(Kernel kernel)
{
    public async Task<string> ChatAsync(string message)
    {
        var response = await kernel.InvokePromptAsync(message);
        return response.ToString();
    }
}

Plugin Patterns

Creating a Plugin

csharp
public class WeatherPlugin
{
    [KernelFunction]
    [Description("Gets the current weather for a specified city")]
    public async Task<string> GetWeather(
        [Description("The city name, e.g., 'Seattle'")] string city,
        [Description("Temperature unit: 'celsius' or 'fahrenheit'")] string unit = "celsius")
    {
        // Call actual weather API
        var weather = await _weatherService.GetCurrentAsync(city);
        return $"Weather in {city}: {weather.Temperature}° {unit}, {weather.Condition}";
    }

    [KernelFunction]
    [Description("Gets the weather forecast for the next N days")]
    public async Task<string> GetForecast(
        [Description("The city name")] string city,
        [Description("Number of days (1-7)")] int days = 3)
    {
        var forecast = await _weatherService.GetForecastAsync(city, days);
        return FormatForecast(forecast);
    }
}

Plugin Best Practices

Practice Why It Matters
Clear [Description] LLM uses this to decide when to call
Specific parameter names Helps LLM map user intent
Idempotent functions Safe to retry on failures
Return meaningful strings LLM needs to understand results
Validate inputs LLM may hallucinate parameters

Function Calling

Automatic Function Calling

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

kernel.Plugins.AddFromObject(new WeatherPlugin(), "Weather");
kernel.Plugins.AddFromObject(new OrderPlugin(), "Orders");

var result = await kernel.InvokePromptAsync(
    "What's the weather in Seattle and do I have any pending orders?",
    new KernelArguments(settings));

Manual Function Selection

csharp
var settings = new OpenAIPromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Required(
        [kernel.Plugins["Weather"]["GetWeather"]])
};

Chat Completion Patterns

Multi-Turn Conversation

csharp
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();

history.AddSystemMessage("You are a helpful assistant.");
history.AddUserMessage(userMessage);

var response = await chatService.GetChatMessageContentAsync(
    history,
    executionSettings: new OpenAIPromptExecutionSettings
    {
        FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
    },
    kernel: kernel);

history.AddAssistantMessage(response.Content!);

Streaming Response

csharp
await foreach (var chunk in chatService.GetStreamingChatMessageContentsAsync(
    history, executionSettings, kernel))
{
    Console.Write(chunk.Content);
}

Multi-Agent Plugin Isolation

csharp
// WRONG - agents share plugins
var sharedKernel = Kernel.CreateBuilder().Build();
sharedKernel.Plugins.AddFromObject(new AllPlugins());

var agent1 = new ChatCompletionAgent { Kernel = sharedKernel };
var agent2 = new ChatCompletionAgent { Kernel = sharedKernel };
// Both agents have same plugins!

// CORRECT - isolated kernels
var kernel1 = CreateKernelForAgent1();
kernel1.Plugins.AddFromObject(new WeatherPlugin());

var kernel2 = CreateKernelForAgent2();
kernel2.Plugins.AddFromObject(new OrderPlugin());

var agent1 = new ChatCompletionAgent { Kernel = kernel1 };
var agent2 = new ChatCompletionAgent { Kernel = kernel2 };

Anti-Patterns to Avoid

Anti-Pattern Why It's Bad Better Approach
Vague [Description] LLM won't call at right time Be specific and actionable
Sharing kernel across agents Plugin leakage Clone or create new kernels
No input validation Hallucinated parameters Validate and return errors
Using deprecated Planners Removed in favor of function calling Use FunctionChoiceBehavior
Ignoring logging Can't debug AI decisions Enable Semantic Kernel logging

Error Handling

csharp
[KernelFunction]
[Description("Places an order for a product")]
public async Task<string> PlaceOrder(
    [Description("Product ID")] string productId,
    [Description("Quantity (1-100)")] int quantity)
{
    // Validate inputs
    if (string.IsNullOrEmpty(productId))
        return "Error: Product ID is required";

    if (quantity < 1 || quantity > 100)
        return "Error: Quantity must be between 1 and 100";

    try
    {
        var order = await _orderService.CreateAsync(productId, quantity);
        return $"Order {order.Id} placed successfully for {quantity} units";
    }
    catch (ProductNotFoundException)
    {
        return $"Error: Product '{productId}' not found";
    }
}

Testing Plugins

csharp
[Fact]
public async Task GetWeather_ReturnsFormattedWeather()
{
    var mockWeatherService = new Mock<IWeatherService>();
    mockWeatherService.Setup(w => w.GetCurrentAsync("Seattle"))
        .ReturnsAsync(new Weather { Temperature = 20, Condition = "Sunny" });

    var plugin = new WeatherPlugin(mockWeatherService.Object);

    var result = await plugin.GetWeather("Seattle", "celsius");

    Assert.Contains("20°", result);
    Assert.Contains("Sunny", result);
}

Microsoft Agent Framework

For complex multi-agent scenarios, consider dotnet-microsoft-agent-framework:

  • Multi-agent orchestration
  • Agent-to-agent communication
  • Enterprise patterns

Deliver

  • kernel setup with clear service and plugin composition
  • AI features that fit naturally into the existing .NET app
  • observable and testable function-calling behavior
  • proper plugin isolation for multi-agent scenarios

Validate

  • plugins have clear, specific descriptions
  • function calling works as expected
  • AI flows are logged and debuggable
  • input validation prevents hallucination issues
  • kernel instances are properly scoped
  • deprecated APIs are not used

Expand your agent's capabilities with these related and highly-rated skills.

managedcode/dotnet-skills

dotnet-project-setup

Create or reorganize .NET solutions with clean project boundaries, repeatable SDK settings, and a maintainable baseline for libraries, apps, tests, CI, and local development.

302 22
Explore
managedcode/dotnet-skills

csharp-scripts

Run single-file C# programs as scripts (file-based apps) for quick experimentation, prototyping, and concept testing. Use when the user wants to write and execute a small C# program without creating a full project.

302 22
Explore
managedcode/dotnet-skills

dotnet-pinvoke

Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging existing native interop code, wrapping a C or C++ library for use in .NET, diagnosing crashes, memory leaks, or corruption at the managed/native boundary. DO NOT USE FOR: COM interop, C++/CLI mixed-mode assemblies, or pure managed code with no native dependencies.

302 22
Explore
managedcode/dotnet-skills

nuget-trusted-publishing

Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet OIDC, keyless NuGet publish, migrate from NuGet API key, NuGet/login, secure NuGet publishing. DO NOT USE FOR: publishing to private feeds or Azure Artifacts (OIDC is nuget.org only). INVOKES: shell (powershell or bash), edit, create, ask_user for guided repo setup.

302 22
Explore
managedcode/dotnet-skills

dotnet-legacy-aspnet

Maintain classic ASP.NET applications on .NET Framework, including Web Forms, older MVC, and legacy hosting patterns, while planning realistic modernization boundaries.

302 22
Explore
managedcode/dotnet-skills

dotnet-code-review

Review .NET changes for bugs, regressions, architectural drift, missing tests, incorrect async or disposal behavior, and platform-specific pitfalls before you approve or merge them.

302 22
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results