learn-langchain-with-phoebe / Builder session 9 of 10
Learn LangChain with Phoebe · Builder track · Session 9 of 10

Multi-agent and subgraphs

The hardest session in the track, and it opens with a warning: multi-agent multiplies cost AND failure modes, and the worst failure is quiet - one agent's fiction becoming the next agent's input. Tonight DataDesk hires an analyst and a writer, you watch a supervisor route between them, and then you deliberately break the team to learn why checkers exist.

🔴 Builder track Practitioners: DA · DE · DS · engineers Python 3.10+ · your b7 DataDesk graph running 45 min
0-3 · Where we are 3-18 · Patterns + the honest gate 18-43 · Build-along: DataDesk hires an analyst 43-45 · Q&A
Part 0

Where DataDesk stands

DataDesk can compute (b1-b4), runs on a graph with state and persistence (b5-b6), pauses for human approval (b7), and reads the wiki with citations (b8). One agent, many tools. Tonight we ask the question every architecture review eventually asks: when is one agent not enough - and what does splitting it actually cost?

Live - presented in session Self-study - read after class ★ Try it now prompt Official docs + Academy covered
★ What you walk out with today A supervisor graph routing between an analyst agent and a writer agent, a live reproduction of the cascading-error failure (and the 20-line checker that catches it), Send() map-reduce for parallel fan-out, and a decision gate that will stop you from shipping multi-agent where one agent would do.
Part 1 · covers Academy Intro to LangGraph M4 + the multi-agent docs

When one agent is not enough 8 min live

Multi-agent is an organizational design decision, not a power-up. You are hiring - and every hire adds handoffs, cost, and new ways to fail. The gate comes before the pattern.

Supervisor routes · sequences · stops Analyst agent finds numbers, only numbers Writer agent prose from findings, no tools tools: csv_stats, column_mean, search_docs tools: none words in, words out each specialist keeps a NARROW mandate + tool list Every arrow is a handoff - and every handoff can carry a confident mistake downstream.
🔍 Click to zoom - the supervisor pattern: an org chart, with failure modes on every arrow
LiveThe honest gate: what multi-agent costs before it pays3 min

Say the costs out loud before any pattern: every extra agent multiplies model calls (the supervisor thinks, then the specialist thinks, then the supervisor thinks again), multiplies latency, and - the dangerous one - multiplies failure surface. The signature multi-agent failure is the cascading error: agent A states a wrong number with total confidence, agent B receives it as ground truth and polishes it into a beautiful paragraph. No stack trace. No exception. Just fluent, formatted fiction.

  • Reach for multi-agent when: the job needs genuinely distinct specialisms (different system prompts, different tools, different guardrails), or genuinely parallel workstreams (Part 2's Send).
  • Do not reach for it when: one agent with a better prompt and a longer tool list would do. That describes most cases you will meet.
  • The test: if you cannot write each agent's job description in one sentence without overlap, you are not splitting work - you are duplicating confusion at 2x token cost.
★ Try it now (any chat AI)I am considering splitting my single AI agent into multiple agents for this job: [describe the job]. Argue AGAINST the split first: what would one well-prompted agent with all the tools do worse, concretely? Only then tell me if a split is justified, and along which one-sentence job descriptions.
LiveThe supervisor pattern - a router with employees3 min

The workhorse multi-agent shape: one supervisor node that reads the conversation and decides who works next, plus specialist agents that do the work and report back. In LangGraph terms, each of them is just a node; the supervisor returns a Command(goto=...) naming the next node, and every specialist edge leads back to the supervisor.

  • Narrow tools per specialist is the real safety feature: the analyst can read CSVs but cannot draft emails; the writer can draft but cannot touch data. Least privilege, from b7's governance mindset.
  • The supervisor is small. It routes and stops - it does not do the work. A routing prompt of five lines beats a clever one of fifty.
  • Everything you built still applies: the supervisor graph compiles with your b6 checkpointer and can carry b7 interrupts. Multi-agent is nodes and edges, not a new framework.
Self-studySubgraphs, swarms, hierarchies3 min read

Subgraphs: a graph as a node. Any compiled LangGraph graph can be added to another graph with add_node("analyst_team", analyst_graph). That turns tonight's supervisor team into a reusable component - a "team as a lego brick" you can drop into a bigger org chart. State either shares keys with the parent or gets translated at the boundary. This is how multi-agent systems stay reviewable: each subgraph is testable alone.

Namechecks: the swarm pattern drops the supervisor - agents hand off directly to each other (fewer hops, harder to audit). Hierarchical stacks supervisors of supervisors - org charts for very big jobs, with every layer adding the cascade risk you will demo tonight. Both are edge-wiring variations on what you build in Demo 1; learn them by need, not by default.

Part 2 · covers Send() map-reduce + the Deep Agents overview

Fan-out and the harness above 5 min live

Not all "more agents" means different specialists. Sometimes it means the SAME work over N items at once - that is Send(), LangGraph's map-reduce. And above all of it sits Deep Agents, a prebuilt harness you should recognize before you hand-roll one.

plan node one Send() per item profile march.csv profile april.csv profile may.csv combine node reducer merges results same worker node, N parallel copies - N unknown until runtime Parallelism ≠ specialists: same job, many items
🔍 Click to zoom - Send() map-reduce: one node fans out to N parallel branches, results reduce to one
LiveSend() - map-reduce for graphs3 min

Normal edges are drawn at build time - but "profile every CSV in the folder" has an N you only know at runtime. Send() solves it: a conditional edge returns a LIST of Send objects, each dispatching one worker copy with its own private state. Workers run in parallel; their outputs merge back through a state reducer (your b6 knowledge, doing the reduce half).

★ The fan-out edge - the whole trickfrom langgraph.types import Send def fan_out(state: State): # one Send per item - N decided at runtime return [Send("profile_one", {"csv": path}) for path in state["csv_paths"]] builder.add_conditional_edges("plan", fan_out) # profile_one writes to a list key with a reducer, e.g.: # profiles: Annotated[list, operator.add] # so parallel results merge instead of overwrite.

Use it for: per-file profiling, per-document summaries, per-segment analyses. It is the cheapest multi-agent win because the workers cannot cascade into each other - they never see each other's output.

Self-studyDeep Agents - the harness you should not hand-roll3 min read

Overview only - this is a full course of its own. Deep Agents is LangChain's batteries-included harness for long-running, open-ended work: it ships a planning tool (the agent writes and updates its own todo list), a filesystem for notes and intermediate artifacts, and spawnable subagents for isolated subtasks - prebuilt, on the same LangGraph primitives you now know.

  • Reach for it when the job is long-horizon and open-ended - "research this market and draft a report" - where an agent needs to plan, park context, and delegate for hours, not seconds.
  • Do not reach for it for DataDesk-shaped work: bounded questions, minutes-long runs, tools you enumerated yourself. Tonight's supervisor is the right altitude.
  • It is not magic. Planning is a tool, the filesystem is state, subagents are subgraphs. You could now build a budget version yourself - which is exactly why you can judge when to buy the prebuilt one.
Demo 1 of 2

DataDesk hires an analyst ★ 14 min · everyone builds

Split DataDesk into an analyst (stats tools only) and a writer (no tools), with a supervisor routing between them. One request, watched end to end: "analyze march.csv and draft a summary for the COO".

Define the two specialists with create_agent - reuse your existing tools, but split them: analyst gets csv_stats, column_mean, search_docs; writer gets an empty tool list and a style-focused system prompt.

Write the supervisor node: a plain model call with a five-line routing prompt, returning Command(goto=...) to "analyst", "writer", or END.

Wire the graph from the file below: START → supervisor, both specialists edge back to supervisor. Compile with your b6 checkpointer if you want the run resumable.

Run: "Analyze march.csv and draft a short summary for the COO." Stream it and narrate the routing: supervisor → analyst (tool calls fire) → supervisor → writer (prose appears) → supervisor → END.

Count the model calls versus b3's single agent answering the same request. That ratio - roughly double or more - is the price tag you accepted at the honest gate.

★ supervisor.py - the whole teamfrom typing import Literal from langgraph.graph import StateGraph, MessagesState, START, END from langgraph.types import Command from langchain.agents import create_agent from langchain.chat_models import init_chat_model model = init_chat_model("claude-haiku-4-5-20251001") # or "ollama:llama3.1" analyst = create_agent(model=model, tools=[csv_stats, column_mean, search_docs], system_prompt="You are the analyst. Report findings as plain numbered " "facts with numbers from your tools. No prose, no advice.") writer = create_agent(model=model, tools=[], system_prompt="You are the writer. Turn the analyst's facts into a short, " "clear stakeholder summary. Do not invent numbers.") def supervisor(state: MessagesState) -> Command[Literal["analyst", "writer", END]]: decision = model.invoke([{"role": "system", "content": "You route a data team. Reply with exactly one word: " "'analyst' if data work is still needed, " "'writer' if findings exist but no summary yet, " "'done' if the request is fully answered."}, *state["messages"]]) word = decision.content.strip().lower() return Command(goto=END if word == "done" else word) def run_analyst(state: MessagesState): return {"messages": [analyst.invoke(state)["messages"][-1]]} def run_writer(state: MessagesState): return {"messages": [writer.invoke(state)["messages"][-1]]} builder = StateGraph(MessagesState) builder.add_node("supervisor", supervisor) builder.add_node("analyst", run_analyst) builder.add_node("writer", run_writer) builder.add_edge(START, "supervisor") builder.add_edge("analyst", "supervisor") builder.add_edge("writer", "supervisor") team = builder.compile()
Local-engine note The routing word trick works on llama3.1 but is less reliable than Claude - if your supervisor loops, tighten the routing prompt to forbid anything but the three words, or give the supervisor the stronger engine and the workers the free one. Mixing engines per node is one line each; that is the b2 swap paying rent again.
Demo 2 of 2

The cascade experiment ★ 8 min · build your own

The leader track teaches cascading errors as a slide (a3). You get to reproduce one in 20 lines - and fix it with a checker node.

Seed the failure: make march_bad.csv - copy march.csv and corrupt one revenue figure by 100x. Ask the team to analyze it and draft the COO summary.

Watch the cascade: the analyst reports the absurd number as fact (its tools said so). The writer - explicitly told not to invent numbers - faithfully polishes the fiction into confident executive prose. Every agent behaved correctly. The SYSTEM failed.

Name what is missing: nothing between analyst and writer ever asks "is this plausible?". Handoffs carry confidence, not verification.

Add the fix: a checker node between them - it re-runs csv_stats and asks the model to flag findings that look inconsistent with the raw stats (orders of magnitude, impossible dates). Route: analyst → checker → writer, with checker sending it back to the analyst on failure.

Re-run on the bad CSV: the checker bounces the finding, the analyst re-examines, and the summary either corrects or flags the anomaly. Twenty lines, and the a3 lesson is now muscle memory: verify at the handoff, not at the end.

Real world

Why this demo is the whole session. Post-mortems of failed multi-agent deployments rarely find a broken agent - they find a missing checker. McKinsey's "verify every step" lesson and b7's approval gates are the same instinct at different altitudes: trust boundaries between components, human or automated, are what turn a chain of fluent guessers into a system you can defend.

Homework

Try it yourself - this week ◐ 40-60 min total

Source material

Official sources covered

This track teaches from the official docs and the free LangChain Academy curricula (login required for lesson content; certificates stay with the Academy - all free). This page covers:

Academy: Intro to LangGraph (M4)Part 1 + Demo 1 · supervisor routing and parallelization; the module's research-assistant capstone is homework-adjacent
LangGraph subgraphs + Send docsPart 1 self-study + Part 2 · graphs as nodes, Send map-reduce with reducers, verified patterns
Deep Agents course + docsOverview card only by design · planning + filesystem + subagents as a prebuilt harness; the full course stays with the Academy
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · The right reason to go multi-agent is...

The honest gate: multi-agent multiplies cost, latency and failure surface. Distinct job descriptions (different prompts, tools, guardrails) or runtime parallelism justify it; ambition alone does not.

2 · Send() is for...

Send is parallelism, not specialization: same job, many items, private state per worker, results reduced into one key. Specialist-to-specialist routing is the supervisor's job.

3 · In the cascade experiment, the writer confidently summarized a wrong number. The systemic fix was...

Every agent behaved correctly; the system failed because handoffs carry confidence, not verification. Cascading errors are a topology problem - verify at the handoff, not at the end.

Builder session 9 cheat sheet · pin this

The honest gateMulti-agent multiplies cost AND failure modes. Justify with distinct specialisms or parallelism - argue for one agent first.
Cascading errorsOne agent's fiction becomes the next one's input - fluent, formatted, no exception raised. THE multi-agent risk.
Supervisor patternSmall router node returns Command(goto="analyst"|"writer"|END); specialists edge back to it. Narrow tools per specialist.
The checker fixVerify at the handoff, not at the end: a checker node between agents validating claims against raw data.
Send()Conditional edge returns [Send("worker", {...}) for item in items] - N parallel copies, merged by a state reducer.
Subgraphsadd_node("team", compiled_graph) - a graph as a node. Teams become testable, reusable components.
Deep AgentsPrebuilt harness: planning tool + filesystem + subagents, for long-horizon open-ended work. Overview only - not for DataDesk-shaped jobs.
Running projectDataDesk is now a team: analyst + checker + writer under a supervisor. b10 puts numbers on whether any of this was worth it.