Introducción
Nuestro producto de voz tuvo dos quejas que no pudimos conciliar internamente. Para los clientes empresariales de habla inglesa, la IA se sintió ágil. Para los clientes que hablaban mandarín (y cada vez más para los clientes que hablaban vietnamita, tagalo e hindi), la IA se sentía lenta. La brecha, medida de un extremo a otro desde el silencio de la persona que llama hasta la primera sílaba de la IA, fue de 260 ms en inglés y de 540 ms en mandarín. Ambos números estaban dentro del presupuesto de latencia publicado.
Sólo uno de ellos se sintió aceptable en una llamada telefónica.
El instinto de cualquier equipo de ingeniería que ve una brecha de latencia es trabajar en el modelo. Inferencia más rápida. Modelo más pequeño. Mejor cuantificación. Hicimos todo eso. Nos dio 60 ms en todos los ámbitos, lo que no cerró nada: la brecha relativa todavía estaba ahí y el inglés se mantuvo dos veces más rápido.
La verdadera solución provino de una observación diferente: tratábamos la latencia como un problema de modelo cuando en realidad era un problema de enrutamiento.
Adónde van realmente los milisegundos
Dividir la respuesta en mandarín de 540 ms en segmentos fue lo primero que aclaró el problema. La contabilidad se veía más o menos así:
- Captura de audio y localización — 80 ms
- Primer token de voz a texto — 140 ms
- Canal de intención + recuperación — 90 ms
- Primer token de modelo grande (generación) — 180 ms
- Primer audio de texto a voz — 50 ms
En la ruta inglesa, los mismos segmentos llegaron a 80/60/90/80/40. Los dos segmentos que divergieron dramáticamente fueron la conversión de voz a texto y la generación de modelos grandes. STT fue más lento en mandarín porque el modelo acústico había sido entrenado con una ventana de contexto más larga (necesaria para la desambiguación tonal) que empujaba el primer token en 80 ms.
La generación del modelo fue más lenta porque el tokenizador produjo más tokens por carácter de significado equivalente en mandarín que en inglés.
Tampoco fue un defecto de modelo. Ambas eran compensaciones que habían sido acumuladas silenciosamente por equipos independientes que optimizaban sus propias métricas: STT para precisión, LLM para calidad de generación. El costo de latencia era real, pero no representaba las pérdidas y ganancias de nadie.
La solución de enrutamiento que compró 200 ms
Dejamos de enrutar todos los idiomas a través de un único LLM. En lugar de eso, construimos una fina capa de clasificación delante de la generación que detecta, en menos de 8 ms, tres cosas: el idioma de la expresión entrante, la clase de intención conversacional y si la solicitud es uno de los aproximadamente 40 patrones de alta frecuencia que identificamos al agrupar 2 millones de segmentos de llamadas.
Cuando el clasificador identifica un patrón de alta frecuencia en un idioma distinto del inglés, enrutamos la generación a un modelo más pequeño y especializado en el idioma que maneja ese patrón directamente. El modelo más pequeño se ha destilado en millones de terminaciones del mismo patrón, por lo que su calidad en esos caminos específicos está dentro del ruido del modelo grande, pero su latencia del primer token es aproximadamente un tercio.
Cuando el clasificador ve una intención de cola (cualquier cosa que no esté en los 40 patrones), la solicitud pasa al modelo grande, como antes. La mayor parte de la caída de la latencia se debe al hecho de que los patrones de alta frecuencia son también los patrones que representan ~78% del volumen de llamadas. Los casos de cola pagan la latencia original, pero son raros.
El clasificador que nadie vio venir
El clasificador fino era la parte del proyecto que nadie había presupuestado. Construirlo llevó más tiempo que construir el sistema de enrutamiento en sí, porque los modos de falla eran sutiles. Un clasificador que desvía erróneamente el 1% de las solicitudes a un modelo pequeño que no las maneja produce alucinaciones, no sólo respuestas degradadas.
Tres cosas hicieron que el clasificador funcionara. En primer lugar, se entrenó con tráfico de producción real, no con datos sintéticos. En segundo lugar, arrojó una puntuación de confianza que el enrutador podía alcanzar: cualquier nivel de confianza por debajo de 0,91 pasa automáticamente al modelo grande.
En tercer lugar, lo implementamos en la sombra durante seis semanas en el oleoducto existente, con el modelo grande proporcionando verdad sobre el terreno, antes de que el tráfico se dirigiera realmente a modelos pequeños.
La implementación en la sombra encontró cuatro clases de errores que el conjunto de pruebas fuera de línea no había detectado. Dos fueron fáciles de corregir en los datos de entrenamiento. Se requieren dos reglas de enrutamiento deliberadas: todo lo que toca la verificación de identidad, los pagos o la cancelación de citas siempre va al modelo grande, independientemente de la confianza del clasificador, porque el costo de una alucinación en esos caminos es mayor que la ganancia de latencia.
El lado TTS del problema
Mientras se revisaban los cambios de LLM y STT, un equipo paralelo estaba trabajando en la salida del discurso. El primer audio TTS de 50 ms en inglés fue efectivamente inmejorable; la brecha de 70 ms a 90 ms en la mayoría de los idiomas distintos del inglés se debió a modelos de voz más pequeños, un almacenamiento en caché menos agresivo y un único grupo de GPU compartido que priorizaba el inglés bajo carga.
Dividimos la infraestructura TTS en grupos fijados por idiomas. Mandarin TTS ahora se ejecuta en su propio grupo, con sus propias reglas de escalamiento, en hardware cercano a las regiones donde se origina la mayor parte de nuestro tráfico en mandarín. La latencia cayó de 70-90 ms a 45 ms a las dos semanas de la transición.
Nada de esto fue inteligente; era un trabajo de infraestructura que nadie se había molestado en hacer porque la mejora marginal en cualquier idioma no lo había justificado, de forma aislada.
La lección, y ahora la estamos anotando internamente, es que "no invertimos en esto porque ninguna métrica de cara al usuario lo justificaba" es exactamente el tipo de decisión que se acumula en una brecha de 280 ms entre dos idiomas durante cuatro años.
Medir la paridad, no los promedios
Un cambio pequeño pero importante que hicimos internamente fue la forma en que informa el panel de latencia del equipo. Solíamos realizar un seguimiento de p50 y p95 de la latencia de un extremo a otro, promediados en todos los idiomas, frente a un único SLO. El tablero se veía verde la mayor parte del tiempo.
El nuevo panel informa p50 y p95 por idioma contra un paridad SLO: la brecha entre el lenguaje admitido más lento y el más rápido tiene su propio presupuesto, que se aplica por separado. Establecimos el presupuesto de paridad en 60 ms. Cuando la brecha excede el presupuesto, se llama al personal de guardia.
El panel de paridad hace algo que el panel basado en promedios no podría: hace que las regresiones en el lenguaje más lento sean visibles con la misma urgencia que las regresiones en el lenguaje más rápido. Cuando se hace un promedio de 32 idiomas, una regresión de 200 ms en vietnamita mueve el promedio en 6 ms. Cuando mides la paridad, el tablero se mueve 200 ms.
lo que sigue siendo lento
Después del trabajo de enrutamiento, los grupos de TTS y el panel de paridad, nuestro peor idioma (cantonés, principalmente porque el corpus del modelo acústico de soporte es más pequeño) se sitúa en 320 ms. El inglés está a 220 ms. La brecha restante de 100 ms es real y sabemos aproximadamente dónde se encuentra: el modelo acústico cantonés STT es más antiguo y aún no tiene la nueva arquitectura, y lo volveremos a entrenar en el tercer trimestre.
Pero "el lenguaje más lento está 100 ms detrás del más rápido" es una conversación diferente a "el lenguaje más lento está 280 ms detrás del más rápido". La primera es una regresión conocida con una corrección trimestral prevista. Esta última fue una emergencia en la experiencia del cliente que no sabíamos que teníamos.
Qué haríamos diferente la próxima vez
Tres cosas, en orden de prioridad, si estuviéramos reconstruyendo la pila de latencia desde cero con lo que sabemos ahora.
- Primero construya el clasificador-enrutador, luego el modelo. La capa de enrutamiento terminó siendo la pieza de mayor apalancamiento. Tratarlo como un "lo agregaremos más tarde si lo necesitamos" resultó significar que vivimos con latencia de modelo único durante 18 meses más de lo necesario.
- Establezca SLO de paridad antes que los SLO de idioma. La tentación es establecer objetivos por idioma y dejar que surja la paridad. La paridad no surge; diverge, lentamente, en la dirección del idioma principal del equipo.
- Utilice la infraestructura por idioma como si cada idioma fuera un producto independiente. Mandarin TTS merecía su propio grupo de GPU desde el primer día, no desde el día en que medimos la brecha de latencia.
Nada de esto es una investigación novedosa. Nada de eso requirió un documento. Requirió tratar la paridad de latencia como un compromiso de producto y luego financiar la poco glamorosa infraestructura para respaldar el compromiso. Tenemos la paridad que necesitamos ahora. No lo tuvimos durante cuatro años.