Invoering
Ons spraakproduct had twee klachten die we intern niet konden verzoenen. Bij Engelssprekende zakelijke klanten voelde de AI pittig aan. Van Mandarijnsprekende klanten – en in toenemende mate van Vietnamese, Tagalog- en Hindi-sprekende klanten – voelde de AI traag aan. De kloof, end-to-end gemeten vanaf de stilte van de beller tot de eerste lettergreep van de AI, bedroeg 260 ms in het Engels en 540 ms in het Mandarijn. Beide cijfers vielen binnen het gepubliceerde latentiebudget.
Slechts één van hen voelde zich acceptabel tijdens een telefoongesprek.
Het instinct van elk technisch team dat een latentiegat ziet, is om aan het model te sleutelen. Snellere gevolgtrekking. Kleiner model. Betere kwantisering. Dat hebben we allemaal gedaan. Het leverde ons over de hele linie 60 ms op, wat niets opleverde: de relatieve kloof was er nog steeds en het Engels bleef twee keer zo snel.
De echte oplossing kwam voort uit een andere observatie: we behandelden latentie als een modelprobleem, terwijl het eigenlijk een routeringsprobleem was.
Waar de milliseconden eigenlijk naartoe gaan
Het opdelen van de 540 ms Mandarijn-reactie in segmenten was het eerste dat het probleem verduidelijkte. De boekhouding zag er ongeveer zo uit:
- Audio-opname en eindpunt — 80 ms
- Spraak-naar-tekst eerste token — 140 ms
- Intentie + ophaalpijplijn — 90 ms
- Groot model eerste token (generatie) — 180 ms
- Tekst-naar-spraak eerste audio — 50 ms
Op het Engelse pad kwamen dezelfde segmenten binnen op 80/60/90/80/40. De twee segmenten die dramatisch uiteenliepen waren spraak-naar-tekst en de generatie van grote modellen. STT was langzamer in het Mandarijn omdat het akoestische model was getraind met een langer contextvenster – noodzakelijk voor tonale ondubbelzinnigheid – waardoor het eerste token met 80 ms werd gepusht.
Het genereren van modellen verliep langzamer omdat de tokeniser meer tokens per teken met een gelijkwaardige betekenis in het Mandarijn produceerde dan in het Engels.
Geen van beide was een modelfout. Beide waren compromissen die stilletjes waren verzameld door onafhankelijke teams die optimaliseerden voor hun eigen statistieken: STT voor nauwkeurigheid, de LLM voor generatiekwaliteit. De latentiekosten waren reëel, maar het was niemands P&L.
De routeringsoplossing die 200 ms kocht
We zijn gestopt met het routeren van alle talen via één enkele LLM. In plaats daarvan hebben we vóór de generatie een dunne classificatielaag gebouwd die in minder dan 8 ms drie dingen detecteert: de taal van de inkomende uiting, de gespreksintentieklasse en of het verzoek een van de ongeveer 40 hoogfrequente patronen is die we hebben geïdentificeerd door het clusteren van 2 miljoen oproepsegmenten.
Wanneer de classificator een hoogfrequent patroon in een niet-Engelse taal identificeert, sturen we de generatie door naar een kleiner, taalspeciaal model dat dat patroon rechtstreeks afhandelt. Het kleinere model is gedestilleerd op basis van miljoenen voltooiingen van hetzelfde patroon, dus de kwaliteit ervan op die specifieke paden valt binnen de ruis van het grote model – maar de latentie van het eerste token is ongeveer een derde.
Wanneer de classificator een staartintentie ziet – alles wat niet in de 40 patronen voorkomt – valt het verzoek, net als voorheen, door naar het grote model. Het grootste deel van de latentiedaling komt voort uit het feit dat de hoogfrequente patronen dat wel zijn Ook de patronen die verantwoordelijk zijn voor ~78% van het belvolume. De staartgevallen betalen de oorspronkelijke latentie, maar ze zijn zeldzaam.
De classificator die niemand zag aankomen
De dunne classificator was het deel van het project waar niemand op had gerekend. Het bouwen ervan duurde langer dan het bouwen van het routeringssysteem zelf, omdat de faalwijzen subtiel waren. Een classifier die 1% van de verzoeken verkeerd doorstuurt naar een klein model dat deze niet afhandelt, produceert hallucinaties en niet alleen maar verslechterde reacties.
Drie dingen zorgden ervoor dat de classificator werkte. Ten eerste werd het getraind op echt productieverkeer, niet op synthetische gegevens. Ten tweede leverde het een betrouwbaarheidsscore op die de router zou kunnen bepalen: alles onder de 0,91 wordt automatisch doorgegeven aan het grote model.
Ten derde hebben we het zes weken lang in de schaduw gezet op de bestaande pijplijn, waarbij het grote model de grondwaarheid leverde, voordat er daadwerkelijk verkeer naar de kleine modellen werd geleid.
Bij de schaduwimplementatie werden vier soorten fouten aangetroffen die de offline testset had gemist. Twee daarvan waren eenvoudig op te lossen in de trainingsgegevens. Twee vereiste weloverwogen routeringsregels: alles wat te maken heeft met identiteitsverificatie, betalingen of het annuleren van afspraken gaat altijd naar het grote model, ongeacht het vertrouwen van de classificator, omdat de kosten van een hallucinatie op die paden hoger zijn dan de latentiewinst.
De TTS-kant van het probleem
Terwijl de LLM- en STT-wijzigingen werden beoordeeld, werkte een parallel team aan de spraakuitvoer. De eerste TTS-audio van 50 ms in het Engels was feitelijk onverslaanbaar; De kloof van 70 ms-90 ms bij de meeste niet-Engelse talen werd veroorzaakt door kleinere stemmodellen, minder agressieve caching en een enkele gedeelde GPU-pool die voorrang gaf aan Engels onder belasting.
We hebben de TTS-infrastructuur opgesplitst in taalgebonden pools. Mandarijn TTS draait nu op zijn eigen pool, met zijn eigen schaalregels, op hardware dichtbij de regio's waar het meeste van ons Mandarijn-verkeer vandaan komt. De latentie daalde binnen twee weken na de omschakeling van 70-90 ms naar 45 ms.
Niets van dit alles was slim; het was infrastructuurwerk waar niemand de moeite voor had genomen, omdat de marginale verbetering van welke taal dan ook op zichzelf dit niet had gerechtvaardigd.
De les – en die zijn we nu intern aan het opschrijven – is dat “we hierin niet hebben geïnvesteerd omdat geen enkele gebruikersgerichte maatstaf dit rechtvaardigt” precies het soort beslissing is dat leidt tot een kloof van 280 ms tussen twee talen over een periode van vier jaar.
Pariteit meten, geen gemiddelden
Een kleine maar consequente verandering die we intern hebben doorgevoerd, was de manier waarop het latentiedashboard van het team rapporteert. Vroeger hielden we de p50 en p95 van end-to-end latentie bij, gemiddeld over alle talen, tegen één enkele SLO. Het dashboard zag er meestal groen uit.
Het nieuwe dashboard rapporteert p50 en p95 per taal tegen een pariteit SLO — de kloof tussen de langzaamste en de snelst ondersteunde taal heeft zijn eigen budget, dat afzonderlijk wordt gehandhaafd. We hebben het pariteitsbudget ingesteld op 60 ms. Wanneer het gat groter is dan het budget, wordt de oproepdienst opgeroepen.
Het pariteitsdashboard doet iets wat het gemiddelde niet zou kunnen: het maakt regressies in de langzaamste taal met dezelfde urgentie zichtbaar als regressies in de snelste taal. Wanneer u het gemiddelde neemt van 32 talen, verplaatst een regressie van 200 ms in het Vietnamees het gemiddelde met 6 ms. Wanneer u de pariteit meet, wordt het dashboard met 200 ms verplaatst.
Wat gaat het nog langzaam
Na het routeringswerk, de TTS-pools en het pariteitsdashboard bedraagt onze slechtste taal (Kantonees, vooral omdat het ondersteunende akoestische modelcorpus kleiner is) 320 ms. Engels staat op 220 ms. De resterende kloof van 100 ms is reëel en we weten ongeveer waar deze zich bevindt: het Kantonese STT-akoestische model is ouder en nog niet op de nieuwe architectuur, en we zullen het in het derde kwartaal opnieuw trainen.
Maar "de langzaamste taal ligt 100 ms achter op de snelste" is een ander gesprek dan "de langzaamste taal ligt 280 ms achter op de snelste." De eerste is een bekende regressie waarvoor een driemaandelijkse oplossing is gepland. Dit laatste was een noodsituatie op het gebied van de klantervaring waarvan we niet wisten dat we die hadden.
Wat we de volgende keer anders zouden doen
Drie dingen, in volgorde van prioriteit, als we de latency-stack helemaal opnieuw zouden opbouwen met wat we nu weten.
- Bouw eerst de classifier-router en vervolgens het model. De routeringslaag was uiteindelijk het onderdeel met de hoogste hefboomwerking. Door het te behandelen als een "we zullen het later toevoegen als we het nodig hebben" bleek dat we 18 maanden langer met een latentie van één model leefden dan nodig was.
- Stel pariteits-SLO's in vóór taal-SLO's. De verleiding is groot om doelstellingen per taal te stellen en gelijkheid te laten ontstaan. Pariteit komt niet naar voren; het divergeert langzaam in de richting van de primaire taal van het team.
- Resource de infrastructuur per taal alsof elke taal een afzonderlijk product is. Mandarin TTS verdiende vanaf dag één zijn eigen GPU-pool, niet vanaf de dag dat we de latentiekloof maten.
Dit alles is geen nieuw onderzoek. Voor niets daarvan was een papier nodig. Het vereiste dat latentiepariteit als een productverplichting werd behandeld en vervolgens de weinig glamoureuze infrastructuur werd gefinancierd om deze verplichting te ondersteunen. We hebben nu de pariteit die we nodig hebben. Vier jaar lang hebben we het niet gehad.