Semantic Kernel — Microsoft AI SDK Complete Guide (2026)
Advertisement
Introduction
Why Semantic Kernel?
Semantic Kernel (SK) is Microsoft's open-source SDK for integrating large language models into applications. It sits between raw LLM API calls and full agent frameworks like AutoGen — providing structure through plugins, functions, and planners without the complexity of multi-agent orchestration.
SK's core strength is enterprise integration: it supports OpenAI, Azure OpenAI, Hugging Face, and local models through a unified interface. Its plugin system maps naturally to existing enterprise services (REST APIs, databases, Microsoft Graph), making it the preferred choice for .NET shops and Azure-centric teams. In 2026, SK's Python SDK is mature and production-ready.
Installation and Setup
pip install semantic-kernelimport asyncio
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.connectors.ai.open_ai import OpenAIChatPromptExecutionSettings
# Initialize the kernel
kernel = Kernel()
# Add an OpenAI chat service
kernel.add_service(
OpenAIChatCompletion(
service_id="gpt4o",
ai_model_id="gpt-4o",
api_key="your-openai-api-key",
)
)Kernel Functions: The Core Building Block
Kernel functions are the atomic units of work in Semantic Kernel. They can be either prompt-based (LLM calls) or native (Python code):
from semantic_kernel.functions import kernel_function
from semantic_kernel.functions.kernel_arguments import KernelArguments
# Semantic (prompt-based) function
SUMMARIZE_PROMPT = """Summarize the following text in {{$max_sentences}} sentences.
Focus on the most important points.
Text:
{{$input}}
Summary:"""
summarize_function = kernel.add_function(
prompt=SUMMARIZE_PROMPT,
function_name="summarize",
plugin_name="TextUtils",
description="Summarize text to a given number of sentences",
prompt_execution_settings=OpenAIChatPromptExecutionSettings(
service_id="gpt4o",
max_tokens=500,
temperature=0.1,
)
)
async def run_summarize():
result = await kernel.invoke(
summarize_function,
KernelArguments(
input="Long article text here...",
max_sentences=3
)
)
print(str(result))
asyncio.run(run_summarize())Native Plugins: Connecting to Real Services
Native plugins wrap Python functions and make them callable by the kernel (and by AI planners):
from semantic_kernel.functions import kernel_function
from typing import Annotated
import httpx
import json
from datetime import datetime
class WeatherPlugin:
"""Plugin for retrieving weather information."""
@kernel_function(
description="Get current weather conditions for a city",
name="get_current_weather"
)
async def get_current_weather(
self,
city: Annotated[str, "The city name to get weather for"]
) -> str:
"""Return formatted weather data for the given city."""
# Mock implementation — replace with real weather API
mock_data = {
"london": {"temp_c": 12, "condition": "overcast", "humidity": 78},
"tokyo": {"temp_c": 24, "condition": "sunny", "humidity": 55},
"new york": {"temp_c": 18, "condition": "partly cloudy", "humidity": 62},
}
city_key = city.lower()
data = mock_data.get(city_key, {"temp_c": 20, "condition": "unknown", "humidity": 60})
return json.dumps({
"city": city,
"temperature_celsius": data["temp_c"],
"condition": data["condition"],
"humidity_percent": data["humidity"],
"retrieved_at": datetime.now().isoformat()
})
@kernel_function(
description="Get weather forecast for the next N days",
name="get_forecast"
)
async def get_forecast(
self,
city: Annotated[str, "The city name"],
days: Annotated[int, "Number of forecast days (1-7)"] = 3
) -> str:
"""Return a multi-day weather forecast."""
forecast = [
{"day": i + 1, "temp_c": 15 + i, "condition": "variable"}
for i in range(min(days, 7))
]
return json.dumps({"city": city, "forecast": forecast})
class DatabasePlugin:
"""Plugin for database operations."""
def __init__(self, connection_string: str):
self.connection_string = connection_string
self._data_store = {} # Mock in-memory store
@kernel_function(description="Query records by filter criteria", name="query_records")
async def query_records(
self,
table: Annotated[str, "Table name to query"],
filter_field: Annotated[str, "Field to filter on"],
filter_value: Annotated[str, "Value to filter for"]
) -> str:
"""Query the database and return matching records."""
# Mock query — replace with real DB call
results = [
{"id": 1, "name": "Sample Record", filter_field: filter_value}
]
return json.dumps({"table": table, "results": results, "count": len(results)})
# Register plugins
kernel.add_plugin(WeatherPlugin(), plugin_name="Weather")
kernel.add_plugin(DatabasePlugin("postgresql://..."), plugin_name="Database")Semantic Memory: Long-Term Context
Semantic Kernel's memory system stores and retrieves information by semantic similarity:
from semantic_kernel.connectors.memory.chroma import ChromaMemoryStore
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbedding
from semantic_kernel.memory import SemanticTextMemory
# Set up embedding service
kernel.add_service(
OpenAITextEmbedding(
service_id="ada",
ai_model_id="text-embedding-3-small",
api_key="your-openai-api-key",
)
)
# Set up memory store
memory_store = ChromaMemoryStore(persist_directory="./chroma_db")
memory = SemanticTextMemory(storage=memory_store, embeddings_generator=kernel.get_service("ada"))
async def memory_demo():
# Store information
await memory.save_information(
collection="company_docs",
id="doc_001",
text="Our return policy allows returns within 30 days of purchase with receipt.",
description="Return policy document"
)
await memory.save_information(
collection="company_docs",
id="doc_002",
text="Customer support is available Monday-Friday 9am-5pm EST at 1-800-EXAMPLE.",
description="Support hours document"
)
# Retrieve by semantic similarity
results = await memory.search(
collection="company_docs",
query="How do I return a product?",
limit=2,
min_relevance_score=0.7
)
for result in results:
print(f"Relevance: {result.relevance:.2f}")
print(f"Content: {result.text}\n")
asyncio.run(memory_demo())AI Planning: Automatic Function Composition
SK's planner automatically selects and sequences kernel functions to fulfill a user request:
from semantic_kernel.planners.function_calling_stepwise_planner import (
FunctionCallingStepwisePlanner,
FunctionCallingStepwisePlannerOptions
)
async def run_planner_demo():
# Add several plugins
kernel.add_plugin(WeatherPlugin(), plugin_name="Weather")
# Add a math plugin
math_prompt = "Calculate: {{$expression}}\nResult:"
kernel.add_function(
prompt=math_prompt,
function_name="calculate",
plugin_name="Math",
description="Evaluate a mathematical expression"
)
# Configure and run the planner
planner = FunctionCallingStepwisePlanner(
service_id="gpt4o",
options=FunctionCallingStepwisePlannerOptions(max_iterations=10)
)
question = "What's the weather in Tokyo, and what is 25% of the temperature in Celsius?"
result = await planner.invoke(kernel, question)
print(f"Final answer: {result.final_answer}")
asyncio.run(run_planner_demo())Building an Agent with Process Framework
SK's Process Framework (v1.0+) enables building stateful agent workflows:
from semantic_kernel.processes.local_runtime.local_kernel_process import LocalKernelProcess
from semantic_kernel.processes.kernel_process import KernelProcess, KernelProcessStep
class DocumentAnalysisStep(KernelProcessStep):
"""Step that extracts key information from a document."""
@kernel_function(name="analyze")
async def analyze(self, document: str) -> str:
result = await kernel.invoke(
kernel.get_function("TextUtils", "summarize"),
KernelArguments(input=document, max_sentences=5)
)
return str(result)
# Processes chain steps together with state passing
# (Full process framework setup requires SK v1.0+ process configuration)Comparing Semantic Kernel to LangChain
| Feature | Semantic Kernel | LangChain |
|---|---|---|
| Primary language | C#, Python | Python |
| Enterprise support | Microsoft-backed | Community |
| Azure integration | First-class | Plugin |
| Plugin system | Typed, schema-driven | Tools/chains |
| Planner | Built-in stepwise | LangGraph |
| Memory | Built-in, pluggable | Third-party |
| Learning curve | Moderate | Lower |
Common Mistakes
- Using synchronous calls — SK's Python SDK is async-first; always use
await kernel.invoke(). - Missing function descriptions — The planner uses descriptions to select functions; vague descriptions cause wrong function selection.
- Not setting
service_id— With multiple services, always specify which service a function or execution setting uses. - Ignoring token limits — Set
max_tokensinPromptExecutionSettingsto prevent unexpectedly large responses. - Storing raw text in memory — Chunk long documents before storing; semantic search degrades on chunks over 500 tokens.
- Running planners on untested plugins — Test each plugin function independently before exposing it to the planner.
Best Practices
- Organize related functions into plugins with clear, consistent naming
- Write precise
@kernel_functiondescriptions — they are the planner's only guide for function selection - Use
KernelArgumentsfor all function calls to ensure proper type coercion and template rendering - Chunk documents into 200–400 token segments before storing in semantic memory
- Set temperature=0 for extraction and classification functions; use higher values only for creative generation
- Log kernel invocations in production using SK's built-in event hooks for debugging and cost tracking
Key Takeaways
- Semantic Kernel provides a plugin architecture that wraps both LLM prompt functions and native Python functions under a unified interface
- The built-in planner automatically selects and sequences kernel functions to fulfill complex user requests — no manual chain construction required
- Semantic memory enables long-term context retrieval by storing and searching text by embedding similarity
- Function descriptions in
@kernel_functionare critical for planner accuracy — write them as if explaining the function to a non-technical user - SK's async-first Python SDK requires
awaiton allkernel.invoke()calls; synchronous usage is not supported - Azure OpenAI integration is first-class in SK, making it the natural choice for enterprise teams on the Azure platform
- Chunk documents to 200–400 tokens before storing in memory; semantic search accuracy drops significantly on longer chunks
- SK sits between raw API calls and full agent frameworks — ideal for structured enterprise workflows, less suited for open-ended multi-agent systems
Advertisement