๐Ÿ”€ Route: send each request to the right place

A coding question, a request for a poem and a 40-page contract need very different handling. Routing works out what kind of request has arrived and passes it to the tool, workflow or specialised agent best suited to it.

What kind of thing is this?

Routing is a general design pattern that you build in your own code. There is no "router" setting in the Claude API. Claude is often used as the classifier inside a router. Anthropic describes the pattern as routing in Building effective agents.

What is it?

Routing is a two-part process: first classify the request (decide what type it is), then dispatch it (hand it to the matching handler). Each handler can have its own instructions, tools, skills or even its own model.

Intent
What the user is trying to achieve, such as "fix my code" or "write an email".
Classification
Sorting something into one of a fixed set of categories.
Route / handler
The destination that deals with one category: a tool, a workflow or a specialised agent.
Confidence
How sure the classifier is about its choice.
Fallback route
The safe default used when no route fits or confidence is low, for example "ask a clarifying question".

Why is it important?

Real-world analogy

The receptionist

At a large office, a receptionist greets every visitor, asks what they need, and directs them: "Accounts is on floor 2, IT support is on floor 3." The receptionist doesn't fix laptops or do anyone's taxes. They just get each visitor to the right department. If a visitor's request is unclear, the receptionist asks a question instead of guessing. If nothing fits, they send the visitor to the general enquiries desk, which is the fallback.

How does it work?

  1. Define the routes: a short, fixed list of categories with clear descriptions.
  2. Classify: use simple rules (keywords, form fields) or ask Claude to choose one category.
  3. Check the decision: is the category valid? Is the confidence high enough? Is required information missing?
  4. Dispatch to the chosen handler, or to the fallback.
  5. Respond and log which route was used, so you can measure accuracy later.

What can a router base its decision on?

๐ŸŽฏ User intent

"Help me debug" โ†’ coding. "Draft a letter" โ†’ writing.

๐Ÿ“ฆ Task type or input

Has a PDF attached โ†’ document analysis.

โš™๏ธ Conditions

Order value over $500 โ†’ human review. Customer is a VIP โ†’ priority queue.

๐Ÿงฐ Required capabilities

Needs live data โ†’ a route with web search. Needs code execution โ†’ a coding agent.

Workflow diagram

Only one route runs for each request. The fallback catches unclear requests, missing information and low-confidence classifications.

Try it: watch the router decide

Interactive demoA simulation in your browser using keyword rules. A real router would usually ask Claude to classify.

    Practical example: a help-desk assistant

    RouteExample requestWhat the handler has
    Research"What are the latest trends in solar panels?"Web search tool, research-brief skill
    Coding"Why does my loop never stop?"Code execution tool, code-review skill
    Writing"Draft a thank-you note to a client"House style skill, no tools needed
    Document analysis"List the deadlines in this contract" (PDF attached)PDF input, document-analysis skill
    Fallback"Can you sort this out?"Asks one clarifying question

    Code example

    Version 1: rule-based router. This runs with plain Python, with no API key and no AI. Rules are fast and free, but brittle.

    
    # simple_router.py: route requests using keyword rules. Run: python simple_router.py
    ROUTES = {
        "coding":   ["code", "bug", "error", "python", "function", "crash"],
        "research": ["research", "find", "studies", "trends", "latest"],
        "writing":  ["write", "draft", "email", "letter", "poem"],
        "document": ["pdf", "contract", "document", "attached"],
    }
    
    def route(request: str, has_attachment: bool = False) -> str:
        words = request.lower()
        scores = {name: sum(k in words for k in keys) for name, keys in ROUTES.items()}
        best = max(scores, key=scores.get)
        if scores[best] == 0:
            return "fallback"                       # nothing matched: ask the user to clarify
        if best == "document" and not has_attachment:
            return "missing_info"                   # right route, but the file is missing
        return best
    
    for text, attached in [("My Python code has a bug", False),
                           ("Summarise this contract", False),
                           ("Help me with the thing", False)]:
        print(f"{text!r:35} -> {route(text, attached)}")
    
    
    'My Python code has a bug'          -> coding
    'Summarise this contract'           -> missing_info
    'Help me with the thing'            -> fallback
    

    Version 2: Claude as the classifier. Claude understands meaning, not just keywords. Structured outputs guarantee that the reply is valid JSON in the shape we ask for. It needs pip install anthropic and the ANTHROPIC_API_KEY environment variable on your computer or server.

    
    # claude_router.py: Claude classifies, our code checks and dispatches.
    import json
    import anthropic
    
    client = anthropic.Anthropic()
    ROUTES = ["research", "coding", "writing", "document_analysis", "unclear"]
    
    def classify(request: str) -> dict:
        response = client.messages.create(
            model="claude-opus-5-5",
            max_tokens=4096,
            system=("You route requests for a help desk. Pick exactly one route. "
                    "Use 'unclear' when the request is ambiguous. "
                    "If key information is missing (e.g. a document that was not attached), describe it in missing_info."),
            messages=[{"role": "user", "content": request}],
            output_config={
                "effort": "low",                         # classification is easy: think briefly
                "format": {"type": "json_schema", "schema": {
                    "type": "object",
                    "properties": {
                        "route": {"type": "string", "enum": ROUTES},   # only these values are allowed
                        "confidence": {"type": "number"},              # 0.0 to 1.0
                        "missing_info": {"type": "string"},            # "" if nothing is missing
                    },
                    "required": ["route", "confidence", "missing_info"],
                    "additionalProperties": False,
                }},
            },
        )
        return json.loads(next(b.text for b in response.content if b.type == "text"))
    
    # Handlers: in a real app each would call its own prompt, tools or agent.
    HANDLERS = {
        "research": lambda r: f"[research agent] searching sources for: {r}",
        "coding": lambda r: f"[coding agent] debugging: {r}",
        "writing": lambda r: f"[writing agent] drafting: {r}",
        "document_analysis": lambda r: f"[document agent] analysing: {r}",
    }
    
    def handle(request: str) -> str:
        decision = classify(request)
        print("decision:", decision)
        if decision["missing_info"]:
            return f"Before I start, could you provide: {decision['missing_info']}?"
        if decision["route"] == "unclear" or decision["confidence"] < 0.6:
            return "Could you tell me a bit more? Is this about research, code, writing or a document?"
        return HANDLERS[decision["route"]](request)
    
    print(handle("My Python script crashes with a KeyError on line 12"))
    print(handle("Can you sort this out?"))
    
    
    decision: {'route': 'coding', 'confidence': 0.95, 'missing_info': ''}
    [coding agent] debugging: My Python script crashes with a KeyError on line 12
    decision: {'route': 'unclear', 'confidence': 0.3, 'missing_info': ''}
    Could you tell me a bit more? Is this about research, code, writing or a document?
    

    Step-by-step explanation

    1. Version 1 counts keyword matches for each route with sum(k in words for k in keys) and picks the highest score using max(..., key=scores.get).
    2. A score of zero means nothing matched, so it returns "fallback". A document request with no attachment returns "missing_info".
    3. Version 2 puts the routing rules in the system prompt, which is standing instructions that apply to the whole conversation.
    4. output_config.format with a json_schema forces the reply into our shape. The enum means Claude can only choose one of our five routes.
    5. "effort": "low" tells Claude it doesn't need to think deeply, which makes classification faster and cheaper.
    6. handle() checks the decision before acting: missing information โ†’ ask for it, unclear or low confidence โ†’ clarify, otherwise call the matching handler.
    7. HANDLERS is a dictionary of destinations. Adding a new route means adding one entry to ROUTES and one handler.

    Handling unclear requests, missing information and fallbacks

    Routing and orchestration compared

    RoutingOrchestration
    Question it answers"Who should handle this?""How do we split this big job, and who does each part?"
    Handlers used per requestUsually oneSeveral, often in combination
    After the hand-offThe router's job is doneThe orchestrator monitors, checks and combines the results
    AnalogyReceptionistProject manager

    Use cases

    Advantages and limitations

    โœ… Advantages

    • Each route can be specialised and tested separately
    • Saves cost by sending easy work to cheaper handlers
    • Clear place to add safety rules

    โš ๏ธ Limitations

    • A wrong classification sends the request down the wrong path
    • The classification step adds a little time and cost
    • Requests that mix two types are tricky

    ๐Ÿšซ Common mistakes

    • No "unclear" option or fallback
    • Overlapping categories
    • Too many routes
    • Never checking routing accuracy

    Best practices

    Knowledge check

    1. What are the two parts of routing?

    2. A user writes "Can you help with the thing?" What should a good router do?

    3. Why add an enum list of routes to the classifier's output?

    4. What is the main difference between routing and orchestration?

    5. Is routing a built-in Claude API feature?

    Mini project

    Build a three-route school helper.

    1. Routes: maths, essay, unclear.
    2. Start with simple_router.py and change the keywords.
    3. Write 10 test requests and the correct route for each. Count how many your router gets right.
    4. Then try claude_router.py with the same 10 requests and compare the accuracy.
    5. Bonus: if a maths request has no numbers in it, return "missing_info".

    Key takeaways

    Further learning