LangGraph vs AutoGen
Workflow orchestration vs conversation-centric programming
Overview
Workflow orchestration vs conversation-centric programming
Verdict
Workflow orchestration vs conversation-centric programming
Details
LangGraph vs AutoGen
Overview
A detailed comparison of two popular multi-agent frameworks: LangGraph (by LangChain) and AutoGen (by Microsoft). Both enable building sophisticated AI agent systems, but with fundamentally different approaches.
Quick Comparison Table
| Feature | LangGraph | AutoGen |
|---|---|---|
| Maintainer | LangChain | Microsoft |
| Paradigm | Stateful workflows (graph-based) | Conversation-centric |
| State Management | Explicit TypedDict state | Message-based conversation |
| Control Flow | Explicit edges and conditions | Implicit via conversation |
| Human-in-the-Loop | Built-in interrupt/resume | Built-in human proxy |
| Persistence | Checkpointers (memory, SQLite, Postgres) | Conversation history |
| Streaming | Native streaming support | Streaming support |
| Multi-Agent | Graph nodes as agents | Agent-to-agent conversation |
| Learning Curve | Moderate (graph concepts) | Low (conversation model) |
| Best For | Complex workflows, pipelines | Multi-agent conversations |
Philosophy
LangGraph
"Build stateful, multi-actor applications with LLMs"
LangGraph treats agent systems as graphs:
- Nodes represent actions (LLM calls, tools, etc.)
- Edges define control flow
- State flows through the graph
- Explicit, deterministic execution
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
messages: list[BaseMessage]
context: dict
iteration: int
builder = StateGraph(AgentState)
builder.add_node("research", research_node)
builder.add_node("write", write_node)
builder.add_edge("research", "write")
builder.set_entry_point("research")
builder.add_edge("write", END)
workflow = builder.compile()
AutoGen
"Build multi-agent conversation systems"
AutoGen treats agent systems as conversations:
- Agents have roles and personalities
- Agents converse with each other
- Messages flow between agents
- Implicit, emergent behavior
from autogen import ConversableAgent, UserProxyAgent
researcher = ConversableAgent(
name="Researcher",
system_message="You are a research assistant.",
llm_config=llm_config,
)
writer = ConversableAgent(
name="Writer",
system_message="You are a content writer.",
llm_config=llm_config,
)
researcher.initiate_chat(
writer,
message="Research and write about AI agents",
)
State Management
LangGraph
Explicit, typed state:
from typing import TypedDict, Annotated, List
from langgraph.graph import add_messages
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
context: dict
iteration: int
status: str
def research_node(state: AgentState) -> dict:
# Access state
messages = state["messages"]
context = state["context"]
# Return updates
return {
"messages": [new_message],
"context": {"research": results},
"iteration": state["iteration"] + 1,
}
Benefits:
- Type-safe state definition
- Explicit state transitions
- Easy to debug and test
- State persists across checkpoints
AutoGen
Message-based state:
researcher = ConversableAgent(
name="Researcher",
system_message="You are a research assistant.",
llm_config=llm_config,
)
writer = ConversableAgent(
name="Writer",
system_message="You are a content writer.",
llm_config=llm_config,
)
# State is implicit in conversation history
researcher.initiate_chat(
writer,
message="Research and write about AI agents",
)
# Access conversation history
print(researcher.chat_messages)
print(writer.chat_messages)
Benefits:
- Natural conversation flow
- Less boilerplate
- Emergent behavior
- Easy to add/remove agents
Control Flow
LangGraph
Explicit control flow:
from langgraph.graph import StateGraph, END
from typing import Literal
def should_continue(state: AgentState) -> Literal["write", "finalize"]:
if state["iteration"] >= 3:
return "finalize"
return "write"
builder = StateGraph(AgentState)
builder.add_node("research", research_node)
builder.add_node("write", write_node)
builder.add_node("finalize", finalize_node)
builder.add_edge("research", "write")
builder.add_conditional_edges(
"write",
should_continue,
{"write": "write", "finalize": "finalize"},
)
builder.add_edge("finalize", END)
workflow = builder.compile()
Features:
- Conditional edges
- Parallel execution
- Loops and cycles
- Human interrupts
AutoGen
Implicit control flow:
researcher = ConversableAgent(
name="Researcher",
system_message="You are a research assistant. TERMINATE when done.",
llm_config=llm_config,
max_consecutive_auto_reply=3,
)
writer = ConversableAgent(
name="Writer",
system_message="You are a content writer. TERMINATE when done.",
llm_config=llm_config,
max_consecutive_auto_reply=3,
)
user = UserProxyAgent(
name="User",
human_input_mode="TERMINATE",
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""),
)
# Control via system messages and termination conditions
user.initiate_chat(
researcher,
message="Research and write about AI agents",
max_turns=10,
)
Features:
- Termination messages
- Max turns limit
- Human proxy for control
- Group chat for multi-agent
Human-in-the-Loop
LangGraph
Built-in interrupt and resume:
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
workflow = builder.compile(checkpointer=checkpointer)
# Run with interrupt
config = {"configurable": {"thread_id": "session-1"}}
workflow.invoke(input_data, config=config)
# Interrupt before node
builder.interrupt_before("review")
# Resume after human input
snapshot = workflow.get_state(config)
if snapshot.next:
# Human reviewed, resume
workflow.invoke(None, config=config)
AutoGen
Human proxy agent:
user_proxy = UserProxyAgent(
name="Human",
human_input_mode="ALWAYS", # Always ask for input
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""),
)
# Human participates in conversation
researcher.initiate_chat(
user_proxy,
message="Research about AI agents",
)
# Or human-in-the-loop for specific agents
assistant = ConversableAgent(
name="Assistant",
system_message="You are helpful.",
human_input_mode="TERMINATE", # Ask until TERMINATE
)
Multi-Agent Patterns
LangGraph
Nodes as specialized agents:
from langgraph.graph import StateGraph
class MultiAgentState(TypedDict):
messages: list[BaseMessage]
research: dict
draft: str
review: dict
builder = StateGraph(MultiAgentState)
# Specialized agent nodes
builder.add_node("researcher", researcher_node)
builder.add_node("writer", writer_node)
builder.add_node("editor", editor_node)
builder.add_node("manager", manager_node)
# Define workflow
builder.add_edge("researcher", "writer")
builder.add_edge("writer", "editor")
builder.add_edge("editor", "manager")
builder.add_conditional_edges(
"manager",
should_loop,
{"writer": "writer", "finalize": "finalize"},
)
workflow = builder.compile()
AutoGen
Agents in conversation:
from autogen import GroupChat, GroupChatManager
researcher = ConversableAgent(name="Researcher", ...)
writer = ConversableAgent(name="Writer", ...)
editor = ConversableAgent(name="Editor", ...)
manager = ConversableAgent(name="Manager", ...)
groupchat = GroupChat(
agents=[researcher, writer, editor, manager],
messages=[],
max_round=12,
speaker_selection_method="auto",
)
manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config)
researcher.initiate_chat(
manager,
message="Create a blog post about AI agents",
)
Persistence
LangGraph
Multiple checkpointers:
# In-memory (development)
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
# SQLite (persistent)
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
# PostgreSQL (production)
from langgraph.checkpoint.postgres import PostgresSaver
checkpointer = PostgresSaver(conn)
workflow = builder.compile(checkpointer=checkpointer)
# Time travel
history = workflow.get_state_history(config)
for checkpoint in history:
print(checkpoint.values)
AutoGen
Conversation history:
# Access conversation history
print(agent.chat_messages)
# Save/restore conversations
import json
history = json.dumps(agent.chat_messages)
# Restore
agent.chat_messages = json.loads(history)
Streaming
LangGraph
Native streaming:
async for event in workflow.astream(input_data, config=config):
for node_name, node_output in event.items():
print(f"[{node_name}] {node_output}")
yield node_output
# Stream state
async for state in workflow.astream(input_data, config=config, stream_mode="values"):
print(f"Step: {state['iteration']}")
AutoGen
Streaming chat:
# Stream chat completion
for chunk in llm_client.stream(messages):
print(chunk.choices[0].delta.content, end='', flush=True)
# Agent streaming
async for message in agent.a_generate_reply_stream(messages):
print(message.content, end='', flush=True)
Error Handling
LangGraph
Node-level error handling:
from langgraph.errors import NodeInterrupt
async def resilient_node(state: AgentState) -> dict:
try:
result = await perform_action()
return {"result": result}
except Exception as e:
# Log and continue
return {"error": str(e), "result": None}
# Or raise to stop
# raise NodeInterrupt(f"Failed: {e}")
AutoGen
Conversation-level error handling:
try:
agent.initiate_chat(
other_agent,
message="Do something",
)
except Exception as e:
print(f"Conversation error: {e}")
# Handle or retry
Best Use Cases
Choose LangGraph When:
- ✅ Complex workflows: Multi-step processes with clear stages
- ✅ State management: Need explicit state tracking
- ✅ Persistence: Need to save/resume workflows
- ✅ Human-in-the-loop: Need interrupts and approvals
- ✅ Parallel execution: Need concurrent branches
- ✅ Testing: Need deterministic, testable workflows
Choose AutoGen When:
- ✅ Multi-agent conversations: Natural conversation flows
- ✅ Rapid prototyping: Quick setup and experimentation
- ✅ Emergent behavior: Let agents figure out the flow
- ✅ Human participation: Humans as conversation participants
- ✅ Group dynamics: Multi-agent group discussions
- ✅ Flexibility: Less rigid structure
Migration Guide
From LangGraph to AutoGen
# LangGraph
builder = StateGraph(AgentState)
builder.add_node("research", research_node)
builder.add_node("write", write_node)
builder.add_edge("research", "write")
# AutoGen
researcher = ConversableAgent(name="Researcher", ...)
writer = ConversableAgent(name="Writer", ...)
researcher.initiate_chat(writer, message="Research and write")
From AutoGen to LangGraph
# AutoGen
researcher.initiate_chat(writer, message="Research and write")
# LangGraph
builder = StateGraph(AgentState)
builder.add_node("researcher", researcher_node)
builder.add_node("writer", writer_node)
builder.add_edge("researcher", "writer")
workflow = builder.compile()
result = workflow.invoke({"messages": [HumanMessage(content="Research and write")]})
Conclusion
Both frameworks are powerful tools for building AI agent systems. The choice depends on your needs:
- LangGraph excels at structured workflows with explicit state, persistence, and human-in-the-loop support.
- AutoGen excels at multi-agent conversations with natural interaction patterns and emergent behavior.
For production systems requiring reliability and control, I recommend LangGraph. For rapid prototyping and conversational applications, AutoGen is excellent.
Resources
- LangGraph Documentation: https://langchain-ai.github.io/langgraph/
- LangGraph GitHub: https://github.com/langchain-ai/langgraph
- AutoGen Documentation: https://microsoft.github.io/autogen/
- AutoGen GitHub: https://github.com/microsoft/autogen
Last updated: May 2026
