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:

  1. Rule-based (keywords, length)
  2. Priority-based (cost, quality, speed)
  3. Context-aware (history, user tier)
  4. A/B testing (experimentation)
  5. 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