Semantic Kernel — Microsoft AI SDK Complete Guide (2026)

Sanjeev SharmaSanjeev Sharma
7 min read

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-kernel
import 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

FeatureSemantic KernelLangChain
Primary languageC#, PythonPython
Enterprise supportMicrosoft-backedCommunity
Azure integrationFirst-classPlugin
Plugin systemTyped, schema-drivenTools/chains
PlannerBuilt-in stepwiseLangGraph
MemoryBuilt-in, pluggableThird-party
Learning curveModerateLower

Common Mistakes

  1. Using synchronous calls — SK's Python SDK is async-first; always use await kernel.invoke().
  2. Missing function descriptions — The planner uses descriptions to select functions; vague descriptions cause wrong function selection.
  3. Not setting service_id — With multiple services, always specify which service a function or execution setting uses.
  4. Ignoring token limits — Set max_tokens in PromptExecutionSettings to prevent unexpectedly large responses.
  5. Storing raw text in memory — Chunk long documents before storing; semantic search degrades on chunks over 500 tokens.
  6. 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_function descriptions — they are the planner's only guide for function selection
  • Use KernelArguments for 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_function are critical for planner accuracy — write them as if explaining the function to a non-technical user
  • SK's async-first Python SDK requires await on all kernel.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

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading