Module 5: OpenRouter - Introduction
Automatic Model Selection
Overview
You'll implement intelligent model auto-selection based on query type (code, analysis, simple chat, etc.).
Time: 25 minutes
Difficulty: Medium-High
🎯 Objectives
- ✅ Classifier for query type
- ✅ Routing rules by type
- ✅ Machine learning (optional)
- ✅ A/B testing
🧠 Rule-Based Selection
def classify_query(prompt: str) -> str:
"""Classify the query type."""
prompt_lower = prompt.lower()
# Code
if any(w in prompt_lower for w in ["código", "code", "function", "script", "python"]):
return "code"
# Complex analysis
elif any(w in prompt_lower for w in ["analiza", "explica detalladamente", "razonamiento"]):
return "analysis"
# Translation
elif any(w in prompt_lower for w in ["traduce", "translate"]):
return "translation"
# Creative
elif any(w in prompt_lower for w in ["escribe", "redacta", "crea"]):
return "creative"
# Simple chat (default)
else:
return "simple"
def select_model(query_type: str) -> str:
"""Select the model based on type."""
routing = {
"code": "mistralai/codestral-latest", # Code-specialized
"analysis": "openai/gpt-4-turbo", # Complex reasoning
"translation": "google/gemini-pro", # Multilingual
"creative": "anthropic/claude-3-opus", # Creative writing
"simple": "mistralai/mixtral-8x7b-instruct" # Cheap for simple
}
return routing.get(query_type, "mistralai/mixtral-8x7b-instruct")
# Usage
prompt = "Write a Python function for fibonacci"
query_type = classify_query(prompt)
model = select_model(query_type)
print(f"Query type: {query_type}, Model: {model}")
🎯 Smart Router Class
from openai import OpenAI
import os
class SmartRouter:
"""Intelligent multi-criteria router."""
def __init__(self):
self.client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY")
)
def route(self, prompt: str, priority: str = "balanced") -> str:
"""
Select the model based on prompt and priority.
Args:
prompt: The user's query
priority: "cost", "quality", "balanced", "speed"
"""
# Detect type
query_type = self.classify(prompt)
# Routing based on priority
if priority == "cost":
return self._route_cost(query_type)
elif priority == "quality":
return self._route_quality(query_type)
elif priority == "speed":
return self._route_speed(query_type)
else: # balanced
return self._route_balanced(query_type)
def classify(self, prompt: str) -> str:
"""Classify the query."""
prompt_lower = prompt.lower()
if "code" in prompt_lower or "python" in prompt_lower:
return "code"
elif len(prompt) > 200:
return "complex"
else:
return "simple"
def _route_cost(self, query_type: str) -> str:
"""Prioritize cost."""
return "mistralai/mixtral-8x7b-instruct" # Always the cheapest
def _route_quality(self, query_type: str) -> str:
"""Prioritize quality."""
if query_type == "code":
return "openai/gpt-4-turbo"
else:
return "anthropic/claude-3-opus"
def _route_balanced(self, query_type: str) -> str:
"""Balance cost/quality."""
routing = {
"simple": "mistralai/mixtral-8x7b-instruct",
"code": "mistralai/codestral-latest",
"complex": "openai/gpt-3.5-turbo"
}
return routing.get(query_type, "mistralai/mixtral-8x7b-instruct")
def _route_speed(self, query_type: str) -> str:
"""Prioritize speed."""
return "anthropic/claude-3-haiku" # Fastest
def chat(self, prompt: str, priority: str = "balanced") -> str:
"""Chat with automatic routing."""
model = self.route(prompt, priority)
print(f"[Using: {model}]")
response = self.client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Usage
router = SmartRouter()
print(router.chat("Hi", priority="cost")) # Mixtral (cheap)
print(router.chat("Explain quantum theory in detail", priority="quality")) # Claude Opus
print(router.chat("Quick question", priority="speed")) # Claude Haiku
📊 A/B Testing
import random
class ABTestRouter:
"""Router with A/B testing."""
def __init__(self):
self.client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENROUTER_API_KEY")
)
self.results = {"A": [], "B": []}
def chat(self, prompt: str) -> dict:
"""Chat with an A/B test."""
# 50/50 split
variant = "A" if random.random() < 0.5 else "B"
# Variants
models = {
"A": "openai/gpt-3.5-turbo",
"B": "anthropic/claude-3-haiku"
}
model = models[variant]
response = self.client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
result = {
"variant": variant,
"model": model,
"response": response.choices[0].message.content,
"tokens": response.usage.total_tokens
}
self.results[variant].append(result)
return result
def analyze(self):
"""Analyze the A/B results."""
print("=== A/B Test Results ===")
for variant in ["A", "B"]:
results = self.results[variant]
if not results:
continue
avg_tokens = sum(r["tokens"] for r in results) / len(results)
print(f"\nVariant {variant} ({results[0]['model']}):")
print(f" Queries: {len(results)}")
print(f" Avg tokens: {avg_tokens:.0f}")
# Test
tester = ABTestRouter()
for _ in range(20):
tester.chat("Test query")
tester.analyze()
🎯 Context-Aware Selection
def context_aware_route(
prompt: str,
conversation_history: list,
user_tier: str = "free"
) -> str:
"""Selection based on the full context."""
# Tier-based (freemium model)
if user_tier == "free":
max_cost = 0.30 # Mixtral maximum
elif user_tier == "pro":
max_cost = 1.00 # GPT-3.5 maximum
else: # enterprise
max_cost = 100.0 # No limit
# Conversation length
total_messages = len(conversation_history)
# If the conversation is long → model with a large context window
if total_messages > 20:
if max_cost >= 10.0:
return "anthropic/claude-3-opus" # 200k context
else:
return "openai/gpt-3.5-turbo" # 16k context
# Query length
elif len(prompt) > 500:
if max_cost >= 10.0:
return "openai/gpt-4-turbo"
else:
return "anthropic/claude-3-haiku"
# Default: cheap
else:
return "mistralai/mixtral-8x7b-instruct"
# Test
history = [] # Empty
print(context_aware_route("Hi", history, "free")) # Mixtral
history = [{"role": "user", "content": "..."}] * 25 # Many messages
print(context_aware_route("Continue", history, "enterprise")) # Claude Opus
📊 Machine Learning Selection (Advanced)
# Placeholder for the ML approach
def ml_route(prompt: str, historical_performance: dict) -> str:
"""
Use ML to predict the best model.
Features:
- Prompt length
- Keywords
- The model's historical performance on similar queries
- Time of day (load balancing)
Requires: scikit-learn, a trained model
"""
# Simplified version (keyword-based as a proxy)
features = {
"length": len(prompt),
"has_code": "code" in prompt.lower(),
"has_math": any(w in prompt.lower() for w in ["calcular", "matemáticas"]),
"is_creative": any(w in prompt.lower() for w in ["escribe", "crea"])
}
# Simple heuristic (placeholder for the ML model)
if features["has_code"]:
return "mistralai/codestral-latest"
elif features["is_creative"]:
return "anthropic/claude-3-opus"
elif features["length"] > 300:
return "openai/gpt-4-turbo"
else:
return "mistralai/mixtral-8x7b-instruct"
✅ Summary
Selection strategies:
- Rule-based (keywords, length)
- Priority-based (cost, quality, speed)
- Context-aware (history, user tier)
- A/B testing (experimentation)
- ML-based (advanced)
Result: 80%+ of queries use the optimal model
Next: 07-providers-comparison.md
You'll compare providers side-by-side (OpenAI vs Anthropic vs Google).
Time: 15 min