AgentStack
SKILL verified MIT Self-run

Semantic Kernel

skill-managedcode-dotnet-skills-semantic-kernel · by managedcode

Build AI-enabled .NET applications with Semantic Kernel using services, plugins, prompts, and function-calling patterns that remain testable and maintainable. USE FOR: adding AI-driven prompts, plugins, or orchestration to a .NET app; reviewing kernel construction, service registration, or plugin usage; building function-calling. DO NOT USE FOR: unrelated stacks; generic tasks that do not need th…

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add skill-managedcode-dotnet-skills-semantic-kernel

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Semantic Kernel? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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](references/patterns.md) - Plugin patterns, function calling patterns, multi-agent patterns, prompt templates, and RAG patterns
  • [anti-patterns.md](references/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
  6. For Semantic Kernel dotnet-1.77.0 and later, keep OpenAPI plugin server URL validation enabled by default unless a trusted migration path requires a temporary exception, and use the updated Microsoft Agent Framework 1.0-compatible migration samples when moving SK agent code to Agent Framework.

Kernel Setup

Basic Configuration

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

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

// Register plugins
builder.Services.AddSingleton();
builder.Services.AddSingleton();

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

Plugin Patterns

Creating a Plugin

public class WeatherPlugin
{
    [KernelFunction]
    [Description("Gets the current weather for a specified city")]
    public async Task 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 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

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

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

Chat Completion Patterns

Multi-Turn Conversation

var chatService = kernel.GetRequiredService();
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

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

Multi-Agent Plugin Isolation

// 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

[KernelFunction]
[Description("Places an order for a product")]
public async Task 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  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

[Fact]
public async Task GetWeather_ReturnsFormattedWeather()
{
    var mockWeatherService = new Mock();
    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 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

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.