Realtime voice agent — amit egy 280 ms-os latency-budget tanított nekünk
WebRTC, OpenAI Realtime API, ElevenLabs fallback, és egy magyar nagyi, aki belebeszélt a botba. Hogyan tartottuk az end-to-end latency-t 300 ms alatt.
A voice agent nem akkor jó, ha gyorsan válaszol. Akkor jó, ha bármikor félbe lehet szakítani — és nem zavarodik össze.
Amikor 2026 márciusában elindítottuk a Nortinia Voice-t a 16 weboldalon, az első prod-incidensünk egy nagymama volt. Bejött az oldalra, megnyomta a mikrofon-gombot, és azt mondta: "Halló, halló, halló kedves, nem akarom én ezt, csak…". A bot szépen megvárta, amíg befejezi, és válaszolt 2.8 másodperc múlva — addigra a nagymama már letette. A barge-in handling, a latency-budget és a kapcsolat-csere-stratégia ekkor lett a hetünk fő témája, és most leírom, mit tanultunk 8 hét gyártás alatt.
A latency-budget per leg
A célunk egy 300 ms-os end-to-end first-token-latency volt, mert ezen a határon a beszélgetés "élővé" válik. Ezt kellett szétosztanunk a hálózati hopok között. A budget így néz ki éles üzemben.
- Mikrofon → böngésző capture: 8–12 ms (Opus encoder, 20 ms frame)
- Böngésző → OpenAI Realtime WebRTC: 35–80 ms (EU-régió, sticky session)
- OpenAI VAD + first token: 120–180 ms (gpt-4o-realtime-preview)
- TTS first chunk → böngésző: 25–45 ms (server-side streaming)
- Böngésző → hangszóró: 8–15 ms (AudioWorklet, jitter buffer 40 ms)
Fallback: ElevenLabs, amikor az OpenAI elesik
A live OpenAI Realtime API havi 1-2 alkalommal 5-15 percre kiesik EU-régióban. Mi ezt nem szerettük volna a felhasználóknak megmutatni, ezért egy mint-time provider failover logikát építettünk az engine VoiceSessionMintService-be: a session-token kiosztásakor a backend végigmegy egy tenant-priority listán (OpenAI → ElevenLabs → WebSpeech), és circuit-breaker-rel kihagyja azt, amelyik az utolsó 60 másodpercben hibázott. A panel oldali kód már discriminated union-nal kezeli a `session.kind`-ot, így a frontend változatlan maradt. Az ElevenLabs latency-je ~420 ms, ami érezhetően lassabb, de "működik" és "nem működik" között ez a különbség.
Barge-in: a legnehezebb mérnöki probléma
A felhasználó beszélni akar, amikor a bot beszél. Ez egyszerűen hangzik, de három alrendszer kell hozzá: szerver-oldali VAD, ami az input-stream-en érzékeli a beszédet (OpenAI Realtime ezt natívan adja); kliens-oldali audio-cancellation, hogy a bot saját hangja ne triggerelje a VAD-ot (AEC az AudioWorklet-ben); és egy clean abort-szignál, ami megszakítja a folyamatban lévő `response.create`-et és törli a TTS-queue-t. A 2.97.43-as panel-verziónktól ez 110 ms alatt működik — és pont ezért tud a nagymama is félbeszakítani.
A latency 0 ms-tól 300 ms-ig egy mérnöki probléma. 300-tól 1000 ms-ig egy UX-probléma. 1000 felett egy üzleti probléma.