Wstęp
Nasz produkt głosowy miał dwie skargi, których nie mogliśmy wewnętrznie pogodzić. W przypadku anglojęzycznych klientów korporacyjnych sztuczna inteligencja wydawała się żwawa. W przypadku klientów mówiących po mandaryńsku – a coraz częściej w przypadku klientów mówiących po wietnamsku, tagalsku i hindi – sztuczna inteligencja działała wolno. Różnica, mierzona od końca do końca od ciszy rozmówcy do pierwszej sylaby AI, wyniosła 260 ms w języku angielskim i 540 ms w języku mandaryńskim. Obie liczby mieściły się w opublikowanym budżecie opóźnień.
Tylko jeden z nich podczas rozmowy telefonicznej czuł się akceptowalnie.
Instynkt każdego zespołu inżynierów, który dostrzega lukę w opóźnieniu, polega na szlifowaniu modelu. Szybsze wnioskowanie. Mniejszy model. Lepsza kwantyzacja. Zrobiliśmy to wszystko. Ogólnie rzecz biorąc, zapewniło nam to 60 ms, co niczego nie zamknęło — względna różnica nadal istniała, a angielski pozostał dwa razy szybszy.
Prawdziwe rozwiązanie wynikało z innej obserwacji: opóźnienia traktowaliśmy jako problem modelowy, podczas gdy w rzeczywistości był to problem z routingiem.
Gdzie właściwie idą milisekundy
Pierwszą rzeczą, która wyjaśniła problem, było podzielenie odpowiedzi Mandarin 540 ms na segmenty. Rachunek wyglądał mniej więcej tak:
- Przechwytywanie dźwięku i punktowanie końcowe — 80 ms
- Pierwszy token zamiany mowy na tekst — 140 ms
- Intencja + potok pobierania — 90 ms
- Pierwszy token dużego modelu (generacja) — 180 ms
- Pierwsze audio podczas zamiany tekstu na mowę — 50 ms
Na ścieżce języka angielskiego te same segmenty osiągnęły poziom 80/60/90/80/40. Dwa segmenty, które znacznie się od siebie różniły, to zamiana mowy na tekst i generowanie dużych modeli. STT był wolniejszy w języku mandaryńskim, ponieważ model akustyczny został przeszkolony przy użyciu dłuższego okna kontekstowego — niezbędnego do ujednoznacznienia tonalnego — które przesunęło pierwszy token o 80 ms.
Generowanie modelu było wolniejsze, ponieważ tokenizator wygenerował więcej tokenów na znak o równoważnym znaczeniu w języku mandaryńskim niż w języku angielskim.
Nie była to też wada modelu. Obydwa były kompromisami, które zostały po cichu wynegocjowane przez niezależne zespoły optymalizujące pod kątem własnych wskaźników — STT pod kątem dokładności, LLM pod kątem jakości generowania. Koszt opóźnień był realny, ale nie stanowił niczyjego zysku i strat.
Poprawka routingu, która kupiła 200 ms
Przestaliśmy kierować wszystkie języki przez jeden LLM. Zamiast tego zbudowaliśmy cienką warstwę klasyfikacyjną przed generacją, która w czasie krótszym niż 8 ms wykrywa trzy rzeczy: język wypowiedzi przychodzącej, klasę intencji konwersacji oraz to, czy żądanie jest jednym z około 40 wzorców o wysokiej częstotliwości, które zidentyfikowaliśmy poprzez grupowanie segmentów połączeń 2M.
Kiedy klasyfikator zidentyfikuje wzorzec o wysokiej częstotliwości w języku innym niż angielski, kierujemy generację do mniejszego, wyspecjalizowanego językowo modelu, który bezpośrednio obsługuje ten wzorzec. Mniejszy model został wydestylowany na milionach uzupełnień tego samego wzorca, więc jego jakość na tych konkretnych ścieżkach mieści się w szumie dużego modelu — ale jego opóźnienie pierwszego tokena wynosi mniej więcej jedną trzecią.
Kiedy klasyfikator widzi intencję końcową — cokolwiek, co nie znajduje się w 40 wzorach — żądanie trafia do dużego modelu, tak jak poprzednio. Większość spadku opóźnień wynika z faktu, że wzorce o wysokiej częstotliwości są takie same Również wzorce, które odpowiadają za ~78% wolumenu połączeń. Ogony pokrywają oryginalne opóźnienie, ale są rzadkie.
Klasyfikator, którego nikt się nie spodziewał
Cienki klasyfikator był częścią projektu, na którą nikt nie przewidział budżetu. Budowanie go trwało dłużej niż budowanie samego systemu routingu, ponieważ tryby awarii były subtelne. Klasyfikator, który błędnie kieruje 1% żądań do małego modelu, który ich nie obsługuje, powoduje halucynacje, a nie tylko pogorszone odpowiedzi.
Trzy rzeczy sprawiły, że klasyfikator zadziałał. Po pierwsze, był szkolony na rzeczywistym ruchu produkcyjnym, a nie na danych syntetycznych. Po drugie, zwrócił poziom pewności, który router mógł przekroczyć — wszystko poniżej 0,91 zaufania automatycznie przechodzi do dużego modelu.
Po trzecie, wdrażaliśmy go w tle na sześć tygodni w stosunku do istniejącego rurociągu, przy czym duży model zapewniał podstawowe informacje, zanim jakikolwiek ruch został faktycznie przekierowany do małych modeli.
Wdrożenie w tle wykazało cztery klasy błędów, które przeoczył zestaw testowy offline. Dwa z nich można było łatwo naprawić w danych treningowych. Dwie wymagane, przemyślane reguły routingu — wszystko, co dotyczy weryfikacji tożsamości, płatności lub anulowania spotkań, zawsze trafia do dużego modelu, niezależnie od zaufania klasyfikatora, ponieważ koszt halucynacji na tych ścieżkach jest wyższy niż wygrana w zakresie opóźnień.
Problem po stronie TTS
Podczas gdy zmiany w LLM i STT były sprawdzane, równoległy zespół pracował nad dźwiękiem mowy. Pierwszy dźwięk TTS w języku angielskim trwający 50 ms był w rzeczywistości nie do pobicia; przerwa 70–90 ms w większości języków innych niż angielski wynikała z mniejszych modeli głosu, mniej agresywnego buforowania i jednej współdzielonej puli procesorów graficznych, w której priorytetem był język angielski pod obciążeniem.
Podzieliliśmy infrastrukturę TTS na pule z przypiętymi językami. Mandarin TTS działa teraz na własnej puli, z własnymi regułami skalowania, na sprzęcie znajdującym się blisko regionów, z których pochodzi większość naszego ruchu w języku Mandarin. Opóźnienie spadło z 70–90 ms do 45 ms w ciągu dwóch tygodni od przełączenia.
Nic z tego nie było sprytne; były to prace związane z infrastrukturą, którymi nikt się nie zajmował, ponieważ marginalna poprawa w jakimkolwiek pojedynczym języku nie uzasadniała tego samodzielnie.
Lekcja — którą teraz spisujemy wewnętrznie — jest taka, że „nie inwestowaliśmy w to, ponieważ nie uzasadniał tego żaden pojedynczy wskaźnik dostępny dla użytkownika”. Jest to dokładnie ten rodzaj decyzji, która składa się na różnicę 280 ms między dwoma językami w ciągu czterech lat.
Mierzenie parytetu, a nie średnich
Jedną małą, ale istotną zmianą, którą wprowadziliśmy wewnętrznie, był sposób, w jaki zespół raportuje panel opóźnień. Kiedyś śledziliśmy wartości p50 i p95 kompleksowych opóźnień, uśrednione dla wszystkich języków, w odniesieniu do pojedynczego SLO. Deska rozdzielcza przez większość czasu była zielona.
Nowy pulpit nawigacyjny zgłasza p50 i p95 na język przeciwko A parytet SLO — różnica pomiędzy najwolniejszym i najszybszym obsługiwanym językiem ma swój własny, oddzielnie egzekwowany budżet. Ustawiamy budżet parzystości na 60 ms. Kiedy różnica przekracza budżet, dyżurny zostaje wezwany.
Panel parzystości robi coś, czego nie da się zrobić na podstawie średniej: sprawia, że regresje w najwolniejszym języku są widoczne z taką samą pilnością, jak regresje w najszybszym. Jeśli uśrednisz wyniki dla 32 języków, regresja w języku wietnamskim wynosząca 200 ms powoduje przesunięcie średniej o 6 ms. Kiedy mierzysz parzystość, przesuwa deskę rozdzielczą o 200 ms.
Co jest nadal powolne
Po routingu, pulach TTS i panelu parzystości nasz najgorszy język (kantoński, głównie dlatego, że korpus modelu akustycznego jest mniejszy) wynosi 320 ms. Angielski ma czas 220 ms. Pozostała przerwa 100 ms jest realna i mniej więcej wiemy, gdzie ona występuje — kantoński model akustyczny STT jest starszy i nie korzysta jeszcze z nowej architektury, więc przeszkolimy go w trzecim kwartale.
Ale „najwolniejszy język jest 100 ms za najszybszym” to inna rozmowa niż „najwolniejszy język jest 280 ms za najszybszym”. Pierwsza z nich to znana regresja z planowaną kwartalną poprawką. Ten ostatni przypadek był sytuacją awaryjną związaną z obsługą klienta, o której istnieniu nie wiedzieliśmy.
Co następnym razem zrobilibyśmy inaczej
Trzy rzeczy w kolejności priorytetów, jeśli odbudowujemy stos opóźnień od zera na podstawie tego, co wiemy teraz.
- Najpierw zbuduj router klasyfikatora, a następnie model. Warstwa routingu okazała się elementem o największym wpływie. Traktowanie tego jako „dodamy to później, jeśli będzie potrzebne” okazało się oznaczać, że opóźnienia w przypadku jednego modelu trwały o 18 miesięcy dłużej, niż było to konieczne.
- Ustaw SLO parzystości przed SLO języka. Istnieje pokusa, aby wyznaczyć cele dla poszczególnych języków i pozwolić na osiągnięcie parytetu. Nie pojawia się parytet; powoli odbiega w kierunku podstawowego języka zespołu.
- Korzystaj z infrastruktury dla poszczególnych języków tak, jakby każdy język był oddzielnym produktem. Mandarin TTS zasługiwał na własną pulę procesorów graficznych od pierwszego dnia, a nie od dnia, w którym zmierzyliśmy różnicę w opóźnieniach.
Żadne z tych badań nie jest nowatorskie. Żadne z nich nie wymagało papieru. Wymagało to potraktowania parytetu opóźnień jako zobowiązania dotyczącego produktu, a następnie sfinansowania nieestetycznej infrastruktury w celu poparcia tego zobowiązania. Mamy teraz parytet, którego potrzebujemy. Nie mieliśmy go przez cztery lata.