Skip to main content

AutoGen

AutoGen, developed by Microsoft Research, is a framework for building multi-agent systems through conversable agents that communicate via message passing. Its core design principle is that complex tasks can be solved by having specialized agents engage in structured conversations, much like a team collaborating in a group chat.

Core Concepts

Conversable Agents

Every agent in AutoGen inherits from ConversableAgent, which provides a unified interface for sending and receiving messages, generating replies, and executing code.

from autogen import ConversableAgent

agent = ConversableAgent(
name="assistant",
system_message="You are a helpful AI assistant.",
llm_config={"model": "gpt-4o", "temperature": 0},
)

The key property of conversable agents is that they can talk to each other. An agent generates a reply based on received messages, then sends that reply back, creating a conversation loop that continues until a termination condition is met.

Agent Types

AutoGen provides several specialized agent types built on the conversable agent base.

Agent TypePurpose
AssistantAgentLLM-powered agent that generates responses and code
UserProxyAgentRepresents the human user; can execute code and solicit human input
ConversableAgentBase class for building custom agents
GroupChatManagerCoordinates multi-agent group conversations

AssistantAgent and UserProxyAgent

The most common AutoGen pattern pairs an AssistantAgent (the AI) with a UserProxyAgent (the human proxy).

from autogen import AssistantAgent, UserProxyAgent

assistant = AssistantAgent(
name="analyst",
system_message="""You are a data analyst. When given a question, write
Python code to analyze the data and answer it. Always include
visualizations when appropriate.""",
llm_config={
"model": "gpt-4o",
"temperature": 0,
},
)

user_proxy = UserProxyAgent(
name="user",
human_input_mode="TERMINATE", # Ask for input only when terminating
max_consecutive_auto_reply=5,
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""),
code_execution_config={
"work_dir": "coding_workspace",
"use_docker": False, # Set True in production for sandboxing
},
)

# Start the conversation
user_proxy.initiate_chat(
assistant,
message="Analyze the top 10 programming languages by GitHub stars in 2025.",
)

:::info Human Input Modes The human_input_mode parameter controls when AutoGen asks for real human input:

  • ALWAYS: Asks the human for input at every turn.
  • TERMINATE: Only asks when the conversation is about to end.
  • NEVER: Fully autonomous, never asks for human input. :::

Conversation Flow

  1. user_proxy sends the initial message to assistant.
  2. assistant generates a reply (often containing Python code).
  3. user_proxy automatically executes the code in a sandboxed environment.
  4. The execution result is sent back to assistant.
  5. assistant reviews the output and either refines or produces a final answer with "TERMINATE."
  6. The conversation ends when the termination condition is met.

Code Execution

One of AutoGen's standout features is built-in code execution. The UserProxyAgent can automatically run code blocks generated by assistant agents.

user_proxy = UserProxyAgent(
name="executor",
code_execution_config={
"work_dir": "output",
"use_docker": True, # Sandboxed execution
"timeout": 120, # Max seconds per code block
"last_n_messages": 3, # Look at last 3 messages for code
},
human_input_mode="NEVER",
)

:::warning Security Considerations Always use use_docker=True in production environments. Without Docker, generated code runs directly on the host machine with full access to the filesystem and network. Docker sandboxing significantly reduces the blast radius of malicious or buggy generated code. :::

Custom Code Execution

For more control, you can configure a custom code executor.

from autogen.coding import LocalCommandLineCodeExecutor

executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="sandbox",
functions=[], # Optional: pre-registered Python functions
)

user_proxy = UserProxyAgent(
name="executor",
code_execution_config={"executor": executor},
human_input_mode="NEVER",
)

Group Chat

Group chat enables multiple agents to collaborate in a shared conversation, managed by a GroupChatManager that decides who speaks next.

from autogen import GroupChat, GroupChatManager

# Define specialized agents
researcher = AssistantAgent(
name="researcher",
system_message="""You are a research specialist. Search for information
and present findings with citations. Always be thorough.""",
llm_config={"model": "gpt-4o"},
)

coder = AssistantAgent(
name="coder",
system_message="""You are a Python developer. Write clean, well-documented
code. Always include error handling and type hints.""",
llm_config={"model": "gpt-4o"},
)

reviewer = AssistantAgent(
name="reviewer",
system_message="""You are a code reviewer. Review code for correctness,
performance, and security. Be constructive and specific. When the solution
is satisfactory, respond with TERMINATE.""",
llm_config={"model": "gpt-4o"},
)

user_proxy = UserProxyAgent(
name="admin",
human_input_mode="NEVER",
code_execution_config={"work_dir": "group_work", "use_docker": True},
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""),
)

# Create group chat
group_chat = GroupChat(
agents=[user_proxy, researcher, coder, reviewer],
messages=[],
max_round=15,
speaker_selection_method="auto", # LLM decides who speaks next
)

manager = GroupChatManager(
groupchat=group_chat,
llm_config={"model": "gpt-4o"},
)

# Start the multi-agent collaboration
user_proxy.initiate_chat(
manager,
message="""Build a Python script that fetches the top 5 trending
repositories from GitHub API and generates a summary report.""",
)

Speaker Selection Methods

MethodDescription
autoLLM decides the next speaker based on conversation context
round_robinAgents speak in a fixed rotating order
randomRandom agent selection
manualHuman selects the next speaker at each turn
Custom functionYour own logic for speaker selection
def custom_speaker_selection(last_speaker, groupchat):
"""Custom logic: always have the reviewer speak after the coder."""
if last_speaker.name == "coder":
return reviewer
return "auto" # Fall back to LLM selection for other cases

group_chat = GroupChat(
agents=[user_proxy, researcher, coder, reviewer],
messages=[],
speaker_selection_method=custom_speaker_selection,
)

Nested Chats

Nested chats allow an agent to trigger a separate, contained conversation as part of its reply generation. This is useful for complex sub-tasks.

researcher = AssistantAgent(
name="researcher",
llm_config={"model": "gpt-4o"},
)

analyst = AssistantAgent(
name="analyst",
llm_config={"model": "gpt-4o"},
)

# Register a nested chat: when user_proxy receives a message from the
# manager, it triggers a sub-conversation between researcher and analyst
user_proxy.register_nested_chats(
[
{
"recipient": researcher,
"message": "Research the following topic thoroughly.",
"max_turns": 3,
"summary_method": "reflection_with_llm",
},
{
"recipient": analyst,
"message": "Analyze the research findings and provide recommendations.",
"max_turns": 2,
"summary_method": "reflection_with_llm",
},
],
trigger=manager,
)

:::tip Nested Chat Summaries The summary_method parameter controls how the nested conversation is summarized before being returned to the outer conversation. "reflection_with_llm" uses an LLM to generate a concise summary, while "last_msg" simply uses the final message. :::

Custom Agents

You can build custom agents by subclassing ConversableAgent and overriding the reply generation method.

from autogen import ConversableAgent
import json

class DataValidationAgent(ConversableAgent):
"""An agent that validates data quality before passing it downstream."""

def __init__(self, validation_rules: dict, **kwargs):
super().__init__(**kwargs)
self.validation_rules = validation_rules
self.register_reply(
trigger=ConversableAgent,
reply_func=self._validate_data,
)

def _validate_data(self, recipient, messages, sender, config):
"""Custom reply function that validates incoming data."""
last_message = messages[-1].get("content", "")

# Attempt to parse and validate
try:
data = json.loads(last_message)
errors = []
for field, rule in self.validation_rules.items():
if field not in data:
errors.append(f"Missing required field: {field}")
elif rule == "positive" and data[field] <= 0:
errors.append(f"Field '{field}' must be positive")

if errors:
return True, f"Validation failed:\n" + "\n".join(errors)
return True, "Validation passed. Data is clean."
except json.JSONDecodeError:
return True, "Error: Input is not valid JSON."

validator = DataValidationAgent(
name="validator",
validation_rules={"age": "positive", "name": "required"},
llm_config=False, # No LLM needed -- pure logic
)

Function Calling

AutoGen supports registering Python functions that agents can call directly.

from autogen import register_function

def get_stock_price(symbol: str) -> str:
"""Get the current stock price for a given ticker symbol."""
# Simulated implementation
prices = {"AAPL": 195.50, "GOOGL": 175.20, "MSFT": 420.00}
price = prices.get(symbol.upper(), None)
if price:
return f"{symbol.upper()}: ${price}"
return f"Symbol {symbol} not found."

# Register with both the caller and executor
register_function(
get_stock_price,
caller=assistant, # The agent that decides to call the function
executor=user_proxy, # The agent that executes the function
description="Get the current stock price for a ticker symbol.",
)

Pros and Cons

Strengths

  • Conversation-first design: Multi-agent collaboration through natural message passing is intuitive.
  • Built-in code execution: First-class support for generating and running code with Docker sandboxing.
  • Flexible group chat: Sophisticated speaker selection and conversation management.
  • Microsoft ecosystem: Strong integration with Azure OpenAI and enterprise tools.
  • Nested chats: Enables complex, hierarchical agent workflows.

Weaknesses

  • Less structured than graph-based: No explicit state machine or graph; control flow emerges from conversations.
  • Debugging complexity: Tracing multi-agent conversations with nested chats can be challenging.
  • Termination sensitivity: Poorly defined termination conditions lead to infinite conversations or premature stops.
  • Limited streaming: Streaming support is less mature than LangGraph.
  • API evolution: The framework is undergoing significant changes (AutoGen 0.4+ / AG2 fork).

:::warning AutoGen Versioning AutoGen's ecosystem has fragmented. The original Microsoft Research project and the community-driven AG2 fork have diverged. When consulting documentation, ensure you are referencing the correct version for your project. :::

Interview Talking Points

  • Explain how AutoGen's conversation-based orchestration differs from LangGraph's graph-based approach.
  • Describe the roles of AssistantAgent vs. UserProxyAgent and why the separation matters.
  • Walk through a group chat scenario: how does the GroupChatManager decide who speaks next?
  • Discuss code execution sandboxing -- why is Docker important, and what are the risks without it?
  • Compare nested chats with LangGraph's subgraphs as mechanisms for hierarchical agent composition.