Building a useful AI application requires more than a single chat.completions.create() call. Real applications need memory so the AI remembers context across sessions, tools so it can take actions in the world, and planning capabilities so it can break down complex goals into steps. Microsoft Semantic Kernel is an open-source SDK that provides all of this in a production-ready framework for C# and Python, with first-class support for Azure OpenAI, OpenAI, and local models via Ollama.
This guide covers the core concepts — plugins, memory, and planners — with working code examples in both languages, and shows how to connect Semantic Kernel to a local Ollama server for fully offline development.
Core Concepts
Plugins (formerly Skills)
A plugin in Semantic Kernel is a class that exposes one or more functions the AI can call. Functions can be native code (regular Python or C# methods) or semantic functions (LLM prompts with input variables). The kernel discovers these functions and makes them available to the AI as tools.
Memory
Semantic Kernel’s memory system provides vector-based semantic search over stored information. You can store facts, documents, or conversation history and retrieve the most relevant pieces for a given query. This is the foundation of RAG-style applications built within the framework.
Planners
A planner takes a high-level goal and uses the AI to create a step-by-step plan that executes the goal using available plugins. Rather than hardcoding a pipeline, you describe the objective and let the AI figure out which functions to call in what order.
Installation
Python
pip install semantic-kernel
C#
<!-- In your .csproj file -->
<PackageReference Include="Microsoft.SemanticKernel" Version="1.21.1" />
Or via the Package Manager Console:
Install-Package Microsoft.SemanticKernel
Connecting to Ollama (Local Models)
Ollama provides an OpenAI-compatible API, and Semantic Kernel supports OpenAI-compatible endpoints. This means you can develop entirely offline without an API key.
Start your Ollama server and pull a model:
ollama pull llama3:8b
ollama pull nomic-embed-text
Python — Connect to Ollama
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.ollama import OllamaChatCompletion, OllamaTextEmbedding
kernel = Kernel()
# Add chat completion service
kernel.add_service(
OllamaChatCompletion(
service_id="ollama-chat",
ai_model_id="llama3:8b",
host="http://localhost:11434",
)
)
# Add embedding service for memory
kernel.add_service(
OllamaTextEmbedding(
service_id="ollama-embed",
ai_model_id="nomic-embed-text",
host="http://localhost:11434",
)
)
C# — Connect to Ollama
using Microsoft.SemanticKernel;
var builder = Kernel.CreateBuilder();
// Ollama via OpenAI-compatible endpoint
builder.AddOpenAIChatCompletion(
modelId: "llama3:8b",
apiKey: "ollama", // Ollama ignores the key but the parameter is required
endpoint: new Uri("http://localhost:11434/v1")
);
var kernel = builder.Build();
Connecting to Azure OpenAI
For production deployments, Azure OpenAI is the typical choice for enterprise Semantic Kernel applications:
Python — Azure OpenAI
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
kernel.add_service(
AzureChatCompletion(
service_id="azure-chat",
deployment_name="gpt-4o",
endpoint="https://your-resource.openai.azure.com",
api_key="your-azure-api-key",
api_version="2024-02-01",
)
)
C# — Azure OpenAI
builder.AddAzureOpenAIChatCompletion(
deploymentName: "gpt-4o",
endpoint: "https://your-resource.openai.azure.com",
apiKey: "your-azure-api-key"
);
Building a Plugin
Plugins are annotated classes whose methods become tools available to the AI.
Python Plugin Example
from semantic_kernel.functions import kernel_function
from semantic_kernel.plugin_definition import kernel_function_context_parameter
class WeatherPlugin:
@kernel_function(
description="Get the current weather for a given city",
name="get_weather"
)
def get_weather(self, city: str) -> str:
# In a real plugin, call a weather API here
return f"The weather in {city} is 22°C and partly cloudy."
@kernel_function(
description="List cities with extreme weather today",
name="get_extreme_weather_cities"
)
def get_extreme_weather_cities(self) -> str:
return "Phoenix (45°C), Barrow, AK (-32°C), Dubai (48°C)"
# Register the plugin
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
C# Plugin Example
using Microsoft.SemanticKernel;
using System.ComponentModel;
public class WeatherPlugin
{
[KernelFunction("get_weather")]
[Description("Get the current weather for a given city")]
public string GetWeather([Description("The city name")] string city)
{
// Call your weather API here
return $"The weather in {city} is 22°C and partly cloudy.";
}
}
// Register the plugin
kernel.Plugins.AddFromType<WeatherPlugin>("weather");
Memory: Storing and Retrieving Information
Semantic Kernel’s memory allows you to store text with associated metadata and retrieve the most semantically relevant entries for a query.
Python Memory Example
from semantic_kernel.memory import SemanticTextMemory, VolatileMemoryStore
memory = SemanticTextMemory(
storage=VolatileMemoryStore(), # In-memory; use ChromaDB or Azure for persistence
embeddings_generator=kernel.get_service("ollama-embed"),
)
# Store facts
await memory.save_information(
collection="company_docs",
id="doc1",
text="Our refund policy allows returns within 30 days of purchase.",
)
await memory.save_information(
collection="company_docs",
id="doc2",
text="Enterprise customers receive priority support with a 4-hour SLA.",
)
# Retrieve relevant information
results = await memory.search(
collection="company_docs",
query="What is the return policy?",
limit=2,
min_relevance_score=0.5,
)
for result in results:
print(f"Relevance: {result.relevance:.2f} — {result.text}")
Persistent Memory with ChromaDB
For persistent storage across sessions:
from semantic_kernel.connectors.memory.chroma import ChromaMemoryStore
memory = SemanticTextMemory(
storage=ChromaMemoryStore(persist_directory="./chroma_data"),
embeddings_generator=kernel.get_service("ollama-embed"),
)
Planners
The FunctionChoiceBehavior system (the modern replacement for the older StepwisePlanner) allows the AI to automatically select and chain plugin functions to answer a query.
Python — Auto Function Calling
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import OpenAIChatPromptExecutionSettings
settings = OpenAIChatPromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto()
)
from semantic_kernel.contents import ChatHistory
history = ChatHistory()
history.add_user_message("What's the weather like in Tokyo and is it an extreme weather city today?")
response = await kernel.invoke_prompt(
prompt="{{$history}}",
arguments=KernelArguments(history=history, settings=settings),
)
print(response)
With FunctionChoiceBehavior.Auto(), the kernel will automatically call get_weather("Tokyo") and get_extreme_weather_cities(), synthesize the results, and return a coherent answer — without you writing the orchestration logic.
A Complete Python Application
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.ollama import OllamaChatCompletion
from semantic_kernel.contents import ChatHistory
async def main():
kernel = Kernel()
kernel.add_service(
OllamaChatCompletion(
service_id="chat",
ai_model_id="llama3:8b",
)
)
kernel.add_plugin(WeatherPlugin(), plugin_name="weather")
history = ChatHistory()
history.add_system_message(
"You are a helpful assistant. Use available tools to answer questions."
)
while True:
user_input = input("You: ")
if user_input.lower() in ["exit", "quit"]:
break
history.add_user_message(user_input)
response = await kernel.invoke_prompt(
prompt="{{$history}}",
arguments={"history": history},
)
print(f"Assistant: {response}\n")
history.add_assistant_message(str(response))
asyncio.run(main())
When to Use Semantic Kernel
Semantic Kernel makes the most sense when you are building production-grade AI applications that need structured tool use, conversation memory, and multi-step reasoning — especially in enterprise environments where Azure OpenAI, C#, or .NET is already part of the stack. For quick scripts or simple chatbot prototypes, it is more ceremony than you need. For anything that will be maintained, tested, and deployed by a team, the framework’s structure pays for itself quickly.