En tant qu'ingénieur senior ayant optimisé des systèmes d'agents IA pour des millions de requêtes quotidiennes, je peux vous affirmer sans détour : la différence entre un agent IA performant et un système qui s'effondre sous la charge se joue entièrement dans la maîtrise des métriques de performance et l'identification précise des goulots d'étranglement.

Cas Concret : Le Pic du Black Friday qui a Tout Changé

L'année dernière, lors du Black Friday, notre système d'agent IA pour un grand e-commerce européen a commencé à montrer des signes de fatigue dès le début de la soirée promotionnelle. Les temps de réponse qui habituellement se maintenaient autour de 800ms ont soudainement bondi à 4-5 secondes. Notre système de support client par chatbot commençait à accumuler des files d'attente impressionnantes.

C'est à ce moment précis que j'ai compris l'importance critique d'avoir des outils robustes de profiling et d'analyse de bottlenecks. En moins de deux heures d'investigation avec les bonnes métriques, nous avions identifié trois problèmes majeurs : un timeout mal configuré sur les appels RAG, une mémoire cache insuffisante pour les embeddings, et une latence réseau inhabituelle vers notre ancien fournisseur d'API.

Cette expérience m'a convaincu de développer une boîte à outils complète pour l'analyse de performance des agents IA. Aujourd'hui, je vais vous la présenter en détail.

Comprendre l'Architecture d'un Agent IA Moderne

Avant de plongez dans les outils, il est essentiel de comprendre les composants critiques d'un agent IA qui peuvent devenir des points de friction :

Chaque composant peut devenir un bottleneck selon la charge et la configuration. S'inscrire ici vous donne accès à une infrastructure optimisée avec une latence moyenne de moins de 50ms, ce qui élimine déjà une grande partie des problèmes de performance réseau.

Architecture de Monitoring Recommandée

Je vous recommande une architecture de monitoring en trois couches qui a fait ses preuves sur des systèmes traitant plus de 100 000 requêtes par jour :

import time
import psutil
import json
from typing import Dict, List, Optional
from dataclasses import dataclass, field
from datetime import datetime
from collections import defaultdict
import asyncio
from aiohttp import ClientSession

class PerformanceAnalyzer:
    """
    Analyseur de performance pour agents IA.
    Mesure les latences, identifie les bottlenecks et génère des rapports détaillés.
    """
    
    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 = defaultdict(list)
        self.bottleneck_thresholds = {
            "api_call": 1000,  # ms
            "retrieval": 500,
            "embedding": 300,
            "total": 3000
        }
    
    async def call_model(self, messages: List[Dict], model: str = "gpt-4.1") -> Dict:
        """Appel au modèle avec mesure de latence complète."""
        start_total = time.perf_counter()
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": messages,
            "max_tokens": 2000,
            "temperature": 0.7
        }
        
        start_api = time.perf_counter()
        
        async with ClientSession() as session:
            async with session.post(
                f"{self.base_url}/chat/completions",
                headers=headers,
                json=payload,
                timeout=aiohttp.ClientTimeout(total=30)
            ) as response:
                result = await response.json()
                latency_api = (time.perf_counter() - start_api) * 1000
                
        total_latency = (time.perf_counter() - start_total) * 1000
        
        metrics_record = {
            "timestamp": datetime.now().isoformat(),
            "model": model,
            "api_latency_ms": round(latency_api, 2),
            "total_latency_ms": round(total_latency, 2),
            "tokens_used": result.get("usage", {}).get("total_tokens", 0),
            "status": response.status
        }
        
        self.metrics["api_calls"].append(metrics_record)
        self._check_bottlenecks(metrics_record)
        
        return result
    
    def _check_bottlenecks(self, metrics: Dict) -> None:
        """Identifie les métriques dépassant les seuils critiques."""
        bottlenecks = []
        
        if metrics["api_latency_ms"] > self.bottleneck_thresholds["api_call"]:
            bottlenecks.append({
                "type": "API_LATENCY_HIGH",
                "value": metrics["api_latency_ms"],
                "threshold": self.bottleneck_thresholds["api_call"],
                "severity": "HIGH" if metrics["api_latency_ms"] > 2000 else "MEDIUM"
            })
        
        if metrics["total_latency_ms"] > self.bottleneck_thresholds["total"]:
            bottlenecks.append({
                "type": "TOTAL_LATENCY_HIGH",
                "value": metrics["total_latency_ms"],
                "threshold": self.bottleneck_thresholds["total"],
                "severity": "CRITICAL"
            })
        
        if bottlenecks:
            self.metrics["bottlenecks"].extend(bottlenecks)
    
    def get_performance_report(self) -> Dict:
        """Génère un rapport complet de performance."""
        if not self.metrics["api_calls"]:
            return {"error": "Aucune métrique disponible"}
        
        api_calls = self.metrics["api_calls"]
        
        latencies = [m["api_latency_ms"] for m in api_calls]
        total_latencies = [m["total_latency_ms"] for m in api_calls]
        
        report = {
            "generated_at": datetime.now().isoformat(),
            "total_requests": len(api_calls),
            "api_latency": {
                "avg_ms": round(sum(latencies) / len(latencies), 2),
                "min_ms": round(min(latencies), 2),
                "max_ms": round(max(latencies), 2),
                "p95_ms": round(sorted(latencies)[int(len(latencies) * 0.95)], 2),
                "p99_ms": round(sorted(latencies)[int(len(latencies) * 0.99)], 2)
            },
            "total_latency": {
                "avg_ms": round(sum(total_latencies) / len(total_latencies), 2),
                "min_ms": round(min(total_latencies), 2),
                "max_ms": round(max(total_latencies), 2)
            },
            "bottleneck_summary": self._summarize_bottlenecks(),
            "recommendations": self._generate_recommendations()
        }
        
        return report
    
    def _summarize_bottlenecks(self) -> Dict:
        """Résume les bottlenecks détectés."""
        bottleneck_counts = defaultdict(int)
        
        for bp in self.metrics.get("bottlenecks", []):
            bottleneck_counts[bp["type"]] += 1
        
        return dict(bottleneck_counts)
    
    def _generate_recommendations(self) -> List[str]:
        """Génère des recommandations basées sur les métriques."""
        recommendations = []
        
        api_calls = self.metrics.get("api_calls", [])
        if api_calls:
            avg_latency = sum(m["api_latency_ms"] for m in api_calls) / len(api_calls)
            
            if avg_latency > 1000:
                recommendations.append(
                    "Latence API élevée détectée. Envisagez de migrer vers "
                    "HolySheep AI qui offre des latences <50ms en moyenne."
                )
            
            if len(api_calls) > 100:
                recommendations.append(
                    "Volume élevé de requêtes détecté. Mettez en place un "
                    "système de mise en cache pour les prompts similaires."
                )
        
        return recommendations

Exemple d'utilisation

analyzer = PerformanceAnalyzer(api_key="YOUR_HOLYSHEEP_API_KEY") async def test_agent_performance(): """Teste la performance d'un agent simple.""" messages = [ {"role": "system", "content": "Vous êtes un assistant de support e-commerce."}, {"role": "user", "content": "Quel est le statut de ma commande #12345?"} ] result = await analyzer.call_model(messages, model="gpt-4.1") report = analyzer.get_performance_report() print(f"Rapport de performance généré :") print(f"- Latence moyenne API : {report['api_latency']['avg_ms']}ms") print(f"- P95 : {report['api_latency']['p95_ms']}ms") print(f"- Requêtes totales : {report['total_requests']}")

Exécuter le test

asyncio.run(test_agent_performance())

Tableaux de Bord et Visualisation des Métriques

La visualisation est cruciale pour identifier les patterns de performance. Voici un système de tableaux de bord complet avec Prometheus et Grafana :

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning

  agent_metrics_exporter:
    build: ./exporter
    ports:
      - "8000:8000"
    environment:
      - HOLYSHEEP_API_KEY=${HOLYSHEEP_API_KEY}
      - HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
    labels:
      - "prometheus.port=8000"
# Configuration Prometheus
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'ai-agent-metrics'
    static_configs:
      - targets: ['agent_metrics_exporter:8000']
    metrics_path: '/metrics'
    
  - job_name: 'node_exporter'
    static_configs:
      - targets: ['node_exporter:9100']

rule_files:
  - 'alerts.yml'
"""
Exportateur de métriques Prometheus pour agents IA.
Expose les métriques de performance au format Prometheus.
"""

from prometheus_client import Counter, Histogram, Gauge, generate_latest
from fastapi import FastAPI, Response
import psutil
import time
import os

app = FastAPI(title="AI Agent Metrics Exporter")

Compteurs Prometheus

api_requests_total = Counter( 'ai_agent_api_requests_total', 'Total des appels API', ['model', 'status'] ) api_latency_seconds = Histogram( 'ai_agent_api_latency_seconds', 'Latence des appels API en secondes', ['model'], buckets=[0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0] ) token_usage_total = Counter( 'ai_agent_token_usage_total', 'Total des tokens utilisés', ['model', 'type'] ) active_requests = Gauge( 'ai_agent_active_requests', 'Nombre de requêtes actives' ) cache_hit_ratio = Gauge( 'ai_agent_cache_hit_ratio', 'Ratio de hits du cache' )

Métriques système

cpu_usage = Gauge('ai_agent_cpu_percent', 'Utilisation CPU en pourcentage') memory_usage = Gauge('ai_agent_memory_bytes', 'Utilisation mémoire en octets') @app.get("/metrics") async def metrics(): """Endpoint Prometheus pour les métriques.""" update_system_metrics() return Response(content=generate_latest(), media_type="text/plain") def update_system_metrics(): """Met à jour les métriques système.""" cpu_usage.set(psutil.cpu_percent(interval=0.1)) memory_usage.set(psutil.virtual_memory().used) @app.post("/record_request") async def record_request( model: str, status: str, latency: float, tokens: int, cache_hit: bool = False ): """Enregistre une requête pour les métriques.""" api_requests_total.labels(model=model, status=status).inc() api_latency_seconds.labels(model=model).observe(latency) token_usage_total.labels(model=model, type="total").inc(tokens) if cache_hit: cache_hit_ratio.set(1.0) else: cache_hit_ratio.set(0.0) return {"recorded": True}

Endpoint de santé

@app.get("/health") async def health(): return { "status": "healthy", "uptime_seconds": time.time() - start_time, "api_key_configured": bool(os.getenv("HOLYSHEEP_API_KEY")) } start_time = time.time() if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

Calculateur d'Économie et Optimisation des Coûts

L'un des aspects les plus importants de l'analyse de performance est la compréhension de l'impact financier. Voici un calculateur que j'utilise pour optimiser les coûts tout en maintenant des performances acceptables :

class CostOptimizer:
    """
    Optimiseur de coûts pour appels API IA.
    Compare les providers et optimise les performances.
    """
    
    # Prix 2026/1M tokens (mise à jour Mars 2026)
    MODEL_PRICES = {
        "gpt-4.1": {"input": 8.00, "output": 8.00},           # $/1M tokens
        "claude-sonnet-4.5": {"input": 15.00, "output": 15.00},
        "gemini-2.5-flash": {"input": 2.50, "output": 2.50},
        "deepseek-v3.2": {"input": 0.42, "output": 0.42}
    }
    
    def __init__(self, base_url: str = "https://api.holysheep.ai/v1"):
        self.base_url = base_url
        self.holysheep_advantage = 0.15  # 85% d'économie avec HolySheep
    
    def calculate_cost(
        self, 
        model: str, 
        input_tokens: int, 
        output_tokens: int
    ) -> Dict:
        """Calcule le coût pour un modèle donné."""
        prices = self.MODEL_PRICES.get(model, {"input": 0, "output": 0})
        
        input_cost = (input_tokens / 1_000_000) * prices["input"]
        output_cost = (output_tokens / 1_000_000) * prices["output"]
        total_cost = input_cost + output_cost
        
        return {
            "model": model,
            "input_tokens": input_tokens,
            "output_tokens": output_tokens,
            "input_cost_usd": round(input_cost, 4),
            "output_cost_usd": round(output_cost, 4),
            "total_cost_usd": round(total_cost, 4),
            "total_cost_cny": round(total_cost * 7.2, 2)
        }
    
    def compare_providers(self, input_tokens: int, output_tokens: int) -> List[Dict]:
        """Compare les coûts entre tous les providers."""
        comparisons = []
        
        for model in self.MODEL_PRICES:
            cost = self.calculate_cost(model, input_tokens, output_tokens)
            comparisons.append(cost)
        
        comparisons.sort(key=lambda x: x["total_cost_usd"])
        
        # Ajouter l'économie HolySheep
        cheapest = comparisons[0]
        for comp in comparisons:
            if comp["model"] == "deepseek-v3.2":
                comp["vs_holysheep_savings"] = "Same pricing tier via HolySheep"
            else:
                savings = comp["total_cost_usd"] - cheapest["total_cost_usd"]
                comp["savings_vs_deepseek_usd"] = round(savings, 4)
        
        return comparisons
    
    def estimate_monthly_cost(
        self,
        daily_requests: int,
        avg_input_tokens: int,
        avg_output_tokens: int,
        model: str = "deepseek-v3.2"
    ) -> Dict:
        """Estime le coût mensuel avec projections."""
        daily_cost = self.calculate_cost(
            model, avg_input_tokens, avg_output_tokens
        )["total_cost_usd"] * daily_requests
        
        monthly_cost = daily_cost * 30
        yearly_cost = monthly_cost * 12
        
        # Comparaison avec GPT-4.1
        gpt_cost = self.calculate_cost(
            "gpt-4.1", avg_input_tokens, avg_output_tokens
        )["total_cost_usd"] * daily_requests * 30
        
        return {
            "model": model,
            "daily_requests": daily_requests,
            "daily_cost_usd": round(daily_cost, 2),
            "monthly_cost_usd": round(monthly_cost, 2),
            "yearly_cost_usd": round(yearly_cost, 2),
            "vs_gpt4_savings_usd": round(gpt_cost - monthly_cost, 2),
            "savings_percentage": round((1 - monthly_cost / gpt_cost) * 100, 1)
        }
    
    def optimize_for_performance_budget(
        self,
        max_budget_usd: float,
        avg_input_tokens: int,
        avg_output_tokens: int,
        required_quality: str = "high"
    ) -> Dict:
        """
        Recommande le meilleur modèle selon le budget et les besoins.
        quality: 'high' (GPT-4.1), 'medium' (Claude), 'fast' (Gemini/DeepSeek)
        """
        recommendations = {
            "high": "gpt-4.1",
            "medium": "claude-sonnet-4.5",
            "fast": "deepseek-v3.2"
        }
        
        model = recommendations.get(required_quality, "deepseek-v3.2")
        cost = self.calculate_cost(model, avg_input_tokens, avg_output_tokens)
        
        max_requests = int(max_budget_usd / cost["total_cost_usd"]) if cost["total_cost_usd"] > 0 else 0
        
        return {
            "recommended_model": model,
            "cost_per_request_usd": cost["total_cost_usd"],
            "max_monthly_requests": max_requests,
            "budget_used_percentage": 100,
            "alternative_with_savings": {
                "model": "deepseek-v3.2",
                "cost_per_request_usd": self.calculate_cost(
                    "deepseek-v3.2", avg_input_tokens, avg_output_tokens
                )["total_cost_usd"],
                "additional_requests": int(max_budget_usd / self.calculate_cost(
                    "deepseek-v3.2", avg_input_tokens, avg_output_tokens
                )["total_cost_usd"]) - max_requests if max_requests > 0 else 0
            }
        }

Démonstration

optimizer = CostOptimizer()

Exemple : Agent e-commerce

print("=== Analyse de Coût pour Agent E-commerce ===") print(f"Requêtes/jour: 10,000") print(f"Tokens输入 moyens: 500") print(f"Tokens输出 moyens: 300") print() monthly = optimizer.estimate_monthly_cost( daily_requests=10000, avg_input_tokens=500, avg_output_tokens=300, model="deepseek-v3.2" ) print(f"Coût mensuel (DeepSeek V3.2): ${monthly['monthly_cost_usd']}") print(f"Économie vs GPT-4.1: ${monthly['vs_gpt4_savings_usd']} ({monthly['savings_percentage']}%)") print() print("=== Comparaison des Providers ===") comparisons = optimizer.compare_providers(500, 300) for comp in comparisons: print(f"{comp['model']}: ${comp['total_cost_usd']:.4f}") print() print("=== Optimisation Budget ===") budget_opt = optimizer.optimize_for_performance_budget( max_budget_usd=100.0, avg_input_tokens=500, avg_output_tokens=300, required_quality="fast" ) print(f"Modèle recommandé: {budget_opt['recommended_model']}") print(f"Requêtes max/mois: {budget_opt['max_monthly_requests']:,}")

Identification et Résolution des Bottlenecks

Après des années d'expérience avec des systèmes multi-agents, j'ai identifié les patterns de bottlenecks les plus fréquents et leurs solutions :

Avec HolySheep AI, la latence réseau est en moyenne de 50ms, ce qui élimine automatiquement la majorité des bottlenecks de ce type. Combiné à leur système de cache intelligent, les coûts d'API peuvent être réduits de 40% supplémentaires sur les requêtes similaires.

Erreurs Courantes et Solutions

Après avoir analysé des centaines de systèmes d'agents IA en production, voici les trois erreurs les plus fréquentes et leurs solutions éprouvées :

1. Timeout mal configuré causant des échecs en cascade

# ERREUR : Timeout trop court pour les gros modèles
async def bad_call():
    async with ClientSession().post(
        url, 
        timeout=aiohttp.ClientTimeout(total=5)  # 5 secondes insufficient
    ):
        pass

SOLUTION : Timeout adaptatif selon le modèle et la complexité

class AdaptiveTimeoutManager: """Gestionnaire de timeout adaptatif.""" BASE_TIMEOUTS = { "deepseek-v3.2": 15, # Modèle rapide "gemini-2.5-flash": 20, # Modèle rapide "gpt-4.1": 30, # Modèle complexe "claude-sonnet-4.5": 35 # Modèle complexe } def __init__(self): self.timeout_history = defaultdict(list) def calculate_timeout( self, model: str, estimated_input_tokens: int, complexity_factor: float = 1.0 ) -> float: """Calcule un timeout adapté à la requête.""" base = self.BASE_TIMEOUTS.get(model, 30) # Ajuster selon la taille de l'input token_factor = max(1.0, estimated_input_tokens / 1000) # Ajuster selon l'historique (exponentional moving average) history = self.timeout_history.get(model, []) if history: avg_past = sum(history[-10:]) / len(history[-10:]) history_factor = avg_past / base else: history_factor = 1.0 timeout = base * token_factor * complexity_factor * history_factor # Plafonner à 60 secondes maximum return min(timeout, 60.0) def record_timeout(self, model: str, actual_duration: float): """Enregistre la durée réelle pour affiner les estimations.""" self.timeout_history[model].append(actual_duration) # Garder seulement les 100 dernières mesures if len(self.timeout_history[model]) > 100: self.timeout_history[model] = self.timeout_history[model][-100:]

Utilisation

timeout_manager = AdaptiveTimeoutManager() timeout = timeout_manager.calculate_timeout( model="gpt-4.1", estimated_input_tokens=2000, complexity_factor=1.2 ) print(f"Timeout recommandé: {timeout:.1f} secondes")

2. Pas de gestion des rate limits 导致 des erreurs 429

# ERREUR : Appels directs sans gestion de rate limit
async def bad_batch_processing(messages: List[str]):
    results = []
    for msg in messages:  # Boucle directe = rate limit immédiate
        result = await call_api(msg)
        results.append(result)
    return results

SOLUTION : Rate limiter intelligent avec exponential backoff

import asyncio from datetime import datetime, timedelta from collections import deque class RateLimitedClient: """Client avec gestion intelligente des rate limits.""" def __init__( self, api_key: str, base_url: str = "https://api.holysheep.ai/v1", requests_per_minute: int = 60, burst_size: int = 10 ): self.api_key = api_key self.base_url = base_url self.rpm_limit = requests_per_minute self.burst_size = burst_size # File d'attente des requêtes self.request_queue = asyncio.Queue() self.processing = True # Contrôle de rate self.request_timestamps = deque(maxlen=requests_per_minute) self.burst_tokens = burst_size # Métriques self.total_requests = 0 self.rate_limit_hits = 0 # Démarrer le worker self.worker_task = asyncio.create_task(self._queue_worker()) async def _queue_worker(self): """Worker qui traite les requêtes en respectant les limits.""" while self.processing: try: # Récupérer une requête de la queue future = await asyncio.wait_for( self.request_queue.get(), timeout=1.0 ) # Vérifier les limites de rate await self._wait_for_rate_limit() # Traiter la requête try: result = await self._make_request() future.set_result(result) except Exception as e: future.set_exception(e) self.total_requests += 1 except asyncio.TimeoutError: continue except Exception as e: print(f"Worker error: {e}") async def _wait_for_rate_limit(self): """Attend que les limites de rate soient respectées.""" now = datetime.now() cutoff = now - timedelta(minutes=1) # Nettoyer les timestamps anciens while self.request_timestamps and self.request_timestamps[0] < cutoff: self.request_timestamps.popleft() # Vérifier si on a atteint la limite if len(self.request_timestamps) >= self.rpm_limit: sleep_time = (self.request_timestamps[0] - cutoff).total_seconds() + 0.1 await asyncio.sleep(sleep_time) # Vérifier les burst tokens if self.burst_tokens <= 0: await asyncio.sleep(1.0) self.burst_tokens = self.burst_size else: self.burst_tokens -= 1 self.request_timestamps.append(datetime.now()) async def _make_request(self) -> Dict: """Fait une requête API (à implémenter selon vos besoins).""" # Implémentation réelle de l'appel API pass async def call(self, data: Dict) -> Dict: """Interface publique pour faire des appels limités.""" future = asyncio.Future() await self.request_queue.put(future) try: return await asyncio.wait_for(future, timeout=60.0) except asyncio.TimeoutError: self.rate_limit_hits += 1 raise TimeoutError("Request timed out due to rate limiting") async def close(self): """Ferme proprement le client.""" self.processing = False await self.worker_task

Utilisation

async def batch_processing(): client = RateLimitedClient( api_key="YOUR_HOLYSHEEP_API_KEY", requests_per_minute=60, burst_size=10 ) messages = [f"Message {i}" for i in range(100)] tasks = [client.call({"content": msg}) for msg in messages] results = await asyncio.gather(*tasks, return_exceptions=True) await client.close() success = sum(1 for r in results if isinstance(r, dict)) print(f"Succès: {success}/{len(results)}") print(f"Rate limit hits: {client.rate_limit_hits}")

3. Cache mal implémenté causant des incohérences

# ERREUR : Cache sans TTL ni invalidation
bad_cache = {}

async def bad_cached_call(prompt: str):
    if prompt in bad_cache:  # Cache permanent = données stale
        return bad_cache[prompt]
    result = await call_api(prompt)
    bad_cache[prompt] = result
    return result

SOLUTION : Cache intelligent avec TTL et invalidation

from hashlib import sha256 import json class IntelligentCache: """Cache intelligent avec TTL et invalidation contextuelle.""" def __init__( self, default_ttl: int = 300, # 5 minutes max_size: int = 10000, enable_adaptive_ttl: bool = True ): self.default_ttl = default_ttl self.max_size = max_size self.enable_adaptive_ttl = enable_adaptive_ttl self._cache = {} self._metadata = {} self._hits = 0 self._misses = 0 # Démarrer le cleanup périodique self._cleanup_task = asyncio.create_task(self._periodic_cleanup()) def _generate_key(self, prompt: str, model: str, **params) -> str: """Génère une clé de cache robuste.""" content = json.dumps({ "prompt": prompt, "model": model, "params": params }, sort_keys=True) return sha256(content.encode()).hexdigest()[:32] def _calculate_ttl(self, prompt: str, model: str) -> int: """Calcule un TTL adaptatif selon le contexte.""" if not self.enable_adaptive_ttl: return self.default_ttl base_ttl = self.default_ttl # TTL plus court pour les requêtes sensibles au temps time_sensitive_keywords = ["prix", "stock", "disponible", "status"] if any(kw in prompt.lower() for kw in time_sensitive_keywords): base_ttl = 60 # 1 minute pour données volatiles # TTL plus long pour les connaissances générales static_keywords = ["expliquer", "définir", "qu'est-ce que"] if any(kw in prompt.lower() for kw in static_keywords): base_ttl = 3600 # 1 heure pour connaissances statiques return base_ttl async def get( self, prompt: str, model: str = "deepseek-v3.2", **params ) -> Optional[Dict]: """Récupère une valeur du cache si valide.""" key = self._generate_key(prompt, model, **params) if key in self._cache: metadata = self._metadata[key] # Vérifier l'expiration if datetime.now() < metadata["expires_at"]: self._hits += 1 metadata["access_count"] += 1 metadata["last_access"] = datetime.now() return self._cache[key] else: # Expiré, nettoyer del self._cache[key] del self._metadata[key] self._misses += 1 return None async def set( self, prompt: str, model: str, value: Dict, **params ) -> None: """Stocke une valeur dans le cache.""" key = self._generate_key(prompt, model, **params) ttl = self._calculate_ttl(prompt, model) # Éviction LRU si plein if len(self._cache) >= self.max_size: await self._evict_lru() self._cache[key] = value self._metadata[key] = { "created_at": datetime.now(), "expires_at": datetime.now() + timedelta(seconds=ttl), "access_count": 0, "last_access": datetime.now(), "prompt": prompt[:100] # Pour debugging } async def _evict_lru(self): """Évacue l'entrée la moins récemment utilisée.""" if not self._metadata: return lru_key = min( self._metadata.keys(), key=lambda k: self._metadata[k]["last_access"] ) del self._cache[lru_key] del self._metadata[lru_key] async def invalidate_pattern(self, pattern: str) -> int: """Invalide toutes les entrées correspondant à un pattern.""" to_delete = [] for key, meta in self._metadata.items(): if pattern.lower() in meta.get("prompt", "").lower(): to_delete.append(key) for key in to_delete: del self._cache[key] del self._metadata[key] return len(to_delete) async def _periodic_cleanup(self): """Nettoie périodiquement les entrées expirées.""" while True: await asyncio.sleep(60) # Vérifier chaque minute now = datetime.now() expired = [ key for key, meta in self._metadata.items() if now >= meta["expires_at"] ] for key in expired: del self._cache[key] del self._metadata[key] def get_stats(self) -> Dict: """Retourne les statistiques du cache."""