Preluarea turului și barge-in
Două decizii despart un agent vocal care pare o conversație de unul care pare un chioșc: când a terminat apelantul de vorbit și ce înseamnă o întrerupere. Amândouă sunt configurație pe asistent. Amândouă au valori implicite alese pe apeluri reale. Și amândouă merită schimbate pentru cazul tău.
Reglează asta înainte de orice altceva. E diferența pe care o aud efectiv apelanții.
Două vocabulare, și îți trebuie cel corect
E cel mai confuz lucru din configurarea unui asistent, deci vine primul.
Scrii chei plate, snake_case, prin API-ul REST și prin dashboard.start_speaking_plan.on_punctuation_seconds — plat, un singur nivel, fără imbricare.
Citești camelCase imbricat în @callagent/contracts.startSpeakingPlan.transcriptionEndpointing.onPunctuationSeconds — asta primește gateway-ul după ce convertește control plane-ul.
Convertorul citește cheile plate și nimic altceva. Un bloc imbricat trimis către API se salvează, e întors de GET și nu ajunge niciodată la gateway. O să pară că a mers.
Toate exemplele de pe pagina asta arată forma plată, pentru că aia e cea pe care o scrii.
Când a terminat apelantul?
Cele patru așteptări
Gateway-ul alege o singură așteptare per tur, în funcție de cum arată ultimele cuvinte ale apelantului.
| Așteptare | Când se aplică | Implicit | Interval |
|---|---|---|---|
start_speaking_plan.wait_seconds | Încă nu există transcriere finală — doar activitate vocală. | 0.4 | 0–5 |
start_speaking_plan.on_punctuation_seconds | Transcrierea se termină cu ., ? sau !. | 0.1 | 0–3 |
start_speaking_plan.on_number_seconds | Se termină în mijlocul unor cifre. | 0.5 | 0–3 |
start_speaking_plan.on_no_punctuation_seconds | Nu se termină nici cu una, nici cu alta. | 1.5 | 0–3 |
A patra e rostul blocului. O terminație fără punctuație înseamnă că transcriber-ul însuși nu crede că propoziția s-a încheiat, deci așteaptă mai mult decât ai aștepta după un punct. Ridic-o când apelanții tăi se pierd în vorbă; scade-o când asistentul pare greoi după răspunsuri scurte.
on_number_seconds există pentru că oamenii citesc cifrele cu pauze în ele. „Comanda mea e patru patru șapte… nouă doi" conține pauze care ar încheia orice altă propoziție. O jumătate de secundă de răbdare în plus, cât se rostesc cifre, e diferența dintre a prinde un număr de comandă și a-l cere a doua oară.
Smart endpointing
O judecată dată de model asupra faptului că propoziția sună încheiată, peste regulile de tăcere.
| Cheie | Implicit | Interval |
|---|---|---|
start_speaking_plan.smart_endpointing_provider | callagent | off · callagent · livekit · model |
start_speaking_plan.completion_threshold | 0.7 | 0–1 |
start_speaking_plan.smart_endpointing_ms | 2000 | 100–10000 |
Doar callagent e implementat
Dacă alegi livekit sau model, gateway-ul scrie un warning și rulează în tăcere tot scorerul intern. Sunt valori de enum, nu implementări.
off are înțeles și nu e același lucru cu omiterea blocului: un bloc absent înseamnă „folosește valoarea implicită", iar valoarea implicită e pornit.
Reguli proprii
Suprascrie așteptarea pentru anumite formulări:
{
"start_speaking_plan": {
"wait_seconds": 0.4,
"custom_rules": [
{
"target": "customer",
"type": "regex",
"pattern": "\\b(stai să verific|o secundă|un moment)\\b",
"timeout_seconds": 6
}
]
}
}target e customer (implicit), assistant sau both. type e regex (implicit), contains sau exact. timeout_seconds e în secunde, 0–15, și e convertit în milisecundele contractului pe drumul spre gateway.
pattern și timeout_seconds sunt amândouă obligatorii — o regulă căreia îi lipsește unul dintre ele e aruncată în tăcere. Un regex care nu compilează e aruncat și el, cu un motiv scris în log.
Strategia de endpointing
Mecanismul care decide, spre deosebire de cât așteaptă, stă pe transcriber:
transcriber.endpointing.type | Se declanșează când |
|---|---|
vad_timeout | Expiră cronometrul de tăcere. |
provider | Transcriber-ul spune că enunțul s-a încheiat. Niciodată pe cronometru. |
punctuation | Punctuație terminală, la așteptarea de punctuație; altfel, așteptarea completă de tăcere. |
semantic | Un predicat de completitudine întoarce adevărat; altfel, așteptarea completă. |
hybrid | Implicit. Oricare semnal activ se declanșează primul. |
Tot pe blocul acela: min_speech_ms (implicit 120 — o tuse nu e un tur) și max_wait_ms (implicit 20000).
max_wait_ms e 20 de secunde, nu trei. E un plafon, nu o țintă; celelalte reguli încheie aproape orice tur cu mult înainte. Un plafon scurt e exact ce produce un asistent care întrerupe un apelant care citește ceva de pe un ecran. Dacă îl pui sub cea mai lungă așteptare a ta, plafonul se declanșează mereu primul și setările tale de așteptare nu mai decid nimic — gateway-ul scrie un warning când vede asta.
Nu există niciun câmp de formular pentru transcriber.endpointing.silence_ms
silence_ms, punctuation_seconds și number_grace_ms există pe blocul de transcriber din contract și control plane-ul nu le scrie niciodată. Cele patru așteptări de mai sus sunt locul de unde vin duratele. Dacă vezi numele astea vechi într-un dump de schemă, sunt aceleași reglaje sub un nume pe care nu îl setează nimeni.
Când se oprește asistentul?
Cât timp asistentul vorbește, transcriber-ul continuă să ruleze. stop_speaking_plan decide care parte din vorbirea care intră e o întrerupere.
| Cheie | Implicit | Interval | Ce face |
|---|---|---|---|
enabled | true | false e exprimat ca un barge-in pe care nimeni nu îl poate declanșa, nu ca un plan absent. | |
num_words | 0 | 0–10 | Câte cuvinte transcrise trebuie înainte de oprire. 0 înseamnă doar activitate vocală. |
voice_seconds | 0.2 | 0–0.5 | Cât trebuie să persiste vocea ca să conteze. |
backoff_seconds | 1 | 0–10 | După o întrerupere, cât se așteaptă înainte de reluare. |
num_words: 0 e intenționat. Orice valoare peste zero obligă gateway-ul să aștepte transcrierea înainte să se poată opri din vorbit, ceea ce costă 200–400 ms la fiecare întrerupere, inclusiv la cele urgente.
Decizia, în ordine
- Nu vorbește acum → nicio întrerupere.
- Enunțul conține o expresie de întrerupere → întrerupe imediat, sărind peste toate porțile de mai jos.
- Audio-ul pare ecou al a ce tocmai s-a redat → nu e întrerupere.
- Tot enunțul e o expresie de confirmare → nu e întrerupere.
- Vocea nu a durat
voice_seconds→ încă nu. num_words > 0și sunt mai puține cuvinte de atât → încă nu.- Altfel → întrerupe.
Cele două liste de expresii
E partea care afectează cel mai mult cum se simte un apel.
Expresiile de confirmare nu întrerup. Un apelant care spune „mhm" în timp ce asistentul explică ceva e de acord, nu întrerupe, iar un asistent care se oprește brusc de fiecare dată e obositor. Douăzeci implicit:
i understand · i see · i got it · i hear you · im listening · im with you · right · okay · ok · sure · alright · uh-huh · mm-hmm · yeah · yes · yep · got it · gotcha · makes sense · sounds good
Potrivirea se face pe tot enunțul, normalizat. „okay dar stai" nu e o confirmare și va întrerupe. Pentru o instalare în limba română, înlocuiește listele cu ale tale — implicitele sunt în engleză.
Expresiile de întrerupere întrerup mereu, imediat, fără să aștepte num_words sau voice_seconds — și înaintea gărzii de ecou, deci funcționează chiar și când acustica e proastă. Treisprezece implicit:
stop · shut up · shut · wait · hold on · hold up · excuse me · actually · no no · listen · hang on · one moment · let me
Astea se potrivesc pe graniță de token în interiorul enunțului, nu pe tot enunțul.
Reglează listele, nu pragurile
Dacă asistentul tău pare nervos, adaugă în acknowledgement_phrases înainte să ridici num_words. Ridicarea lui num_words întârzie fiecare întrerupere, inclusiv „stop".
Respingerea ecoului
Separată de plan și neconfigurabilă per asistent. Gateway-ul ține un vârf care se atenuează al a ce tocmai a trimis și tratează audio-ul de intrare aflat cu peste 6 dB sub el ca ecou, ținut 600 ms — pentru că operatorul de rețea tamponează ce i s-a dat — cu o atenuare de 20 dB pe secundă. Astea sunt setări de mediu ale gateway-ului, nu câmpuri de asistent.
O expresie de întrerupere bate garda de ecou, intenționat.
Ce produce o întrerupere
assistant.speech.interrupted poartă spokenText, remainingText, spokenMs, detectionMs și stopAudioMs. Apelurile de model și de sinteză aflate în zbor emit llm.aborted și tts.aborted cu abortReason: barge_in.
Transcrierea păstrează doar ce s-a spus cu voce tare: mesajul poartă interrupted: true, deci contextul modelului reflectă ce a auzit apelantul, nu ce intenționa asistentul să spună. Greșeala asta e bug-ul clasic al agenților vocali — modelul crede că a livrat o propoziție pe care nu a auzit-o nimeni și răspunde la următoarea întrebare ca și cum ar fi livrat-o.
Trei metrici: interruption_ms, barge_in_detection_ms și barge_in_stop_audio_ms, ultima cu o țintă de 120 ms.
Salutul
first_message_interruptions_enabled e implicit false și de obicei acolo ar trebui să rămână. Apelanții vorbesc frecvent peste prima secundă a unui apel conectat — erau la mijlocul unei propoziții cât suna, sau spun „alo?" înainte să se termine salutul. Dacă tratezi asta ca întrerupere, abandonezi salutul degeaba.
Las-o pe false dacă salutul tău conține o dezvăluire sau o notificare de înregistrare. Vezi Dezvăluire AI și consimțământ.
Tăcere și durată
| Câmp | Implicit | Interval |
|---|---|---|
silence_timeout_seconds | 30 | 1–600 peste API, 5–600 în contract |
max_duration_seconds | 1800 | de la 10 până la plafonul platformei |
Gateway-ul le impune sub alte nume
CallSession nu citește direct silence_timeout_seconds și max_duration_seconds de pe asistent. Citește limits.maxSilenceSeconds și limits.maxDurationSeconds din configurația per apel pe care o trimite control plane-ul. Valorile vin de la asistent, dar dacă depanezi un apel care a trecut de limită, uită-te în blocul limits al configurației apelului.
Tăcerea nu e mereu o eroare, așa că message_plan o umple înainte să o facă timeout-ul: mesajele de inactivitate se rostesc după un timeout de inactivitate (implicit 10 s), cel mult de trei ori, cu contorul resetat când vorbește apelantul.
Un bloc complet, gata de copiat
{
"transcriber": {
"provider": "deepgram",
"model": "nova-3",
"endpointing": { "type": "hybrid", "min_speech_ms": 120, "max_wait_ms": 20000 }
},
"start_speaking_plan": {
"wait_seconds": 0.4,
"smart_endpointing_provider": "callagent",
"completion_threshold": 0.7,
"smart_endpointing_ms": 2000,
"on_punctuation_seconds": 0.1,
"on_no_punctuation_seconds": 1.5,
"on_number_seconds": 0.5,
"custom_rules": [
{ "target": "customer", "type": "contains", "pattern": "stai să verific", "timeout_seconds": 6 }
]
},
"stop_speaking_plan": {
"enabled": true,
"num_words": 0,
"voice_seconds": 0.2,
"backoff_seconds": 1,
"acknowledgement_phrases": ["bine", "da", "mhm", "sigur", "am înțeles"],
"interruption_phrases": ["stop", "stai", "o clipă", "de fapt"]
},
"first_message_interruptions_enabled": false,
"silence_timeout_seconds": 30
}Fă PATCH cu asta pe un asistent, publică și dă un apel.
Mai departe
- Cum funcționează un apel — unde stă endpointing-ul în pipeline.
- Asistenți — restul configurației.