Módulo 5: OpenRouter - Introducción

Model Selection Automática

Descripción

Implementarás auto-selection inteligente de modelo según tipo de query (código, análisis, chat simple, etc.).

Tiempo: 25 minutos
Dificultad: Media-Alta


🎯 Objetivos

  • ✅ Classifier para tipo de query
  • ✅ Routing rules por tipo
  • ✅ Machine learning (opcional)
  • ✅ A/B testing

🧠 Rule-Based Selection

def classify_query(prompt: str) -> str:
    """Clasifica tipo de query."""
    
    prompt_lower = prompt.lower()
    
    # Código
    if any(w in prompt_lower for w in ["código", "code", "function", "script", "python"]):
        return "code"
    
    # Análisis complejo
    elif any(w in prompt_lower for w in ["analiza", "explica detalladamente", "razonamiento"]):
        return "analysis"
    
    # Traducción
    elif any(w in prompt_lower for w in ["traduce", "translate"]):
        return "translation"
    
    # Creativo
    elif any(w in prompt_lower for w in ["escribe", "redacta", "crea"]):
        return "creative"
    
    # Chat simple (default)
    else:
        return "simple"

def select_model(query_type: str) -> str:
    """Selecciona modelo según tipo."""
    
    routing = {
        "code": "mistralai/codestral-latest",  # Especializado código
        "analysis": "openai/gpt-4-turbo",  # Razonamiento complejo
        "translation": "google/gemini-pro",  # Multilingüe
        "creative": "anthropic/claude-3-opus",  # Escritura creativa
        "simple": "mistralai/mixtral-8x7b-instruct"  # Barato para simple
    }
    
    return routing.get(query_type, "mistralai/mixtral-8x7b-instruct")

# Uso
prompt = "Escribe una función Python para 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:
    """Router inteligente multi-criterio."""
    
    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:
        """
        Selecciona modelo según prompt y prioridad.
        
        Args:
            prompt: Query del usuario
            priority: "cost", "quality", "balanced", "speed"
        """
        
        # Detecta tipo
        query_type = self.classify(prompt)
        
        # Routing según prioridad
        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:
        """Clasifica 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:
        """Prioriza costo."""
        return "mistralai/mixtral-8x7b-instruct"  # Siempre el más barato
    
    def _route_quality(self, query_type: str) -> str:
        """Prioriza calidad."""
        if query_type == "code":
            return "openai/gpt-4-turbo"
        else:
            return "anthropic/claude-3-opus"
    
    def _route_balanced(self, query_type: str) -> str:
        """Balance costo/calidad."""
        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:
        """Prioriza velocidad."""
        return "anthropic/claude-3-haiku"  # Más rápido
    
    def chat(self, prompt: str, priority: str = "balanced") -> str:
        """Chat con routing automático."""
        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

# Uso
router = SmartRouter()

print(router.chat("Hola", priority="cost"))  # Mixtral (barato)
print(router.chat("Explica teoría cuántica en detalle", priority="quality"))  # Claude Opus
print(router.chat("Quick question", priority="speed"))  # Claude Haiku

📊 A/B Testing

import random

class ABTestRouter:
    """Router con 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 con 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):
        """Analiza resultados A/B."""
        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:
    """Selección según contexto completo."""
    
    # Tier-based (freemium model)
    if user_tier == "free":
        max_cost = 0.30  # Mixtral máximo
    elif user_tier == "pro":
        max_cost = 1.00  # GPT-3.5 máximo
    else:  # enterprise
        max_cost = 100.0  # Sin límite
    
    # Conversation length
    total_messages = len(conversation_history)
    
    # Si conversación larga → Modelo con context window grande
    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: Barato
    else:
        return "mistralai/mixtral-8x7b-instruct"

# Test
history = []  # Vacío
print(context_aware_route("Hola", history, "free"))  # Mixtral

history = [{"role": "user", "content": "..."}] * 25  # Muchos mensajes
print(context_aware_route("Continúa", history, "enterprise"))  # Claude Opus

📊 Machine Learning Selection (Avanzado)

# Placeholder para ML approach
def ml_route(prompt: str, historical_performance: dict) -> str:
    """
    Usa ML para predecir mejor modelo.
    
    Features:
    - Prompt length
    - Keywords
    - Historical performance del modelo en queries similares
    - Time of day (load balancing)
    
    Requiere: scikit-learn, modelo entrenado
    """
    
    # Simplified version (keyword-based como 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 para 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"

✅ Resumen

Estrategias de selection:

  1. Rule-based (keywords, length)
  2. Priority-based (cost, quality, speed)
  3. Context-aware (history, user tier)
  4. A/B testing (experimentación)
  5. ML-based (avanzado)

Resultado: 80%+ queries usan modelo óptimo


Siguiente: 07-comparacion-providers.md

Compararás providers side-by-side (OpenAI vs Anthropic vs Google).

Tiempo: 15 min