درس 6 — Router et tenir la charge

Le routage de modèles : petit d'abord, grand si besoin

6 دقائق قراءة

هذا المحتوى غير مترجم بعد. تُعرض النسخة الأصلية.

Le routage de modèles : petit d'abord, grand si besoin

L'idée de la cascade

La plupart des questions de support sont simples ; un petit modèle y répond bien, plus vite et moins cher. Une cascade (popularisée par FrugalGPT, voir les références) essaie d'abord le petit modèle et n'escalade vers le grand que si un signal indique que la réponse est douteuse.

flowchart TD
  Q["Question"] --> S["flash-lite : réponse + confiance (JSON)"]
  S --> C{"confiance >= CONF_MIN ?"}
  C -->|"oui"| R1["Réponse du petit (≈ 0,43 $ / 1 000)"]
  C -->|"non"| B{"budget de la requête OK ?"}
  B -->|"oui"| G["flash : nouvelle réponse (≈ 0,98 $ / 1 000)"]
  B -->|"non"| R1
  G --> R2["Réponse du grand"]
Signal pour escaladerCoûtFiabilité
Confiance auto-déclarée par le modèle (notre lab)nul (même appel)faible, voir les mesures
Règles sur la question (calcul, date, plusieurs sujets)nulbonne sur les cas prévus
Validateur : un 2ᵉ appel juge la réponseun appelmoyenne à bonne
Classifieur entraîné sur vos donnéesentraînementla meilleure, une fois calibrée
Vérification déterministe (JSON valide, montant recalculé)nulexcellente, mais spécifique

Le code

Le petit modèle répond en JSON structuré (schéma imposé par response_schema) avec sa confiance :

files/router.py (extrait)
SCHEMA = {
    "type": "object",
    "properties": {"answer": {"type": "string"}, "confidence": {"type": "number"}},
    "required": ["answer", "confidence"],
}

small = await ask(self.client, SMALL_MODEL, question)
res = Result(small.answer, "small", [small], ttft=small.ttft)
big_estimate = cost_usd(BIG_MODEL, small.prompt_tokens, small.cached_tokens, 2 * small.output_tokens)
if small.confidence < self.conf_min and small.cost + big_estimate <= self.max_cost:
    big = await ask(self.client, BIG_MODEL, question)
    res = Result(big.answer, "escalated", [small, big], ttft=small.latency + big.ttft)

Une sortie illisible (JSON cassé) reçoit une confiance de 0 : elle escalade automatiquement.

Ce que disent les mesures

Sur les 16 questions, le petit modèle a déclaré une confiance de 1,0 sur 15 questions, et de 0,9 à 0,95 sur la seule question qu'il a ratée (q12 : « Je commande en express un vendredi à 15 h, quand est-ce que je reçois mon colis ? » ; il répond « le prochain jour ouvré » sans conclure « mardi »).

Seuil CONF_MINq12 (confiance 0,9)EscaladesQualitéCoût du lot
0,8reste au petit, fausse094 %0,00612 $
0,95escalade, juste1100 %0,00716 $

Avec CONF_MIN = 0,95, le routeur a atteint 100 % de qualité pour un coût proche du petit modèle seul. Que faut-il en conclure ?

Améliorer le signal sans appel supplémentaire

Les questions ratées ont un profil : calcul ou raisonnement sur une date. Une règle simple, combinée à la confiance, attrape ce profil sans aucun appel :

règle d
import re

RISKY = re.compile(r"\b(combien je paie|total|remise|quand|quel jour|si je commande)\b", re.I)

def must_escalate(question: str, confidence: float, conf_min: float = 0.8) -> bool:
    return confidence < conf_min or bool(RISKY.search(question))

Dans une cascade, quel est le coût caché d'une escalade pour l'utilisateur ?

Exercice

Intégrez must_escalate dans Router.answer et écrivez un test sans clé qui vérifie que q10 (calcul de remise) est escaladée même avec une confiance de 1,0.

Voir la solution

Dans router.py :

if must_escalate(question, small.confidence, self.conf_min) and small.cost + big_estimate <= self.max_cost:

Dans test_router.py, en réutilisant le faux client :

def test_calcul_toujours_escalade():
    cl = client({R.SMALL_MODEL: 1.0, R.BIG_MODEL: 0.9})
    q = "Je suis pro : 2 suspensions à 80 € avec la remise, combien je paie au total ?"
    assert run(R.Router(cl).answer(q)).route == "escalated"

Attention à l'effet sur le coût : si 20 % de votre trafic contient « quand », vous escaladez 20 % des requêtes. Mesurez la part réelle sur vos journaux.

Résultat obtenu

Deux exécutions réelles du routeur le 2026-10-15 (16 questions, 4 en parallèle), extrait de bench.py --strategies router :

# CONF_MIN=0.8
router    TTFT p50 0.88  p95 1.16   lat p50 0.97  p95 1.32   qualité 94%   coût 0.00612 $   appels 14  cache 2  escal. 0
q12 small [0.9] False 1.32 La livraison express est en 24 h ouvrées pour toute commande passée avant 13 h, du lundi a…

# CONF_MIN=0.95
router    TTFT p50 0.85  p95 1.56   lat p50 0.95  p95 1.76   qualité 100%  coût 0.00716 $   appels 15  cache 2  escal. 1
q12 escalated [0.9, 0.95] 0.731 True 2.7 3.19 La livraison express en 24 h ouvrées s'applique uniquement aux commandes passées avant 13 h…

Je sais faire

  • Construire une cascade petit → grand modèle avec un signal d'escalade
  • Expliquer pourquoi la confiance auto-déclarée est mal calibrée
  • Choisir un seuil à partir des confiances observées sur les réussites et les échecs
  • Combiner confiance et règles déterministes pour escalader
التالي