Lesson 4 of 6·11 min read

Multi-Agent with LangGraph

LangGraph isn't just for single agents — it's the most powerful framework for multi-agent orchestration. Multiple specialized agents work together in coordination, controlled by a state graph.

Supervisor Pattern

The most common multi-agent pattern: A supervisor agent decides which worker becomes active next:

from langgraph.graph import StateGraph, END

def supervisor_node(state: AgentState) -> dict:
    # LLM decides which agent goes next
    response = supervisor_llm.invoke(
        f"Current task: {state['task']}\n"
        f"Results so far: {state['results']}\n"
        f"Available agents: researcher, analyst, writer\n"
        f"Which agent should work next? (or FINISH)"
    )
    return {"next_agent": response.content}

Supervisor Routing

graph = StateGraph(AgentState)
graph.add_node("supervisor", supervisor_node)
graph.add_node("researcher", researcher_node)
graph.add_node("analyst", analyst_node)
graph.add_node("writer", writer_node)

graph.add_conditional_edges("supervisor", route_to_agent, {
    "researcher": "researcher",
    "analyst": "analyst",
    "writer": "writer",
    "FINISH": END
})
# Every worker goes back to the supervisor
for worker in ["researcher", "analyst", "writer"]:
    graph.add_edge(worker, "supervisor")

Agent Handoffs

With handoffs, an agent transfers control directly to another without a supervisor:

PatternDescriptionUse Case
SupervisorCentral controlComplex workflows
HandoffDirect transferSpecialized chains
BroadcastTo all simultaneouslyParallel analysis
VotingMajority decisionQuality assurance

Shared State

All agents share a common state. Important design decisions:

Define State Schema

class MultiAgentState(TypedDict):
    messages: Annotated[list, add_messages]
    task: str
    research_data: list[dict]
    analysis: dict
    draft: str
    next_agent: str
    iteration_count: int

Avoid State Conflicts

  • Each agent writes only to its own state fields
  • Shared fields (e.g., messages) use reducer functions
  • Iteration counters prevent endless cycles

Tool Delegation

Agents can delegate tools to other agents:

def researcher_node(state: MultiAgentState) -> dict:
    tools = [web_search, arxiv_search, database_query]
    agent = create_react_agent(llm, tools)
    result = agent.invoke({"messages": state["messages"]})
    return {"research_data": extract_data(result)}

Parallel Agent Execution

LangGraph supports parallel execution via fan-out nodes:

graph.add_node("parallel_research", parallel_research_node)
# Multiple agents work simultaneously
# Results are merged in the state

Practical tip: Limit iteration depth (e.g., max 5 cycles). Without a limit, a multi-agent system can loop forever — with corresponding costs. Define clear exit conditions.