Skip to main content
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.
All migration samples are available in the semantic-kernel-migration samples directory.

Key Differences at a Glance

ConceptSemantic KernelAgent Framework
Agent CreationChatCompletionAgent(service=...)client.as_agent(...)
Tool Definition@kernel_function plugin classes@tool decorator with auto-schema
Session ManagementImplicit via ChatHistoryAgentThreadExplicit via agent.create_session()
OrchestrationSequentialOrchestration, GroupChatOrchestrationSequentialBuilder, GroupChatBuilder, workflow graphs
StreamingVia get_streaming_response()await agent.run(..., stream=True)
Multi-AgentProcess Framework, Team abstractionsWorkflow builders with checkpoints & resume

API Mapping Reference

Agent Creation

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)

Tools and Functions

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

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

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.
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.
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)

Process Framework (Fan-out/Fan-in)

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

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

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

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
  1. Session Management: AF requires explicit session creation. SK’s implicit thread state won’t migrate automatically.
  2. Plugin System: SK’s @kernel_function plugins must be converted to AF’s @tool decorators.
  3. Response Types: SK returns ChatMessageContent objects; AF returns AgentResponse with .text, .messages, and .data properties.
  4. Orchestration Runtime: SK’s InProcessRuntime is not needed in AF. Workflows run directly without runtime management.
  5. Streaming Format: SK streams ChatMessageContent chunks; AF streams AgentResponseUpdate objects.

Migration Checklist

1

Update agent construction

Replace ChatCompletionAgent(service=...) with client.as_agent(...)
2

Convert plugins to tools

Transform @kernel_function class methods to standalone @tool functions
3

Add explicit sessions

Create sessions with agent.create_session() for stateful conversations
4

Update orchestrations

Replace SK orchestrations with AF builders (SequentialBuilder, GroupChatBuilder, WorkflowBuilder)
5

Migrate streaming code

Update streaming logic to handle AgentResponseUpdate instead of ChatMessageContent chunks
6

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

Build docs developers (and LLMs) love