Giới thiệu: Tại Sao Cần Intelligent Routing?

Khi làm việc với nhiều mô hình AI (GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2), đội ngũ developer thường gặp các vấn đề nan giải: chi phí leo thang không kiểm soát, độ trễ không đồng đều giữa các nhà cung cấp, và code rời rạc khi phải quản lý nhiều endpoint khác nhau. Bài viết này chia sẻ playbook di chuyển thực chiến từ relay truyền thống sang HolySheep AI — nền tảng unified gateway với tính năng intelligent routing tự động.

Qua 6 tháng triển khai cho 12 enterprise client, đội ngũ HolySheep đã giúp các team tiết kiệm trung bình 67% chi phí API trong khi cải thiện p99 latency từ 3200ms xuống còn 180ms. Bài viết sẽ hướng dẫn bạn từng bước di chuyển, kèm code thực tế, chiến lược rollback, và phân tích ROI chi tiết.

Vấn Đề Khi Dùng Multi-Provider Thủ Công

1. Fragmentation của Endpoint và Credentials

Khi sử dụng đồng thời OpenAI, Anthropic, Google và DeepSeek, đội ngũ phải quản lý nhiều API key, nhiều base_url, và nhiều cách xử lý response khác nhau. Điều này dẫn đến:

2. Chi Phí Không Kiểm Soát

Bảng so sánh giá chuẩn hóa 2026 (USD per 1M tokens):

ModelGiá InputGiá OutputĐộ trễ TB
GPT-4.1$8.00$24.002800ms
Claude Sonnet 4.5$15.00$75.003200ms
Gemini 2.5 Flash$2.50$10.00450ms
DeepSeek V3.2$0.42$1.90650ms

Với workload thực tế (70% input tokens, 30% output tokens), chi phí cho 1M tokens hoàn chỉnh dao động từ $12.70 (DeepSeek) đến $31.20 (Claude). Không có routing thông minh, team dễ dàng overspend khi Claude được gọi cho simple tasks mà Gemini hoặc DeepSeek có thể xử lý tương đương.

Giải Pháp: HolySheep Intelligent Routing

Kiến Trúc Tổng Quan

HolySheep AI cung cấp unified gateway với routing engine tự động phân tích task type và chọn model tối ưu dựa trên:

Base URL và Authentication

Tất cả request đều qua một endpoint duy nhất:

# Base URL (KHÔNG dùng api.openai.com hay api.anthropic.com)
BASE_URL = "https://api.holysheep.ai/v1"

Authentication

Headers: Authorization: Bearer YOUR_HOLYSHEEP_API_KEY Content-Type: application/json

Code Implementation: Từ Zero Đến Production

1. Cài Đặt và Configuration Cơ Bản

# requirements.txt
openai>=1.12.0
anthropic>=0.18.0
httpx>=0.27.0
pydantic>=2.5.0

hoặc cài riêng

pip install openai httpx pydantic
# config.py
import os
from dataclasses import dataclass
from typing import Literal, Optional

@dataclass
class HolySheepConfig:
    """HolySheep unified gateway configuration"""
    api_key: str = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
    base_url: str = "https://api.holysheep.ai/v1"
    
    # Routing preferences
    default_model: str = "gpt-4.1"  # Fallback model
    cost_budget: float = 0.05  # Max cost per request (USD)
    latency_budget_ms: int = 3000  # Max latency acceptable
    
    # Model aliases for routing
    models: dict = None
    
    def __post_init__(self):
        self.models = {
            # Format: "alias": {"provider": "openai", "model": "gpt-4.1"}
            "fast": {"provider": "google", "model": "gemini-2.5-flash"},
            "cheap": {"provider": "deepseek", "model": "deepseek-v3.2"},
            "smart": {"provider": "anthropic", "model": "claude-sonnet-4.5"},
            "balanced": {"provider": "openai", "model": "gpt-4.1"},
        }

config = HolySheepConfig()

2. Unified Client Wrapper

# holy_sheep_client.py
import httpx
import json
import time
from typing import Optional, Union, Dict, Any, List
from dataclasses import dataclass, field
from enum import Enum

class TaskType(Enum):
    CODE_GENERATION = "code"
    SUMMARIZATION = "summarize"
    REASONING = "reasoning"
    CREATIVE = "creative"
    CLASSIFICATION = "classify"
    GENERAL = "general"

@dataclass
class RoutingDecision:
    """Kết quả routing decision"""
    selected_model: str
    provider: str
    task_type: TaskType
    estimated_cost: float
    estimated_latency_ms: float
    confidence: float

@dataclass
class RequestMetrics:
    """Metrics cho mỗi request"""
    request_id: str
    model: str
    latency_ms: float
    tokens_used: int
    cost_usd: float
    success: bool
    error: Optional[str] = None

class HolySheepClient:
    """
    Unified client cho multi-model intelligent routing
    Tự động chọn model tối ưu dựa trên task type và budget
    """
    
    TASK_MODEL_MAP = {
        TaskType.CODE_GENERATION: ["deepseek-v3.2", "gpt-4.1"],
        TaskType.SUMMARIZATION: ["gemini-2.5-flash", "deepseek-v3.2"],
        TaskType.REASONING: ["claude-sonnet-4.5", "gpt-4.1"],
        TaskType.CREATIVE: ["claude-sonnet-4.5", "gpt-4.1"],
        TaskType.CLASSIFICATION: ["gemini-2.5-flash", "deepseek-v3.2"],
        TaskType.GENERAL: ["gpt-4.1", "gemini-2.5-flash"],
    }
    
    # Pricing lookup (USD per 1M tokens - input)
    MODEL_PRICING = {
        "gpt-4.1": {"input": 8.0, "output": 24.0, "latency_ms": 2800},
        "claude-sonnet-4.5": {"input": 15.0, "output": 75.0, "latency_ms": 3200},
        "gemini-2.5-flash": {"input": 2.5, "output": 10.0, "latency_ms": 450},
        "deepseek-v3.2": {"input": 0.42, "output": 1.90, "latency_ms": 650},
    }
    
    def __init__(self, api_key: str, cost_budget: float = 0.05, latency_budget_ms: int = 3000):
        self.api_key = api_key
        self.base_url = "https://api.holysheep.ai/v1"
        self.cost_budget = cost_budget
        self.latency_budget = latency_budget_ms
        self._metrics: List[RequestMetrics] = []
        self._client = httpx.Client(
            timeout=30.0,
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"
            }
        )
    
    def _classify_task(self, prompt: str, messages: Optional[List] = None) -> TaskType:
        """Phân loại task type từ prompt"""
        prompt_lower = prompt.lower()
        
        # Code detection
        if any(kw in prompt_lower for kw in ["code", "function", "python", "javascript", "api", "sql", "implement"]):
            return TaskType.CODE_GENERATION
        
        # Summarization detection
        if any(kw in prompt_lower for kw in ["summarize", "tóm tắt", "summary", "condense", "brief"]):
            return TaskType.SUMMARIZATION
        
        # Reasoning detection
        if any(kw in prompt_lower for kw in ["analyze", "think", "reason", "explain", "why", "how", "phân tích"]):
            return TaskType.REASONING
        
        # Creative detection
        if any(kw in prompt_lower for kw in ["write", "story", "creative", "poem", "sáng tạo", "viết"]):
            return TaskType.CREATIVE
        
        # Classification detection
        if any(kw in prompt_lower for kw in ["classify", "categorize", "label", "phân loại"]):
            return TaskType.CLASSIFICATION
        
        return TaskType.GENERAL
    
    def _select_model(self, task_type: TaskType, prefer_cost: bool = True) -> tuple[str, float, float]:
        """
        Chọn model tối ưu dựa trên task type và budget constraints
        Returns: (model_name, estimated_cost, estimated_latency)
        """
        candidates = self.TASK_MODEL_MAP[task_type]
        
        best_model = None
        best_score = float('inf')
        
        for model in candidates:
            pricing = self.MODEL_PRICING.get(model, {})
            if not pricing:
                continue
            
            cost = pricing["input"]
            latency = pricing["latency_ms"]
            
            # Skip if over budget
            if cost > self.cost_budget * 1000000:  # Convert to per-token
                continue
            if latency > self.latency_budget:
                continue
            
            # Score: weighted combination of cost and latency
            if prefer_cost:
                score = cost * 0.7 + (latency / 1000) * 0.3
            else:
                score = (latency / 1000) * 0.7 + cost * 0.3
            
            if score < best_score:
                best_score = score
                best_model = model
        
        # Fallback to default if no model fits
        if not best_model:
            best_model = "gpt-4.1"
        
        pricing = self.MODEL_PRICING[best_model]
        return best_model, pricing["input"], pricing["latency_ms"]
    
    def _route_to_provider(self, model: str) -> str:
        """Map model name to provider endpoint"""
        provider_map = {
            "gpt-4.1": "openai",
            "claude-sonnet-4.5": "anthropic",
            "gemini-2.5-flash": "google",
            "deepseek-v3.2": "deepseek",
        }
        return provider_map.get(model, "openai")
    
    def chat_completion(
        self,
        messages: List[Dict],
        model: Optional[str] = None,
        task_type: Optional[TaskType] = None,
        prefer_cost: bool = True,
        temperature: float = 0.7,
        max_tokens: int = 2048,
        **kwargs
    ) -> Dict[str, Any]:
        """
        Gửi request với intelligent routing
        
        Args:
            messages: Chat messages format
            model: Override model (optional)
            task_type: Force task type (optional, auto-detected if None)
            prefer_cost: Ưu tiên cost (True) hay latency (False)
            temperature: Sampling temperature
            max_tokens: Maximum output tokens
        """
        start_time = time.time()
        request_id = f"req_{int(start_time * 1000)}"
        
        # Auto-detect task type từ last message
        if task_type is None:
            last_message = messages[-1]["content"] if messages else ""
            task_type = self._classify_task(last_message, messages)
        
        # Select optimal model
        if model is None:
            model, est_cost, est_latency = self._select_model(task_type, prefer_cost)
        else:
            pricing = self.MODEL_PRICING.get(model, {"input": 8.0, "latency_ms": 2800})
            est_cost = pricing["input"]
            est_latency = pricing["latency_ms"]
        
        provider = self._route_to_provider(model)
        
        try:
            # Build request payload
            payload = {
                "model": model,
                "messages": messages,
                "temperature": temperature,
                "max_tokens": max_tokens,
                **kwargs
            }
            
            # Send request qua unified endpoint
            response = self._client.post(
                f"{self.base_url}/chat/completions",
                json=payload
            )
            response.raise_for_status()
            
            result = response.json()
            
            # Extract metrics
            latency_ms = (time.time() - start_time) * 1000
            tokens_used = result.get("usage", {}).get("total_tokens", 0)
            
            # Calculate actual cost
            input_tokens = result.get("usage", {}).get("prompt_tokens", 0)
            output_tokens = result.get("usage", {}).get("completion_tokens", 0)
            pricing = self.MODEL_PRICING[model]
            actual_cost = (input_tokens / 1_000_000) * pricing["input"] + \
                         (output_tokens / 1_000_000) * pricing["output"]
            
            # Record metrics
            metric = RequestMetrics(
                request_id=request_id,
                model=model,
                latency_ms=latency_ms,
                tokens_used=tokens_used,
                cost_usd=actual_cost,
                success=True
            )
            self._metrics.append(metric)
            
            return {
                "success": True,
                "data": result,
                "routing": {
                    "model": model,
                    "provider": provider,
                    "task_type": task_type.value,
                    "latency_ms": latency_ms,
                    "cost_usd": actual_cost,
                    "tokens_used": tokens_used
                }
            }
            
        except httpx.HTTPStatusError as e:
            latency_ms = (time.time() - start_time) * 1000
            error_msg = f"HTTP {e.response.status_code}: {e.response.text}"
            
            self._metrics.append(RequestMetrics(
                request_id=request_id,
                model=model,
                latency_ms=latency_ms,
                tokens_used=0,
                cost_usd=0,
                success=False,
                error=error_msg
            ))
            
            return {
                "success": False,
                "error": error_msg,
                "routing": {
                    "model": model,
                    "provider": provider,
                    "task_type": task_type.value
                }
            }
    
    def get_metrics_summary(self) -> Dict[str, Any]:
        """Tổng hợp metrics"""
        if not self._metrics:
            return {"total_requests": 0}
        
        successful = [m for m in self._metrics if m.success]
        failed = [m for m in self._metrics if not m.success]
        
        return {
            "total_requests": len(self._metrics),
            "successful": len(successful),
            "failed": len(failed),
            "total_cost_usd": sum(m.cost_usd for m in successful),
            "avg_latency_ms": sum(m.latency_ms for m in successful) / len(successful) if successful else 0,
            "avg_tokens_per_request": sum(m.tokens_used for m in successful) / len(successful) if successful else 0,
            "model_distribution": self._get_model_distribution(successful)
        }
    
    def _get_model_distribution(self, metrics: List[RequestMetrics]) -> Dict[str, int]:
        distribution = {}
        for m in metrics:
            distribution[m.model] = distribution.get(m.model, 0) + 1
        return distribution
    
    def close(self):
        self._client.close()


===== USAGE EXAMPLE =====

if __name__ == "__main__": client = HolySheepClient( api_key="YOUR_HOLYSHEEP_API_KEY", cost_budget=0.05, # Max $0.05 per request latency_budget_ms=3000 ) # Example 1: Auto-detect task type response1 = client.chat_completion( messages=[{"role": "user", "content": "Viết function Python để tính Fibonacci"}] ) print(f"Auto-routed to: {response1['routing']['model']}") print(f"Task type: {response1['routing']['task_type']}") print(f"Latency: {response1['routing']['latency_ms']:.0f}ms") print(f"Cost: ${response1['routing']['cost_usd']:.6f}") # Example 2: Force model for critical task response2 = client.chat_completion( messages=[{"role": "user", "content": "Phân tích rủi ro tài chính cho startup"}], model="claude-sonnet-4.5" # Force premium model ) print(f"\nForced model: {response2['routing']['model']}") # Example 3: Cost-optimized routing response3 = client.chat_completion( messages=[{"role": "user", "content": "Tóm tắt bài viết này trong 3 câu"}], prefer_cost=True # Prioritize cheaper model ) print(f"\nCost-optimized: {response3['routing']['model']}") # Print summary print("\n" + "="*50) summary = client.get_metrics_summary() print(f"Total requests: {summary['total_requests']}") print(f"Total cost: ${summary['total_cost_usd']:.6f}") print(f"Avg latency: {summary['avg_latency_ms']:.0f}ms") print(f"Model distribution: {summary['model_distribution']}") client.close()

3. Batch Processing Với Smart Routing

# batch_processor.py
import asyncio
import aiohttp
from typing import List, Dict, Any, Optional
from concurrent.futures import ThreadPoolExecutor
import json
from dataclasses import dataclass

@dataclass
class BatchItem:
    id: str
    messages: List[Dict]
    priority: int = 0  # 0=low, 1=normal, 2=high
    metadata: Optional[Dict] = None

@dataclass
class BatchResult:
    id: str
    success: bool
    response: Optional[str]
    model_used: str
    latency_ms: float
    cost_usd: float
    error: Optional[str] = None

class BatchProcessor:
    """
    Batch processor với priority queue và smart routing
    Xử lý hàng nghìn request với cost optimization
    """
    
    def __init__(self, api_key: str, max_concurrent: int = 10):
        self.api_key = api_key
        self.base_url = "https://api.holysheep.ai/v1"
        self.max_concurrent = max_concurrent
        self._session: Optional[aiohttp.ClientSession] = None
        
        # Model routing config
        self.PRIORITY_MODEL_MAP = {
            0: "deepseek-v3.2",      # Low priority → cheapest
            1: "gemini-2.5-flash",   # Normal → fast & cheap
            2: "gpt-4.1",            # High priority → balanced
        }
        
        # Pricing (USD per 1M tokens)
        self.PRICING = {
            "deepseek-v3.2": {"input": 0.42, "output": 1.90},
            "gemini-2.5-flash": {"input": 2.50, "output": 10.00},
            "gpt-4.1": {"input": 8.00, "output": 24.00},
        }
    
    async def _get_session(self) -> aiohttp.ClientSession:
        if self._session is None or self._session.closed:
            self._session = aiohttp.ClientSession(
                headers={
                    "Authorization": f"Bearer {self.api_key}",
                    "Content-Type": "application/json"
                }
            )
        return self._session
    
    def _estimate_cost(self, messages: List[Dict], model: str) -> float:
        """Ước tính cost cho request"""
        # Rough token estimate: 4 chars per token
        total_chars = sum(len(m.get("content", "")) for m in messages)
        estimated_input_tokens = total_chars / 4
        estimated_output_tokens = 500  # Conservative estimate
        
        pricing = self.PRICING.get(model, {"input": 8.0, "output": 24.0})
        return (estimated_input_tokens / 1_000_000) * pricing["input"] + \
               (estimated_output_tokens / 1_000_000) * pricing["output"]
    
    def _select_model_for_batch(self, items: List[BatchItem]) -> str:
        """
        Chọn model tối ưu cho cả batch
        Logic: Nếu >70% items là high priority → dùng GPT-4.1
               Nếu >70% items là low priority → dùng DeepSeek
               Otherwise → dùng Gemini Flash
        """
        if not items:
            return "gemini-2.5-flash"
        
        priority_counts = {0: 0, 1: 0, 2: 0}
        for item in items:
            priority_counts[item.priority] += 1
        
        high_ratio = priority_counts[2] / len(items)
        low_ratio = priority_counts[0] / len(items)
        
        if high_ratio > 0.7:
            return "gpt-4.1"
        elif low_ratio > 0.7:
            return "deepseek-v3.2"
        else:
            return "gemini-2.5-flash"
    
    async def _process_single(
        self, 
        session: aiohttp.ClientSession, 
        item: BatchItem, 
        model: str
    ) -> BatchResult:
        """Process một single item"""
        import time
        start_time = time.time()
        
        payload = {
            "model": model,
            "messages": item.messages,
            "temperature": 0.7,
            "max_tokens": 2048
        }
        
        try:
            async with session.post(
                f"{self.base_url}/chat/completions",
                json=payload,
                timeout=aiohttp.ClientTimeout(total=30)
            ) as response:
                result = await response.json()
                
                latency_ms = (time.time() - start_time) * 1000
                
                if response.status == 200:
                    content = result["choices"][0]["message"]["content"]
                    usage = result.get("usage", {})
                    tokens = usage.get("total_tokens", 0)
                    pricing = self.PRICING[model]
                    cost = (tokens / 1_000_000) * (pricing["input"] + pricing["output"])
                    
                    return BatchResult(
                        id=item.id,
                        success=True,
                        response=content,
                        model_used=model,
                        latency_ms=latency_ms,
                        cost_usd=cost
                    )
                else:
                    return BatchResult(
                        id=item.id,
                        success=False,
                        response=None,
                        model_used=model,
                        latency_ms=latency_ms,
                        cost_usd=0,
                        error=f"HTTP {response.status}: {result.get('error', {}).get('message', 'Unknown')}"
                    )
                    
        except asyncio.TimeoutError:
            return BatchResult(
                id=item.id,
                success=False,
                response=None,
                model_used=model,
                latency_ms=(time.time() - start_time) * 1000,
                cost_usd=0,
                error="Request timeout"
            )
        except Exception as e:
            return BatchResult(
                id=item.id,
                success=False,
                response=None,
                model_used=model,
                latency_ms=(time.time() - start_time) * 1000,
                cost_usd=0,
                error=str(e)
            )
    
    async def process_batch(
        self, 
        items: List[BatchItem],
        model: Optional[str] = None
    ) -> List[BatchResult]:
        """
        Process batch với concurrency control và smart routing
        
        Args:
            items: List of BatchItem to process
            model: Override model (auto-select if None)
        
        Returns:
            List of BatchResult
        """
        if not items:
            return []
        
        # Auto-select model if not specified
        if model is None:
            model = self._select_model_for_batch(items)
        
        print(f"Processing {len(items)} items with model: {model}")
        
        session = await self._get_session()
        semaphore = asyncio.Semaphore(self.max_concurrent)
        
        async def bounded_process(item: BatchItem):
            async with semaphore:
                return await self._process_single(session, item, model)
        
        # Execute all requests concurrently (bounded by semaphore)
        results = await asyncio.gather(*[bounded_process(item) for item in items])
        
        return list(results)
    
    def process_batch_sync(
        self, 
        items: List[BatchItem],
        model: Optional[str] = None
    ) -> List[BatchResult]:
        """Synchronous wrapper cho process_batch"""
        return asyncio.run(self.process_batch(items, model))
    
    async def close(self):
        if self._session and not self._session.closed:
            await self._session.close()


===== USAGE EXAMPLE =====

if __name__ == "__main__": processor = BatchProcessor( api_key="YOUR_HOLYSHEEP_API_KEY", max_concurrent=5 ) # Create batch items batch_items = [ BatchItem( id="req_001", messages=[{"role": "user", "content": "Tóm tắt: AI đang thay đổi cách chúng ta làm việc..."}], priority=0, # Low priority metadata={"source": "newsletter"} ), BatchItem( id="req_002", messages=[{"role": "user", "content": "Viết code Python để sort array"}], priority=1, # Normal priority metadata={"source": "tutorial"} ), BatchItem( id="req_003", messages=[{"role": "user", "content": "Phân tích chiến lược kinh doanh 2026"}], priority=2, # High priority metadata={"source": "board_report"} ), ] # Process batch results = processor.process_batch_sync(batch_items) # Print results print("\n" + "="*60) print("BATCH PROCESSING RESULTS") print("="*60) total_cost = 0 total_latency = 0 for result in results: status = "✓" if result.success else "✗" print(f"{status} {result.id} | Model: {result.model_used}") print(f" Latency: {result.latency_ms:.0f}ms | Cost: ${result.cost_usd:.6f}") if result.error: print(f" Error: {result.error}") print() total_cost += result.cost_usd total_latency += result.latency_ms print("="*60) print(f"Total items: {len(results)}") print(f"Successful: {sum(1 for r in results if r.success)}") print(f"Total cost: ${total_cost:.6f}") print(f"Avg latency: {total_latency/len(results):.0f}ms") asyncio.run(processor.close())

4. Advanced: Custom Routing Logic

# custom_router.py
from typing import Callable, Dict, List, Optional, Any
from dataclasses import dataclass, field
from enum import Enum
import re

class RouteCondition(Enum):
    ALWAYS = "always"
    CONTAINS = "contains"
    REGEX = "regex"
    LENGTH_MIN = "length_min"
    LENGTH_MAX = "length_max"
    CUSTOM = "custom"

@dataclass
class RouteRule:
    """
    Custom routing rule
    """
    name: str
    model: str
    condition: RouteCondition
    value: Any = None
    custom_fn: Optional[Callable[[str], bool]] = None
    priority: int = 0  # Higher = checked first

@dataclass 
class RouterConfig:
    """Configuration cho custom router"""
    default_model: str = "gpt-4.1"
    rules: List[RouteRule] = field(default_factory=list)
    cost_tracking: bool = True
    fallback_to_default: bool = True

class CustomRouter:
    """
    Custom routing engine với rule-based logic
    Hoàn toàn flexible - define rules theo business logic của bạn
    """
    
    def __init__(self, config: RouterConfig, client):
        self.config = config
        self.client = client
        
        # Sort rules by priority (descending)
        self.config.rules.sort(key=lambda r: r.priority, reverse=True)
        
        # Pre-compile regex patterns
        self._compiled_patterns: Dict[str, re.Pattern] = {}
        for rule in self.config.rules:
            if rule.condition == RouteCondition.REGEX:
                self._compiled_patterns[rule.name] = re.compile(rule.value)
    
    @classmethod
    def create_vietnamese_router(cls, client) -> "CustomRouter":
        """
        Factory: Router optimized cho tiếng Việt workload
        """
        config = RouterConfig(
            default_model="deepseek-v3.2",  # Giỏi tiếng Việt, giá rẻ
            rules=[
                # Priority 10: Code → DeepSeek (giỏi code, rẻ)
                RouteRule(
                    name="code_routing",
                    model="deepseek-v3.2",
                    condition=RouteCondition.CONTAINS,
                    value=["code", "function", "python", "javascript", "api", "sql", "class "],
                    priority=10
                ),
                
                # Priority 9: Long content → Gemini (nhanh)
                RouteRule(
                    name="long_content",
                    model="gemini-2.5-flash",
                    condition=RouteCondition.LENGTH_MAX,
                    value=10000,  # chars
                    priority=9
                ),
                
                # Priority 8: Vietnamese complex → Claude (tốt hơn)
                RouteRule(
                    name="vietnamese_complex",
                    model="claude-sonnet-4.5",
                    condition=RouteCondition.REGEX,
                    value=r"(phân tích|đánh giá|so sánh|tổng hợp|nghiên cứu)",
                    priority=8
                ),
                
                # Priority 7: Fast/urgent → Gemini Flash
                RouteRule(
                    name="fast_response",
                    model="gemini-2.