This guide helps Semantic Kernel (SK) developers move to the Microsoft Agent Framework (AF) with minimal guesswork. The frameworks share similar primitives but differ in their approach to agent orchestration, tool handling, and session management.
Key Differences at a Glance
Concept Semantic Kernel Agent Framework Agent Creation ChatCompletionAgent(service=...)client.as_agent(...)Tool Definition @kernel_function plugin classes@tool decorator with auto-schemaSession Management Implicit via ChatHistoryAgentThread Explicit via agent.create_session() Orchestration SequentialOrchestration, GroupChatOrchestrationSequentialBuilder, GroupChatBuilder, workflow graphsStreaming Via get_streaming_response() await agent.run(..., stream=True)Multi-Agent Process Framework, Team abstractions Workflow builders with checkpoints & resume
API Mapping Reference
Agent Creation
Semantic Kernel
Agent Framework
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
agent = ChatCompletionAgent(
service = OpenAIChatCompletion(),
name = "Support" ,
instructions = "Answer in one sentence." ,
)
# Run agent
response = await agent.get_response(
messages = "How do I reset my bike tire?"
)
print (response.message.content)
Semantic Kernel
Agent Framework
from semantic_kernel.functions import kernel_function
class SpecialsPlugin :
@kernel_function ( name = "specials" , description = "List daily specials" )
def specials ( self ) -> str :
return "Clam chowder, Cobb salad, Chai tea"
# Attach plugins at construction
agent = ChatCompletionAgent(
service = OpenAIChatCompletion(),
name = "Host" ,
instructions = "Answer menu questions accurately." ,
plugins = [SpecialsPlugin()],
)
In production, always use approval_mode="always_require" for tools that perform actions. The migration samples use "never_require" only for brevity.
Session and Thread Management
Semantic Kernel
Agent Framework
from semantic_kernel.agents import ChatHistoryAgentThread
# SK manages thread state internally
thread = ChatHistoryAgentThread()
response = await agent.get_response(
messages = "What soup can I order today?" ,
thread = thread,
)
# Thread persists across calls
follow_up = await agent.get_response(
messages = "Any vegan options?" ,
thread = thread,
)
AF agents are stateless by default . Always create and pass a session when you need conversation history to persist across run() calls.
Streaming Responses
Semantic Kernel
Agent Framework
async for chunk in agent.get_streaming_response(
messages = "Tell me about electric bikes"
):
print (chunk.message.content, end = "" )
Orchestration Patterns
Sequential Orchestration
Run agents one after another, passing output to the next agent.
Semantic Kernel
Agent Framework
from semantic_kernel.agents import SequentialOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
writer = ChatCompletionAgent(
name = "WriterAgent" ,
instructions = "Write a concise marketing sentence." ,
service = AzureChatCompletion( credential = credential),
)
reviewer = ChatCompletionAgent(
name = "ReviewerAgent" ,
instructions = "Give brief feedback." ,
service = AzureChatCompletion( credential = credential),
)
orchestration = SequentialOrchestration(
members = [writer, reviewer],
)
runtime = InProcessRuntime()
runtime.start()
result = await orchestration.invoke(
task = "Write a tagline for a budget eBike." ,
runtime = runtime,
)
Group Chat Orchestration
Multiple agents collaborate with an LLM-backed manager deciding who speaks next.
Semantic Kernel
Agent Framework
from semantic_kernel.agents import GroupChatOrchestration
researcher = ChatCompletionAgent(
name = "Researcher" ,
description = "Collects background information." ,
instructions = "Gather concise facts." ,
service = AzureChatCompletion( credential = credential),
)
planner = ChatCompletionAgent(
name = "Planner" ,
description = "Creates actionable plans." ,
instructions = "Draft a structured action plan." ,
service = AzureChatCompletion( credential = credential),
)
# Custom manager required (see samples for implementation)
orchestration = GroupChatOrchestration(
members = [researcher, planner],
manager = ChatCompletionGroupChatManager(
topic = "Launch a hackathon" ,
service = AzureChatCompletion( credential = credential),
max_rounds = 8 ,
),
)
result = await orchestration.invoke( task = "Plan the event" , runtime = runtime)
from agent_framework.orchestrations import GroupChatBuilder
researcher = client.as_agent(
name = "Researcher" ,
description = "Collects background information." ,
instructions = "Gather concise facts." ,
)
planner = client.as_agent(
name = "Planner" ,
description = "Creates actionable plans." ,
instructions = "Draft a structured action plan." ,
)
# Built-in LLM-based orchestrator
workflow = GroupChatBuilder(
participants = [researcher, planner],
orchestrator_agent = client.as_agent(),
).build()
async for event in workflow.run( "Plan the event" , stream = True ):
if event.type == "output" :
final_message = event.data[ - 1 ]
print (final_message.text)
Process Framework (Fan-out/Fan-in)
Semantic Kernel Process → Agent Framework Workflow
Semantic Kernel’s Process Framework uses KernelProcess with steps and edges. Agent Framework uses WorkflowBuilder with custom executors. # Semantic Kernel Process
from semantic_kernel.processes import KernelProcess, ProcessBuilder
process = ProcessBuilder( name = "fan_out_fan_in" )
step_a = process.add_step(StepA)
step_b1 = process.add_step(StepB)
step_b2 = process.add_step(StepB)
step_c = process.add_step(StepC)
process.on_input_event( "start" ) \
.send_event_to(step_a.where_input_event_is( "process" ))
step_a.on_event( "done" ) \
.send_event_to([step_b1, step_b2])
step_b1.on_event( "done" ).send_event_to(step_c)
step_b2.on_event( "done" ).send_event_to(step_c)
kernel_process = process.build()
# Agent Framework Workflow
from agent_framework import WorkflowBuilder, executor
@executor
async def step_a ( input_data : str , context ):
result = await process_data(input_data)
await context.send_message(result, target = [ "step_b1" , "step_b2" ])
@executor
async def step_b ( input_data : str , context ):
processed = await transform(input_data)
await context.send_message(processed, target = "step_c" )
@executor
async def step_c ( messages : list , context ):
aggregated = combine(messages)
await context.yield_output(aggregated)
workflow = (
WorkflowBuilder( start_executor = step_a)
.add_edge(step_a, step_b1)
.add_edge(step_a, step_b2)
.add_edge(step_b1, step_c)
.add_edge(step_b2, step_c)
.build()
)
AF workflows support checkpoints and resume capabilities that SK Process Framework does not. Use the workflow samples as a blueprint when modernizing complex agent graphs.
Provider-Specific Migrations
Azure AI Agent Service
Semantic Kernel
Agent Framework
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings
async with AzureCliCredential() as credential:
async with AzureAIAgent.create_client( credential = credential) as client:
settings = AzureAIAgentSettings()
definition = await client.agents.create_agent(
model = settings.model_deployment_name,
name = "Support" ,
instructions = "Answer customer questions." ,
)
agent = AzureAIAgent( client = client, definition = definition)
response = await agent.get_response( "How do I upgrade?" )
OpenAI Assistants API
Semantic Kernel
Agent Framework
from semantic_kernel.agents import OpenAIAssistantAgent
agent = OpenAIAssistantAgent(
service = OpenAIAssistant(),
name = "Assistant" ,
instructions = "You are a helpful assistant." ,
enable_code_interpreter = True ,
)
response = await agent.get_response( "Calculate 2^16" )
Copilot Studio
Copilot Studio Agent Migration
Semantic Kernel
Agent Framework
from semantic_kernel.agents import CopilotStudioAgent
from semantic_kernel.connectors.copilot_studio import CopilotStudioSettings
settings = CopilotStudioSettings()
agent = CopilotStudioAgent( settings = settings)
response = await agent.get_response( "Help me file a claim" )
Breaking Changes and Deprecations
Important Breaking Changes
Session Management : AF requires explicit session creation. SK’s implicit thread state won’t migrate automatically.
Plugin System : SK’s @kernel_function plugins must be converted to AF’s @tool decorators.
Response Types : SK returns ChatMessageContent objects; AF returns AgentResponse with .text, .messages, and .data properties.
Orchestration Runtime : SK’s InProcessRuntime is not needed in AF. Workflows run directly without runtime management.
Streaming Format : SK streams ChatMessageContent chunks; AF streams AgentResponseUpdate objects.
Migration Checklist
Update agent construction
Replace ChatCompletionAgent(service=...) with client.as_agent(...)
Convert plugins to tools
Transform @kernel_function class methods to standalone @tool functions
Add explicit sessions
Create sessions with agent.create_session() for stateful conversations
Update orchestrations
Replace SK orchestrations with AF builders (SequentialBuilder, GroupChatBuilder, WorkflowBuilder)
Migrate streaming code
Update streaming logic to handle AgentResponseUpdate instead of ChatMessageContent chunks
Test with sample workflows
Run side-by-side comparisons using the migration samples to verify behavior parity
Additional Resources
Migration Samples Runnable side-by-side code comparisons for all patterns
Agent Framework Docs Complete documentation for the Agent Framework
Semantic Kernel Docs Official Semantic Kernel documentation
Community Support Get help from the community on Discord
Migration Tips
Keep both implementations open side-by-side while migrating. The code samples are formatted to make copy/paste easy across SDKs.
Start with single-agent patterns before tackling orchestrations
Test streaming behavior early — AF’s streaming API is simpler but has different event types
Use agent.create_session() liberally during development; you can optimize session management later
For complex multi-agent graphs, use AF’s workflow checkpointing to enable pause/resume capabilities
Tools map cleanly from SK plugins to AF @tool callables; introduce hosted tools (MCP, web search) after achieving parity