Skip to content

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.

parțiale stt→endpointing decide→modelul pornește

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șteptareCând se aplicăImplicitInterval
start_speaking_plan.wait_secondsÎncă nu există transcriere finală — doar activitate vocală.0.40–5
start_speaking_plan.on_punctuation_secondsTranscrierea se termină cu ., ? sau !.0.10–3
start_speaking_plan.on_number_secondsSe termină în mijlocul unor cifre.0.50–3
start_speaking_plan.on_no_punctuation_secondsNu se termină nici cu una, nici cu alta.1.50–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.

CheieImplicitInterval
start_speaking_plan.smart_endpointing_providercallagentoff · callagent · livekit · model
start_speaking_plan.completion_threshold0.70–1
start_speaking_plan.smart_endpointing_ms2000100–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:

json
{
  "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.typeSe declanșează când
vad_timeoutExpiră cronometrul de tăcere.
providerTranscriber-ul spune că enunțul s-a încheiat. Niciodată pe cronometru.
punctuationPunctuație terminală, la așteptarea de punctuație; altfel, așteptarea completă de tăcere.
semanticUn predicat de completitudine întoarce adevărat; altfel, așteptarea completă.
hybridImplicit. 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.

CheieImplicitIntervalCe face
enabledtruefalse e exprimat ca un barge-in pe care nimeni nu îl poate declanșa, nu ca un plan absent.
num_words00–10Câte cuvinte transcrise trebuie înainte de oprire. 0 înseamnă doar activitate vocală.
voice_seconds0.20–0.5Cât trebuie să persiste vocea ca să conteze.
backoff_seconds10–10După 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 ​

  1. Nu vorbește acum → nicio întrerupere.
  2. Enunțul conține o expresie de întrerupere → întrerupe imediat, sărind peste toate porțile de mai jos.
  3. Audio-ul pare ecou al a ce tocmai s-a redat → nu e întrerupere.
  4. Tot enunțul e o expresie de confirmare → nu e întrerupere.
  5. Vocea nu a durat voice_seconds → încă nu.
  6. num_words > 0 și sunt mai puține cuvinte de atât → încă nu.
  7. 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âmpImplicitInterval
silence_timeout_seconds301–600 peste API, 5–600 în contract
max_duration_seconds1800de 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 ​

json
{
  "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 ​

Scrisă după cod. Ce nu este încă implementat este marcat ca atare, niciodată descris ca funcțional.