Handoff pattern
In the handoff pattern, multiple agents are processed by a fixed sequence: agent 1 finishes and hands its output to agent 2, and so on. It is a sequential workflow. Elsewhere it is called sequential orchestration, a pipeline, or prompt chaining.
In LangGraph
The sequence is just edges between nodes. Each agent reads the state the previous one wrote.
from typing import TypedDictfrom langgraph.graph import StateGraph, START, END class State(TypedDict): topic: str text: str def research(state: State): return {"text": f"notes on {state['topic']}"}def draft(state: State): return {"text": f"draft from: {state['text']}"}def review(state: State): return {"text": f"reviewed: {state['text']}"} builder = StateGraph(State)builder.add_node("research", research)builder.add_node("draft", draft)builder.add_node("review", review) builder.add_edge(START, "research")builder.add_edge("research", "draft")builder.add_edge("draft", "review")builder.add_edge("review", END)graph = builder.compile()Why use it
Deterministic and reliable. The same input takes the same path, so each stage can be tested and traced on its own. It is also the simplest of the multi-agent patterns to build.
The catch
It is rigid. There is no backtracking and no choosing a different path based on what a stage found. A weak early stage passes its output downstream, and nothing stops the later stages from building on it. If the stages could run side by side, use map-reduceSwarm and map-reduceA queen agent spawns a worker per task, then collects the results.Opens in a new tab instead.
The other meaning of handoff
LangChain’s docs use the word for something dynamic: the agent itself decides who goes next, by returning a Command that names the next node and updates the state. That is closer to a routerRouter patternA manager that only decides which specialist handles the request.Opens in a new tab than to a pipeline, and it needs a limit on bouncing between agents.
from typing import Literalfrom langgraph.types import Command def triage(state) -> Command[Literal["billing", "tech"]]: # The agent itself decides who goes next, and what to carry over. target = "billing" if "invoice" in state["query"] else "tech" return Command(goto=target, update={"handled_by": target})Sources
- AI Agent Orchestration Patterns, Microsoft Azure Architecture Center · accessed October 5, 2026
- Handoffs, LangChain Docs · accessed October 5, 2026
- Building effective agents, Anthropic · accessed October 5, 2026