ProCat Solutions
Másfél másodperc a válaszig: így épül egy valós idejű voice agent
Telefonos AI-ügynök STT, LLM és TTS streaming lánccal: latency-költségvetés, endpointing, jitter buffer, SIP és WebRTC média, barge-in és a magyar nyelv csapdái.
Ha a beszédfelismerés, a nyelvi modell és a beszédszintézis egymás után, blokkolva fut, a hívó három-öt másodpercet vár minden válaszra. Telefonban ez vállalhatatlan. Az elmúlt hónapokban több telefonos AI-ügynököt raktunk össze, és mindegyiknél ugyanaz a három kérdés jött elő: mennyi idő telik el a hívó utolsó szava és a válasz között, mi történik, ha közbevág, és hogyan bírja a rendszer a magyar nyelvet. Az alábbi architektúrára jutottunk, a buktatóival együtt.

Minden streamel
A klasszikus felállás három lépcsős: beszédfelismerés (STT), nyelvi modell (LLM), beszédszintézis (TTS). A három-öt másodperces várakozás elkerülésére mindhárom lépcső streaming módban fut:
- az STT részleges (partial) átiratokat ad, ahogy a hang érkezik, nem várja meg a mondat végét;
- az LLM tokenenként streamel, és az első mondatzáró írásjelnél már továbbadjuk a szöveget;
- a TTS mondatrészenként szintetizál, az első audio-chunk akkor megy ki, amikor a modell még a folytatást generálja.
Az egész egy aszinkron csővezeték, amelyben minden szakasznak saját sorbaállítása és megszakítási jele van. Node.js alatt ez magától adódik: streamek, async iterátorok, AbortController.
A csend küszöbe
A késleltetés nagyobb része nem a modellekben keletkezik. A döntésben van: mikor fejezte be a hívó a mondatot? Egy fix csendküszöb, például 700 ms, egyszerű, de kétféleképpen rossz. Rövid szünetnél belevág a hívóba, hosszú küszöbnél lassúnak tűnik a rendszer.
Mi három jelet kombinálunk: VAD-ot (voice activity detection) a nyers hangon, az STT saját end-of-speech jelzését, és egy egyszerű nyelvi heurisztikát, amely a részleges átiratból megbecsüli, lezárult-e szintaktikailag a mondat. Magyarban ez nehezebb, mint angolban, mert szabadabb a szórend, a kérdőszavak és a ragok viszont sokat segítenek. A jeleket egy állapotgép súlyozza, a küszöb adaptív: ha a hívó lassan, szünetekkel beszél, a rendszer türelmesebb lesz.
Ezredmásodpercekre bontva
Az élményt a hívó utolsó szótagja és az első visszahallott hang közötti idő határozza meg. Ezt nagyjából így osztjuk fel, tájékoztató nagyságrendekkel:
- endpointing döntés: 200-400 ms
- STT véglegesítés: 100-300 ms
- LLM első token: 300-600 ms
- TTS első audio-chunk: 150-300 ms
- hálózat és jitter buffer: 100-200 ms
Összesen egy-másfél másodperc, ami már természetesnek hat. Minden szakaszt külön mérünk, span-ekkel, hívásonként. Ha csak a végösszeget látnánk, nem tudnánk, hol romlott el. Jól bevált a kitöltő reakció: ha az LLM első tokenje késik, egy rövid, kontextusfüggő nyugtázás (“Rendben, megnézem.”) már kimehet. Ez időt nyer, és a hívó nem hallgat néma vonalat.

Négy mintavételi frekvencia
A telefonos oldal a legkevésbé látványos, és ez viszi el a legtöbb munkát. PSTN felől SIP trunkön RTP érkezik, jellemzően G.711 (8 kHz, alaw/ulaw), jobb esetben Opus. Böngészőből WebRTC jön, Opus 48 kHz-en. Az STT modellek többnyire 16 kHz-es PCM-et várnak, a TTS gyakran 24 kHz-et ad. A médiarétegben tehát minden irányban resampling van. Ezt egy helyen, egyértelmű formátumszerződéssel kell megoldani, különben a hang cincogóssá válik, vagy fél sebességgel szól.
Az RTP-csomagok egyenetlenül érkeznek, ezért a bejövő oldalon adaptív jitter buffer dolgozik, 20-60 ms-os tartományban. A kimenő oldalon pacing kell: a TTS gyorsabban termel hangot, mint ahogy a vonal elviszi, ezért 20 ms-os keretekben, órajel szerint küldjük. Enélkül a túloldali jitter buffer eldobja a csomagokat.
Ha a hívó közbevág
A közbevágás neve barge-in. Ilyenkor azonnal le kell állítani a TTS-lejátszást, ki kell üríteni a kimenő puffert, meg kell szakítani az LLM-generálást, és az új inputot új körként kell kezelni. A nehezebb rész a félbehagyott válasz: a beszélgetési előzménybe azt írjuk, ami ténylegesen elhangzott; a generált, de ki nem mondott rész kimarad.
Minden külső hívásnak van timeoutja. Ha az STT-szolgáltató adott időn belül nem válaszol, másodlagos szolgáltatóra váltunk, az LLM-nél kisebb modellre esünk vissza. Újrapróbálkozás csak idempotens lépéseknél megengedett; egy félig lejátszott TTS-t nem ismétlünk meg. Ha minden kiesik, az ügynök előre rögzített hangfájllal elnézést kér és visszahívást ígér. Ez rosszabb a normál működésnél, de sokkal jobb a csendnél.
Tizedikén, háromkor
A magyar agglutináló nyelv, ezért az STT-modellek a ritkább szóalakoknál bizonytalanabbak, mint angolban. A tapasztalataink:
- a tulajdonnevek és szakszavak (utcanevek, termékkódok) felismerése javul, ha az STT szószedetet vagy prompt-hintet kap;
- a számokat, dátumokat és időpontokat nem szabad nyersen a TTS-re bízni: “2024. 12. 10.” helyett “kétezer-huszonnégy december tizedike” formában adjuk át, ragozással együtt (“tizedikén”, “háromkor”);
- a telefonszámokat és azonosítókat csoportosítva, szünetekkel olvastatjuk fel, utána visszakérdezünk;
- a magyar TTS-hangok hangsúlyozása között nagy a szórás, ezért több szolgáltatót hasonlítunk össze ugyanazon a mondatkészleten.
A legfontosabb tanulság: a hangalapú ügynök valós idejű médiarendszer, amelyben az LLM csak az egyik szakasz. A késleltetés, a megszakíthatóság és a nyelvi normalizálás legalább annyi mérnöki munkát kíván, mint a prompt.