Skip to main content

Overview

The Router workflow uses an LLM to analyze incoming requests and intelligently route them to the most appropriate specialized agent. Unlike hardcoded routing logic, the router makes dynamic decisions based on request content and agent capabilities.
Router agents use structured output to provide routing confidence and reasoning, making decisions transparent and auditable.

Key Features

  • Intelligent Routing: LLM analyzes request and selects best agent
  • Automatic Prompt Generation: Routing instructions built from agent descriptions
  • Confidence Scoring: Router provides confidence level and reasoning
  • Tool Integration: Router can use tools directly or delegate to agents
  • Single Selection: Routes to exactly one agent (not parallel execution)

Basic Usage

import asyncio
from fast_agent import FastAgent

fast = FastAgent("Router Workflow")

@fast.agent(
    name="fetcher",
    model="haiku",
    instruction="You are an agent with a tool enabling you to fetch URLs.",
    servers=["fetch"],
)
@fast.agent(
    name="code_expert",
    model="haiku",
    instruction="""You are an expert in code analysis and software engineering.
    When asked about code, architecture, or development practices,
    you provide thorough and practical insights.""",
    servers=["filesystem"],
)
@fast.agent(
    name="general_assistant",
    model="haiku",
    instruction="""You are a knowledgeable assistant that provides clear,
    well-reasoned responses about general topics, concepts, and principles.""",
)
@fast.router(
    name="route",
    model="sonnet",
    default=True,
    agents=["code_expert", "general_assistant", "fetcher"],
)
async def main() -> None:
    async with fast.run() as agent:
        # Router intelligently selects the appropriate agent
        await agent.route.send("Analyze the code quality of main.py")
        await agent.route.send("What are the principles of effective beekeeping?")
        await agent.route.send("Fetch and summarize https://example.com")

if __name__ == "__main__":
    asyncio.run(main())

Configuration Parameters

name
string
required
Name of the router workflow
agents
list[str]
required
List of agent names the router can delegate to
model
string
Model to use for routing decisions (recommend capable models)
use_history
bool
default:"false"
Whether router maintains conversation history
routing_instruction
string
Optional custom routing instruction template

How It Works

  1. Request Analysis: Router receives the user request
  2. Agent Selection: LLM analyzes request against agent capabilities
  3. Routing Decision: Router selects the single best agent
  4. Delegation: Request is forwarded to the selected agent
  5. Response Return: Selected agent’s response is returned to user

Routing Response Format

The router uses structured output for transparency:
class RoutingResponse(BaseModel):
    agent: str              # Name of selected agent
    confidence: str         # high, medium, or low
    reasoning: str | None   # Explanation of routing decision
Example routing decision:
{
  "agent": "code_expert",
  "confidence": "high",
  "reasoning": "Request specifically asks for code analysis which is the code_expert's specialty"
}

Automatic Agent Discovery

The router automatically generates routing instructions from agent cards:
ROUTING_AGENT_INSTRUCTION = """
Select from the following agents to handle the request:
<fastagent:agents>
[
  {"name": "code_expert", "description": "Expert in code analysis..."},
  {"name": "general_assistant", "description": "Knowledgeable assistant..."},
  {"name": "fetcher", "description": "Agent that can fetch URLs..."}
]
</fastagent:agents>

You must respond with the 'name' of one of the agents listed above.
"""

Router vs Agent Tools

Router agents can also use MCP tools directly without delegating:
# Request: "Download and summarize https://example.com"
# Router can either:
# 1. Use 'fetch' tool directly (if it has the server)
# 2. Delegate to 'fetcher' agent

@fast.router(
    name="smart_router",
    model="sonnet",
    agents=["specialist1", "specialist2"],
    servers=["fetch"],  # Router has tools too!
)

Advanced Examples

Multi-Domain Customer Service

@fast.agent(
    "billing_specialist",
    instruction="Handle all billing, payments, and invoice questions",
    servers=["database"],
)
@fast.agent(
    "technical_support",
    instruction="Resolve technical issues, bugs, and product questions",
    servers=["jira", "filesystem"],
)
@fast.agent(
    "account_manager",
    instruction="Handle account changes, upgrades, and general inquiries",
    servers=["database"],
)
@fast.router(
    name="customer_service",
    model="sonnet",
    agents=["billing_specialist", "technical_support", "account_manager"],
)
async def main() -> None:
    async with fast.run() as agent:
        await agent.customer_service.prompt()  # Interactive customer service

Content Moderation Router

@fast.agent(
    "content_reviewer",
    instruction="Review content for policy compliance and safety",
)
@fast.agent(
    "spam_detector",
    instruction="Identify and classify spam, scams, and low-quality content",
)
@fast.agent(
    "sensitivity_checker",
    instruction="Check for sensitive topics requiring special handling",
)
@fast.router(
    name="moderation_router",
    model="sonnet",
    agents=["content_reviewer", "spam_detector", "sensitivity_checker"],
)
async def main() -> None:
    async with fast.run() as agent:
        result = await agent.moderation_router.send("Check this user submission...")

Development Workflow Router

@fast.agent(
    "code_reviewer",
    instruction="Review code for quality, style, and best practices",
    servers=["filesystem", "github"],
)
@fast.agent(
    "test_generator",
    instruction="Generate comprehensive unit tests for code",
    servers=["filesystem"],
)
@fast.agent(
    "doc_writer",
    instruction="Write clear technical documentation",
    servers=["filesystem"],
)
@fast.agent(
    "refactorer",
    instruction="Suggest and implement code refactoring improvements",
    servers=["filesystem"],
)
@fast.router(
    name="dev_assistant",
    model="sonnet",
    agents=["code_reviewer", "test_generator", "doc_writer", "refactorer"],
)
async def main() -> None:
    async with fast.run() as agent:
        await agent.dev_assistant.prompt()  # Interactive development assistant

Custom Routing Instructions

Override the default routing logic with custom instructions:
CUSTOM_ROUTING = """
You are a specialized router for medical queries.

Prioritization rules:
1. Emergency queries ALWAYS go to emergency_handler
2. Prescription questions go to pharmacist
3. General health goes to general_practitioner
4. If uncertain, route to general_practitioner

Available agents:
{context}
"""

@fast.router(
    name="medical_router",
    agents=["emergency_handler", "pharmacist", "general_practitioner"],
    routing_instruction=CUSTOM_ROUTING,
)

Best Practices

Clear Specializations

Make agent descriptions distinct and specific to avoid routing confusion

Capable Router Model

Use a capable model (like Sonnet) for routing decisions

Test Edge Cases

Test ambiguous queries to ensure sensible routing

Monitor Confidence

Track low-confidence routes to improve agent descriptions

Performance Considerations

Router adds an extra LLM call before the actual agent execution. For latency-sensitive applications, consider:
  • Using a fast routing model (like Haiku)
  • Caching routing decisions for common patterns
  • Using Agents as Tools for LLM-native routing

Use Cases

  • Customer Service: Route support requests to appropriate departments
  • Content Processing: Different handlers for different content types
  • Development Tools: Route dev tasks to specialized agents
  • Multi-Domain Systems: Single entry point for diverse capabilities
  • Triage Systems: Classify and route based on priority/type

Comparison with Other Patterns

FeatureRouterAgents as ToolsOrchestrator
Selection MethodStructured LLM callTool callingPlan generation
ExecutesSingle agentMultiple agentsMultiple agents
ParallelNoYesYes
ComplexityLowMediumHigh
Use CaseSimple delegationDynamic compositionComplex tasks

Debugging Router Decisions

Enable detailed logging to see routing decisions:
import logging
logging.basicConfig(level=logging.INFO)

# You'll see:
# INFO: Routing structured request to agent: code_expert (confidence: high)
# INFO: Reasoning: Request specifically mentions code analysis

Build docs developers (and LLMs) love