AutoGen multi-agent

Written by

in

Intermediate

A single AI agent has limits — it can only do so much on its own. But what happens when you put multiple specialized agents together, each with a distinct role, and let them collaborate on complex tasks? That’s the core idea behind AutoGen, Microsoft’s open-source framework for building multi-agent AI systems.

This guide walks through AutoGen’s architecture, shows you how to build agent teams that collaborate autonomously, and covers real-world patterns for code generation, analysis, and human-in-the-loop workflows.


Why multi-agent?

A single LLM call is stateless and limited by its context window. Multi-agent systems break complex problems into specialized roles:

  • Specialization — each agent has a focused system prompt and tools, making it better at its specific job.
  • Verification — one agent generates, another reviews. Errors that slip past a single agent get caught by a critic.
  • Decomposition — complex tasks split into subtasks that agents handle in parallel or sequence.
  • Human-in-the-loop — agents can pause, ask for approval, and incorporate human feedback before proceeding.

AutoGen (now in version 0.4, rewritten as AutoGen AgentChat) provides the primitives to build these systems: agents, teams, and conversation patterns.

Architecture overview

AUTOGEN MULTI-AGENT ARCHITECTURE Task / User Input AGENT TEAM Coder Agent Writes code based on task requirements Reviewer Agent Reviews code for bugs, style, and correctness Executor Agent Runs code and reports results or errors Feedback loop Termination Condition

AutoGen agents communicate through messages. A team defines how agents take turns (round-robin, selector-based, or custom). A termination condition decides when the conversation is done — after a keyword, a maximum number of turns, or when an agent signals completion.

Setting up AutoGen

pip install autogen-agentchat autogen-ext[openai,azure]

AutoGen 0.4 is a complete rewrite. If you’ve used the older pyautogen package, the API has changed significantly — the new version is more modular and production-ready.

Configure the model client

from autogen_ext.models.openai import AzureOpenAIChatCompletionClient
from azure.identity import DefaultAzureCredential

model_client = AzureOpenAIChatCompletionClient(
    azure_deployment="gpt-4o",
    azure_endpoint="https://your-resource.openai.azure.com/",
    credential=DefaultAzureCredential(),
    model="gpt-4o",
    api_version="2025-01-01-preview",
)

Your first multi-agent team

Let’s build a code-generation team with three agents: a coder, a reviewer, and an executor.

from autogen_agentchat.agents import AssistantAgent, CodeExecutorAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor

coder = AssistantAgent(
    name="coder",
    model_client=model_client,
    system_message="""You are an expert Python developer.
    Write clean, well-documented code to solve the task.
    Always include error handling and type hints.
    When the code is approved and tested, respond with TERMINATE.""",
)

reviewer = AssistantAgent(
    name="reviewer",
    model_client=model_client,
    system_message="""You are a senior code reviewer.
    Review the code for:
    - Correctness and edge cases
    - Security vulnerabilities
    - Performance concerns
    - Code style and readability
    Provide specific, actionable feedback.
    If the code is production-ready, say APPROVED.""",
)

executor = CodeExecutorAgent(
    name="executor",
    code_executor=LocalCommandLineCodeExecutor(work_dir="./workspace"),
)

Assemble the team

termination = TextMentionTermination("TERMINATE")

team = RoundRobinGroupChat(
    participants=[coder, reviewer, executor],
    termination_condition=termination,
    max_turns=12,
)

# Run the team on a task
result = await team.run(
    task="Write a Python function that validates email addresses using regex. Include unit tests."
)

for message in result.messages:
    print(f"[{message.source}]: {message.content[:200]}")

The flow: the coder writes the code, the reviewer checks it, the executor runs it. If the reviewer finds issues, the loop continues. When the coder says “TERMINATE,” the conversation ends.

Selector-based teams

Round-robin is predictable but rigid. For more dynamic conversations, use SelectorGroupChat — a model decides which agent should speak next based on the conversation context:

from autogen_agentchat.teams import SelectorGroupChat

planner = AssistantAgent(
    name="planner",
    model_client=model_client,
    system_message="""You are a project planner.
    Break tasks into clear steps and delegate to the right agent.
    Coordinate the team's work and track progress.""",
)

researcher = AssistantAgent(
    name="researcher",
    model_client=model_client,
    system_message="""You are a research specialist.
    Gather information, find best practices, and provide context
    for the team's decisions.""",
)

team = SelectorGroupChat(
    participants=[planner, coder, reviewer, researcher],
    model_client=model_client,  # used to select the next speaker
    termination_condition=termination,
)

The selector model analyzes each message and picks the most appropriate next agent. The planner might start by breaking down the task, then the researcher gathers requirements, the coder implements, and the reviewer verifies — all orchestrated dynamically.

Tools and function calling

Agents become much more powerful when they can call external tools. Define tools as Python functions:

from autogen_agentchat.agents import AssistantAgent

async def search_database(query: str, limit: int = 10) -> str:
    """Search the product database for matching items."""
    # In production, query your actual database
    results = await db.search(query, limit=limit)
    return json.dumps(results)

async def send_notification(recipient: str, message: str) -> str:
    """Send a notification to a user via email."""
    await email_service.send(recipient, message)
    return f"Notification sent to {recipient}"

support_agent = AssistantAgent(
    name="support",
    model_client=model_client,
    tools=[search_database, send_notification],
    system_message="""You are a customer support agent.
    Use the available tools to look up product information
    and send notifications when needed.""",
)

Human-in-the-loop

For sensitive operations, you’ll want human approval before agents take action. AutoGen supports this through the UserProxyAgent or by adding a handoff mechanism:

from autogen_agentchat.agents import UserProxyAgent

human = UserProxyAgent(
    name="human",
    description="A human user who provides approvals and feedback.",
)

team = RoundRobinGroupChat(
    participants=[planner, coder, human],
    termination_condition=termination,
)

# When running in a console, the human agent prompts for input
# In a web app, you'd connect it to your UI
result = await team.run(
    task="Refactor the authentication module to use OAuth 2.0"
)
Safety first: When agents can execute code or call APIs, always run them in sandboxed environments. Use DockerCommandLineCodeExecutor instead of LocalCommandLineCodeExecutor in production to isolate code execution.

Conversation patterns

PatternImplementationBest for
Round-robinRoundRobinGroupChatPredictable pipelines (write → review → test)
Dynamic selectionSelectorGroupChatComplex tasks where the next speaker depends on context
Two-agent chatDirect agent.run()Simple back-and-forth between two agents
Nested teamsTeams as participants in other teamsHierarchical workflows with sub-teams
SwarmSwarm with handoffsCustomer service routing, escalation flows

Real-world scenario: data analysis pipeline

Here’s a practical example — a team that analyzes a CSV dataset and produces a report:

analyst = AssistantAgent(
    name="analyst",
    model_client=model_client,
    system_message="""You are a data analyst.
    When given a dataset, write Python code using pandas
    to explore the data: shape, dtypes, missing values,
    key statistics, and notable patterns.""",
)

visualizer = AssistantAgent(
    name="visualizer",
    model_client=model_client,
    system_message="""You are a data visualization expert.
    Take the analyst's findings and create matplotlib charts
    that tell a clear story. Save charts as PNG files.
    Use a clean, professional style.""",
)

writer = AssistantAgent(
    name="writer",
    model_client=model_client,
    system_message="""You are a technical writer.
    Synthesize the analysis and visualizations into a
    concise executive summary. Include key findings,
    recommendations, and the charts.
    End with TERMINATE when the report is complete.""",
)

executor = CodeExecutorAgent(
    name="executor",
    code_executor=LocalCommandLineCodeExecutor(work_dir="./analysis"),
)

pipeline = RoundRobinGroupChat(
    participants=[analyst, executor, visualizer, executor, writer],
    termination_condition=TextMentionTermination("TERMINATE"),
    max_turns=20,
)

result = await pipeline.run(
    task="Analyze the sales data in ./data/sales_2024.csv. Find trends, seasonality, and anomalies."
)

AutoGen vs. other frameworks

FeatureAutoGenCrewAILangGraph
Multi-agent patternsRound-robin, selector, swarm, nestedSequential, hierarchicalState machine graphs
Code executionBuilt-in (local + Docker)Via toolsVia tools
Human-in-the-loopNative UserProxyAgentHuman input toolInterrupt nodes
LanguagePython, .NET (preview)PythonPython, JavaScript
Model supportOpenAI, Azure, Ollama, etc.OpenAI, Azure, OllamaVia LangChain
Best forResearch, complex collaborationRole-based agent teamsDeterministic workflows

AutoGen excels at open-ended collaboration where agents need to iterate and refine. LangGraph is stronger for workflows where you need precise control over every state transition. CrewAI offers a simpler API for straightforward role-based teams.

Production considerations

  1. Sandbox code execution — always use Docker-based executors in production. Never let agents run arbitrary code on your host machine.
  2. Set turn limits — agents can get stuck in loops. Always configure max_turns and combine with timeout-based termination.
  3. Monitor token usage — multi-agent conversations consume tokens fast. Each agent turn is a full API call. Track costs per conversation.
  4. Log everything — save the full conversation transcript for debugging. AutoGen supports structured logging out of the box.
  5. Start simple — begin with two agents (generator + reviewer) and add complexity only when needed. More agents means more coordination overhead.
  6. Test termination conditions — the most common production issue is agents that never terminate. Test edge cases where the task can’t be completed.

The .NET preview

AutoGen also has a .NET version (Microsoft.AutoGen) in preview. It follows the same multi-agent concepts but integrates with the .NET ecosystem:

using Microsoft.AutoGen.AgentChat;
using Microsoft.AutoGen.Contracts;

var coder = new AssistantAgent(
    name: "coder",
    modelClient: azureClient,
    systemMessage: "You are an expert C# developer...");

var reviewer = new AssistantAgent(
    name: "reviewer",
    modelClient: azureClient,
    systemMessage: "You are a senior code reviewer...");

var team = new RoundRobinGroupChat(
    [coder, reviewer],
    terminationCondition: new MaxMessageTermination(10));

var result = await team.RunAsync("Build a REST API for a todo app");

Next steps

  1. Clone the repo: github.com/microsoft/autogen — check the /python/samples folder for patterns.
  2. Start with two agents — a coder and a reviewer working on a real task in your codebase.
  3. Add code execution — let the executor run the generated code and feed errors back for automatic debugging.
  4. Explore the docs: microsoft.github.io/autogen
What would your agent team look like? Multi-agent systems shine when tasks need multiple perspectives. Share what you’d build in the comments — research pipelines, code review teams, data analysis squads — and I’ll help you design the architecture.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *