Semantic Routing#

This guide covers how to use semantic routing to direct queries to appropriate agents.

Overview#

Semantic routing uses vector similarity to match user queries with predefined routes, enabling:

  • Zero LLM calls for routing decisions

  • Sub-millisecond latency using Redis vector search

  • Dynamic route management without code changes

import os
os.environ.setdefault("OPENAI_API_KEY", "your-api-key-here")

REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379")

Basic Usage#

from redis_openai_agents import SemanticRouter, Route

# Define routes with reference phrases
router = SemanticRouter(
    name="support-router",
    redis_url=REDIS_URL,
    routes=[
        Route(
            name="billing",
            references=[
                "payment issue",
                "invoice problem",
                "refund request",
                "subscription billing",
                "charge on my card"
            ],
            metadata={"agent": "billing_agent", "priority": "high"}
        ),
        Route(
            name="technical",
            references=[
                "bug report",
                "error message",
                "not working",
                "crash",
                "performance issue"
            ],
            metadata={"agent": "tech_agent", "priority": "medium"}
        ),
        Route(
            name="sales",
            references=[
                "pricing information",
                "enterprise plan",
                "demo request",
                "upgrade options",
                "volume discount"
            ],
            metadata={"agent": "sales_agent", "priority": "high"}
        )
    ]
)

print(f"Router '{router.name}' initialized with {len(router.routes)} routes")

Routing Queries#

# Test various queries
test_queries = [
    "I need help with my payment",
    "The app keeps crashing on startup",
    "Can I get a demo of your product?",
    "I want a refund for last month",
    "What are your enterprise pricing options?"
]

for query in test_queries:
    match = router.route(query)
    print(f"Query: '{query}'")
    print(f"  → Route: {match.name}")
    print(f"  → Agent: {match.metadata.get('agent')}")
    print(f"  → Distance: {match.distance:.4f}")
    print()

Distance Thresholds#

Each route can have its own distance threshold for matching precision.

# Router with custom thresholds
precise_router = SemanticRouter(
    name="precise-router",
    redis_url=REDIS_URL,
    routes=[
        Route(
            name="password_reset",
            references=["reset password", "forgot password", "can't log in"],
            distance_threshold=0.2,  # Strict matching
            metadata={"action": "password_reset_flow"}
        ),
        Route(
            name="general_help",
            references=["help", "question", "how do I", "support"],
            distance_threshold=0.4,  # Lenient matching (catch-all)
            metadata={"action": "general_support"}
        )
    ]
)
# Test threshold behavior
queries = [
    "I forgot my password",           # Should match password_reset
    "How do I change my settings?",   # Should match general_help
    "Reset my account password",      # Should match password_reset
]

for query in queries:
    match = precise_router.route(query)
    print(f"'{query}' → {match.name} (distance: {match.distance:.4f})")

Integration with Agents#

from agents import Agent, Runner

# Define specialized agents
billing_agent = Agent(
    name="billing_agent",
    instructions="You handle billing and payment issues. Be helpful with refunds and subscriptions."
)

tech_agent = Agent(
    name="tech_agent",
    instructions="You handle technical issues. Help troubleshoot bugs and errors."
)

sales_agent = Agent(
    name="sales_agent",
    instructions="You handle sales inquiries. Provide pricing and demo information."
)

# Agent registry
agents = {
    "billing_agent": billing_agent,
    "tech_agent": tech_agent,
    "sales_agent": sales_agent
}
async def route_and_run(query: str) -> str:
    """Route query to appropriate agent and run."""
    # Route the query (no LLM call!)
    match = router.route(query)
    agent_name = match.metadata.get("agent")
    
    print(f"Routing to: {agent_name}")
    
    # Get the agent
    agent = agents.get(agent_name)
    if not agent:
        return f"No agent found for route: {match.name}"
    
    # Run the agent
    result = await Runner.run(agent, input=query)
    return result.final_output
# Route and run
response = await route_and_run("I was charged twice for my subscription")
print(f"\nResponse: {response[:200]}...")

Dynamic Route Management#

Routes can be added or removed at runtime.

# Add a new route
router.add_route(
    Route(
        name="feedback",
        references=["feedback", "suggestion", "feature request", "improvement idea"],
        metadata={"agent": "feedback_agent"}
    )
)

print(f"Router now has {len(router.routes)} routes")

# Test new route
match = router.route("I have a suggestion for a new feature")
print(f"Query routed to: {match.name}")
# Remove a route
router.remove_route("feedback")
print(f"Router now has {len(router.routes)} routes")

Multi-Match Routing#

Get multiple potential matches for a query.

# Get top-k matches
query = "I need help with billing and have a technical question"
matches = router.route_many(query, k=3)

print(f"Query: '{query}'")
print("\nTop matches:")
for i, match in enumerate(matches, 1):
    print(f"  {i}. {match.name} (distance: {match.distance:.4f})")

Best Practices#

1. Use Diverse Reference Phrases#

Include various ways users might express the same intent:

Route(
    name="cancel",
    references=[
        "cancel subscription",
        "stop my plan",
        "end membership",
        "don't want to continue",
        "unsubscribe"
    ]
)

2. Have a Fallback Route#

Route(
    name="general",
    references=["help", "question", "other"],
    distance_threshold=0.5,  # Very lenient
    metadata={"agent": "general_agent"}
)

3. Monitor Route Performance#

Track which routes are used and their match distances to refine references.

Cleanup#

# Clean up routers
router.clear()
precise_router.clear()

print("Routers cleaned up!")