Diagram showing a supervisor coordinating research and writing workers before delivering a final response.

LangGraph Supervisor Tutorial: Build a Multi-Agent System

A LangGraph supervisor tutorial should begin with a simple idea: a useful multi-agent system is not a group of bots talking at random. It is a workflow with a clear decision-maker. One component owns the conversation, chooses the next piece of work, and decides when the answer is ready. In this tutorial, you will build that decision-maker—a supervisor—for a small research-and-writing assistant.

This is the second article in the LangGraph multi-agent systems series. Part 1 introduced stateful conversational agents. Here, we add specialist workers without losing control of the overall task.

What a LangGraph supervisor tutorial teaches

A supervisor is the agent the user talks to. It delegates bounded tasks to specialists, receives concise results, and remains accountable for the final response. The specialists do not independently take over the conversation.

This pattern is useful when a request crosses genuinely separate domains, when a worker needs focused instructions or tools, or when independent work can run in parallel. It is not the default answer to every complicated prompt: if one agent with a few well-described tools can do the job, keep the design simpler.

The architecture we are building

Our example has three roles:

  • Supervisor: understands the request, selects a worker, and synthesises the final answer.
  • Research worker: gathers factual material and returns a short, source-aware brief.
  • Writing worker: turns an approved brief into a structured draft.

The key boundary is deliberate: workers receive a task, not the entire conversation by default, and they return a useful result, not their full message history. That keeps the supervisor’s context focused and makes each worker easier to test.

Diagram showing supervisor state sending focused task cards to research and writing workers, each returning a concise result.
Workers receive a focused task and return a concise result; the supervisor keeps the broader conversation state.

Prerequisites

  • Python 3.10 or later
  • A tool-calling chat model configured for LangChain
  • langchain, a model integration such as langchain-openai, and langgraph
pip install -U langchain langchain-openai langgraph

The example uses LangChain’s current create_agent helper for agent loops. It produces a LangGraph graph underneath, so the system can later add checkpoints, interrupts, or more explicit graph control.

1. Define narrow workers

Start by making workers boringly specific. Their prompts should say what they own, what they must return, and what they must not do. The workers below have no direct user-facing role.

from langchain.agents import create_agent
from langchain.tools import tool

MODEL = "openai:gpt-5"  # Replace with a tool-calling model available to you.

research_agent = create_agent(
    model=MODEL,
    tools=[],
    system_prompt=(
        "You are a research specialist. Return a concise factual brief. "
        "State important uncertainty. Do not write the final response."
    ),
)

writer_agent = create_agent(
    model=MODEL,
    tools=[],
    system_prompt=(
        "You are a technical writing specialist. Turn the supplied brief "
        "into a clear draft. Do not claim facts that are not in the brief."
    ),
)

In production, the research worker would receive carefully chosen search, documentation, or database tools. The point is not the number of workers. It is the contract between each worker and the supervisor.

2. Expose workers as supervisor tools

The supervisor calls workers as tools. Each wrapper creates a clean task for the worker and returns only its final message. This prevents intermediate worker turns from expanding the main conversation.

@tool("research_topic")
def research_topic(query: str) -> str:
    """Research a topic and return a concise factual brief."""
    result = research_agent.invoke({
        "messages": [{"role": "user", "content": query}]
    })
    return result["messages"][-1].content

@tool("draft_from_brief")
def draft_from_brief(brief: str) -> str:
    """Write a technical draft from an approved research brief."""
    result = writer_agent.invoke({
        "messages": [{"role": "user", "content": brief}]
    })
    return result["messages"][-1].content

Tool names and descriptions matter. They are the supervisor’s working vocabulary. A vague tool called do_work makes delegation ambiguous; research_topic states the capability and expected input.

3. Create the supervisor

Give one main agent the worker tools. The instruction makes control flow explicit: research before drafting, ask for clarification when needed, and never expose internal delegation as a substitute for an answer.

supervisor = create_agent(
    model=MODEL,
    tools=[research_topic, draft_from_brief],
    system_prompt=(
        "You are the supervisor for a technical research assistant. "
        "You own the conversation and final answer. "
        "For requests requiring factual research, call research_topic first. "
        "Call draft_from_brief only after you have a sufficient brief. "
        "Keep worker outputs concise, check missing assumptions, "
        "and give the user a direct final response."
    ),
)

result = supervisor.invoke({
    "messages": [{
        "role": "user",
        "content": "Explain when a team should use a supervisor pattern."
    }]
})

print(result["messages"][-1].content)

A supervisor is different from a simple router. A router usually classifies a request once and dispatches it. A supervisor can use the evolving conversation and worker results to decide what should happen next across several steps.

Control what crosses the boundary

Context engineering is the practical heart of this LangGraph supervisor tutorial. Passing the full chat history to every worker is easy, but erodes the benefit of specialisation. Pass the smallest context that lets the worker succeed.

Worker Give it Return
Research Question, scope, source rules Findings, sources, uncertainty
Writing Approved brief, audience, format A draft, not research history
Supervisor User conversation and worker summaries The final answer and next action

Guardrails to add before this becomes a product

  • Bound the loop: set a maximum number of worker calls per request.
  • Validate inputs: use typed tool parameters and reject unknown worker names.
  • Make failure visible: return an error state or request clarification; do not invent a worker result.
  • Trace delegation: record which worker ran, the task it received, duration, and its summary.
  • Start synchronously: use background jobs only when work is independent and the user does not need it immediately.

Common mistakes

Making every worker a generalist. If all workers have the same prompt and tools, the system adds coordination cost without useful separation.

Letting workers answer the user directly. That is a handoff pattern, not a supervisor pattern. Use it only when the active agent should genuinely change.

Returning full histories. It creates context bloat. Return a compact, structured summary unless the supervisor needs more.

Using an LLM for rules code can enforce. Budget limits, permissions, retries, and stop conditions should be deterministic.

Where the series goes next

You now have a coordinator and two bounded workers. Next, we will make the data flow explicit: shared state, worker-specific context, and the difference between passing a summary and sharing mutable conversation history.

Official references

Leave a Comment

Are you human? Please solve:Captcha


Alpesh Kumar
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.