Vissza a bloghoz

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.

ProCat Solutions voice-aisttttsllmsipwebrtcarchitektura
Megosztás
Másfél másodperc a válaszig: így épül egy valós idejű voice agent

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.

Telefonáló ember egy kávézóban

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.

Mikrofon, fejhallgató és hangteszt egy fejlesztői asztalon

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.

Megosztás
Széchenyi Terv Plusz kedvezményezetti infoblokk
QR Code