Trong quá trình xây dựng hệ thống AI Agent cho startup của mình, tôi đã trải qua không ít lần "đau đầu" với các vấn đề về SLA, rate limiting, retry logic và multi-model fallback. Bài viết này sẽ chia sẻ checklist SRE mà tôi đã đúc kết được, kèm theo hướng dẫn triển khai thực tế với HolySheep AI — nền tảng mà team đã chọn để giải quyết bài toán này một cách hiệu quả.

Mục lục

Vấn đề thực tế khi vận hành AI Agent SaaS

Khi xây dựng AI Agent SaaS, đội ngũ kỹ thuật thường gặp những thách thức cốt lõi sau:

Từ kinh nghiệm vận hành hệ thống phục vụ hơn 50,000 request/ngày, tôi đã xây dựng bộ công cụ SRE với HolySheep AI — nền tảng cung cấp latency trung bình dưới 50ms, hỗ trợ WeChat/Alipay thanh toán, và tỷ giá ¥1 = $1 giúp tiết kiệm chi phí đến 85%.

SLA Monitoring với HolySheep

HolySheep cung cấp dashboard theo dõi SLA với các chỉ số quan trọng. Tuy nhiên, để chủ động hơn, bạn nên triển khai monitoring riêng.

Metrics cần theo dõi

#!/usr/bin/env python3
"""
SLA Monitoring Client cho HolySheep AI
Metrics: Success Rate, Latency, Error Classification
"""

import time
import asyncio
import aiohttp
from dataclasses import dataclass
from typing import Optional, List
from collections import defaultdict
import statistics

@dataclass
class RequestMetrics:
    timestamp: float
    latency_ms: float
    success: bool
    model: str
    error_type: Optional[str] = None
    tokens_used: Optional[int] = None

class HolySheepSLAMonitor:
    def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
        self.api_key = api_key
        self.base_url = base_url
        self.metrics: List[RequestMetrics] = []
        self.error_counts = defaultdict(int)
        self.total_requests = 0
        
    async def call_with_metrics(
        self, 
        model: str,
        prompt: str,
        max_tokens: int = 1000
    ) -> dict:
        """Gọi API với metrics tracking"""
        start_time = time.perf_counter()
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            "max_tokens": max_tokens
        }
        
        try:
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    f"{self.base_url}/chat/completions",
                    headers=headers,
                    json=payload,
                    timeout=aiohttp.ClientTimeout(total=30)
                ) as response:
                    latency_ms = (time.perf_counter() - start_time) * 1000
                    
                    if response.status == 200:
                        data = await response.json()
                        tokens = data.get("usage", {}).get("total_tokens", 0)
                        
                        self._record_success(model, latency_ms, tokens)
                        return {"success": True, "data": data, "latency_ms": latency_ms}
                    else:
                        error_body = await response.text()
                        self._record_error(model, latency_ms, response.status, error_body)
                        return {"success": False, "error": error_body, "latency_ms": latency_ms}
                        
        except asyncio.TimeoutError:
            latency_ms = (time.perf_counter() - start_time) * 1000
            self._record_error(model, latency_ms, "TIMEOUT", "Request timeout")
            return {"success": False, "error": "timeout", "latency_ms": latency_ms}
            
        except Exception as e:
            latency_ms = (time.perf_counter() - start_time) * 1000
            self._record_error(model, latency_ms, "EXCEPTION", str(e))
            return {"success": False, "error": str(e), "latency_ms": latency_ms}
    
    def _record_success(self, model: str, latency_ms: float, tokens: int):
        self.metrics.append(RequestMetrics(
            timestamp=time.time(),
            latency_ms=latency_ms,
            success=True,
            model=model,
            tokens_used=tokens
        ))
        self.total_requests += 1
    
    def _record_error(self, model: str, latency_ms: float, error_code, error_msg: str):
        self.metrics.append(RequestMetrics(
            timestamp=time.time(),
            latency_ms=latency_ms,
            success=False,
            model=model,
            error_type=f"{error_code}: {error_msg}"
        ))
        self.error_counts[error_code] += 1
        self.total_requests += 1
    
    def get_sla_report(self, window_seconds: int = 300) -> dict:
        """Generate SLA report for monitoring window"""
        cutoff_time = time.time() - window_seconds
        recent_metrics = [m for m in self.metrics if m.timestamp >= cutoff_time]
        
        if not recent_metrics:
            return {"error": "No data in window"}
        
        total = len(recent_metrics)
        successful = sum(1 for m in recent_metrics if m.success)
        success_rate = (successful / total) * 100
        
        latencies = [m.latency_ms for m in recent_metrics]
        latencies.sort()
        
        return {
            "window_seconds": window_seconds,
            "total_requests": total,
            "successful_requests": successful,
            "success_rate_pct": round(success_rate, 3),
            "sla_compliant": success_rate >= 99.5,
            "latency": {
                "p50": round(latencies[int(len(latencies) * 0.50)], 2),
                "p95": round(latencies[int(len(latencies) * 0.95)], 2),
                "p99": round(latencies[int(len(latencies) * 0.99)], 2),
                "avg": round(statistics.mean(latencies), 2),
                "max": round(max(latencies), 2)
            },
            "error_breakdown": dict(self.error_counts),
            "target_met": success_rate >= 99.5
        }

Sử dụng

monitor = HolySheepSLAMonitor(api_key="YOUR_HOLYSHEEP_API_KEY") async def main(): # Test với các model khác nhau models = ["gpt-4.1", "claude-sonnet-4.5", "gemini-2.5-flash", "deepseek-v3.2"] for model in models: result = await monitor.call_with_metrics( model=model, prompt="Hello, tell me a short joke" ) print(f"{model}: {result}") # In SLA report report = monitor.get_sla_report(window_seconds=300) print(f"\n=== SLA Report ===") print(f"Success Rate: {report['success_rate_pct']}%") print(f"SLA Compliant: {report['sla_compliant']}") print(f"P99 Latency: {report['latency']['p99']}ms") if __name__ == "__main__": asyncio.run(main())

Prometheus Integration

# prometheus.yml
scrape_configs:
  - job_name: 'holysheep-sla-monitor'
    static_configs:
      - targets: ['your-monitor-host:9090']
    metrics_path: '/metrics'

Exporters cần expose các metrics:

- holysheep_request_total{status="success|error",model="xxx"}

- holysheep_request_latency_seconds{quantile="0.99",model="xxx"}

- holysheep_token_usage_total{model="xxx"}

- holysheep_cost_estimate_usd{model="xxx"}

Rate Limiting — Triển khai tầng bảo vệ đầu tiên

Rate limiting là lớp bảo vệ quan trọng nhất để ngăn chặn cost explosion và abuse. Tôi khuyến nghị triển khai multi-tier rate limiting.

Architecture Rate Limiting

#!/usr/bin/env python3
"""
Multi-Tier Rate Limiting với Token Bucket + Sliding Window
Tier 1: Per-User (100 req/min)
Tier 2: Per-API-Key (1000 req/min) 
Tier 3: Per-Model (500 req/min)
"""

import time
import asyncio
import hashlib
from dataclasses import dataclass, field
from typing import Dict, Optional, Tuple
from collections import defaultdict
import threading

@dataclass
class RateLimitConfig:
    requests_per_minute: int
    burst_size: int
    window_seconds: int = 60

class TokenBucket:
    """Token Bucket implementation với refill logic"""
    
    def __init__(self, capacity: int, refill_rate: float):
        self.capacity = capacity
        self.refill_rate = refill_rate  # tokens per second
        self.tokens = float(capacity)
        self.last_refill = time.time()
        self._lock = threading.Lock()
    
    def consume(self, tokens: int = 1) -> Tuple[bool, float]:
        """Try to consume tokens, returns (allowed, wait_time_ms)"""
        with self._lock:
            self._refill()
            
            if self.tokens >= tokens:
                self.tokens -= tokens
                return True, 0.0
            
            # Calculate wait time
            tokens_needed = tokens - self.tokens
            wait_seconds = tokens_needed / self.refill_rate
            return False, wait_seconds * 1000
    
    def _refill(self):
        """Refill tokens based on elapsed time"""
        now = time.time()
        elapsed = now - self.last_refill
        
        if elapsed > 0:
            new_tokens = elapsed * self.refill_rate
            self.tokens = min(self.capacity, self.tokens + new_tokens)
            self.last_refill = now

class SlidingWindowCounter:
    """Sliding Window Counter cho accurate rate limiting"""
    
    def __init__(self, window_seconds: int = 60, max_requests: int = 100):
        self.window_seconds = window_seconds
        self.max_requests = max_requests
        self.requests: Dict[str, list] = defaultdict(list)
        self._lock = threading.Lock()
    
    def is_allowed(self, key: str, request_count: int = 1) -> Tuple[bool, int, float]:
        """
        Check if request is allowed
        Returns: (allowed, current_count, retry_after_seconds)
        """
        with self._lock:
            now = time.time()
            window_start = now - self.window_seconds
            
            # Clean old requests
            self.requests[key] = [
                ts for ts in self.requests[key] 
                if ts > window_start
            ]
            
            current_count = len(self.requests[key])
            
            if current_count + request_count <= self.max_requests:
                self.requests[key].extend([now] * request_count)
                return True, current_count + request_count, 0.0
            
            # Calculate retry-after
            oldest_in_window = min(self.requests[key]) if self.requests[key] else now
            retry_after = (oldest_in_window + self.window_seconds) - now
            
            return False, current_count, max(0, retry_after)

class MultiTierRateLimiter:
    """
    Multi-tier rate limiter
    Check order: User -> API Key -> Model -> Global
    """
    
    def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
        self.api_key = api_key
        self.base_url = base_url
        
        # Tier configurations
        self.tier_configs = {
            "user": RateLimitConfig(requests_per_minute=100, burst_size=20),
            "api_key": RateLimitConfig(requests_per_minute=1000, burst_size=100),
            "model": RateLimitConfig(requests_per_minute=500, burst_size=50),
        }
        
        # Sliding window counters
        self.sliding_windows = {
            tier: SlidingWindowCounter(
                window_seconds=cfg.window_seconds,
                max_requests=cfg.requests_per_minute
            )
            for tier, cfg in self.tier_configs.items()
        }
        
        # Token buckets for burst handling
        self.token_buckets = {
            tier: TokenBucket(
                capacity=cfg.burst_size,
                refill_rate=cfg.requests_per_minute / 60.0
            )
            for tier, cfg in self.tier_configs.items()
        }
    
    def _get_user_id(self, request_context: dict) -> str:
        """Extract user identifier from request context"""
        return hashlib.sha256(
            f"{request_context.get('user_id', 'anonymous')}"
            .encode()
        ).hexdigest()[:16]
    
    def _get_model_id(self, model: str) -> str:
        """Get model-specific identifier"""
        return f"model:{model}"
    
    async def check_rate_limit(
        self, 
        request_context: dict,
        model: str,
        tokens: int = 1
    ) -> Tuple[bool, Optional[float], dict]:
        """
        Check all rate limit tiers
        Returns: (allowed, retry_after_ms, breakdown)
        """
        user_id = self._get_user_id(request_context)
        api_key_id = self.api_key[:8]  # Partial key for identification
        model_id = self._get_model_id(model)
        
        tiers_to_check = [
            ("user", user_id),
            ("api_key", api_key_id),
            ("model", model_id)
        ]
        
        breakdown = {}
        max_retry_after = 0.0
        
        for tier, key in tiers_to_check:
            # Check sliding window
            allowed, count, retry_after = self.sliding_windows[tier].is_allowed(key)
            
            # Check token bucket for burst
            bucket_allowed, wait_ms = self.token_buckets[tier].consume()
            
            total_wait = max(retry_after, wait_ms / 1000)
            breakdown[tier] = {
                "allowed": allowed and bucket_allowed,
                "count": count,
                "retry_after_s": total_wait
            }
            
            if not (allowed and bucket_allowed):
                max_retry_after = max(max_retry_after, total_wait)
        
        is_allowed = all(b["allowed"] for b in breakdown.values())
        
        return is_allowed, max_retry_after if not is_allowed else None, breakdown
    
    async def call_with_rate_limit(
        self,
        request_context: dict,
        model: str,
        prompt: str,
        **kwargs
    ) -> dict:
        """Make API call với rate limit enforcement"""
        
        allowed, retry_after, breakdown = await self.check_rate_limit(
            request_context, model
        )
        
        if not allowed:
            return {
                "success": False,
                "error": "rate_limit_exceeded",
                "retry_after_ms": retry_after * 1000,
                "breakdown": breakdown
            }
        
        # Proceed with API call through HolySheep
        import aiohttp
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            **kwargs
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(
                f"{self.base_url}/chat/completions",
                headers=headers,
                json=payload
            ) as response:
                return await response.json()

Sử dụng

limiter = MultiTierRateLimiter(api_key="YOUR_HOLYSHEEP_API_KEY") async def protected_endpoint(user_id: str, model: str, prompt: str): context = {"user_id": user_id} result = await limiter.call_with_rate_limit( request_context=context, model=model, prompt=prompt ) if not result.get("success", True): print(f"Rate limited! Retry after: {result.get('retry_after_ms')}ms") return result print(f"Success! Tokens: {result.get('usage', {}).get('total_tokens')}") return result

Test

asyncio.run(protected_endpoint("user_123", "deepseek-v3.2", "Hello!"))

Retry Logic thông minh

Retry logic cần được thiết kế cẩn thận để tránh cascade failure. Dưới đây là implementation với exponential backoff và jitter.

#!/usr/bin/env python3
"""
Smart Retry với Exponential Backoff, Jitter và Circuit Breaker
Hỗ trợ HolySheep AI với multi-model fallback
"""

import time
import asyncio
import random
from enum import Enum
from dataclasses import dataclass, field
from typing import Callable, Optional, List, Any
from collections import defaultdict
import aiohttp

class RetryStrategy(Enum):
    EXPONENTIAL = "exponential"
    LINEAR = "linear"
    FIBONACCI = "fibonacci"

@dataclass
class RetryConfig:
    max_attempts: int = 3
    base_delay_ms: int = 100
    max_delay_ms: int = 5000
    strategy: RetryStrategy = RetryStrategy.EXPONENTIAL
    jitter: bool = True
    jitter_factor: float = 0.3
    retryable_status_codes: List[int] = field(
        default_factory=lambda: [408, 429, 500, 502, 503, 504]
    )
    retryable_exceptions: tuple = (
        aiohttp.ClientError,
        asyncio.TimeoutError,
        ConnectionError
    )

class CircuitState(Enum):
    CLOSED = "closed"      # Normal operation
    OPEN = "open"          # Failing, reject requests
    HALF_OPEN = "half_open"  # Testing if recovery possible

@dataclass
class CircuitBreaker:
    name: str
    failure_threshold: int = 5
    recovery_timeout_seconds: float = 30.0
    half_open_max_calls: int = 3
    
    state: CircuitState = field(default=CircuitState.CLOSED)
    failure_count: int = field(default=0)
    success_count: int = field(default=0)
    last_failure_time: float = field(default=0)
    half_open_calls: int = field(default=0)
    
    async def call(self, func: Callable, *args, **kwargs) -> Any:
        """Execute function with circuit breaker protection"""
        
        if self.state == CircuitState.OPEN:
            if time.time() - self.last_failure_time >= self.recovery_timeout_seconds:
                self.state = CircuitState.HALF_OPEN
                self.half_open_calls = 0
                return await func(*args, **kwargs)
            else:
                raise CircuitBreakerOpenError(f"Circuit {self.name} is OPEN")
        
        if self.state == CircuitState.HALF_OPEN:
            if self.half_open_calls >= self.half_open_max_calls:
                raise CircuitBreakerOpenError(
                    f"Circuit {self.name} half-open limit reached"
                )
            self.half_open_calls += 1
        
        try:
            result = await func(*args, **kwargs)
            self._on_success()
            return result
        except Exception as e:
            self._on_failure()
            raise
    
    def _on_success(self):
        if self.state == CircuitState.HALF_OPEN:
            self.success_count += 1
            if self.success_count >= self.half_open_max_calls:
                self.state = CircuitState.CLOSED
                self.failure_count = 0
                self.success_count = 0
        else:
            self.failure_count = max(0, self.failure_count - 1)
    
    def _on_failure(self):
        self.failure_count += 1
        self.last_failure_time = time.time()
        
        if self.state == CircuitState.HALF_OPEN:
            self.state = CircuitState.OPEN
            self.success_count = 0
        elif self.failure_count >= self.failure_threshold:
            self.state = CircuitState.OPEN
    
    def get_status(self) -> dict:
        return {
            "name": self.name,
            "state": self.state.value,
            "failure_count": self.failure_count,
            "success_count": self.success_count
        }

class CircuitBreakerOpenError(Exception):
    pass

class SmartRetry:
    """Smart retry với exponential backoff, jitter và circuit breaker"""
    
    def __init__(self, config: RetryConfig, circuit_breaker: Optional[CircuitBreaker] = None):
        self.config = config
        self.circuit_breaker = circuit_breaker
        self.call_counts = defaultdict(int)
    
    def _calculate_delay(self, attempt: int) -> float:
        """Calculate delay with exponential backoff and jitter"""
        if self.config.strategy == RetryStrategy.EXPONENTIAL:
            delay = self.config.base_delay_ms * (2 ** attempt)
        elif self.config.strategy == RetryStrategy.LINEAR:
            delay = self.config.base_delay_ms * (attempt + 1)
        elif self.config.strategy == RetryStrategy.FIBONACCI:
            a, b = 1, 1
            for _ in range(attempt):
                a, b = b, a + b
            delay = self.config.base_delay_ms * a
        else:
            delay = self.config.base_delay_ms
        
        # Cap at max delay
        delay = min(delay, self.config.max_delay_ms)
        
        # Add jitter
        if self.config.jitter:
            jitter_range = delay * self.config.jitter_factor
            delay = delay + random.uniform(-jitter_range, jitter_range)
        
        return delay / 1000  # Convert to seconds
    
    def _is_retryable(self, error: Exception, response: Optional[dict] = None) -> bool:
        """Determine if error/reponse is retryable"""
        if isinstance(error, self.config.retryable_exceptions):
            return True
        
        if response and isinstance(response, dict):
            status = response.get("status") or response.get("status_code")
            if status in self.config.retryable_status_codes:
                return True
        
        return False
    
    async def execute(
        self, 
        func: Callable, 
        *args, 
        fallback_func: Optional[Callable] = None,
        **kwargs
    ) -> Any:
        """
        Execute function với smart retry logic
        """
        last_error = None
        
        for attempt in range(self.config.max_attempts):
            self.call_counts["attempt"] += 1
            
            try:
                if self.circuit_breaker:
                    result = await self.circuit_breaker.call(func, *args, **kwargs)
                else:
                    result = await func(*args, **kwargs)
                
                # Check if response indicates error
                if isinstance(result, dict):
                    status = result.get("status") or result.get("status_code")
                    if status in self.config.retryable_status_codes:
                        raise aiohttp.ClientResponseError(
                            request_info=None,
                            history=None,
                            status=status,
                            message=result.get("error", "Unknown error")
                        )
                
                return result
                
            except Exception as e:
                last_error = e
                self.call_counts["error"] += 1
                
                # Check if should retry
                if not self._is_retryable(e) or attempt == self.config.max_attempts - 1:
                    break
                
                # Calculate delay
                delay = self._calculate_delay(attempt)
                
                print(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay:.2f}s...")
                await asyncio.sleep(delay)
        
        # Fallback if available
        if fallback_func:
            self.call_counts["fallback"] += 1
            print("Primary failed, attempting fallback...")
            return await fallback_func()
        
        raise last_error

class HolySheepMultiModelRetry:
    """
    Multi-model retry với automatic fallback
    Priority: Primary Model -> Fallback 1 -> Fallback 2 -> Error
    """
    
    def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
        self.api_key = api_key
        self.base_url = base_url
        
        # Model priority chain (cheapest first for cost optimization)
        self.model_chain = [
            ("deepseek-v3.2", RetryConfig(max_attempts=3)),
            ("gemini-2.5-flash", RetryConfig(max_attempts=2)),
            ("claude-sonnet-4.5", RetryConfig(max_attempts=2)),
            ("gpt-4.1", RetryConfig(max_attempts=1)),
        ]
        
        # Circuit breakers per model
        self.circuit_breakers = {
            model: CircuitBreaker(
                name=model,
                failure_threshold=3,
                recovery_timeout_seconds=60
            )
            for model, _ in self.model_chain
        }
        
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
    
    async def _call_model(self, model: str, prompt: str, **kwargs) -> dict:
        """Call specific model"""
        payload = {
            "model": model,
            "messages": [{"role": "user", "content": prompt}],
            **kwargs
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(
                f"{self.base_url}/chat/completions",
                headers=self.headers,
                json=payload,
                timeout=aiohttp.ClientTimeout(total=30)
            ) as response:
                return await response.json()
    
    async def call_with_fallback(
        self,
        prompt: str,
        primary_model: Optional[str] = None,
        **kwargs
    ) -> dict:
        """
        Call với automatic model fallback
        Tries models in chain until success
        """
        errors = []
        
        # Build effective model chain
        if primary_model:
            chain = [(m, cfg) for m, cfg in self.model_chain if m == primary_model]
            chain += [(m, cfg) for m, cfg in self.model_chain if m != primary_model]
        else:
            chain = self.model_chain
        
        for model, retry_config in chain:
            breaker = self.circuit_breakers[model]
            
            retry = SmartRetry(retry_config, breaker)
            
            try:
                result = await retry.execute(
                    self._call_model,
                    model=model,
                    prompt=prompt,
                    **kwargs
                )
                
                # Add metadata
                result["_meta"] = {
                    "model_used": model,
                    "circuit_status": breaker.get_status()
                }
                
                return result
                
            except Exception as e:
                errors.append({"model": model, "error": str(e)})
                print(f"Model {model} failed: {e}")
                continue
        
        # All models failed
        return {
            "error": "All models failed",
            "errors": errors
        }
    
    def get_health_report(self) -> dict:
        """Get health status of all models"""
        return {
            model: breaker.get_status()
            for model, breaker in self.circuit_breakers.items()
        }

Sử dụng

client = HolySheepMultiModelRetry(api_key="YOUR_HOLYSHEEP_API_KEY") async def main(): # Single call với automatic fallback result = await client.call_with_fallback( prompt="Explain quantum computing in simple terms", temperature=0.7 ) if "error" in result: print(f"All models failed: {result['errors']}") else: print(f"Success with {result['_meta']['model_used']}") print(f"Response: {result['choices'][0]['message']['content']}") # Check model health print("\nModel Health Report:") for model, status in client.get_health_report().items(): print(f" {model}: {status['state']}") asyncio.run(main())

Multi-Model Fallback và Circuit Breaker

Đây là phần quan trọng nhất trong SRE checklist. Tôi đã triển khai hệ thống circuit breaker cho từng model và automatic fallback chain.

Model Fallback Chain Strategy

#!/usr/bin/env python3
"""
Production Multi-Model Fallback System
Priority: deepseek-v3.2 (cheapest) -> gemini-2.5-flash -> claude-sonnet-4.5 -> gpt-4.1

HolySheep Pricing 2026 (per 1M tokens):
- deepseek-v3.2: $0.42 (INPUT) / $0.42 (OUTPUT)
- gemini-2.5-flash: $2.50 (INPUT) / $10.00 (OUTPUT)
- claude-sonnet-4.5: $15.00 (INPUT) / $15.00 (OUTPUT)
- gpt-4.1: $8.00 (INPUT) / $8.00 (OUTPUT)
"""

import asyncio
import aiohttp
import time
from dataclasses import dataclass
from typing import List, Optional, Tuple
from enum import Enum

class ModelTier(Enum):
    TIER_1_CHEAP = "deepseek-v3.2"      # $0.42/M
    TIER_2_BALANCED = "gemini-2.5-flash" # $2.50/M
    TIER_3_PREMIUM = "claude-sonnet-4.5" # $15.00/M
    TIER_4_MAX = "gpt-4.1"               # $8.00/M

@dataclass
class ModelConfig:
    name: str
    max_tokens: int
    timeout_seconds: float
    failure_threshold: int
    recovery_timeout_seconds: float
    input_cost_per_m: float
    output_cost_per_m: float

MODEL_CONFIGS = {
    "deepseek-v3.2": ModelConfig(
        name="deepseek-v3.2",
        max_tokens=8192,
        timeout_seconds=10.0,
        failure_threshold=5,
        recovery_timeout_seconds=60.0,
        input_cost_per_m=0.42,
        output_cost_per_m=0.42
    ),
    "gemini-2.5-flash": ModelConfig(
        name="gemini-2.5-flash",
        max_tokens=8192,
        timeout_seconds=15.0,
        failure_threshold=3,
        recovery_timeout_seconds=120.0,
        input_cost