Introduction
Notre produit vocal avait deux plaintes que nous n'avons pas pu concilier en interne. Pour les entreprises clientes anglophones, l’IA semblait vive. De la part des clients parlant le mandarin – et de plus en plus des clients parlant le vietnamien, le tagalog et l’hindi – l’IA semblait lente. L'écart, mesuré de bout en bout depuis le silence de l'appelant jusqu'à la première syllabe de l'IA, était de 260 ms en anglais et de 540 ms en mandarin. Les deux chiffres respectaient le budget de latence publié.
Un seul d’entre eux s’est senti acceptable lors d’un appel téléphonique.
L’instinct de toute équipe d’ingénierie qui constate un écart de latence est de se pencher sur le modèle. Inférence plus rapide. Modèle plus petit. Meilleure quantification. Nous avons fait tout cela. Cela nous a fait gagner 60 ms dans tous les domaines, ce qui n'a rien fermé : l'écart relatif était toujours là et l'anglais est resté deux fois plus rapide.
La vraie solution est venue d'une observation différente : nous traitions la latence comme un problème de modèle alors qu'il s'agissait en réalité d'un problème de routage.
Où vont réellement les millisecondes
Diviser la réponse mandarin de 540 ms en segments a été la première chose qui a clarifié le problème. La comptabilité ressemblait à peu près à ceci :
- Capture audio et point final — 80 ms
- Premier jeton de synthèse vocale — 140 ms
- Intention + pipeline de récupération — 90 ms
- Premier jeton grand modèle (génération) — 180 ms
- Texte-parole en premier audio — 50 ms
Sur le parcours anglais, les mêmes segments s'établissaient à 80/60/90/80/40. Les deux segments qui divergeaient considérablement étaient la synthèse vocale et la génération de grands modèles. STT était plus lent en mandarin car le modèle acoustique avait été entraîné avec une fenêtre contextuelle plus longue – nécessaire à la désambiguïsation tonale – qui poussait le premier jeton de 80 ms.
La génération du modèle était plus lente car le tokeniser produisait plus de jetons par caractère de signification équivalente en mandarin qu'en anglais.
Il ne s’agissait pas non plus d’un défaut de modèle. Les deux étaient des compromis qui avaient été discrètement accumulés par des équipes indépendantes optimisant leurs propres mesures : STT pour la précision, le LLM pour la qualité de la génération. Le coût de la latence était réel, mais ce n'était le compte de résultat de personne.
Le correctif de routage qui a acheté 200 ms
Nous avons arrêté de router toutes les langues via un seul LLM. Au lieu de cela, nous avons construit une fine couche de classification avant la génération qui détecte, en moins de 8 ms, trois éléments : la langue de l'énoncé entrant, la classe d'intention de conversation et si la demande fait partie d'une quarantaine de modèles haute fréquence que nous avons identifiés en regroupant 2 millions de segments d'appel.
Lorsque le classificateur identifie un modèle haute fréquence dans une langue autre que l'anglais, nous acheminons la génération vers un modèle plus petit, spécialisé dans la langue, qui gère directement ce modèle. Le plus petit modèle a été distillé sur des millions de réalisations du même modèle, de sorte que sa qualité sur ces chemins spécifiques se situe dans le bruit du grand modèle – mais sa latence du premier jeton est d'environ un tiers.
Lorsque le classificateur voit une intention de queue (tout ce qui ne figure pas dans les 40 modèles) la requête passe au grand modèle, comme avant. La plus grande partie de la baisse de latence vient du fait que les modèles de hautes fréquences sont aussi les modèles qui représentent environ 78 % du volume d’appels. Les tail cases paient la latence d'origine, mais ils sont rares.
Le classificateur que personne n'a vu venir
Le classificateur mince était la partie du projet pour laquelle personne n'avait prévu de budget. Sa construction a pris plus de temps que la construction du système de routage lui-même, car les modes de défaillance étaient subtils. Un classificateur qui détourne 1 % des requêtes vers un petit modèle qui ne les gère pas produit des hallucinations, pas seulement des réponses dégradées.
Trois choses ont fait fonctionner le classificateur. Premièrement, il a été formé sur du trafic de production réel, et non sur des données synthétiques. Deuxièmement, il a renvoyé un score de confiance que le routeur pouvait atteindre : tout ce qui est inférieur à 0,91 est automatiquement transmis au grand modèle.
Troisièmement, nous l'avons déployé pendant six semaines sur le pipeline existant, le grand modèle fournissant la vérité sur le terrain, avant que le trafic ne soit réellement acheminé vers les petits modèles.
Le déploiement fantôme a révélé quatre classes d'erreurs que l'ensemble de test hors ligne avait manquées. Deux étaient faciles à corriger dans les données d’entraînement. Deux règles de routage délibérées sont requises : tout ce qui touche à la vérification d'identité, aux paiements ou à l'annulation de rendez-vous est toujours transmis au grand modèle, quelle que soit la confiance du classificateur, car le coût d'une hallucination sur ces chemins est plus élevé que le gain de latence.
Le côté TTS du problème
Pendant que les modifications LLM et STT étaient en cours de révision, une équipe parallèle travaillait sur la sortie vocale. Le premier audio TTS de 50 ms en anglais était effectivement imbattable ; l'écart de 70 à 90 ms sur la plupart des langues autres que l'anglais était dû à des modèles vocaux plus petits, une mise en cache moins agressive et un pool GPU partagé unique qui donnait la priorité à l'anglais sous charge.
Nous divisons l'infrastructure TTS en pools épinglés par langue. Mandarin TTS fonctionne désormais sur son propre pool, avec ses propres règles de mise à l'échelle, sur du matériel proche des régions d'où provient la majeure partie de notre trafic mandarin. La latence est passée de 70-90 ms à 45 ms dans les deux semaines suivant le basculement.
Rien de tout cela n’était intelligent ; c'était un travail d'infrastructure que personne n'avait pris la peine de faire parce que l'amélioration marginale d'une seule langue ne l'avait pas, à elle seule, justifiée.
La leçon - et nous l'écrivons maintenant en interne - est que "nous n'avons pas investi dans cela parce qu'aucune mesure destinée à l'utilisateur ne le justifiait". C'est exactement le genre de décision qui se traduit par un écart de 280 ms entre deux langues sur quatre ans.
Mesurer la parité, pas les moyennes
Un changement mineur mais conséquent que nous avons apporté en interne concerne la façon dont le tableau de bord de latence de l'équipe rend compte. Nous avions l'habitude de suivre les p50 et p95 de latence de bout en bout, en moyenne dans toutes les langues, par rapport à un seul SLO. Le tableau de bord était vert la plupart du temps.
Le nouveau tableau de bord rapporte p50 et p95 par langue contre un parité SLO — l'écart entre la langue prise en charge la plus lente et la plus rapide a son propre budget, appliqué séparément. Nous fixons le budget de parité à 60 ms. Lorsque l'écart dépasse le budget, les astreintes sont bipées.
Le tableau de bord de parité fait quelque chose que le tableau de bord basé sur la moyenne ne peut pas faire : il rend visibles les régressions dans la langue la plus lente avec la même urgence que les régressions dans la langue la plus rapide. Lorsque vous faites une moyenne sur 32 langues, une régression de 200 ms en vietnamien déplace la moyenne de 6 ms. Lorsque vous mesurez la parité, cela déplace le tableau de bord de 200 ms.
Ce qui est encore lent
Après le travail de routage, les pools TTS et le tableau de bord de parité, notre pire langue (le cantonais, principalement parce que le corpus de modèles acoustiques de support est plus petit) se situe à 320 ms. L'anglais est à 220 ms. L'écart restant de 100 ms est réel et nous savons à peu près où il se situe : le modèle acoustique cantonais STT est plus ancien et n'est pas encore sur la nouvelle architecture, et nous le recyclerons au troisième trimestre.
Mais « la langue la plus lente a 100 ms de retard sur la plus rapide » est une conversation différente de « la langue la plus lente a 280 ms de retard sur la plus rapide ». La première est une régression connue avec une correction trimestrielle prévue. Cette dernière était une urgence en matière d’expérience client dont nous ignorions l’existence.
Ce que nous ferions différemment la prochaine fois
Trois choses, par ordre de priorité, si nous reconstruisions la pile de latence à partir de zéro avec ce que nous savons actuellement.
- Construisez d'abord le classificateur-routeur, puis le modèle. La couche de routage a fini par être l’élément ayant le plus grand effet de levier. Le traiter comme "nous l'ajouterons plus tard si nous en avons besoin" s'est avéré signifier que nous avons vécu avec une latence d'un seul modèle pendant 18 mois de plus que nécessaire.
- Définissez les SLO de parité avant les SLO de langue. La tentation est de fixer des objectifs par langue et de laisser émerger la parité. La parité n’émerge pas ; il diverge lentement vers la langue principale de l'équipe.
- Ressourcez l'infrastructure par langue comme si chaque langue était un produit distinct. Mandarin TTS méritait son propre pool de GPU dès le premier jour, et non depuis le jour où nous avons mesuré l'écart de latence.
Rien de tout cela n’est une recherche nouvelle. Rien de tout cela ne nécessitait de papier. Cela nécessitait de traiter la parité de latence comme un engagement produit, puis de financer l'infrastructure peu glamour pour soutenir cet engagement. Nous avons la parité dont nous avons besoin maintenant. Nous ne l'avons pas eu pendant quatre ans.