Semantic Kernel Tutorial: Microsoft's AI Orchestration Framework for Building Intelligent Applications
Semantic Kernel is an open-source SDK from Microsoft designed to integrate Large Language Models (LLMs) into applications in a structured and modular way. This framework enables developers to build AI applications that combine prompt engineering, plugin systems, and agentic workflows within a cohesive architecture. In this tutorial, we will learn how to use Semantic Kernel with Python, from installation to building AI agents capable of executing complex tasks autonomously.
Why Semantic Kernel?
Unlike other AI frameworks that focus on simple prompt chaining, Semantic Kernel takes a more enterprise-ready approach. Some of its key advantages include:
- Plugin Architecture: Separates business logic from prompts, making code more maintainable
- Multi-Provider Support: Works with OpenAI, Azure OpenAI, Hugging Face, and other providers
- Automatic Function Calling: LLMs can automatically select and execute available functions
- Built-in Memory and RAG: Native integration with vector stores for long-term context
- Planner: Ability to break down complex tasks into executable steps
- Type Safety: Strongly typed with Pydantic support for input/output validation
Semantic Kernel is widely used in Microsoft products like Microsoft 365 Copilot, making it a framework that has been battle-tested at production scale.
Installation
Prerequisites
Make sure Python 3.10 or later is installed on your system.
python --version
Installing Semantic Kernel
pip install semantic-kernel
For additional features, you can install the extras you need:
# For Azure OpenAI
pip install semantic-kernel[azure]
For Hugging Face
pip install semantic-kernel[huggingface]
For Google AI
pip install semantic-kernel[google]
All providers
pip install semantic-kernel[all]
Configuring Environment Variables
Create a .env file in your project root:
# For OpenAI
OPENAIAPIKEY=sk-your-api-key-here
OPENAICHATMODELID=gpt-4o
For Azure OpenAI
AZUREOPENAIAPIKEY=your-azure-key
AZUREOPENAIENDPOINT=https://your-resource.openai.azure.com/
AZUREOPENAICHATDEPLOYMENTNAME=gpt-4o
Basic Usage
Creating Your First Kernel
The Kernel is the core of Semantic Kernel. It acts as a container for all services, plugins, and configurations.
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
kernel = Kernel()
chatservice = OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
)
kernel.addservice(chatservice)
async def main():
result = await kernel.invokeprompt("Explain what machine learning is in 3 sentences.")
print(result)
asyncio.run(main())
Using Chat History
For multi-turn conversations, use ChatHistory:
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.contents import ChatHistory
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
chathistory = ChatHistory()
chathistory.addsystemmessage(
"You are an AI assistant helping Python developers. "
"Answer concisely and provide code examples when needed."
)
async def chat(userinput: str):
chathistory.addusermessage(userinput)
result = await kernel.invokeprompt(
userinput,
chathistory=chathistory
)
response = str(result)
chathistory.addassistantmessage(response)
return response
async def main():
print(await chat("What is a decorator in Python?"))
print(await chat("Give me an example of its usage"))
asyncio.run(main())
Prompt Templates
Semantic Kernel has a template system that allows you to create reusable prompts:
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.prompttemplate import PromptTemplateConfig
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
promptconfig = PromptTemplateConfig(
template="""You are a {{$role}}.
Task: {{$task}}
Provide a detailed and structured answer.""",
inputvariables=[
{"name": "role", "description": "The AI's role"},
{"name": "task", "description": "The task to perform"}
]
)
function = kernel.addfunction(
pluginname="writer",
functionname="generate",
prompttemplateconfig=promptconfig
)
async def main():
result = await kernel.invoke(
function,
role="senior data scientist",
task="Explain the differences between Random Forest and Gradient Boosting"
)
print(result)
asyncio.run(main())
Plugin System
Plugins are a core feature of Semantic Kernel that allow you to define functions that can be automatically called by the LLM.
Creating a Native Plugin
import asyncio
from datetime import datetime
from typing import Annotated
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.functions import kernelfunction
class UtilityPlugin:
@kernelfunction(description="Gets the current date and time")
def getcurrenttime(self) -> str:
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@kernelfunction(description="Calculates discount from original price")
def calculatediscount(
self,
price: Annotated[float, "Original product price"],
discountpercent: Annotated[float, "Discount percentage"]
) -> str:
discounted = price (1 - discountpercent / 100)
savings = price - discounted
return f"Original: ${price:,.2f}, Discount: {discountpercent}%, Final: ${discounted:,.2f}, Saved: ${savings:,.2f}"
@kernelfunction(description="Converts temperature from Celsius to Fahrenheit")
def celsiustofahrenheit(
self,
celsius: Annotated[float, "Temperature in Celsius"]
) -> str:
fahrenheit = (celsius 9/5) + 32
return f"{celsius}°C = {fahrenheit}°F"
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
kernel.addplugin(UtilityPlugin(), pluginname="utility")
async def main():
result = await kernel.invokeprompt(
"What is the price after a 25% discount on $500?"
)
print(result)
asyncio.run(main())
Plugin with Async Functions
import asyncio
import httpx
from semantickernel.functions import kernelfunction
from typing import Annotated
class WeatherPlugin:
@kernelfunction(description="Gets weather information for a city")
async def getweather(
self,
city: Annotated[str, "City name to check weather for"]
) -> str:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": 0,
"longitude": 0,
"currentweather": True
}
)
data = response.json()
weather = data.get("currentweather", {})
return (
f"Weather in {city}: "
f"Temperature {weather.get('temperature', 'N/A')}°C, "
f"Wind speed {weather.get('windspeed', 'N/A')} km/h"
)
Plugin from Prompt Files
You can define plugins from prompt files organized in folders:
plugins/
WriterPlugin/
Summarize/
skprompt.txt
config.json
Translate/
skprompt.txt
config.json
File skprompt.txt:
Summarize the following text in {{$targetlength}} sentences:
{{$input}}
Summary:
File config.json:
{
"schema": 1,
"description": "Summarizes long text into a shorter version",
"inputvariables": [
{
"name": "input",
"description": "Text to summarize"
},
{
"name": "targetlength",
"description": "Number of sentences for the summary",
"default": "3"
}
]
}
Loading plugins from a folder:
kernel.addplugin(parentdirectory="./plugins", pluginname="WriterPlugin")
Automatic Function Calling
One of Semantic Kernel's most powerful features is the LLM's ability to automatically select and call the right function based on conversation context.
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.connectors.ai.openai.promptexecutionsettings import (
OpenAIChatPromptExecutionSettings,
)
from semantickernel.connectors.ai.functionchoicebehavior import FunctionChoiceBehavior
from semantickernel.contents import ChatHistory
from semantickernel.functions import kernelfunction
from typing import Annotated
class MathPlugin:
@kernelfunction(description="Adds two numbers")
def add(
self,
a: Annotated[float, "First number"],
b: Annotated[float, "Second number"]
) -> float:
return a + b
@kernelfunction(description="Multiplies two numbers")
def multiply(
self,
a: Annotated[float, "First number"],
b: Annotated[float, "Second number"]
) -> float:
return a b
@kernelfunction(description="Calculates power")
def power(
self,
base: Annotated[float, "Base number"],
exponent: Annotated[float, "Exponent"]
) -> float:
return base exponent
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
kernel.addplugin(MathPlugin(), pluginname="math")
settings = OpenAIChatPromptExecutionSettings(
serviceid="chat",
functionchoicebehavior=FunctionChoiceBehavior.Auto()
)
chathistory = ChatHistory()
async def main():
chathistory.addusermessage(
"What is the result of (15 + 27) multiplied by 3, then raised to the power of 2?"
)
result = await kernel.invokeprompt(
"{{$chathistory}}",
chathistory=chathistory,
settings=settings
)
print(f"Answer: {result}")
asyncio.run(main())
In the example above, the LLM will automatically:
add(15, 27) to get 42multiply(42, 3) to get 126power(126, 2) to get 15876Advanced Usage
Building AI Agents with Semantic Kernel
Agents in Semantic Kernel allow you to create AI entities with specific personas, tools, and capabilities.
import asyncio
from semantickernel import Kernel
from semantickernel.agents import ChatCompletionAgent
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.contents import ChatHistory
from semantickernel.functions import kernelfunction
from typing import Annotated
class DatabasePlugin:
@kernelfunction(description="Executes a SQL query and returns results")
def executequery(
self,
query: Annotated[str, "SQL query to execute"]
) -> str:
sampledata = {
"SELECT COUNT() FROM users": "Total users: 1,247",
"SELECT AVG(revenue) FROM sales WHERE month='2026-09'":
"Average revenue September 2026: $12,450"
}
for key, value in sampledata.items():
if key.lower() in query.lower():
return value
return f"Query executed: {query}\nRows affected: 0"
@kernelfunction(description="Gets list of available tables in the database")
def listtables(self) -> str:
return "Tables: users, sales, products, orders, inventory"
@kernelfunction(description="Gets the schema of a table")
def gettableschema(
self,
tablename: Annotated[str, "Table name"]
) -> str:
schemas = {
"users": "id INT PK, name VARCHAR, email VARCHAR, createdat TIMESTAMP",
"sales": "id INT PK, productid INT FK, amount DECIMAL, month VARCHAR",
"products": "id INT PK, name VARCHAR, price DECIMAL, category VARCHAR"
}
return schemas.get(tablename, f"Table '{tablename}' not found")
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
kernel.addplugin(DatabasePlugin(), pluginname="database")
agent = ChatCompletionAgent(
kernel=kernel,
name="DataAnalyst",
instructions="""You are a data analyst expert in SQL and data analysis.
Use the available database tools to answer user questions.
Always explain the queries you run and interpret the results.""",
)
async def main():
history = ChatHistory()
history.addusermessage("How many total users are registered in the system?")
async for message in agent.invoke(history):
print(f"Agent: {message.content}")
asyncio.run(main())
Multi-Agent Collaboration
Semantic Kernel supports agent collaboration through AgentGroupChat:
import asyncio
from semantickernel import Kernel
from semantickernel.agents import ChatCompletionAgent, AgentGroupChat
from semantickernel.agents.strategies import TerminationStrategy
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.contents import ChatMessageContent, AuthorRole
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
analyst = ChatCompletionAgent(
kernel=kernel,
name="Analyst",
instructions="""You are a business analyst.
Analyze business problems and identify technical requirements.
Provide measurable and realistic recommendations."""
)
engineer = ChatCompletionAgent(
kernel=kernel,
name="Engineer",
instructions="""You are a senior software engineer.
Evaluate technical recommendations from the analyst.
Provide effort estimates, architecture, and potential risks.
Be specific and technical."""
)
reviewer = ChatCompletionAgent(
kernel=kernel,
name="Reviewer",
instructions="""You are a project reviewer.
Review output from the analyst and engineer.
Provide approval or feedback for improvement.
If the output is good enough, end with the word APPROVED."""
)
class ApprovalTermination(TerminationStrategy):
async def shouldagentterminate(self, agent, history):
if history:
last = history[-1]
return "APPROVED" in last.content.upper()
return False
chat = AgentGroupChat(
agents=[analyst, engineer, reviewer],
terminationstrategy=ApprovalTermination(
agents=[reviewer],
maximumiterations=6
)
)
async def main():
await chat.addchatmessage(
ChatMessageContent(
role=AuthorRole.USER,
content="We want to build a product recommendation system for an e-commerce platform with 100K SKUs and 1M active users."
)
)
async for message in chat.invoke():
print(f"\n{'='*50}")
print(f"[{message.name}]: {message.content}")
asyncio.run(main())
Memory and Vector Store Integration
Semantic Kernel supports integration with various vector stores for memory and RAG features:
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import (
OpenAIChatCompletion,
OpenAITextEmbedding,
)
from semantickernel.memory import SemanticTextMemory, VolatileMemoryStore
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
embeddingservice = OpenAITextEmbedding(
aimodelid="text-embedding-3-small",
serviceid="embedding"
)
memorystore = VolatileMemoryStore()
memory = SemanticTextMemory(
storage=memorystore,
embeddingsgenerator=embeddingservice
)
async def main():
collection = "companyknowledge"
await memory.saveinformation(
collection=collection,
id="policy1",
text="Annual leave policy is 12 working days per year. "
"Leave can be accumulated up to 6 days into the next year."
)
await memory.saveinformation(
collection=collection,
id="policy2",
text="Standard working hours are Monday-Friday, 09:00-18:00. "
"Overtime is calculated after 8 working hours per day."
)
await memory.saveinformation(
collection=collection,
id="policy3",
text="Employee benefits include health insurance, employment insurance, "
"supplementary insurance, and meal allowance of $5 per day."
)
results = await memory.search(
collection=collection,
query="How many leave days do employees get?",
limit=2
)
context = "\n".join([r.text for r in results])
result = await kernel.invokeprompt(
f"""Based on the following information:
{context}
Answer the question: How many leave days do employees get and can they be accumulated?"""
)
print(result)
asyncio.run(main())
Filters and Hooks
Semantic Kernel provides a filter system for logging, monitoring, and request/response modification:
import asyncio
import time
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
from semantickernel.filters import (
FunctionInvocationContext,
PromptRenderContext,
)
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
@kernel.filter(filtertype="functioninvocation")
async def logfunctionfilter(context: FunctionInvocationContext, next):
starttime = time.time()
print(f"[LOG] Calling function: {context.function.name}")
print(f"[LOG] Arguments: {context.arguments}")
await next(context)
elapsed = time.time() - starttime
print(f"[LOG] Function {context.function.name} completed in {elapsed:.2f}s")
print(f"[LOG] Result: {str(context.result)[:200]}")
@kernel.filter(filtertype="promptrender")
async def modifypromptfilter(context: PromptRenderContext, next):
await next(context)
context.renderedprompt += "\n\nPlease provide a clear and well-structured answer."
print(f"[LOG] Rendered prompt length: {len(context.renderedprompt)}")
async def main():
result = await kernel.invokeprompt("What is a neural network?")
print(f"\nResult: {result}")
asyncio.run(main())
Streaming Responses
For real-time applications, use streaming:
import asyncio
from semantickernel import Kernel
from semantickernel.connectors.ai.openai import OpenAIChatCompletion
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid="gpt-4o",
serviceid="chat"
))
async def main():
print("Response: ", end="", flush=True)
async for chunk in kernel.invokepromptstream(
"Explain the 5 steps in a machine learning pipeline"
):
print(str(chunk), end="", flush=True)
print()
asyncio.run(main())
Best Practices
1. Use Dependency Injection
from semantickernel import Kernel
def createkernel(apikey: str, model: str = "gpt-4o") -> Kernel:
kernel = Kernel()
kernel.addservice(OpenAIChatCompletion(
aimodelid=model,
apikey=apikey,
serviceid="chat"
))
return kernel
2. Proper Error Handling
from semantickernel.exceptions import ServiceResponseException
async def safe
invoke(kernel, prompt):
try:
result = await kernel.invokeprompt(prompt)
return str(result)
except ServiceResponseException as e:
print(f"Service error: {e}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
3. Keep Plugin Scope Focused
Each plugin should have a single, clear responsibility. Avoid creating monolithic plugins that handle too many functions.
class FilePlugin:
@kernelfunction(description="Reads file content")
def readfile(self, path: Annotated[str, "File path"]) -> str:
with open(path, "r") as f:
return f.read()
@kernelfunction(description="Writes content to a file")
def writefile(
self,
path: Annotated[str, "File path"],
content: Annotated[str, "Content to write"]
) -> str:
with open(path, "w") as f:
f.write(content)
return f"File written: {path}"
4. Use Execution Settings
from semantickernel.connectors.ai.openai.promptexecutionsettings import (
OpenAIChatPromptExecutionSettings,
)
settings = OpenAIChatPromptExecutionSettings(
service
id="chat",
temperature=0.7,
maxtokens=2000,
topp=0.9,
)
result = await kernel.invokeprompt(prompt, settings=settings)
5. Test Plugin Functions Independently
import pytest
class TestMathPlugin:
def setupmethod(self):
self.plugin = MathPlugin()
def testadd(self):
result = self.plugin.add(a=10, b=20)
assert result == 30
def testmultiply(self):
result = self.plugin.multiply(a=5, b=6)
assert result == 30
def testpower(self):
result = self.plugin.power(base=2, exponent=10)
assert result == 1024
6. Structured Output with Pydantic
from pydantic import BaseModel, Field
from semantickernel.functions import kernelfunction
class AnalysisResult(BaseModel):
sentiment: str = Field(description="positive, negative, or neutral")
confidence: float = Field(description="Confidence score 0-1")
keytopics: list[str] = Field(description="Main topics detected")
summary: str = Field(description="Brief summary")
class AnalysisPlugin:
@kernelfunction(description="Analyzes sentiment and topics from text")
async def analyzetext(
self,
text: Annotated[str, "Text to analyze"],
kernel: Kernel
) -> str:
result = await kernel.invokeprompt(
f"""Analyze the following text and provide output in JSON format:
- sentiment: positive/negative/neutral
- confidence: score 0-1
- keytopics: list of main topics
- summary: brief summary
Text: {text}
JSON Output:"""
)
return str(result)
Comparison with Other Frameworks
| Feature | Semantic Kernel | LangChain | LlamaIndex |
|---------|----------------|-----------|------------|
| Plugin System | Native, strongly typed | Tools/Agents | Tools |
| Multi-Provider | Yes | Yes | Yes |
| Memory | Built-in | Add-on | Native |
| Agent Framework | ChatCompletionAgent | AgentExecutor | Agent |
| Enterprise Ready | Excellent | Good | Good |
| Learning Curve | Moderate | Low-Moderate | Moderate |
| Languages | Python, C#, Java | Python, JS | Python, TS |
Conclusion
Semantic Kernel is a mature and production-ready AI orchestration framework from Microsoft. With its modular plugin architecture, multi-provider support, and comprehensive agent features, this framework is well-suited for building enterprise AI applications. Its automatic function calling and multi-agent collaboration capabilities make it a strong choice for projects that require structured and scalable LLM integration.
Key takeaways to remember:
- Start with the Kernel and add services as needed
- Use the plugin system to separate business logic from prompts
- Leverage automatic function calling for more natural workflows
- Implement filters for logging and monitoring in production
- Consider multi-agent patterns for complex tasks
- Always test plugin functions independently before integrating with LLMs
With a strong foundation from Microsoft and a growing community, Semantic Kernel is a solid investment for developers looking to build robust, enterprise-grade AI applications.