Routage LLM : L'Architecture Secrète qui Réduit vos Coûts IA de 60% (Sans Perte de Qualité)
Guide complet sur le routage LLM pour optimiser les coûts : routage par complexité, cascade, consensus. Comparatif Martian, Unify, OpenRouter. Code et architecture pour un router custom.
Routage LLM : L'Architecture Secrète qui Réduit vos Coûts IA de 60%
Imaginez un monde où chaque requête utilisateur est envoyée au modèle LLM parfait pour la tâche : GPT-4o mini pour les questions simples, Claude 3.5 Sonnet pour l'analyse complexe, Mistral Large pour les tâches en français. Sans que l'utilisateur ne remarque la différence.
C'est exactement ce que fait le routage LLM. Et les entreprises qui l'adoptent réduisent leurs coûts de 50 à 70% avec moins de 2% de perte de qualité.
TL;DR
- Routage LLM = envoyer chaque requête au modèle le plus adapté (rapport qualité/coût optimal)
- 3 stratégies principales : routage par complexité, routage en cascade, routage par consensus
- Économies typiques : 50-70% de réduction des coûts LLM avec < 2% de dégradation qualité
- Outils : Martian, Unify, OpenRouter pour le routage managé ; classifier custom pour le contrôle total
- Pour le RAG : combiner le routage LLM avec le prompt caching pour des économies > 80%
Pourquoi le Routage LLM est Indispensable
Le problème : un seul modèle pour tout
La plupart des entreprises utilisent un seul modèle pour toutes les requêtes :
Toutes les requêtes → GPT-4o → Réponses
$$$$$
Le problème ? 80% des requêtes sont simples et ne nécessitent pas la puissance (et le coût) d'un GPT-4o.
La distribution typique des requêtes
| Complexité | % requêtes | Exemple | Modèle optimal | Coût relatif |
|---|---|---|---|---|
| Triviale | 30% | "Bonjour", "Merci" | Règle simple (pas de LLM) | $0 |
| Simple | 35% | "Quels sont vos horaires ?" | GPT-4o mini / Mistral Small | $0,001 |
| Moyenne | 25% | "Comparez les offres Pro et Business" | Claude 3.5 Haiku / GPT-4o mini | $0,005 |
| Complexe | 8% | "Analysez les tendances de mes ventes Q3" | GPT-4o / Claude 3.5 Sonnet | $0,03 |
| Expert | 2% | "Rédigez un contrat adapté à mon cas" | Claude Opus 4 / GPT-5 | $0,08 |
L'impact financier
Pour 100 000 requêtes/mois :
| Approche | Coût mensuel | Qualité moyenne |
|---|---|---|
| Tout sur GPT-4o | $3 000 | 9,2/10 |
| Tout sur GPT-4o mini | $150 | 7,8/10 |
| Avec routage intelligent | $600 | 9,0/10 |
| Économie vs GPT-4o | -80% | -0,2 point |
Les 3 Stratégies de Routage
Stratégie 1 : Routage par complexité
Le plus courant. Un classifier analyse la requête et l'envoie au bon modèle.
┌─────────────────┐
│ Classifier │
│ (complexité) │
└───┬──────┬──────┘
│ │
┌─────────┼──────┼──────────┐
▼ ▼ ▼ ▼
┌────────┐ ┌──────┐ ┌──────┐ ┌───────┐
│Trivial │ │Simple│ │Medium│ │Complex│
│(règle) │ │(mini)│ │(std) │ │(pro) │
└────────┘ └──────┘ └──────┘ └───────┘
$0 $0,001 $0,005 $0,03
Implémentation :
DEVELOPERpythonfrom openai import OpenAI import anthropic client_openai = OpenAI() client_anthropic = anthropic.Anthropic() # Classifier de complexité (lui-même un LLM léger) CLASSIFIER_PROMPT = """Analyse la complexité de cette requête utilisateur. Réponds UNIQUEMENT par un des niveaux suivants : - TRIVIAL : salutations, remerciements, confirmations - SIMPLE : question factuelle directe, info de base - MEDIUM : comparaison, synthèse, question multi-facettes - COMPLEX : analyse, rédaction longue, raisonnement multi-étapes - EXPERT : tâche créative complexe, analyse de données, juridique Requête : {query} Niveau :""" async def classify_complexity(query: str) -> str: """Classifier la complexité avec un modèle léger.""" response = client_openai.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "user", "content": CLASSIFIER_PROMPT.format(query=query)} ], max_tokens=10, temperature=0, ) return response.choices[0].message.content.strip() # Mapping complexité → modèle MODEL_ROUTING = { "TRIVIAL": None, # Réponse template, pas de LLM "SIMPLE": {"provider": "openai", "model": "gpt-4o-mini"}, "MEDIUM": {"provider": "anthropic", "model": "claude-3-5-haiku-20241022"}, "COMPLEX": {"provider": "openai", "model": "gpt-4o"}, "EXPERT": {"provider": "anthropic", "model": "claude-sonnet-4-20250514"}, } TRIVIAL_RESPONSES = { "bonjour": "Bonjour ! Comment puis-je vous aider ?", "merci": "Je vous en prie ! N'hésitez pas si vous avez d'autres questions.", } async def route_and_generate(query: str, context: str) -> dict: """Route la requête vers le bon modèle et génère la réponse.""" complexity = await classify_complexity(query) config = MODEL_ROUTING[complexity] if config is None: # Requête triviale → réponse template for keyword, response in TRIVIAL_RESPONSES.items(): if keyword in query.lower(): return {"response": response, "model": "template", "cost": 0} if config["provider"] == "openai": response = client_openai.chat.completions.create( model=config["model"], messages=[ {"role": "system", "content": f"Contexte:\n{context}"}, {"role": "user", "content": query}, ], ) return { "response": response.choices[0].message.content, "model": config["model"], "cost": estimate_cost(response.usage, config["model"]), } elif config["provider"] == "anthropic": response = client_anthropic.messages.create( model=config["model"], max_tokens=2048, system=f"Contexte:\n{context}", messages=[{"role": "user", "content": query}], ) return { "response": response.content[0].text, "model": config["model"], "cost": estimate_cost_anthropic(response.usage, config["model"]), }
Stratégie 2 : Routage en cascade
Commence par le modèle le moins cher. Si la confiance est trop faible, escalade vers un modèle supérieur.
Query → GPT-4o mini → Confiance > 80% ? → Oui → Réponse ✓
│
Non
↓
Claude 3.5 Sonnet → Confiance > 80% ? → Oui → Réponse ✓
│
Non
↓
GPT-4o → Réponse (forcée) ✓
Implémentation :
DEVELOPERpythonimport re CASCADE_MODELS = [ {"provider": "openai", "model": "gpt-4o-mini", "threshold": 0.8}, {"provider": "anthropic", "model": "claude-sonnet-4-20250514", "threshold": 0.7}, {"provider": "openai", "model": "gpt-4o", "threshold": 0.0}, # Fallback ] CONFIDENCE_PROMPT_SUFFIX = """ Après ta réponse, ajoute sur la dernière ligne : CONFIDENCE: X.XX (entre 0 et 1, ta confiance dans la réponse)""" async def cascade_route(query: str, context: str) -> dict: """Routage en cascade avec évaluation de confiance.""" for config in CASCADE_MODELS: response, confidence = await generate_with_confidence( query, context, config ) if confidence >= config["threshold"]: return { "response": response, "model": config["model"], "cascade_level": CASCADE_MODELS.index(config) + 1, } # Fallback : dernière réponse return { "response": response, "model": CASCADE_MODELS[-1]["model"], "cascade_level": len(CASCADE_MODELS), } async def generate_with_confidence(query, context, config): """Génère une réponse et extrait le score de confiance.""" full_query = query + CONFIDENCE_PROMPT_SUFFIX if config["provider"] == "openai": resp = client_openai.chat.completions.create( model=config["model"], messages=[ {"role": "system", "content": f"Contexte:\n{context}"}, {"role": "user", "content": full_query}, ], ) text = resp.choices[0].message.content else: resp = client_anthropic.messages.create( model=config["model"], max_tokens=2048, system=f"Contexte:\n{context}", messages=[{"role": "user", "content": full_query}], ) text = resp.content[0].text # Extraire la confiance confidence_match = re.search(r"CONFIDENCE:\s*([\d.]+)", text) confidence = float(confidence_match.group(1)) if confidence_match else 0.5 clean_response = re.sub(r"\nCONFIDENCE:.*$", "", text).strip() return clean_response, confidence
Stratégie 3 : Routage par consensus
Pour les requêtes critiques : interroger plusieurs modèles et prendre la réponse majoritaire ou la combiner.
Query → ┌─ GPT-4o mini ──────────┐
├─ Claude 3.5 Haiku ─────┤→ Comparateur → Réponse finale
└─ Mistral Small ────────┘
Implémentation :
DEVELOPERpythonimport asyncio async def consensus_route(query: str, context: str) -> dict: """Interroge 3 modèles et combine les réponses.""" models = [ {"provider": "openai", "model": "gpt-4o-mini"}, {"provider": "anthropic", "model": "claude-3-5-haiku-20241022"}, {"provider": "openai", "model": "gpt-4o-mini"}, # Mistral via OpenAI-compatible ] # Appels parallèles tasks = [generate(query, context, m) for m in models] responses = await asyncio.gather(*tasks) # Combiner les réponses combined = await synthesize_responses(query, responses) return { "response": combined, "models_used": [m["model"] for m in models], "individual_responses": responses, } async def synthesize_responses(query, responses): """Un modèle synthétise les réponses des autres.""" synthesis_prompt = f"""Voici 3 réponses à la même question. Synthétise la meilleure réponse en combinant les points forts de chacune. Si les réponses se contredisent, privilégie le consensus. Question : {query} Réponse 1 : {responses[0]} Réponse 2 : {responses[1]} Réponse 3 : {responses[2]} Synthèse :""" resp = client_openai.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": synthesis_prompt}], ) return resp.choices[0].message.content
Comparatif des Solutions de Routage
Outils de routage managés
| Outil | Type | Modèles supportés | Prix | Latence ajoutée | Production-ready |
|---|---|---|---|---|---|
| Martian | Router ML | 20+ | Usage-based | ~50ms | Oui |
| Unify | Router + benchmark | 50+ | Gratuit (pay LLM) | ~30ms | Oui |
| OpenRouter | Proxy + routage | 100+ | +5,5% sur recharge (pas de markup au token) | ~20ms | Oui |
| RouteLLM | Open-source | Configurable | Gratuit | Variable | Partiellement |
| Custom | DIY | Illimité | Dev time | ~10ms | Dépend |
Martian : Le router ML
DEVELOPERpythonimport requests def route_with_martian(query: str, context: str) -> dict: """Routage via Martian - sélection automatique du meilleur modèle.""" response = requests.post( "https://api.withmartian.com/v1/chat/completions", headers={"Authorization": "Bearer MARTIAN_API_KEY"}, json={ "messages": [ {"role": "system", "content": context}, {"role": "user", "content": query}, ], "model": "router", # Martian choisit le modèle "max_tokens": 1024, "route_params": { "max_cost": 0.01, # Budget max par requête "min_quality": 0.85, # Qualité minimum } } ) result = response.json() return { "response": result["choices"][0]["message"]["content"], "model_used": result["model"], # Quel modèle a été choisi "cost": result["usage"]["total_cost"], }
OpenRouter : L'agrégateur universel
DEVELOPERpythonfrom openai import OpenAI # OpenRouter est compatible OpenAI SDK client = OpenAI( base_url="https://openrouter.ai/api/v1", api_key="OPENROUTER_API_KEY", ) def route_with_openrouter(query: str, context: str) -> dict: """Routage via OpenRouter avec sélection par prix.""" response = client.chat.completions.create( model="openrouter/auto", # Routage automatique messages=[ {"role": "system", "content": context}, {"role": "user", "content": query}, ], max_tokens=1024, extra_body={ "route": "cost", # Optimiser pour le coût # Options : "cost", "quality", "balanced" } ) return { "response": response.choices[0].message.content, "model_used": response.model, }
Unify : Le benchmarker
DEVELOPERpythonimport unify client = unify.Unify(api_key="UNIFY_API_KEY") def route_with_unify(query: str, context: str) -> dict: """Routage via Unify - benchmark-driven.""" response = client.generate( messages=[ {"role": "system", "content": context}, {"role": "user", "content": query}, ], # Syntaxe : model@provider ou "router" model="router", routing_strategy="lowest_cost", # ou "highest_quality", "balanced" ) return { "response": response, "model_used": client.last_model_used, }
Routage LLM pour le RAG
Architecture RAG avec routage
┌────────────────────────────────────────────────────────┐
│ RAG + LLM ROUTING │
├────────────────────────────────────────────────────────┤
│ │
│ Query utilisateur │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Classifier │ ← Analyse complexité + intent │
│ │ (GPT-4o │ │
│ │ mini) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ Simple Complexe │
│ │ │ │
│ ▼ ▼ │
│ ┌──────┐ ┌──────────┐ │
│ │Light │ │ Full │ │
│ │ RAG │ │ RAG │ │
│ │(top3)│ │ (top10 │ │
│ └──┬───┘ │ +rerank)│ │
│ │ └────┬─────┘ │
│ ▼ ▼ │
│ GPT-4o Claude 3.5 │
│ mini Sonnet │
│ ($0,001) ($0,015) │
│ │ │ │
│ └─────┬─────┘ │
│ ▼ │
│ Réponse finale │
└────────────────────────────────────────────────────────┘
Combiner routage et prompt caching
Le combo ultime pour réduire les coûts :
| Optimisation | Économie | Cumulé |
|---|---|---|
| Baseline (GPT-4o pour tout) | 0% | $3 000/mois |
| + Routage par complexité | -60% | $1 200/mois |
| + Prompt caching (Anthropic) | -85% sur cached | $480/mois |
| + Cache sémantique RAG | -30% requêtes | $336/mois |
| Total | -89% | $336/mois |
Métriques et Monitoring
KPIs de routage
DEVELOPERpython# Métriques essentielles à tracker routing_metrics = { # Distribution "requests_per_model": "Counter par modèle", "complexity_distribution": "Histogram des niveaux", # Qualité "user_satisfaction_per_model": "Score moyen par modèle", "cascade_escalation_rate": "% de requêtes escaladées", "consensus_disagreement_rate": "% de désaccords", # Coûts "cost_per_request_avg": "Coût moyen par requête", "cost_savings_vs_single_model": "Économie vs modèle unique", "classifier_cost_overhead": "Surcoût du classifier", # Performance "routing_latency_p50": "< 50ms", "total_latency_p50": "< 2s", "cache_hit_rate": "> 70%", }
Dashboard type
| Métrique | Cible | Alerte si |
|---|---|---|
| Coût moyen / requête | < $0,008 | > $0,015 |
| Qualité moyenne | > 8,5/10 | < 8,0/10 |
| % requêtes vers modèle cher | < 15% | > 25% |
| Latence routage | < 50ms | > 100ms |
| Cache hit rate | > 70% | < 50% |
| Taux d'escalade cascade | < 20% | > 35% |
ROI du Routage LLM
Calculateur ROI
| Profil entreprise | Volume | Sans routage | Avec routage | Économie annuelle |
|---|---|---|---|---|
| Startup | 50K req/mois | $1 500/mois | $450/mois | $12 600/an |
| PME | 300K req/mois | $9 000/mois | $2 700/mois | $75 600/an |
| Enterprise | 2M req/mois | $60 000/mois | $18 000/mois | $504 000/an |
| E-commerce | 1M req/mois | $30 000/mois | $9 000/mois | $252 000/an |
Temps de mise en place
| Approche | Temps dev | Maintenance | Recommandation |
|---|---|---|---|
| OpenRouter auto | 1 jour | Aucune | POC / startup |
| Martian / Unify | 2-3 jours | Faible | PME |
| Custom classifier | 1-2 semaines | Moyenne | Enterprise |
| Custom ML router | 1-2 mois | Élevée | Très gros volumes |
Ailog et le Routage LLM
Le pipeline RAG d'Ailog intègre nativement le routage intelligent :
- Classifier automatique qui analyse la complexité de chaque question
- Multi-modèles avec fallback automatique en cas d'erreur
- Prompt caching combiné pour des économies maximales
- Dashboard de suivi des coûts et de la qualité par modèle
Découvrez aussi le prompt caching pour aller encore plus loin dans l'optimisation, ou explorez les stratégies de caching RAG pour réduire la latence.
FAQ
Le routage LLM ajoute-t-il de la latence ?
Oui, mais très peu. Le classifier ajoute typiquement 30-80ms (un appel GPT-4o mini avec 50 tokens). Pour un budget total de 2-3 secondes de latence, c'est négligeable. L'astuce : utilisez un classifier basé sur des règles (regex, longueur) pour les cas triviaux, et un LLM classifier uniquement pour les cas ambigus.
Comment mesurer la qualité pour ajuster le routage ?
Trois approches complémentaires : (1) feedback utilisateur (pouce haut/bas), (2) LLM-as-judge qui note les réponses sur 10, (3) métriques RAG (faithfulness, relevance) avec des frameworks comme RAGAS. Comparez les scores par modèle pour ajuster les seuils de routage.
Faut-il un router managé ou custom ?
Pour démarrer, un router managé (OpenRouter, Martian) suffit : mise en place en 1 jour, pas de maintenance. Quand votre volume dépasse 500K requêtes/mois ou que vous avez des besoins spécifiques (modèles privés, latence ultra-basse), passez à un classifier custom.
Le routage fonctionne-t-il avec le streaming ?
Oui. Le classifier décide du modèle avant la génération. La réponse est ensuite streamée depuis le modèle choisi, comme d'habitude. La seule contrainte : le routage en cascade avec évaluation de confiance est incompatible avec le streaming pur (il faut attendre la réponse complète pour évaluer la confiance).
Quel est le risque de dégradation de qualité ?
Avec un routage bien calibré, la dégradation est minime : < 2% en moyenne. Le risque principal est un classifier mal entraîné qui envoie des requêtes complexes vers un modèle léger. Solution : commencez conservateur (seuils hauts) et baissez progressivement en monitorant la qualité.
Prêt à diviser vos coûts IA par 3 ? Créez votre compte Ailog et bénéficiez d'un routage LLM intelligent intégré à votre pipeline RAG, hébergé en France.
Tags
Articles connexes
Évaluer un système RAG : Métriques et méthodologies
Guide complet pour mesurer la performance de votre RAG : faithfulness, relevancy, recall, et frameworks d'évaluation automatisée.
Prompt Caching : L'Astuce qui Divise votre Facture LLM par 10 (Anthropic, OpenAI, Google)
Guide complet sur le prompt caching pour réduire vos coûts LLM : fonctionnement du prefix matching, stratégies par fournisseur (Anthropic, OpenAI, Google), calculs d'économies et optimisation RAG.
Cache RAG Intelligent : Comment Réduire vos Coûts LLM de 80% (Sans Sacrifier la Qualité)
Guide complet du cache RAG : semantic cache, prompt caching, embedding cache, comparaison Redis vs GPTCache, et calculs de ROI pour réduire vos coûts LLM de 80%.