/pattern/routing/

02 · WorkflowClassifier RouterIntent RoutingConditional Branching

Routing.
Classify once. Dispatch to the right specialist.

A classification or decision module classifies a request and dispatches it to specific targets, such as a specialized prompt, agent, or tool.

When to reach for it

  • Different request classes require distinct handling.
  • Specialized tools exist for specific intents.
  • Misrouting carries a high cost.

When it backfires

  • All tasks use the same flow.
  • The classification is unstable.
  • The routing logic becomes more complex than the task itself.

The tradeoff

More precise handling is achieved at the expense of additional decision logic and the risk of misclassification.

The mental model

A shape you can draw on a napkin.

One classifier decides which downstream specialist handles the work — the rest stay idle for this turn.

ClassifyBillingTechnicalRefund
Walk it through

A real run, step by step.

Task"Triage this incoming customer email."
1 / 5
ClassifyEmail contains keywords: 'invoice', 'charge', 'dispute' → category: billing
Branchclassifier(email) → "billing"
Handlerbilling_handler(email) → { status, refundEligible, nextSteps }
Composeresponse = compose_reply(handler_output, tone=professional)
AnswerDraft response routed through billing specialist. No technical or refund agents were invoked.
In code

The loop is already built in.

LangGraphpython
from langgraph.graph import StateGraph, END
from typing import Literal

def classify(state) -> Literal["billing", "technical", "refund"]:
    return classifier_llm(state["email"])

def billing_handler(state): ...
def technical_handler(state): ...
def refund_handler(state): ...

g = StateGraph(State)
g.add_node("classify", classify)
g.add_node("billing", billing_handler)
g.add_node("technical", technical_handler)
g.add_node("refund", refund_handler)

# Conditional edges keyed on classifier output
g.add_conditional_edges("classify", classify, {
    "billing": "billing",
    "technical": "technical",
    "refund": "refund",
})
for node in ["billing", "technical", "refund"]:
    g.add_edge(node, END)
g.set_entry_point("classify")
router = g.compile()
Pitfalls

Two ways this pattern will hurt you.

Categories overlap so the classifier ping-pongs

A request matches two categories equally well, and the classifier flips between them on re-runs. The user sees inconsistent routing.

Fix · Add an explicit hierarchy or tie-break rule; expose confidence scores and route low-confidence cases to an 'unknown' bucket.

No 'unknown' bucket — borderline cases get force-routed

The classifier always emits a known label, even when the input is ambiguous. Borderline requests go to the wrong specialist silently.

Fix · Reserve an 'unknown' or 'escalate' branch for confidence below a threshold. Route those to a generalist or human.

Framework support

Where Routing is native.

LangGraphNative
Microsoft Agent FrameworkNative
Anthropic Cookbookdocumented as a recipeAdaptable

Search

Search patterns, frameworks, and pages.