Routing from inside a node
Sometimes the node doing the work already knows where the run should go next. Returning a Command lets it update the state and choose the next node together.
Look back at lesson 6. The ticket was read twice: once by pick_team to choose a route, and the node it chose never learned what the decision was. If one function already knows, it can record the answer and name the destination in one go.
A state that keeps the decision
from typing_extensions import TypedDict
class State(TypedDict):
ticket: str
category: str
reply: strA node that decides and routes
This is the whole idea of the lesson, in five lines.
from typing import Literal
from langgraph.types import Command
def read_ticket(state) -> Command[Literal["billing", "technical"]]:
if "charge" in state["ticket"]:
return Command(update={"category": "billing"}, goto="billing")
return Command(update={"category": "technical"}, goto="technical")update does what a normal return value does, and goto names the node to run next. The return type listing the two destinations is what lets LangGraph work out the shape of the graph, which is why there is no conditional edge anywhere below.
The two replies
def billing(state):
return {"reply": "We will refund the double charge."}
def technical(state):
return {"reply": "Try logging out and back in."}Wiring, with one edge missing
Count the edges. There is only one, into the first node. Nothing says what happens after read_ticket, because read_ticket says it itself.
from langgraph.graph import StateGraph, START
builder = StateGraph(State)
builder.add_node("read_ticket", read_ticket)
builder.add_node("billing", billing)
builder.add_node("technical", technical)
builder.add_edge(START, "read_ticket")print(builder.compile().invoke({"ticket": "charged twice", "category": "", "reply": ""}))The category is in the result as well as the reply, which is the thing lesson 6 could not do. The routing decision was worth keeping, and the node that made it wrote it down.
Which one should you use
| Situation | Use |
|---|---|
| The node doing the work also decides the route | Command |
| The decision is separate, or several nodes share one router | a conditional edge |
| The routing rule is long and you want it in one obvious place | a conditional edge |
Both are correct and you will meet both in real code. A conditional edge keeps the decision outside the work, which reads better when the rule is long. A Command keeps it beside the thing that knows, which reads better when the rule is short.
Command comes back twice more. In lesson 23 you send one into a graph to answer a question it stopped to ask, and a tool can return one to change the state as well as reply.- Add a third route for tickets containing
password, and add it to theLiteral. - Remove
update=and check the category in the result. - Print the graph's edges with and without the return type hint, and compare.
Little by little, you're building something great.