Sari la conținut
megapromotingHai să discutăm

Soluții · Transport & logistică

Când clientul întreabă unde e coletul, agentul nu ghicește: sună curierul, îl întreabă și se întoarce cu răspunsul.

Dispecerizarea prin voce, construită ca mecanism, nu ca promisiune: un tabel cu stări explicite, trei încercări la două minute distanță, rezultatul apelului scris structurat și un filtru care scoate numărul șoferului din tot ce ajunge la model, ca să nu poată fi dictat clientului.

Construit dejaMecanismul de dispecerizare e scris și migrat în platforma noastră vocală: tabela `courier_calls` cu șapte stări posibile, trei încercări implicite, pauză de 120.000 ms între ele și rezultatul apelului păstrat structurat, plus cinci funcții de server care o folosesc — inițierea apelului către curier, verificarea rezultatului, mătura pentru apelurile rămase agățate, identificarea celui care sună înapoi și webhookul de după apel. A doua implementare e filtrul de ieșire scris pentru un client din transport, care elimină recursiv câmpurile de contact ale șoferului din rezultatul uneltei, păstrând numerele dispeceratului. Rezerva, spusă înainte să întrebi: partea de telefon trece printr-o gazdă SIP, iar gazda prin care merg liniile noastre de test nu răspunde la data scrierii — nu-ți dăm un număr de demonstrație pe care nu l-am putea ridica în fața ta.

Într-o firmă de transport sau de livrare, cele mai multe apeluri primite sunt aceeași întrebare pusă de oameni diferiți: unde e marfa, la ce oră ajunge, de ce nu a ajuns. Răspunsul nu e într-un document și nu e într-un sistem — e în capul șoferului, care conduce. Dispecerul face legătura: preia apelul clientului, sună șoferul, revine la client. Munca asta ocupă un om întreg și se face de o sută de ori pe zi, cu aceleași trei propoziții.

Am construit exact acest lanț, ca mecanism cu stări, nu ca funcție de marketing. Un agent vorbește cu clientul. Când are nevoie de un răspuns pe care nu îl are, cheamă o funcție care pornește un al doilea apel — către curier — legat de conversația din care a plecat. Apelul acela are propriul rând într-un tabel, cu status care trece prin `calling`, `in_progress`, `retrying`, `completed`, `failed`, `no_answer`, `timeout`, cu numărul încercării, cu maximum trei încercări și o pauză de două minute între ele. Rezultatul se scrie structurat: rezumatul a ce a spus curierul, timpul estimat, poziția.

Partea care se uită ușor și pe care noi o tratăm ca pe o cerință, nu ca pe o precauție: numărul de telefon al șoferului nu are voie să ajungă la client. Nu e o instrucțiune scrisă în promptul agentului, pentru că o instrucțiune într-un prompt se poate ocoli. E un filtru care parcurge recursiv rezultatul uneltei și elimină câmpurile de contact ale șoferului înainte ca acel rezultat să ajungă la model — păstrând numerele dispeceratului. Ce a fost eliminat nu poate fi dictat, indiferent cum e întrebat agentul.

Iar limita cea mai importantă e una de infrastructură, nu de inteligență: un agent vocal la telefon depinde de o gazdă SIP între operatorul tău și platformă. Când acea gazdă cade, apelurile nu pleacă, iar semnătura defectului e recunoscibilă — cerere expirată, identificator de apel gol, durată zero. Gazda prin care trec liniile noastre de test nu răspunde la data scrierii acestei pagini. Pe web, traseul vocal e verificabil azi; la telefon, prima etapă a oricărei lucrări e să stabilim pe ce gazdă intră numerele tale.

Ce cuprinde

Ce se schimbă concret în transport & logistică

Agentul care vorbește cu clientul poate porni un al doilea apel

Când răspunsul nu e în informația pe care o are, agentul cheamă o funcție de server care sună curierul. Apelul spre curier își păstrează legătura cu conversația din care a plecat, printr-un identificator al conversației-părinte — deci se știe întotdeauna pentru cine s-a sunat și de ce. Contextul comenzii se transmite ca structură, din sistemul tău de comenzi, nu se redictează.

Apelul către curier are stări, nu doar „s-a sunat”

Șapte stări scrise ca restricție în baza de date: `calling`, `in_progress`, `retrying`, `completed`, `failed`, `no_answer`, `timeout`. Plus numărul încercării curente. Diferența dintre „nu a răspuns” și „a căzut sistemul” e vizibilă în date, nu ghicită din jurnale — și asta contează când cineva întreabă mâine de ce nu a primit clientul un răspuns.

Reîncercările sunt configurate, nu improvizate

Implicit: trei încercări, cu 120.000 de milisecunde — două minute — între ele, ambele scrise ca valori implicite în tabel și în configurația procesului. Un șofer care conduce pe un drum fără semnal nu răspunde la prima. Un sistem care sună o singură dată și declară eșec e inutil exact în cazul pentru care a fost construit.

Rezultatul apelului se întoarce structurat, nu ca poveste

Ce a spus curierul se scrie ca rezumat, timp estimat și poziție, într-un câmp structurat legat de rândul apelului. De acolo poate merge mai departe: către agentul care vorbește cu clientul, către dispecerat, către sistemul tău. Un webhook de după apel și o funcție de mătură pentru apelurile rămase agățate completează lanțul, ca un apel pierdut să nu rămână în starea `calling` la nesfârșit.

Numărul șoferului nu poate fi dictat, pentru că nu ajunge la model

Filtrul de ieșire parcurge recursiv rezultatul uneltei și elimină câmpurile de contact ale șoferului, păstrând numerele dispeceratului. E scris în cod, aplicat punctual pe integrarea unde apare problema. Motivul e simplu: interfața furnizorului întorcea numerele șoferilor în răspuns, iar politica firmei interzicea ca agentul să le dea clienților. O instrucțiune în prompt s-ar fi ocolit cu o întrebare bine formulată; un câmp eliminat nu se poate ocoli.

Cine sună înapoi e recunoscut după număr

Curierul care revine cu un apel e identificat de o funcție dedicată, deci nu intră în fluxul general de clienți și nu i se citește meniul de la început. Pare un detaliu; e diferența dintre un sistem pe care șoferii îl folosesc și unul pe care îl ocolesc sunând direct dispecerul, ceea ce anulează întreaga lucrare.

Predarea către dispecer, la îndemâna celui care vorbește

Transfer orb prin `##` și transfer asistat prin `*2`, cu context de aterizare în planul de apelare care distinge extensiile interne de patru cifre de numerele externe. Când clientul cere insistent un om — și în transport cere, pentru că marfa lui întârzie — transferul nu trebuie să treacă printr-un meniu.

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

Pe traseul OpenAI Realtime: detecție semantică a vorbirii cu prag 0,5, pernă de 300 ms, 500 ms de liniște, întrerupere permisă implicit. Pe traseul ElevenLabs, evenimentul de întrerupere e transmis centralei ca să taie redarea. `turn_timeout` se stabilește per agent. Într-un apel de transport, unde interlocutorul e adesea într-o cabină zgomotoasă, pragurile astea sunt jumătate din calitatea percepută.

Ce nu face un agent vocal în transport

Nu decide ruta și nu reoptimizează livrările. Nu dă un tarif dacă nu e conectat la sursa care îl calculează. Nu știe unde e marfa dacă nimeni nu i-a spus — nici curierul, nici sistemul tău. Și nu înlocuiește dispecerul: îi ia apelurile repetitive și îi lasă excepțiile, care sunt exact partea pentru care e plătit.

Traseul

Cum trece o cerere prin sistem.

01

Stabilim întâi pe ce gazdă SIP intră numerele tale

Prima etapă nu e scenariul agentului, ci telefonia: prin ce trunk intră numărul, cine îl controlează, ce se întâmplă când gazda nu răspunde. Livrăm o verificare scrisă a traseului și, dacă traseul nu e sigur, o spunem înainte de a construi ceva deasupra lui. Un agent excelent pe o gazdă care cade e un agent care nu răspunde.

02

Scriem scenariul dispecerizării, cu excepțiile lui

Ce întreabă agentul curierul, în ce ordine, ce face când curierul nu răspunde la a treia încercare, ce se întâmplă când răspunsul e neclar, când transferă la dispecerul uman. Livrăm scenariul scris și lista de stări în care poate ajunge un apel — inclusiv cele urâte.

03

Conectăm sursa comenzilor și punem filtrele la ieșire

Contextul comenzii vine din sistemul tău, iar înainte ca rezultatul unei unelte să ajungă la model trecem prin lista câmpurilor care nu au voie să iasă. Livrăm integrarea, lista scrisă a câmpurilor filtrate și dovada că filtrul se aplică pe rezultat, nu pe instrucțiuni.

04

Rulăm pe un volum mic, cu transcripturile citite de un om

Pornim pe o parte din apeluri, cu transferul la dispecer configurat larg, și citim transcripturile. De acolo se reglează pragurile de întrerupere, `turn_timeout`, formularea întrebărilor și pragul de la care agentul renunță. Livrăm raportul acestor apeluri, cu deciziile de reglaj, nu doar agentul pornit.

1Clientul întreabă2agentul cheamăfuncția de apel3apel către curier, custare proprie4până la treiîncercări, la douăminute5rezultat structurat(rezumat, timpestimat, poziție)6răspuns la client, cunumărul șoferuluifiltrat din drum
Traseul, în 6 pași

Datele

Ce atingem, unde stau și cât rămân

Regulile diferă de la o industrie la alta. Acestea sunt cele care se aplică în transport & logistică.

Numărul șoferului e dată personală a unui om, nu un câmp tehnic
Un curier sau un șofer subcontractat e o persoană fizică. Numărul lui, poziția lui și înregistrarea vocii lui sunt datele lui. De aceea filtrul de ieșire nu e un moft de securitate, ci minimizare aplicată la sursă: câmpul nu ajunge la model, deci nu poate ajunge în conversație și nici în transcript.
Ce se păstrează dintr-un apel
Numărul apelantului și numărul apelat, momentul, durata, rezultatul, înregistrarea audio, transcriptul și analiza de după apel. Pentru apelurile nepreluate există număr, moment și motivul lipsei de răspuns — audio nu există, pentru că nu s-a produs. Toate sunt legate de spațiul de lucru al firmei tale; nu există un depozit comun peste clienți.
Anunțul de la începutul apelului e decizia ta, nu o setare
Că interlocutorul vorbește cu un sistem automat, că apelul e înregistrat și pe ce temei — se stabilesc împreună cu tine și intră în scenariu, în ambele sensuri: și către client, și către curier. Curierul sunat de un agent trebuie să știe cu ce vorbește la fel de mult ca și clientul.
Ș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. Retenția configurabilă per spațiu de lucru nu e implementată — apare într-un document de proiectare, în nicio migrare. Până când va fi, ștergerea la termen se face prin procedură.
Unde stau datele
PostgreSQL prin Supabase pe infrastructură proprie, cu migrări versionate, dintre care o parte activează izolarea pe rând. 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.

Un caz

Un apel care are stare, nu doar un rezultat

Situația

Într-un flux de livrare, întrebarea „unde e comanda mea” nu are răspuns în niciun sistem: răspunsul e la curier. Varianta simplă — agentul îi scrie curierului un mesaj și speră — pică la primul curier care conduce și nu se uită la telefon.

Ce am construit

Am construit dispecerizarea ca tabel, nu ca funcție. Fiecare apel către curier are un rând cu șapte stări posibile, numărul încercării, maximum trei încercări, o pauză de două minute între ele și rezultatul păstrat structurat — rezumat, timp estimat, poziție. Rândul păstrează legătura cu conversația clientului din care a plecat. În jurul tabelului: funcția care pornește apelul, cea care verifică rezultatul, mătura pentru apelurile rămase agățate, identificarea curierului care sună înapoi și webhookul de după apel.

Ce a ieșit

Se poate răspunde, oricând și din date, la întrebările pe care un dispecerat le primește zilnic: s-a sunat, de câte ori, ce a răspuns, de ce nu s-a sunat. Un apel pierdut nu mai rămâne blocat într-o stare intermediară, pentru că are cine să-l măture.

Ce nu spune cazul

Mecanismul e scris și migrat în platformă; partea de telefon depinde de o gazdă SIP, iar cea prin care trec liniile noastre de test nu răspunde la data scrierii. Nu prezentăm dispecerizarea ca pe ceva ce poți încerca sunând azi la un număr al nostru.

Întrebări

Ce întreabă cineva din transport & logistică

Agentul sună el însuși curierul sau doar îi trimite un mesaj?

Sună. Există o funcție de server care pornește apelul către curier, legat de conversația din care a plecat, cu contextul comenzii transmis ca structură. Apelul are propriul rând într-un tabel, cu stare, număr de încercare și rezultat — deci se poate răspunde oricând la întrebarea „s-a sunat, și ce a zis”.

Ce se întâmplă dacă șoferul nu răspunde?

Se reîncearcă. Implicit de trei ori, la două minute distanță, valori scrise în tabel și în configurația procesului. Dacă nici a treia oară nu răspunde, apelul rămâne în starea `no_answer` — o stare distinctă de `failed`, care înseamnă că a căzut ceva la noi. Distincția asta e motivul pentru care merită un tabel, nu un jurnal.

Poate agentul să-i dea clientului numărul șoferului?

Nu, și nu pentru că i-am spus să nu o facă. Câmpurile de contact ale șoferului sunt eliminate recursiv din rezultatul uneltei înainte ca acel rezultat să ajungă la model. Numerele dispeceratului rămân. Ce nu ajunge la model nu poate fi dictat, oricât de abil e formulată întrebarea.

Poate să spună unde e coletul chiar acum?

Poate spune ce i-a spus curierul la ultimul apel, cu ora acelui apel, sau ce citește din sistemul tău dacă e conectat la el. Ce nu face — și e o decizie, nu o limitare — e să estimeze singur. O estimare inventată de un agent devine o promisiune pe care o suportă șoferul la ușă.

Pot suna acum la un număr de demonstrație?

Nu azi. Partea de telefon trece printr-o gazdă SIP, iar gazda prin care merg liniile noastre de test nu răspunde la data scrierii acestei pagini. Nu punem pe site un număr pe care nu l-am putea ridica în fața ta. Traseul vocal pe web e altă poveste: acolo se poate verifica imediat.

Vorbește rusă cu clientul și română cu dispecerul?

Configurația agentului acceptă 32 de limbi, iar româna e limba implicită a unui agent nou. Limba se stabilește per agent, deci agentul care vorbește cu clientul și cel care sună curierul pot fi configurați diferit. Ce trebuie știut: pentru sinteza vocii în alte limbi decât engleza, modelul implicit e cel rapid, iar varianta de calitate mai bună e vizibil mai lentă — compromisul se alege conștient.

Ce se întâmplă când clientul îl întrerupe?

Se oprește. Detecția semantică a vorbirii are prag 0,5, pernă de 300 ms și 500 ms de liniște, iar întreruperea e permisă implicit; pe celălalt traseu, evenimentul de întrerupere e transmis centralei ca să taie redarea. Dacă un agent nu poate fi întrerupt, nu e o problemă de ton, ci de configurație — și de răspunsuri prea lungi.

Cât se păstrează înregistrările apelurilor cu șoferii?

Cât stabilești tu, pentru că tu ești operatorul de date. Ce trebuie să știi despre starea de azi a platformei: ștergerea la cerere e implementată ca funcție, iar ștergerea automată la termen, configurabilă per spațiu de lucru, nu e — se face prin procedură. Preferăm să afli asta de la noi, nu dintr-un audit.

Înlocuiește dispecerul?

Nu. Îi ia partea repetitivă — aceeași întrebare, aceeași sunare, același răspuns — și îi lasă excepțiile. Transferul către el rămâne la un cod din tastatură, iar în transport excepțiile sunt frecvente: marfă refuzată, adresă greșită, client care nu răspunde. Acolo e nevoie de un om, și e mai bine să fie un om care nu a răspuns înainte la o sută de „unde e coletul”.

Ce ai vrea să funcționeze mai bine?

Povestește-ne despre procesul tău. Împreună stabilim ce merită construit, ce putem conecta și cum verificăm rezultatul.

Hai să discutăm