LangChain LangGraph Routing

Straight paths suit simple jobs. Real workflows fork. A support app sends billing questions to one team and technical questions to another. A writing app loops back for edits until the draft passes a quality check. Conditional edges give a graph the power to decide its own next step based on the current state.

Traffic Signal Analogy

A traffic officer at a junction reads the situation and waves cars left, right, or straight. The officer does not change the roads. The officer only chooses the route. A router function plays that role inside a graph.

              +--→ [Billing node] ----+
              |                       |
 [Classify] --+--→ [Technical node] --+--→ END
              |                       |
              +--→ [General node] ----+

Conditional Edges

The method add_conditional_edges takes a source node and a router function. The router reads the state and returns the name of the next node.

from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END

class SupportState(TypedDict):
    question: str
    category: str
    answer: str

def classify(state: SupportState):
    prompt = (
        "Reply with one word: billing, technical, or general.\n"
        "Question: " + state["question"]
    )
    label = model.invoke(prompt).content.strip().lower()
    return {"category": label}

def route(state: SupportState) -> Literal["billing", "technical", "general"]:
    if state["category"] in ("billing", "technical"):
        return state["category"]
    return "general"

Defining the Destination Nodes

def billing(state: SupportState):
    return {"answer": "Billing team: please share your invoice number."}

def technical(state: SupportState):
    return {"answer": "Technical team: please restart the app and retry."}

def general(state: SupportState):
    return {"answer": "General help: how can we assist you today?"}

Wiring the Graph

builder = StateGraph(SupportState)
builder.add_node("classify", classify)
builder.add_node("billing", billing)
builder.add_node("technical", technical)
builder.add_node("general", general)

builder.add_edge(START, "classify")
builder.add_conditional_edges("classify", route)

builder.add_edge("billing", END)
builder.add_edge("technical", END)
builder.add_edge("general", END)

graph = builder.compile()
print(graph.invoke({"question": "I was charged twice."})["answer"])

The Literal return type of the router tells LangGraph which nodes the router may choose. You can also pass a dictionary that maps router outputs to node names.

builder.add_conditional_edges(
    "classify",
    route,
    {"billing": "billing", "technical": "technical", "general": "general"},
)

Loops: Revise Until Good

A router can send the flow backward. This pattern creates a write, check, revise cycle.

 START → [Write draft] → [Check quality] --pass--→ END
              ↑                |
              |               fail
              +---[Revise]←----+
class DraftState(TypedDict):
    topic: str
    draft: str
    feedback: str
    rounds: int

def write(state: DraftState):
    text = model.invoke("Write two sentences about " + state["topic"]).content
    return {"draft": text, "rounds": state.get("rounds", 0) + 1}

def check(state: DraftState):
    verdict = model.invoke(
        "Reply PASS if this text is clear and accurate, otherwise reply FAIL:\n"
        + state["draft"]
    ).content
    return {"feedback": verdict}

def decide(state: DraftState):
    if "PASS" in state["feedback"] or state["rounds"] >= 3:
        return END
    return "write"

builder = StateGraph(DraftState)
builder.add_node("write", write)
builder.add_node("check", check)
builder.add_edge(START, "write")
builder.add_edge("write", "check")
builder.add_conditional_edges("check", decide)
graph = builder.compile()

The rounds counter caps the loop at three tries. Every loop needs an exit rule like this one.

Routing Based on Tool Calls

The classic agent graph uses routing too. After the model replies, the router checks for tool requests. A request sends the flow to the tool node, and no request sends the flow to END. LangGraph ships a ready-made router named tools_condition for this exact job.

from langgraph.prebuilt import ToolNode, tools_condition

builder.add_conditional_edges("agent", tools_condition)
builder.add_edge("tools", "agent")

Writing Reliable Routers

  • Return only names that exist in the graph.
  • Handle unexpected labels with a safe default route.
  • Keep routers small and free of side effects.
  • Cap loops with a counter or the recursion limit.

Real-World Scenario

A bank help desk bot receives questions about cards, loans, and branch hours. A classifier node labels each question, and a router sends it to the matching specialist node. Unknown labels go to a general node. A quality loop checks each answer for clarity and returns weak answers for another try, with a limit of three rounds. The routing logic stays readable because every decision lives in a small function with one clear job.

Practice Tasks

  1. Add a fourth category to the support graph and update the router.
  2. Print the route chosen for five different questions.
  3. Build a loop that repeats until a counter reaches three.
  4. Use tools_condition in a small agent graph and describe the two paths it creates.

Testing Routes with Simple Inputs

Routers decide the whole shape of a run, so small mistakes spread far. Test the router function alone with hand-made state dictionaries before connecting it to a model. Pass a billing label and confirm that the function returns the billing node. Pass a strange label and confirm that the function falls back to the general node. These quick checks run in milliseconds and cost nothing. Add them to your test suite, and routing bugs rarely reach users.

Reading the Run History

Each run records which node ran and in what order. Review that order after a surprising result. A loop that ran four times instead of two, or a branch that skipped a check, appears immediately in the history. Tracing tools display the same path as a clear tree, which makes unusual routes easy to spot.

Key Points

  • Conditional edges let state decide the next node.
  • A router function returns the destination name.
  • Loops send the flow back to earlier nodes.
  • Every loop needs a clear exit condition.
  • tools_condition routes agent graphs between model and tools.