Sari la conținut
megapromotingHai să discutăm

Expertise · Agents vocaux

Un agent qui parle — sur votre page et au téléphone — et qui peut être interrompu.

Nous construisons des agents vocaux sur Kallina : rôle écrit, base de connaissances approuvée, outils qu'ils appellent pendant l'échange et une limite au-delà de laquelle ils passent la discussion à un humain. Le roumain est la langue par défaut des nouveaux agents.

Construit dejaTrei implementări proprii, citate mai jos. (1) Platforma Kallina — 472 de funcții edge Deno și 559 de migrări de bază de date, numărate azi în depozit; `https://app.kallina.info` răspunde 200. (2) Componenta de pe acest site, `src/components/agents/KallinaVoiceAgent.tsx`, care implementează traseul corect de sesiune și documentează cele două moduri în care un agent vocal eșuează în tăcere. (3) Puntea `elevenlabs-bridge` și sesiunea `openai-realtime-session`, unde stau parametrii reali de întrerupere și de detecție a vorbirii. Rezerva pe care o spunem: partea de telefon depinde de o gazdă SIP, iar gazda prin care trec liniile noastre de test nu răspunde la data scrierii — vezi pagina de telefonie. Pe web, traseul e verificabil azi.

Un agent vocal, la noi, nu e „un bot care citește un scenariu”. Are patru lucruri scrise înainte de primul apel: un rol, o bază de cunoștințe aprobată de tine, un set de unelte pe care are voie să le cheme, și o limită dincolo de care predă discuția unui om. Ce iese din conversație nu e doar un transcript: apelul are durată, cost defalcat pe furnizor, înregistrare și analiză, toate legate de contul afacerii.

Motorul nu e unul singur, și asta e o decizie, nu un accident. În configurația agentului alegi între ElevenLabs Conversational AI, OpenAI Realtime și Gemini Live, sau lași „auto” și alege platforma după limbă, încărcare și disponibilitate. Peste el alegi separat creierul textual, dintr-un catalog în care fiecare model are latența și costul pe minut afișate în interfață. Când cineva întreabă „de ce răspunde încet”, răspunsul are cifre, nu păreri.

Partea pe care oamenii o simt cel mai tare e întreruperea. Pe OpenAI Realtime, detecția vorbirii e semantică, cu prag 0,5, o pernă de 300 ms înainte și 500 ms de liniște ca să considere că ai terminat de vorbit; comutatorul „permite întreruperi” e pornit implicit. Pe ElevenLabs, evenimentul de întrerupere e trimis mai departe centralei telefonice, ca să oprească redarea imediat. Iar timpul după care agentul consideră că tăcerea ta e un răspuns e configurabil per agent — pe un agent de vânzări scris de noi e strâns la 12 secunde, față de 15 implicit.

Agentul trăiește în două locuri diferite, cu constrângeri diferite. În pagina web intră cu o singură linie de script sau cu o componentă proprie, iar regula de aur e că pagina nu ține niciodată identificatorul agentului și nicio cheie de furnizor — cere platformei o sesiune și primește un URL semnat, de scurtă durată. La telefon intră printr-un trunk SIP, iar acolo constrângerile sunt ale operatorului și ale centralei, nu ale agentului; despre asta scriem separat, pe pagina de telefonie.

Ce que cela comprend

Le travail, par composantes

Sesiunea se cere de la platformă, nu de la furnizorul de voce

Pagina trimite `POST /functions/v1/widget-voice-session` cu identificatorul public al widgetului și primește înapoi un URL semnat. Nu are niciodată identificatorul agentului și nicio cheie. Varianta greșită — `startSession({ agentId })` direct în HTML — ocolește complet stratul de sesiune, de credit și de jurnal al platformei, și expune agentul oricui deschide sursa paginii. E prima verificare pe care o facem pe orice implementare pe care o preluăm.

Microfonul se cere înainte de sesiune, deci un refuz nu costă nimic

Ordinea e fixă și contează: cere microfonul cu `getUserMedia({audio:true})`, și abia dacă omul acceptă cere sesiunea. Dacă vizitatorul refuză, nu se emite niciun URL semnat și nu se consumă niciun minut. Cererea de microfon se face în interiorul apăsării de buton, înainte de orice așteptare care ar putea depăși gestul — altfel browserul ignoră cererea.

Agentul poate fi întrerupt, și asta se reglează cu cifre

Pe OpenAI Realtime: detecție semantică a vorbirii, prag 0,5, pernă 300 ms, 500 ms de liniște, întrerupere permisă implicit. Pe ElevenLabs: evenimentul `interruption` e transmis centralei ca să taie redarea. Peste asta, `turn_timeout` per agent decide după cât timp de tăcere agentul consideră că e rândul lui — implicit 15 secunde, strâns la 12 pe un agent de vânzări. Și un „nu-l pot întrerupe” raportat de un client are, de multe ori, altă cauză decât pragurile: răspunsuri prea lungi. Pe aceea o rezolvăm în prompt și în plafonul de tokeni, nu în detecția vorbirii.

Cheamă unelte în timpul convorbirii

Agentul nu e închis în ce știe. Poate chema funcții pe server în timp ce vorbește — pentru a citi o disponibilitate, a scrie o programare, a trimite un SMS sau a interoga un catalog. Uneltele sunt declarate per agent, cu parametri tipizați și cu un termen de execuție propriu, ca o unealtă lentă să nu blocheze conversația.

Predarea către om e parte din scenariu, nu o excepție

În mesagerie, preluarea de către un coleg are stare proprie pe fir — `handoff_status`, momentul preluării, motivul, cine e alocat, notele de rezolvare — implementată într-un modul dedicat de 619 linii. La telefon, transferul e făcut de centrală: transfer orb prin `##` și transfer asistat prin `*2`, cu apelul aterizând într-un context de dialplan scris pentru asta. Sunt două mecanisme diferite pentru că sunt două canale diferite; le scriem pe amândouă în scenariu.

Motorul și vocea se aleg explicit, nu implicit

Patru poziții de furnizor: `elevenlabs`, `openai-realtime`, `gemini-live` și `auto`. Pentru sinteza vocii în alte limbi decât engleza, implicit e `eleven_flash_v2_5` — 32 de limbi, în jur de 75 ms; varianta de calitate mai bună, `eleven_turbo_v2_5`, e în jur de 250 ms. Pe OpenAI Realtime sunt zece voci și motoare până la `gpt-realtime-2.1`. Alegerea e un câmp în configurația agentului, nu o presupunere din partea noastră.

Limbi

Configurația agentului acceptă 32 de limbi, harta internă de limbi a platformei are 41 de intrări, iar panoul de administrare e tradus în 20. Sunt trei cifre pentru trei lucruri diferite și nu se pot amesteca. Româna e limba implicită a unui agent nou.

Ce rămâne după apel

Transcript, înregistrare audio, durată, cost defalcat pe furnizor, plus o analiză de după apel și un rezumat scurt al conversației, generat pentru memoria clientului. Analiza nu e un scop în sine: pe ea se sprijină decizia dacă agentul a făcut ce trebuia sau dacă scenariul are o gaură.

Consumul se verifică înainte de acțiune, nu la factură

Înainte de orice operațiune care costă, platforma verifică creditul disponibil, iar consumul se scrie defalcat pe furnizor și pe agent. Poarta stă înaintea apelului. Practic: un agent scăpat într-o buclă nu poate consuma la nesfârșit fără să lovească într-o limită.

À quoi cela ressemble

Le parcours, étape par étape.

01

Alegem un singur traseu și îi scriem marginile

Un scenariu cu intrare clară și ieșire clară: apel primit la recepție, confirmare de comandă, verificare de disponibilitate. Scriem explicit ce nu are voie agentul să facă, ce nu are voie să spună și pe ce cale predă discuția unui om. Un agent fără margini scrise nu e mai capabil, e doar mai imprevizibil.

02

Construim agentul: rol, cunoștințe, unelte, limite

Promptul, baza de cunoștințe aprobată de tine, uneltele pe care le poate chema și pragurile de conversație — furnizor, voce, model textual, timp de tăcere, comportament la întrerupere. La final avem un agent configurat, nu un demo.

03

Îl punem pe canal și verificăm traseul fără să consumăm minute

Pe web: o linie de script sau o componentă proprie peste API-ul de pornire și oprire. Există un script care parcurge exact drumul unui browser — rândul din configurație, configurația widgetului, cererea de sesiune — și se oprește la URL-ul semnat, fără să deschidă conexiunea audio. Rulează pe un widget sau pe toate, întoarce cod de ieșire, deci poate intra într-o verificare programată. Pe telefon: numărul intră pe trunk, iar apelurile primite și cele ieșite se testează separat, pentru că se strică separat.

04

Măsurăm ce a ieșit și corectăm scenariul

După primele conversații reale citim transcriptele și analiza de după apel, nu impresiile. Ce corectăm cel mai des nu e modelul, ci lungimea răspunsurilor și marginile scenariului — două lucruri care se schimbă în prompt, în aceeași zi.

IntrareVerificareDeciziePublicareNimic nu trece mai departe neverificat.ORDINEA E ARGUMENTUL
Traseul unei conversații: pagina cere microfonul, platforma emite o sesiune semnată, agentul vorbește și poate fi întrerupt, cheamă o unealtă, iar ce depășește rolul lui se predă unui om.

Datele

Ce que nous touchons, où elles sont et combien de temps elles restent

Les questions que pose toute personne ayant un délégué à la protection des données — posées ici avant qu'il ne les pose.

Unde stau datele
PostgreSQL prin Supabase găzduit pe infrastructură proprie, cu 559 de migrări versionate, dintre care 195 ating politici de Row Level Security. Fișierele — înregistrări, documente de cunoștințe, mostre de voce — stau în depozite separate, cu calea începând cu identificatorul spațiului de lucru, ca izolarea să fie în structură, nu doar în interogare.
Ce nu ajunge niciodată în pagina ta
Cheia furnizorului de voce și identificatorul agentului. Pagina primește doar un URL semnat, de scurtă durată, emis de platformă. Consecința practică: cineva care citește sursa paginii tale nu poate folosi agentul tău pe cheltuiala ta.
Ce se înregistrează dintr-un apel
Audio, transcript, durată, numărul apelantului, rezultatul apelului și analiza de după. Pentru cazurile în care agentul ține minte clientul între apeluri, se salvează și un rezumat scurt al conversației anterioare. Toate sunt legate de un spațiu de lucru; nu există un depozit comun peste clienți.
Ștergerea la cerere există; ștergerea automată la termen încă nu
Spunem asta așa cum e, pentru că e diferența dintre o promisiune și o funcție. Ștergerea la cerere e implementată: o funcție dedicată șterge obiectele din depozitul de fișiere, cheamă procedura de ștergere din bază și invalidează sesiunile; există separat export de date și o funcție pentru datele de apel. Ce nu e implementat: termenele de retenție configurabile per spațiu de lucru. Sunt proiectate într-un document intern din aprilie, dar coloana de configurare nu apare în nicio migrare — deci azi ștergerea la termen se face prin procedură, nu prin ceas. Dacă proiectul tău are nevoie de ștergere automată, ea intră ca lucrare, nu ca setare.
Cine e informat că vorbește cu un agent
Anunțul că interlocutorul vorbește cu un sistem automat, temeiul înregistrării convorbirii și textul care se citește la începutul apelului se stabilesc împreună cu tine și intră în scenariu. Nu sunt o setare tehnică: sunt o decizie a operatorului de date, adică a ta.

Un cas

Le bouton qui ne faisait rien — et qui ne donnait même pas d'erreur

Situația

Un agent vocal pus într-o pagină web. La apăsare nu se întâmpla absolut nimic: fără sunet, fără mesaj, fără eroare în consolă pe care un neinițiat s-o vadă. Genul de defect care se raportează ca „nu merge” și se caută o zi în locul greșit.

Ce am construit

Cauzele erau două, ambele tăcute prin natura lor. Prima: antetul `Permissions-Policy` al serverului conținea `microphone=()`, iar browserul refuză cererea de microfon fără să ridice ceva vizibil pentru utilizator. A doua: SDK-ul vocal era importat static, iar un modul care întoarce 404 la import static doboară tot scriptul — deci și cererea de configurare murea odată cu el, ceea ce face defectul să arate exact ca „nimic nu s-a întâmplat”. Am mutat importul SDK-ului în interiorul apăsării de buton, am pus cererea de microfon înaintea cererii de sesiune și am scris antetul serverului ca `microphone=(self)`, cu politica de conținut care permite explicit rețeaua de distribuție a SDK-ului.

Ce a ieșit

Astăzi, pe acest site, antetul servit în producție este `camera=(), microphone=(self), geolocation=(self)`, iar politica de securitate a conținutului enumeră explicit sursa SDK-ului. Un eșec nu mai e tăcut: refuzul microfonului produce un mesaj în limba română care spune ce anume trebuie schimbat, iar refuzul nu costă nimic, pentru că sesiunea nici nu se mai cere.

Ce nu spune cazul

Cele două cauze sunt de infrastructură, nu de agent. Dacă site-ul tău e servit de altcineva și antetele nu sunt sub controlul nostru, verificarea lor devine o condiție de început a lucrării, nu o surpriză de la final.

Întrebări

Ce que les gens nous demandent avant d'appeler

Cu ce vorbește, concret? Ce motor e în spate?

Alegi între ElevenLabs Conversational AI, OpenAI Realtime și Gemini Live, sau lași „auto” și alege platforma după limbă și disponibilitate. Pentru sinteza vocii în alte limbi decât engleza, implicit e `eleven_flash_v2_5` — 32 de limbi, în jur de 75 ms; dacă vrei calitate mai mare și accepți întârziere mai mare, `eleven_turbo_v2_5` e în jur de 250 ms. Pe OpenAI Realtime sunt zece voci, iar motorul merge până la `gpt-realtime-2.1`. Creierul textual se alege separat, dintr-un catalog în care fiecare model are latența și costul pe minut scrise lângă el.

Îl pot întrerupe când vorbește, sau trebuie să aștept să termine?

Poți. Pe OpenAI Realtime detecția vorbirii e semantică, cu prag 0,5, pernă de 300 ms și 500 ms de liniște, iar comutatorul de întrerupere e pornit implicit. Pe ElevenLabs, evenimentul de întrerupere e trimis centralei telefonice ca să oprească redarea. Dacă totuși ai senzația că „nu-l poți întrerupe”, cauza e de obicei alta: agentul răspunde în paragrafe, nu în propoziții. Aia se repară în prompt și în plafonul de tokeni, nu în praguri.

În câte limbi vorbește?

Configurația agentului acceptă 32 de limbi. Harta internă de limbi a platformei are 41 de intrări, iar panoul de administrare e tradus în 20 — trei cifre pentru trei lucruri diferite. Româna e limba implicită a unui agent nou. Pentru o limbă anume verificăm întâi ce combinație de model de voce și de furnizor o acoperă efectiv, pentru că nu toate modelele acoperă aceleași limbi.

Cum ajunge pe site-ul meu și ce trebuie să schimb la mine?

O linie de script cu identificatorul public al widgetului, sau componenta ta proprie peste `start()` / `stop()` / `toggle()`. Două lucruri trebuie să fie adevărate pe serverul tău, altfel butonul nu face nimic și nu apare nicio eroare: antetul `Permissions-Policy` trebuie să permită `microphone=(self)` — cu `microphone=()` browserul refuză microfonul în tăcere — și politica de securitate a conținutului trebuie să permită încărcarea SDK-ului de pe rețeaua de distribuție folosită. Le verificăm noi înainte de publicare.

Poate suna el primul, nu doar să răspundă?

Da, platforma are apelare în loturi, cu import de contacte, reîncercări și urmărire în timp real. Dar apelurile ieșite nu depind doar de noi: în registrul nostru de probleme e documentat un caz în care centrala operatorului a început să întoarcă `403 Forbidden` la toate ieșirile, cu configurația noastră neschimbată și cu apelurile primite funcționând normal. De aceea testăm ieșirile separat înainte să promitem o campanie de sunat, și de aceea nu vindem un volum de apeluri ieșite înainte de acel test.

Ce se întâmplă când agentul nu știe răspunsul?

Predă. Fiecare agent are limite scrise și o cale de transfer configurată. În mesagerie, firul trece în stare de preluare umană, cu motiv și cu alocare către un coleg. La telefon, centrala face transferul — orb sau asistat — către o extensie sau un număr extern. Ce depășește rolul agentului se oprește, nu se improvizează; asta e o alegere de proiectare, pentru că un agent care improvizează într-un domeniu reglementat e un risc, nu o economie.

Se înregistrează convorbirile? Cât se păstrează?

Da, se înregistrează, se transcriu și se analizează, iar totul e legat de spațiul tău de lucru. Cât se păstrează e o decizie a ta ca operator de date, nu o valoare implicită pe care ți-o impunem — și trebuie spus limpede că ștergerea automată la termen nu e azi o simplă setare în platformă: ștergerea la cerere e implementată, ștergerea la termen se face prin procedură. Dacă ai nevoie de un ceas automat, el se construiește în proiect.

Consumă bani dacă vizitatorul apasă butonul și apoi refuză microfonul?

Nu. Microfonul se cere înaintea sesiunii. Dacă omul refuză, cererea de sesiune nu se mai face deloc, deci nu se emite niciun URL semnat și nu se consumă nimic. Separat, înainte de orice operațiune care costă, platforma verifică creditul disponibil — poarta e înaintea apelului, nu pe factura de la sfârșitul lunii.

Pot avea azi un agent care răspunde la un număr de telefon fix?

Depinde de o piesă care nu e agentul: gazda SIP prin care intră apelul. Partea de agent e gata și se poate arăta în pagină imediat. Partea de telefon cere un trunk funcțional de la operator și o centrală care să răspundă; la data scrierii, gazda prin care trec liniile noastre de test nu răspunde, iar noi nu prezentăm ca disponibil ceva ce nu putem porni în fața ta. Pentru un proiect real, telefonia se dimensionează separat — vezi pagina de telefonie și contact center.

Pe ce se sprijină afirmațiile de mai sus (21 surse)
  1. app.kallina.info răspunde 200 azi; supabase.kallina.info răspunde la funcțiile edgehttps://app.kallina.info/ · 2026-09-06
  2. Antetele servite azi în producție pe megapromoting.com permit microfonul și sursa SDK-uluihttps://www.megapromoting.com/ · 2026-09-06

19 dintre ele sunt cod și fișiere din depozitele noastre. Nu le publicăm numele și nici linia: împreună, pe o singură pagină, ar descrie prea exact cum sunt construite sisteme care nu sunt doar ale noastre. Le parcurgem cu tine, în depozit, la cerere — verificarea rămâne posibilă, doar că se face într-o discuție.

Qu'est-ce que vous voudriez voir mieux fonctionner ?

Racontez-nous votre processus. Ensemble, nous décidons ce qui vaut la peine d'être construit, ce que nous pouvons connecter et comment nous vérifions le résultat.

Hai să discutăm