Router entre plusieurs LLM selon la tâche et le coût
- 01Router par tâche : un modèle gratuit/rapide pour la classification, un modèle premium pour la rédaction
- 02Centraliser tous les appels LLM dans une seule fonction : un seul endroit à changer, à logger, à sécuriser
- 03Prévoir un fallback : si le modèle préféré échoue, dégrader sur un autre plutôt que planter
Tout envoyer au même gros modèle, c'est cher et fragile. Toutes les tâches ne méritent pas un modèle premium : classer une news se fait très bien avec un modèle gratuit, rédiger un article mérite mieux. À la fin de ce tuto, tu auras un routeur LLM unique qui choisit le modèle par tâche et bascule sur un secours en cas de pépin. Exemple en TypeScript.
Étape 1 — Centraliser tous les appels
Le prérequis : un seul point d'entrée pour tous tes appels LLM. Pas de fetch éparpillés. Un seul fichier llm.ts avec une fonction callLLM. Ça te donne un endroit unique où router, logger, réessayer et gérer les clés.
Étape 2 — Définir les tâches et le routage
Attache un modèle à chaque type de tâche, pas à chaque appel :
type Task = "classification" | "redaction" | "traduction";
type Provider = "mistral" | "claude";
// Réglable (idéalement en base ou en config, pas en dur)
const routing: Record<Task, Provider> = {
classification: "mistral", // gratuit, suffisant
redaction: "claude", // qualité premium
traduction: "mistral",
};
L'intérêt : changer la qualité/coût d'une tâche = changer une ligne, sans toucher au code appelant.
Étape 3 — Le routeur avec fallback
async function callProvider(p: Provider, messages: Msg[], json: boolean) {
if (p === "claude") return callClaude(messages, json);
return callMistral(messages, json);
}
export async function callLLM(messages: Msg[], task: Task, json = false): Promise<string> {
const primary = routing[task];
try {
return await callProvider(primary, messages, json);
} catch (err) {
// Crédits épuisés, rate-limit, panne réseau : on dégrade au lieu de planter.
console.error(`[llm] ${primary} KO sur ${task}, fallback Mistral :`, err);
if (primary !== "mistral") return callProvider("mistral", messages, json);
throw err; // le secours lui-même a échoué
}
}
Le fallback vers un modèle gratuit et toujours dispo (ici Mistral) évite qu'une coupure côté fournisseur premium fasse tomber toute ta chaîne.
Étape 4 — Override ponctuel
Parfois une tâche mérite exceptionnellement un modèle plus fort (un contenu long où la justesse prime). Autorise un override sans casser le routage global :
export async function callLLM(
messages: Msg[], task: Task, json = false, modelOverride?: string
) {
// ... si le provider résolu est Claude, passe modelOverride au client Claude
}
Tu réserves ainsi un modèle frontier à quelques appels sensibles sans changer le réglage par défaut de la tâche.
Adapter à ton cas
- Réglage à chaud : stocke
routingen base et expose-le dans une interface admin — tu ajustes coût/qualité sans redéployer. - Routage par difficulté : un routeur peut aussi décider selon la longueur ou la complexité de l'entrée (petit modèle si l'entrée est courte).
- Multi-fournisseurs : ajoute OpenAI/Google au type
Provideret àcallProvider; le reste ne bouge pas. - Budget : combine avec un compteur de coût (voir le tuto sur l'observabilité LLM) pour couper ou dégrader au-delà d'un seuil.
En cas de souci
- Le fallback masque un vrai problème : logge toujours quel provider a échoué et pourquoi. Un fallback silencieux qui tourne en permanence, c'est une facture premium payée pour rien ou une panne non vue.
- Formats de réponse différents : Mistral respecte
response_format: json_object, Claude non (il faut extraire/nettoyer). Uniformise la sortie danscallLLMpour que l'appelant ne voie jamais la différence. - Boucle de fallback : assure-toi que le secours ne peut pas rappeler le routeur (récursion). Appelle directement le client bas niveau.
- Coûts qui explosent quand même : vérifie que les tâches « premium » sont vraiment celles qui le méritent. Beaucoup de charge (scoring, dédup, résumés jetables) doit rester sur le modèle gratuit.
Articles liés
Architecturer un système multi-agents : orchestrateur et sous-agents
Quand un agent ne suffit plus : patterns d'orchestration (orchestrateur/sous-agents, pipeline, débat, parallèle), communication par messages structurés, et les deux risques majeurs. Avec un orchestrateur minimal en Python.

L'optimisation des GPU devient le prochain défi financier pour l'IA d'entreprise
Optimiser l'utilisation des GPU devient un enjeu financier majeur pour les projets IA.
Fine-tuning, RAG ou prompting : quel levier pour adapter un modèle
Une méthode reproductible pour choisir entre prompting, RAG et fine-tuning : diagnostiquer le vrai problème, puis appliquer le bon levier sur un cas concret.