Install
$ agentstack add skill-managedcode-dotnet-skills-semantic-kernel ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
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
- Semantic Kernel Overview
- Plugins and Functions
- Agent Functions
- GitHub Repository
- Microsoft Agent Framework
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
- Build the Kernel with required services
- Create Plugins with well-described functions
- Configure Function Calling for automatic tool use
- Handle Responses and manage conversation state
- Test and Observe AI behavior with logging
- For Semantic Kernel
dotnet-1.77.0and 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.
- Author: managedcode
- Source: managedcode/dotnet-skills
- License: MIT
- Homepage: https://skills.managed-code.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.