AI

Porting AutoGen to Microsoft Agent Framework: what breaks

By · Mon Oct 19 2026 · 10 min read · 0 views

View as a Web Story

AISoftware#ai agents#python#AutoGen#Microsoft Agent Framework#migration

Microsoft and Python logos with an arrow from AutoGen code to Agent Framework code

An AutoGen to Microsoft Agent Framework migration is mostly a rename, except for four defaults that change silently. We ported a two-agent writer and reviewer team on Python 3.15.0, from AutoGen 0.7.5 to Agent Framework 1.22.0, and measured the differences. The agent forgot its history, the tool loop made twice as many model calls, and the team result held one useless message. Installing the umbrella package also pulled 699 MB. This guide shows the code before and after, the numbers, and the fixes.

Is AutoGen still maintained?

No. The AutoGen README states that Microsoft is not providing bug fixes, security fixes, new features, or support for the project, according to the AutoGen repository on GitHub. It calls Microsoft Agent Framework the enterprise-ready successor and points existing users to a migration guide.

AutoGen is an open-source Python framework from Microsoft Research for building multi-agent systems with large language models. Microsoft Agent Framework is the successor SDK from the AutoGen and Semantic Kernel teams, available for Python and .NET. Microsoft declared version 1.0 on April 3, 2026, with stable APIs and a commitment to long-term support, according to the Agent Framework 1.0 announcement.

Some third-party guides say AutoGen still receives security fixes. The README we read says otherwise. For production code, treat that as the decision: staying means no security patches from Microsoft.

What maps to what?

Most AutoGen classes have a direct Agent Framework equivalent, and the names change more than the ideas. The table below combines the AutoGen migration guide on Microsoft Learn with what we ran.

Brand-colored map from AutoGen classes to their Microsoft Agent Framework equivalents

AutoGen 0.7 Agent Framework 1.x What changes
AssistantAgent(model_client=...) Agent(client=...) Parameter renamed
system_message= instructions= Parameter renamed
FunctionTool or a bare async function @tool decorator Schema inferred from the signature
agent.run(task=...) agent.run(...) Task is the first positional argument
RoundRobinGroupChat GroupChatBuilder with selection_func No built-in round robin
TextMentionTermination("APPROVE") termination_condition= callable You write the check
GraphFlow WorkflowBuilder Data flow replaces control flow
AgentTool agent.as_tool() Same idea, new method

GroupChatBuilder is the Agent Framework class that assembles several agents into a turn-taking chat. The orchestration row is the big one. Microsoft's guide says AutoGen pairs an event-driven core with a high-level Team, while Agent Framework centers on a typed, graph-based Workflow. Group chat is still available through the orchestrations package, but it runs on top of that workflow engine, and that is where our surprises came from.

What did our test app look like in AutoGen?

Our test setup was a clean Python 3.15.0 virtual environment on an M-series Mac, with autogen-agentchat 0.7.5 in one and agent-framework 1.22.0 in another. Our app is a writer agent with one price-lookup tool and a reviewer agent that approves the draft. We used a replay client so the run needs no API key. This is the AutoGen version, and it runs as written on autogen-agentchat 0.7.5.

import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination

async def lookup_price(sku: str) -> str:
    """Return the price for a SKU."""
    return f"{sku}: $19"

writer = AssistantAgent("writer", model_client=writer_client, tools=[lookup_price],
                        system_message="Write.", reflect_on_tool_use=True)
reviewer = AssistantAgent("reviewer", model_client=reviewer_client,
                          system_message="Review. Say APPROVE.")
team = RoundRobinGroupChat([writer, reviewer],
    termination_condition=TextMentionTermination("APPROVE") | MaxMessageTermination(6))
result = await team.run(task="Quote SKU A1")

The run returned five messages: the user task, the tool call request, the tool result, the writer's draft and the reviewer's verdict. The stop reason read "Text 'APPROVE' mentioned". Everything a caller needs sits in result.messages.

One setup detail: the replay client refused tools until we passed a model_info with function_calling set to true. Real clients carry this already, so it only matters for test doubles.

Advertisement

What does the same app look like in Agent Framework?

The ported app needs a decorator, a selection function and a termination callable. This version runs on agent-framework-core 1.22.0 and agent-framework-orchestrations 1.3.2.

from agent_framework import Agent, tool
from agent_framework_orchestrations import GroupChatBuilder

@tool
def lookup_price(sku: str) -> str:
    """Return the price for a SKU."""
    return f"{sku}: $19"

writer = Agent(name="writer", client=writer_client, instructions="Write.", tools=[lookup_price])
reviewer = Agent(name="reviewer", client=reviewer_client, instructions="Review. Say APPROVE.")

workflow = GroupChatBuilder(
    participants=[writer, reviewer],
    selection_func=lambda state: "writer" if state.current_round % 2 == 0 else "reviewer",
    termination_condition=lambda conversation: any("APPROVE" in (m.text or "") for m in conversation),
    max_rounds=6,
    output_from="all",
).build()
result = await workflow.run("Quote SKU A1")

Two lines here carry the lessons. selection_func replaces the round robin you got for free. And output_from="all" is there because of the third silent change below. Without it, this code runs and returns the wrong thing.

For tests, we wrote a fake chat client by subclassing BaseChatClient together with FunctionInvocationLayer, then returned canned ChatResponse objects from _inner_get_response. The streaming path needs its own implementation. Our fake broke when the group chat asked for a stream, so we ran the workflow without streaming.

Does Agent Framework remember the conversation?

Not unless you ask. In our test, the second call to an AutoGen AssistantAgent sent the model 4 messages. The same second call to an Agent Framework Agent sent 1 message. With an AgentSession passed in, it sent 3.

Chart of messages the model saw on the second call: AutoGen 4, Agent Framework without a session 1, Agent Framework with a session 3

The AutoGen count of 4 is the system message, the first question, the first answer and the second question. The Agent Framework count of 1 is only the second question. Microsoft's guide confirms the design: an Agent is stateless and does not keep history between invocations, unlike AssistantAgent. A chatbot ported without changes forgets every previous turn and never raises an error.

AgentSession is the Agent Framework object that holds one conversation's history between runs. The fix is to create a session and pass it to every call:

session = agent.create_session()
await agent.run("first question", session=session)
await agent.run("second question", session=session)

Store one session per conversation. In a web app, keep sessions in a store keyed by user and conversation ID. A single session object shared across users would leak one person's history to another.

Why did the tool loop double the model calls?

Because Agent Framework keeps calling the model after a tool runs, and AutoGen's default does not. In our test, one tool turn took 1 model call in AutoGen's default setup and 2 in Agent Framework. AutoGen returned the raw tool result, "A1: $19", as a ToolCallSummaryMessage. Agent Framework returned a final sentence, "Final: $19."

Microsoft's guide states the difference: AssistantAgent is single-turn unless you raise max_tool_iterations, while Agent is multi-turn by default and keeps invoking tools until it can return a final answer. That is better behavior for users and a higher bill for you.

The size of the bill depends on your prompt. The second call re-sends the whole conversation plus the tool result, so a 6,000-token context costs about 6,000 extra input tokens per tool turn. For example, at an input price of $2 per million tokens, that is $0.012 per tool turn, which is $12 for every 1,000 tool turns. Prompt caching lowers it. Agents that chain five tools pay the loop five times.

If you were using reflect_on_tool_use=True in AutoGen, as our sample does, you already paid for the second call, and nothing changes. If you were not, budget for it before you ship.

What happens to the team result?

The default group chat output is a one-line termination notice, not the conversation. Our AutoGen team returned five messages in result.messages. The Agent Framework workflow returned 31 events and exactly one output by default: "The group chat has reached its termination condition."

Those 31 events were 8 executor invocations, 8 completions, 5 superstep starts, 5 superstep completions, 4 group chat events and 1 output. The writer's draft and the reviewer's approval were inside the events, but not in the output.

Setting output_from="all" changed the result to three outputs: the writer's response with its tool call and tool result, the reviewer's verdict, and the termination notice. That is the transcript you wanted. Test your port on the return value, not just on whether it runs.

This is the most dangerous change of the four, because a smoke test passes. The code finishes, the logs look busy, and the value you saved to your database is the termination sentence.

How much does the install weigh?

The obvious command installs far more than you need. pip install agent-framework pulled 699 MB of site-packages and 198 packages in our clean Python 3.15.0 environment. Installing agent-framework-core plus agent-framework-orchestrations pulled 36 MB and 13 packages. AutoGen's autogen-agentchat plus autogen-ext pulled 46 MB and 13 packages.

Bar chart of install size: agent-framework 699 MB, autogen 46 MB, agent-framework-core plus orchestrations 36 MB

Install route Disk size Packages
pip install agent-framework 699 MB 198
pip install autogen-agentchat autogen-ext 46 MB 13
pip install agent-framework-core agent-framework-orchestrations 36 MB 13

The umbrella package depends on agent-framework-core[all], which brings every connector. In our environment that was 29 agent-framework packages, 21 of them pre-release. That matters for serverless deployments with a size limit and for container build times. Install the core package plus only the connector you use, such as agent-framework-openai.

How do you test the port without an API key?

Write a fake chat client, and assert on what the model received and what the app returned. This is the double we used for every number in this guide. It runs offline and costs nothing.

from agent_framework import BaseChatClient, ChatResponse, Content, FunctionInvocationLayer, Message

class FakeClient(FunctionInvocationLayer, BaseChatClient):
    def __init__(self, script):
        super().__init__()
        self.script = list(script)   # tuples are tool calls, strings are replies
        self.calls = 0

    def _inner_get_response(self, *, messages, stream, options, **kwargs):
        async def go():
            self.calls += 1
            item = self.script.pop(0)
            if isinstance(item, tuple):
                call = Content.from_function_call(call_id="1", name=item[0], arguments=item[1])
                return ChatResponse(messages=[Message("assistant", [call])])
            return ChatResponse(messages=[Message("assistant", [item])])
        return go()

Three assertions then guard the four changes. Assert that client.calls equals the number of model calls you budgeted, which catches the doubled tool loop. Assert that the second turn of a conversation sees more than one message, which catches the missing session. And assert that the workflow output contains the reviewer's text, which catches the termination notice.

The class mixes FunctionInvocationLayer into BaseChatClient, the same pattern the OpenAI client in agent-framework-openai uses. Keep that order, because the layer has to wrap the base class to run the tool loop. Remember that this fake supports non-streaming runs only. If your app streams, extend _inner_get_response to return a stream when stream is true.

How stable is the new API?

Stable at 1.0, but the packages around it still move. The Agent Framework release python-1.17.0, dated September 3, 2026, lists a breaking change: it restores sequence-only agent middleware inputs and removes the experimental agent-hooks core extra, according to the python-1.17.0 release notes.

Our environment had core at 1.22.0, orchestrations at 1.3.2 and the OpenAI connector at 1.17.0, so the versions are independent. Pin all of them in a lockfile and read each changelog before you bump. Do not rely on a floating range.

One more limit from the guide: AutoGen offered embedded and experimental distributed runtimes, while Agent Framework focuses on single-process composition today, with distributed execution planned. If your AutoGen system spreads agents across machines, you cannot port that part yet.

Should you port now or wait?

Port now if you run AutoGen in production, because staying means no security patches. Wait only if you depend on AutoGen's distributed runtime, and even then start porting the single-process parts.

Your situation Move
Production AutoGen, single process Port now; the work is small
Production AutoGen, distributed runtime Port agents and tools now; keep the runtime until Microsoft ships one
Prototype or research notebook Optional; freeze the version
New project Start on Agent Framework

We would port in this order. First, swap the model client and one single agent, and write a test with a fake client. Second, port tools to @tool. Third, add sessions wherever history matters. Fourth, port teams, and assert on the returned transcript. Last, trim the install to the core package and the connectors you use.

The bottom line is that the code port is quick and the behavior port is where time goes. Every one of the four changes passes a smoke test. Write assertions on message counts, tool-call counts and the saved transcript, and the migration becomes a checklist instead of a surprise.

Advertisement

FAQ

Is AutoGen deprecated?

Effectively yes. The AutoGen README says Microsoft is not providing bug fixes, security fixes, new features, or support for the project, and names Microsoft Agent Framework as its successor. Existing users are pointed to a migration guide. New projects should start on Agent Framework.

How do I migrate from AutoGen to Microsoft Agent Framework?

Rename AssistantAgent to Agent, model_client to client and system_message to instructions. Replace FunctionTool with the @tool decorator and RoundRobinGroupChat with GroupChatBuilder plus a selection function. Then add sessions for history and set output_from to all so a group chat returns the full transcript.

Why does my Agent Framework agent forget previous messages?

An Agent is stateless by default. In our test the second call sent the model 1 message, against 4 in AutoGen. Create a session with agent.create_session() and pass it to every run call. With a session, the second call sent 3 messages. Keep one session per conversation.

Why does pip install agent-framework take 699 MB?

The umbrella package depends on agent-framework-core with the all extra, which installs every connector. In our clean Python 3.15.0 environment that was 198 packages. Installing agent-framework-core and agent-framework-orchestrations took 36 MB and 13 packages. Add only the connector you need.

Does Agent Framework make more model calls than AutoGen?

For tool use, yes by default. One tool turn took 2 model calls in Agent Framework and 1 in AutoGen's default setup, because Agent Framework keeps going until it has a final answer. AutoGen with reflect_on_tool_use set to true makes the same 2 calls.

Comments

Loading…

Sign in to join the conversation.

Related posts

Logos of Fin, HubSpot, Zendesk and Salesforce Agentforce beside a price per resolved support ticket

What an AI-resolved support ticket really costs in 2026

AI customer support agent pricing per resolution runs from $0.50 to about $4.00 for the same solved ticket. HubSpot charges $0.50 per resolved conversation, Fin charges $0.99, and Zendesk charges

Mon Oct 19 2026 · 10 min read · 0 views

AI