Quand notre fournisseur d'IA a retiré le modèle
Un changement de modèle, des réponses vides sans erreur, et une facture soudain plusieurs fois plus élevée. Ce qui a cassé, et pourquoi la cause était si difficile à voir.

En juillet 2026, plusieurs fonctionnalités ont cessé de fonctionner en même temps : le chat IA, les réponses IA dans les tickets, les résumés de tickets, le constructeur de serveur, ainsi que la modération et la traduction des idées et des rapports de bugs.
La cause n'était pas notre code. Notre fournisseur d'IA avait retiré le modèle que nous utilisions.
Première partie : le modèle a disparu
C'est la partie évidente, et elle a été corrigée rapidement. Un fournisseur arrête un modèle, tu indiques son successeur, terminé.
Le véritable incident a commencé après.
Deuxième partie : des réponses vides, sans erreur
Après le changement, les réponses revenaient. Sauf que parfois, elles étaient vides. Pas tronquées, pas mal formées, mais une réponse complètement vide sans la moindre erreur.
La cause tient à une différence que le nom du modèle ne révèle pas : le successeur est un modèle de raisonnement. Avant la réponse proprement dite, il écrit d'abord un raisonnement interne dans un champ séparé. Les deux puisent dans le même budget de tokens.
Si le budget est épuisé par la réflexion, il revient une réponse formellement correcte : le fournisseur indique « longueur atteinte » et le champ de contenu est vide. Aucune erreur, aucun indice, rien qu'un try/catch verrait.
Nous l'avons reproduit avec un vrai test : un budget de cinq tokens suffit déjà à produire une réponse vide à chaque requête.
Troisième partie : la facture
À l'endroit d'appel le plus coûteux, le constructeur de serveur IA, nous avions fixé un budget généreux parce que de longues réponses y sont produites. La réflexion n'a donc pas atteint de limite, elle a simplement continué.
Les conséquences sont arrivées de deux côtés à la fois. Les requêtes duraient si longtemps qu'elles dépassaient les délais d'expiration. Et elles coûtaient plusieurs fois plus cher, parce qu'un raisonnement invisible complet était payé à chaque fois. À la fin est arrivé un message d'erreur que nous n'avions pas prévu : solde insuffisant.
La correction tient en une ligne. La réflexion peut être désactivée dans le corps de la requête, et le modèle se comporte alors à nouveau comme l'ancien. Depuis, cette ligne a sa place à chaque endroit d'appel, et il y en a plus d'une poignée dans le dépôt.
Quatrième partie : ce que nous avons trouvé en faisant le ménage
Quand on touche de toute façon à chaque appel d'IA, on les regarde. Cela a fait remonter un deuxième sujet, sans lien avec l'incident mais tout aussi coûteux.
Les fournisseurs facturent nettement moins un prompt dont le début reste inchangé et peut être servi depuis un cache. La différence entre un succès et un échec de cache est d'environ trente fois.
On n'obtient pas cette réduction par un drapeau. Nous l'avons testé spécifiquement : un champ du corps de requête prévu pour cela n'avait aucun effet, le cache s'applique de toute façon automatiquement. Le seul levier est l'ordre dans le prompt, du stable au variable.
Quatre endroits où nous avions fait exactement l'inverse :
Une valeur variable dans le bloc d'instructions fixe. La vérification des doublons pour les rapports de bugs avait le nom du module dans le texte d'instructions. Cela donnait à un bloc par ailleurs identique sa propre ligne de cache par module. La valeur a sa place dans la partie variable, où elle change de toute façon.
Le nouveau avant le stable. La même vérification envoyait le nouveau rapport de bug avant les jusqu'à cinquante candidats de comparaison. Cela faisait du plus gros prompt de l'API un échec de cache complet permanent.
Des données par utilisateur dans la partie fixe. Le chat IA public avait les notes sur l'utilisateur individuel dans le bloc d'instructions, donc avant l'historique partagé du salon. Chaque utilisateur d'un même salon avait ainsi son propre début, et l'historique partagé était payé séparément pour chaque utilisateur.
Une fenêtre glissante sur l'historique. Envoyer les N derniers messages à chaque message décale le début à chaque message. L'historique complet devient alors un échec de cache permanent. La bonne approche est de raccourcir par blocs, donc rarement et franchement.
Plus un détail qui ressemble à du pinaillage et n'en est pas : une liste dans un prompt triée selon un seul critère peut changer d'ordre en cas d'égalité. Une seule ligne inversée au milieu du bloc d'instructions coûte le succès de cache pour tout ce qui suit. Les tris dans les prompts ont besoin d'un critère de départage sans ambiguïté.
Ce que nous en avons retenu
Un changement de modèle n'est pas un changement de configuration. Le nom ressemble à une valeur dans une variable. Derrière se trouvait un autre comportement, et c'est le comportement qui a cassé notre code, pas l'interface.
La panne dangereuse était la silencieuse. La disparition de l'ancien modèle a été immédiatement visible et corrigée en quelques minutes. Les réponses vides revenaient comme des réponses formellement valides et auraient pu le rester indéfiniment.
La mesurabilité a sa place à l'endroit d'appel. Nous enregistrons désormais le taux de succès du cache à chacun d'eux. Un endroit bien construit se stabilise à un taux élevé après la première requête, un endroit mal construit reste à zéro. On le voit dans une ligne de log et nulle part ailleurs, parce que les deux fonctionnent.
Et la conclusion inconfortable : utiliser le modèle de quelqu'un d'autre signifie qu'une partie de ton produit dépend d'une décision prise ailleurs. C'est pourquoi, depuis août, chaque serveur peut faire pointer les fonctionnalités IA vers son propre endpoint au lieu de compter sur le nôtre.
Plus d'articles
Garder un œil sur 4 000 serveurs Discord : Grafana, PostHog et ce qu'ils nous ont montré
Une boucle qui causait discrètement la moitié de notre trafic, trois millions de requêtes inutiles par jour et une attaque terminée au bout d'une minute. Ce que notre monitoring voit, et ce qu'il ne voit volontairement pas.
CoulissesCe que faire tourner un bot sur plus de 2 000 serveurs Discord nous a appris
Quatre choses qui fonctionnent autrement à grande échelle que ce qu'on imagine en écrivant le code.
CoulissesLe droit dans notre code
Un bouton de résiliation qui doit fonctionner sans connexion. Un formulaire qui ne doit jamais te refuser. Pourquoi les obligations légales sont pour nous de l'architecture, pas du texte standard.