Microsoft Agent Framework is Microsoft’s unified SDK for building, orchestrating, and deploying AI agents in Python and .NET. It exists to resolve a problem Microsoft created for itself: by early 2025 it was shipping two separate, overlapping agent SDKs. AutoGen offered simple, research-friendly multi-agent abstractions (agents that message each other in a conversation loop) and became popular for its ease of prototyping. Semantic Kernel offered the enterprise features AutoGen lacked: type safety, dependency injection, telemetry, and middleware suitable for production .NET and Python services. Teams had to pick one and accept its gaps, or run both and stitch them together. Agent Framework fuses the two lineages into one SDK, reached version 1.0 on April 3, 2026 with a long-term support commitment, and placed both AutoGen and Semantic Kernel into maintenance mode: bug and security fixes continue, but new capability development now happens only in Agent Framework.
Two Lineages, One Framework
The merge is legible in the framework’s design: agent definition stays close to AutoGen’s simplicity, while the runtime around it (state management, observability, middleware) inherits Semantic Kernel’s production maturity.
flowchart LR
subgraph L1[AutoGen lineage]
A1[Simple agent abstractions]
A2[Conversational multi-agent loops]
end
subgraph L2[Semantic Kernel lineage]
B1[Type safety and DI]
B2[Middleware and telemetry]
B3[Enterprise session state]
end
A1 --> C[Microsoft Agent Framework]
A2 --> C
B1 --> C
B2 --> C
B3 --> C
C --> D[Graph-based Workflows engine]
classDef default fill:#ffffff,stroke:#4338CA,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef data fill:#EEF0F7,stroke:#0D9488,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef process fill:#F7F8FC,stroke:#6366F1,stroke-width:2px,color:#0F172A,rx:8px,ry:8px;
classDef output fill:#4338CA,stroke:#4338CA,stroke-width:2px,color:#ffffff,rx:8px,ry:8px;
class A1,A2,B1,B2,B3 process;
class C data;
class D output;
A single ChatAgent in Agent Framework looks a lot like an AutoGen agent: a name, an instruction string, and a chat client. What changed is everything around it. OpenTelemetry-based tracing runs by default, agents can be composed with typed middleware (functions that intercept a request or response, useful for logging, redaction, or policy enforcement), and the same agent definition targets Azure OpenAI, OpenAI directly, or any Model Context Protocol-compatible tool server without code changes.
# Scenario: adding a redaction middleware to every agent in a customer-
# support pipeline, without touching each agent's own instructions.
from agent_framework import ChatAgent, agent_middleware
@agent_middleware
async def redact_pii(context, next_step):
# Runs before and after every model call this agent makes.
context.request.messages = [scrub_pii(m) for m in context.request.messages]
response = await next_step(context)
response.text = scrub_pii(response.text)
return response
support_agent = ChatAgent(
name="support",
chat_client=client,
instructions="Help the customer, but never repeat account numbers verbatim.",
middleware=[redact_pii],
)
Workflows: Orchestration as a Graph, Not a Script
The framework’s flagship addition over both predecessors is Workflows, a graph-based orchestration engine. Instead of writing imperative control flow to decide which agent runs next, a developer declares a directed graph of executors (agents or plain functions) connected by edges, and the runtime executes it in synchronized “supersteps” until the graph goes idle. This is the same underlying idea as a multi-agent system, but formalized: the graph is inspectable, replayable, and can branch, fan out to parallel steps, and converge results, which a hand-rolled chain of function calls typically cannot do without becoming its own bespoke, undocumented orchestrator.
# Scenario: fan out a research question to three specialist agents in
# parallel, then have a fourth agent synthesize their outputs. Hand-writing
# this with asyncio.gather is possible; the graph makes the shape explicit
# and gives you tracing across all three branches for free.
from agent_framework import WorkflowBuilder
workflow = (
WorkflowBuilder()
.add_fan_out(research_lead, [market_agent, technical_agent, legal_agent])
.add_fan_in([market_agent, technical_agent, legal_agent], synthesis_agent)
.set_start_executor(research_lead)
.build()
)
report = await workflow.run("Should we enter the EU market for this product?")
The five documented orchestration patterns built on top of Workflows reached 1.0 alongside the SDK: sequential (a fixed pipeline), concurrent (fan-out/fan-in, as above), handoff (control passes between agents based on a condition, as in the triage example), group chat (several agents converse until a termination condition is met, AutoGen’s original signature pattern), and magentic (a manager agent dynamically plans which specialist to invoke next, rather than following a fixed graph). Sequential and concurrent are the low-risk defaults; handoff and group chat trade determinism for flexibility, and magentic trades the most determinism for the most adaptability.
| Pattern | Control flow | Best fit |
|---|---|---|
| Sequential | Fixed order, A then B then C | Pipelines with a known, unchanging shape |
| Concurrent | Fan-out then fan-in | Independent subtasks that can run in parallel |
| Handoff | Conditional edge to the next agent | Triage/escalation, tiered support |
| Group chat | Agents converse until a stop condition | Debate, review, brainstorming loops |
| Magentic | A manager agent plans the next step dynamically | Open-ended tasks with no fixed shape |
Native Protocol Support
Agent Framework ships first-party support for the interoperability protocols that had, by 2026, become the connective tissue of the agent ecosystem: MCP for tool and data access, A2A for cross-vendor agent-to-agent communication, AG-UI for streaming agent state to a front end, and OpenAPI for wrapping existing REST services as callable tools. Because these are first-party rather than community-maintained integrations, an agent built in Agent Framework can call a tool exposed by an entirely different vendor’s MCP server, or hand off a task to an agent built on a different SDK entirely, as long as both sides speak A2A.
# Scenario: an Agent Framework agent that calls out to an MCP server run
# by a different team (or a different company) for a proprietary dataset,
# without needing a custom client for that team's API.
from agent_framework import ChatAgent
from agent_framework.mcp import MCPStreamableHTTPTool
pricing_tool = MCPStreamableHTTPTool(
name="pricing-data",
url="https://partner.example.com/mcp",
)
analyst_agent = ChatAgent(
name="analyst",
chat_client=client,
instructions="Answer pricing questions using the pricing-data tool.",
tools=[pricing_tool],
)
Observability: Seeing Every Hop in a Workflow
Debugging a single agent means reading one transcript. Debugging a Workflow graph with fan-out, conditional edges, and a magentic manager means reconstructing which executor ran, in what order, with what input, and why the graph took the branch it took, which is exactly the problem the framework’s unified OpenTelemetry instrumentation is built to solve. Every executor invocation, edge traversal, and superstep emits a span, so a trace of a single workflow.run() call shows the full graph execution, not just the final output.
# Scenario: a Workflow occasionally produces a wrong answer, and the team
# needs to see which branch it took without adding print statements.
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
# Agent Framework emits spans for each executor and edge automatically;
# no manual instrumentation of the workflow itself is required.
result = await workflow.run("Ticket: production database refusing writes since 09:14 UTC.")
# The exported trace shows, in order: triage_agent invoked -> condition
# evaluated on the HIGH-severity edge -> specialist_agent invoked -> final state.
This matters most for the harder-to-reason-about patterns from the table above: a group-chat or magentic Workflow that behaves unexpectedly is far easier to diagnose from a span tree showing exactly which agent spoke when than from re-reading the agents’ instruction strings and guessing.
.NET and Python Parity
Agent Framework ships as a first-class SDK in both .NET and Python, a deliberate choice given that AutoGen’s user base skewed Python (research and data science teams) while Semantic Kernel’s skewed .NET (enterprise application teams). The core abstractions (ChatAgent, WorkflowBuilder, middleware, the MCP and A2A clients) are designed to be conceptually identical across both languages, so a Workflow graph designed by a .NET team and one designed by a Python team look like the same shape even though the syntax differs. In practice this matters for organizations that have both kinds of teams building agents against a shared set of internal conventions, since a graph pattern documented once (say, the handoff pattern in the triage example above) transfers directly regardless of which language a given service is written in.
Migration and the Maintenance-Mode Decision
Both AutoGen and Semantic Kernel remain installable and receive security patches, but Microsoft’s own migration guides are explicit that new feature work lands only in Agent Framework going forward. For teams with an existing AutoGen or Semantic Kernel codebase, Microsoft published side-by-side migration guides rather than an automated converter, because the two source frameworks differ enough in agent definition style that a mechanical port would produce working but idiomatically wrong code. The practical guidance that has emerged from early 2026 migrations: port agent-by-agent, replace bespoke orchestration loops with a Workflow graph as you go rather than trying to preserve the old control flow verbatim, and treat the migration as an opportunity to add the tracing and middleware Agent Framework provides by default rather than carrying over ad hoc logging.
What’s New (2025-2026)
The AutoGen/Semantic Kernel merge itself is the headline event: two SDKs with real production usage each, consolidated into one with a stated long-term support commitment, following the same protocol-consolidation instinct that folded the ACP protocol into A2A under the Linux Foundation around the same period.
Workflows and its five orchestration patterns reaching 1.0 turned what used to be bespoke, per-project orchestration code into a documented, versioned primitive, comparable to how subagent orchestration patterns have standardized around a small number of recurring shapes across the industry rather than one-off designs.
MCP and A2A became first-party, not bolted-on. Shipping both protocols in the 1.0 release rather than as a later add-on signals that Microsoft expects most Agent Framework deployments to be part of a heterogeneous, multi-vendor agent ecosystem rather than a closed, single-SDK system.
Unified OpenTelemetry instrumentation merged what were previously two separate telemetry stories (Semantic Kernel’s hooks, AutoGen’s tracing) into one, which matters in practice because agent evaluation and debugging a multi-agent Workflow both depend on being able to see every hop, not just the final output.
Choosing Agent Framework vs. a Lighter-Weight Harness
Agent Framework is not the only way to build a multi-agent system, and it is not always the right one. It is aimed squarely at teams that need the enterprise scaffolding (typed middleware, DI, telemetry, a graph orchestration engine with replay) and are willing to accept an SDK’s opinions about how agents are structured. A team building a single, tightly scoped agent harness around one model, or one that needs the absolute minimum layer between it and the model API, may be better served by a thinner, custom loop of the kind shown in the agent harness entry. The decision point is roughly: reach for Agent Framework when the system will have multiple agents, multiple teams touching it, or a real production observability requirement; reach for a hand-rolled loop when it will not.
Limitations Worth Naming
Because Agent Framework is opinionated about how agents and workflows are structured, adopting it is a real migration, not a drop-in library import, even for teams already using AutoGen or Semantic Kernel; the migration guides exist because the port is not mechanical. The Workflows engine’s determinism is also a trade-off, not a free win: a graph with many conditional edges and a magentic manager can become as hard to reason about as the ad hoc orchestration code it replaced, just with different tooling around it. And because the framework is young relative to its two predecessors’ combined lifespan, teams evaluating it for long-lived production systems should weigh the stated LTS commitment against the reality that both AutoGen and Semantic Kernel were themselves widely adopted before being placed into maintenance mode.
How to Use: Two agents handed off through a graph-based Workflow
# Scenario: a support ticket first needs a triage agent to classify
# severity, then hands off to a specialist agent only for the hard cases.
# Modeling this as a graph (rather than a hand-rolled if/else chain) keeps
# the routing logic inspectable and lets the framework log every hop.
from agent_framework import ChatAgent, WorkflowBuilder
from agent_framework.azure import AzureOpenAIChatClient
client = AzureOpenAIChatClient(deployment_name="gpt-5.5")
triage_agent = ChatAgent(
name="triage",
chat_client=client,
instructions="Classify the ticket as LOW, MEDIUM, or HIGH severity.",
)
specialist_agent = ChatAgent(
name="specialist",
chat_client=client,
instructions="Diagnose the HIGH severity ticket and propose a fix.",
)
# The graph: triage always runs first; specialist only runs on the
# HIGH-severity edge. Low/medium tickets exit straight to the queue.
workflow = (
WorkflowBuilder()
.add_edge(triage_agent, specialist_agent, condition=lambda msg: "HIGH" in msg.text)
.set_start_executor(triage_agent)
.build()
)
result = await workflow.run("Ticket: production database refusing writes since 09:14 UTC.")
print(result.get_final_state())
Ready to build?
Leverage AI technologies to build your product stack
Superteams can help you build, deploy and launch AI application stacks using open source technologies — from architecture through to production.
Talk to Superteams