AutoGen to Microsoft Agent Framework: Step-by-Step Migration
Multi-agent orchestration was fragmented across two Microsoft frameworks. AutoGen provided flexible agent teams and GroupChat, while Semantic Kernel offered plugins and kernel-based composition. With the February 2026 release of Microsoft Agent Framework (MAF) in Release Candidate status, both converge into a unified API surface with stable orchestration primitives, cleaner tool registration, and integrated support for long-running, human-in-the-loop workflows (Source: Microsoft Foundry). If you are running AutoGen agents in production today, migrating to MAF is now practical: the API is stable, migration effort is low, and the payoff is simpler code with better state management. This guide walks you through three phases of refactoring - agent instantiation, tool definition, and multi-agent coordination - with concrete before/after code for Python.
Before You Start: Inventory and Validation
Understand what you are migrating. AutoGen deployments typically use AssistantAgent and UserProxyAgent classes paired with a dictionary-based llm_config for model and API settings. Semantic Kernel codebases organize logic into Plugin classes decorated with @kernel_function. Both patterns worked, but they diverge significantly from MAF's unified client model.
Start by auditing:
- How many agents run across your system? (MAF tracks agent identity; you will assign each one on creation.)
- How many share a single
llm_configor API key? (This shared-credential pattern is exactly what MAF eliminates via per-agent authentication.) - What tool framework do you use? (AutoGen's
FunctionToolobjects, Semantic Kernel's decorated plugin methods, or raw Python functions?) - Do you have test coverage for agent behavior, tool invocation, and multi-turn conversations? (You will want it when validating the migration.)
Plan 2-3 days per agent for refactoring plus testing. Operator note (first-hand): migrate one agent end-to-end in a staging environment before rolling out to your fleet. Code that passes in AutoGen's loose llm_config dicts may fail in MAF's stricter client instantiation - particularly around credential passing, system message format, and tool schema validation. Test context persistence explicitly: create a thread, send two messages, and confirm the agent recalls the first message in its response to the second.
Phase 1: Agent Instantiation and Client Setup
The biggest single change is authentication and client initialization. AutoGen relied on passing API keys and model metadata in dictionaries; MAF uses a client object that you create once and reuse across all agents.
From AutoGen to MAF
In AutoGen, you set up agents like this:
from autogen import AssistantAgent, UserProxyAgent
llm_config = {
"model": "gpt-4",
"api_type": "azure",
"api_base": os.getenv("AZURE_OPENAI_ENDPOINT"),
"api_key": os.getenv("AZURE_OPENAI_KEY"),
"api_version": "2024-08-01-preview"
}
assistant = AssistantAgent(
name="Assistant",
llm_config=llm_config,
system_message="You are a helpful assistant."
)
user_proxy = UserProxyAgent(
name="User",
human_input_mode="ALWAYS",
code_execution_config=False
)
In MAF, the pattern is declarative and credential-driven:
from azure.identity import DefaultAzureCredential
from azure.ai.foundry import AzureOpenAIResponsesClient
client = AzureOpenAIResponsesClient(
credential=DefaultAzureCredential(),
endpoint=os.getenv("AZURE_OPENAI_ENDPOINT")
)
agent = client.create_agent(
name="Assistant",
instructions="You are a helpful assistant.",
model="gpt-4"
)
# For multi-agent coordination, create a thread
thread = client.create_thread()
Key differences:
- Credentials: AutoGen passed API keys as strings; MAF uses
DefaultAzureCredential()fromazure-identity. This reads from environment variables, Managed Identity, or interactive login - whatever your Azure environment provides. If you run on Azure Container Instances or App Service, Managed Identity is automatic. Locally,az loginauthenticates via your default browser. - Agent vs. User: AutoGen's
UserProxyAgentwas a proxy for human input or code execution. MAF treats agents uniformly; if you need human-in-the-loop, you pause the orchestrator and prompt the user explicitly. - System message: AutoGen's
system_messageparameter becomesinstructionsin MAF. Same content, different name. - Thread for context: MAF's
Threadobject automatically persists conversation history and state. No more manualChatHistorymanagement.
From Semantic Kernel to MAF
If you are using Semantic Kernel, the shift is similar in spirit but different in practice:
AutoGen (before):
from semantic_kernel import Kernel
from semantic_kernel.services import AzureOpenAIChatCompletion
kernel = Kernel()
service = AzureOpenAIChatCompletion(
api_key=os.getenv("AZURE_OPENAI_KEY"),
endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
deployment_id="gpt-4"
)
kernel.add_service(service)
chat_history = ChatHistory()
chat_history.add_user_message("Summarize the main themes...")
result = await kernel.invoke_prompt("{{$input}}", input="...")
MAF (after):
from azure.identity import DefaultAzureCredential
from azure.ai.foundry import AzureOpenAIResponsesClient
client = AzureOpenAIResponsesClient(
credential=DefaultAzureCredential(),
endpoint=os.getenv("AZURE_OPENAI_ENDPOINT")
)
agent = client.create_agent(
name="Summarizer",
instructions="You are a concise summarizer.",
model="gpt-4"
)
thread = client.create_thread()
response = await client.run_agent(agent, thread, "Summarize the main themes...")
The Kernel object disappears; you work directly with the client and thread. The invoke_prompt call becomes a simple run_agent call. Semantic Kernel's service registration abstraction is gone - the client handles it (Source: Nithin Mohan TK, dataa.dev migration series).
Phase 2: Tools and Function Definition
Tools changed most visibly. AutoGen required you to wrap Python functions in FunctionTool objects with explicit schema dictionaries. Semantic Kernel used class-based Plugin decorators. MAF unified both under a single @ai_function decorator and Pydantic-based parameter documentation.
AutoGen FunctionTool to MAF @ai_function
In AutoGen:
from autogen import FunctionTool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
import requests
response = requests.get(f"https://api.weather.example.com/current?q={city}")
return response.json().get("description", "Unknown")
weather_tool = FunctionTool(
func=get_weather,
description="Fetch the current weather for a given city",
schema={
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Name of the city (e.g., San Francisco)"
}
},
"required": ["city"]
}
)
# Pass to agent when you create it
assistant = AssistantAgent(name="Assistant", llm_config=..., tools=[weather_tool])
In MAF:
from microsoft.agents import ai_function
from typing import Annotated
from pydantic import Field
@ai_function
def get_weather(city: Annotated[str, Field(description="Name of the city (e.g., San Francisco)")]) -> str:
"""Get the current weather for a city."""
import requests
response = requests.get(f"https://api.weather.example.com/current?q={city}")
return response.json().get("description", "Unknown")
# Pass function reference directly
agent = client.create_agent(name="Assistant", tools=[get_weather], ...)
The advantages are clear:
- No schema dict: Type hints and Pydantic's
Field()replace the verbose JSON schema. - No wrapper object: The decorator sits on the function itself, not a separate class.
- Automatic registration: Pass the function to
create_agent()directly; MAF inspects it. - Cleaner type-checking: Type hints are Python-native and IDE-discoverable.
The migration path is straightforward: unwrap each FunctionTool, move the description from the schema dict to Field(description="..."), and apply the @ai_function decorator (Source: Nithin Mohan TK).
Semantic Kernel Plugins to MAF Tools
Semantic Kernel plugins were class-based:
from semantic_kernel.functions import kernel_function
from semantic_kernel.functions.kernel_function_decorator import kernel_function
class WeatherPlugin:
@kernel_function(description="Get weather for a city")
def get_weather(self, city: str) -> str:
"""Fetch the current weather."""
...
kernel.add_plugin(WeatherPlugin(), "weather")
In MAF, you move the method out of the class:
from microsoft.agents import ai_function
from typing import Annotated
from pydantic import Field
@ai_function
def get_weather(city: Annotated[str, Field(description="Name of the city")]) -> str:
"""Fetch the current weather."""
...
agent = client.create_agent(name="...", tools=[get_weather], ...)
The [Description] attributes in C# or docstrings in Python become Field(description="...") in the annotation. That is the essence of the change (Source: Nithin Mohan TK).
Phase 3: Multi-Agent Orchestration and Workflows
The third and most consequential shift is how agents coordinate. AutoGen's GroupChat was a messaging loop with heuristics (round-robin, max rounds, speaker selection). MAF replaces it with explicit orchestrator classes and workflow definitions.
In AutoGen:
from autogen import GroupChat, GroupChatManager
group_chat = GroupChat(
agents=[researcher, writer, editor],
messages=[],
max_round=5,
speaker_selection_method="round_robin"
)
manager = GroupChatManager(groupchat=group_chat, llm_config=llm_config)
# Kick off the chat
user_proxy.initiate_chat(
manager,
message="Write a blog post about AI agents. When done, announce FINAL ANSWER."
)
# Extract final output
last_msg = assistant.last_message() # or similar
In MAF:
from microsoft.agents import SequentialOrchestrator
orchestrator = SequentialOrchestrator(agents=[researcher, writer, editor])
result = await orchestrator.run(
user_message="Write a blog post about AI agents. When done, announce FINAL ANSWER."
)
final_message = result.messages[-1].content
The difference is declarative vs. imperative. AutoGen's GroupChat was a live message loop with heuristic speaker selection. MAF's orchestrators are explicit:
- Sequential: Each agent runs in order; output from one becomes input to the next.
- Concurrent: All agents run in parallel (useful for independent research tasks).
- Handoff: An agent passes control to the next based on a condition or signal.
- Magnetic: Context-aware coordination, similar to LangGraph's state management (Source: Seenivasa Ramadurai, Dev.to).
- Custom Graph: Build your own orchestration topology.
For a blog-writing pipeline (research -> draft -> edit), Sequential is the right choice. For parallel research across multiple sources, use Concurrent and then feed results to a synthesis step.
Testing and Validation Checklist
Validate the migration systematically:
- Imports resolved: No remaining
from autogen importstatements. Check thatazure-identityandazure-ai-foundrypackages are installed. - Credentials work: Run
DefaultAzureCredential()and confirm it finds credentials. If using local development, runaz login. - Agent creation succeeds: Call
client.create_agent()and verify the returned object hasname,instructions, andmodelattributes. - Tool invocation: Call each tool directly in Python to confirm it works, then pass it to an agent and check the agent can invoke it.
- Context persistence: Create a thread, send message A ("My favorite color is blue"), send message B ("What is my favorite color?"), confirm the agent answers correctly.
- Workflow execution: Run the orchestrator with a 3-agent pipeline and confirm each agent runs in order and passes output forward.
- Error messages: Test failure paths: missing credentials, invalid model name, tool that raises an exception. Confirm errors are clear, not silent hangs.
Common Pitfalls and Fixes
- "ModuleNotFoundError: No module named 'azure.ai.foundry'": Install via
pip install azure-ai-foundry azure-identity. - "Agent refuses to invoke tools": Ensure tool function names and signatures match exactly. MAF is strict about type hints; if a tool expects
strand the agent passesint, it will fail. - "Thread context is lost after the first message": Reuse the same
threadobject across multiplerun_agent()calls. Creating a new thread for each message discards history. - "Orchestrator hangs waiting for human input": MAF's default is fully autonomous. If you need a human-in-the-loop step, explicitly pause the orchestrator and prompt the user.
- "Cannot find my system message in the response": MAF calls it
instructions, notsystem_message. Update your create_agent() call. - "Tool returns a complex object and the agent chokes": MAF requires tools to return JSON-serializable types. If you return a Pandas DataFrame or custom class, serialize it first (to dict or JSON string).
FAQ
Q: Does MAF run my existing AutoGen code unchanged?
No. The agent and tool APIs diverged enough that you need to refactor. Expect 2-3 days per agent, plus testing.
Q: Can I use MAF with my existing Azure OpenAI setup?
Yes, but authentication changes from explicit API keys to DefaultAzureCredential(). This is a security improvement and works in any Azure compute environment (VMs, containers, App Service) automatically.
Q: What if my multi-agent logic is more complex than Sequential or Handoff?
MAF's five orchestration patterns cover most real-world cases. If you need bespoke logic, build a custom orchestrator class inheriting from the base Orchestrator class and define your own run logic.
Q: Is migration reversible?
No. Once you refactor to MAF, reverting to AutoGen is impractical. Test thoroughly in staging before production rollout.
Q: Does this guide cover C#?
The steps are identical in C#, but syntax differs. The patterns - client creation, agent instantiation, tool definition, orchestrator setup - are language-agnostic. Check the Microsoft Foundry docs for C# examples.
Q: What about support for non-Azure models?
MAF supports OpenAI, Anthropic Claude, AWS Bedrock, and Ollama via appropriate client classes. The pattern is the same: create the client, define agents, pass tools, run the orchestrator (Source: Microsoft Foundry blog).
Related coverage
- Microsoft Agent Framework 1.0: Release Candidate Stability and Workflows - Architecture overview and feature breakdown of MAF's orchestration model.
- Agent Tool Registration Patterns: Decorators vs. Classes - Deeper dive into @ai_function syntax and Pydantic Field usage.
- Multi-Agent Orchestration: Sequential vs. Concurrent vs. Handoff - Detailed comparison of the five MAF orchestration patterns with use-case recommendations.
References
- Doran Gao - From AutoGen to Microsoft Agent Framework case study (Medium, January 2026)
- Microsoft Foundry - Microsoft Agent Framework Release Candidate announcement (February 2026)
- Nithin Mohan TK - Migration Guide: From Semantic Kernel & AutoGen to Microsoft Agent Framework, Part 10 (dataa.dev, November 2025)
- Seenivasa Ramadurai - Microsoft Agent Framework: Combining Semantic Kernel & AutoGen for Advanced AI Agents (Dev.to, October 2025)



