Multi-Agent LangGraph: Supervisor and Worker Patterns

By Carlos Montiel | Enterprise AI Specialist
Leer en español →
Published: 2026-07-28 | By: Carlos Montiel | Reading time: ~4 minutes

A single agent with too many tools becomes slow and imprecise. The supervisor-workers pattern in LangGraph splits the problem across specialized agents coordinated by one that decides who to delegate to.

Why split into multiple agents

An agent with 20 different tools — web search, database queries, report generation, sending emails — has two measurable problems: the model picks the right tool worse when the catalog is large, and the system prompt becomes unmanageable. The supervisor-workers pattern solves this by assigning small subsets of tools to specialized agents, and delegating the "whose turn is it" decision to a supervisor node whose only job is to route.

Basic supervisor structure

from typing import Literal from langgraph.graph import StateGraph, START, END from langchain_core.messages import HumanMessage class TeamState(TypedDict): messages: Annotated[list, operator.add] next: str members = ["researcher", "financial_analyst", "writer"] def supervisor(state: TeamState) -> TeamState: system_prompt = ( f"You are the supervisor of a team with these members: {members}. " "Given the conversation state, decide who should act next, " "or respond 'FINISH' if the task is complete." ) response = llm_with_structured_output.invoke( [SystemMessage(content=system_prompt)] + state["messages"] ) return {"next": response.next}

The supervisor typically uses structured output (`with_structured_output` over a Pydantic model with a `Literal` field restricted to valid member names) to guarantee that routing always targets an existing node, preventing the model from inventing a destination.

Connecting workers and conditional edges

def researcher_node(state: TeamState): result = researcher_agent.invoke({"messages": state["messages"]}) return {"messages": [AIMessage(content=result["output"], name="researcher")]} builder = StateGraph(TeamState) builder.add_node("supervisor", supervisor) builder.add_node("researcher", researcher_node) builder.add_node("financial_analyst", analyst_node) builder.add_node("writer", writer_node) for member in members: builder.add_edge(member, "supervisor") builder.add_conditional_edges( "supervisor", lambda state: state["next"], {"researcher": "researcher", "financial_analyst": "financial_analyst", "writer": "writer", "FINISH": END}, ) builder.add_edge(START, "supervisor") team = builder.compile()

Each worker, after acting, always returns to the supervisor, which decides the next step. This cycle continues until the supervisor determines the task is complete.

Simplifying routing with Command

Recent LangGraph versions let a node return a `Command` object directly, combining the state update with the decision of which node to go to, without needing a separate conditional edge:

from langgraph.types import Command def supervisor(state: TeamState) -> Command[Literal["researcher", "financial_analyst", "writer", "__end__"]]: response = llm_with_structured_output.invoke(state["messages"]) destination = response.next if response.next != "FINISH" else "__end__" return Command(goto=destination, update={"next": destination})

This reduces the `add_conditional_edges` boilerplate when the routing logic naturally lives inside the deciding node itself.

Subgraphs for complex agents as nodes

When a "worker" is itself an agent with its own ReAct tool-calling cycle, it's best to build it as an independent `StateGraph` and use it as a node of the supervisor's graph via `.compile()`, which produces a compatible `Runnable`:

researcher_subgraph = researcher_builder.compile() builder.add_node("researcher", researcher_subgraph)

This hierarchical composition — graphs within graphs — is the recommended way to scale multi-agent architectures without the main graph becoming unreadable: the supervisor doesn't need to know that "researcher" internally makes 4 tool calls in its own cycle.

When NOT to use this pattern

If the tasks don't require real specialization of tools or knowledge, splitting into multiple agents adds latency (every hop through the supervisor is an extra call to the model) and cost with no quality benefit. In our experience, the pattern is justified surgically when there are clearly separable domains — for example, an agent that only queries SQL databases and another that only writes in natural language — and not as the default architecture for any conversational problem.

Carlos Montiel
Enterprise AI Solutions Architect
Specialist in LLMs, Agents, and Orchestration
guatemalia.com/en/#contact · info@guatemalia.com

Need to implement AI at your company?

Carlos Montiel is an enterprise AI solutions architect. He implements LLMs, Agents, RAG, and orchestrators for companies across Guatemala and Latin America. Reach out for a consultation.

Contact Carlos Montiel

info@guatemalia.com