TaxeUK · agent vocal „Maria" · raport tehnic

Auditul Mariei

Am citit toate cele 68 de apeluri din platformă, configurația agentului și fluxul n8n. Concluzia răstoarnă ipoteza de pornire: agentul nu inventează. Repetă fidel ce îi trimite backend-ul — iar backend-ul îi trimite același lucru tuturor.

Agent agent_0701kxj9…fp0ne Apeluri 68 Căutări de dosar 89 Perioada 15.07 – 19.08.2026

Douăzeci și unu din cele douăzeci și șase de defecte sunt în fluxul n8n, nu în prompt. Promptul are problemele lui, dar rescrierea lui nu ar fi reparat aproape nimic din ce a raportat echipa.

Cel mai grav: numele și data nașterii pe care agentul le cere clientului sunt trimise către n8n și aruncate acolo. Fluxul caută exclusiv după telefon. De aceea „Enulescu Valentin" a fost identificat — și de aceea DALCRAN AMET a primit stadiul dosarului lui GHIULSEN AMET.

MăsurătoriCe a returnat efectiv API-ul

Cele 89 de căutări de dosar din cele 68 de apeluri, grupate după ce a primit agentul înapoi. Aceasta este singura tabelă din raport care explică de una singură lista de reclamații a echipei.

Ce a primit agentul de la n8nNr.Consecința în apel
Răspuns complet gol41„Nu găsesc un dosar" — de multe ori pentru clienți care există
Textul fix „a fost finalizat … transferată în contul indicat"28Agentul îl rostește. Toate „halucinările" raportate.
„Nu pot confirma cu exactitate stadiul"7Corect — ramura default a mapării de status
Ecoul propriei cereri (fără Respond to Webhook)5Agentul primește antetele HTTP ale propriei cereri
Eroare de execuție sau {"status":"error"}6Escaladare sau abandon
Date reale de dosar2Ambele: același dosar de test, TEST AGENT, id 63766

Două din optzeci și nouă. Și acelea două erau înregistrarea de test. Nicio căutare din tot setul nu a returnat datele unui client real.

Alte cifre
create_notitaTaxeUK apelat0 din 68
CreareLeadTaxeUK apelat2 din 68
Apeluri în care agentul a promis ceva fără să creeze sarcina13 din 25
Nume trimise către n8n și ignorate de flux42
Cod de client dictat, dar trimis gol66 din 89
Model care rulează agentulqwen35-397b-a17b

DiagnosticTrei cauze rădăcină

RC1

Fluxul caută după telefon și ignoră identitatea

Nodul GetLead primește name și birthday, le trece printr-un If care se uită doar la unique_nr, apoi le abandonează. Căutarea reală se face prin get-client-id-by-phone. Numele și data nașterii nu ajung nicăieri.

Rezultatul: oricine sună de pe un număr aflat în CRM primește dosarul de pe acel număr, indiferent ce nume dictează. Agentul spune „v-am identificat" pentru că, din punctul lui de vedere, căutarea a reușit.

RC2

Valori de test rămase codate în noduri de producție

Trei noduri get-client-id-by-phone au telefonul scris fix ca 000000000. Nodul send-form are phone fix +40740779788. Nodul store-note are client_id fix 43692 și details fix "AgentVocal". Termenul sarcinilor e fix 25/08/2026. UUID-ul fiecărui lead nou e același.

Numărul 000000000 aparține clientului de test TEST AGENT. De aici vin cele două singure răspunsuri „reușite" din tot setul.

RC3

Ce cere promptul nu există în unelte

create_notitaTaxeUK nu este înregistrat ca unealtă pe agent, iar nodul CreareNotita din n8n nu e conectat la nimic. Promptul dedică peste o mie de cuvinte unei acțiuni imposibile.

În paralel, descrierea uneltei CreareLeadTaxeUK spune „doar când clientul a furnizat toate datele obligatorii", iar regula R1–R7 din prompt spune „întotdeauna, fără prag minim". Modelul urmează descrierea uneltei. De aceea: două apeluri din șaizeci și opt.

DefecteCe trebuie reparat, în ordine

Codurile N sunt în fluxul n8n, E în configurația ElevenLabs, P în prompt sau în schema uneltelor.

N · Fluxul n8n

21 defecte
CriticN1

Identitatea nu este verificată niciodată

Nici pe ramura GetLead, nici pe GetClient nu există vreo comparație între numele și data nașterii spuse de client și cele din CRM. Fluxul întoarce dosarul găsit după telefon, iar agentul, primind un rezultat, anunță identificarea.

Test „Valentin Enulescu, 06/05/1996" — flux apelat cu numele corect, răspuns: mesajul fix de dosar finalizat. Agent: „Bun, v-am identificat." · Test DALCRAN AMET — a primit stadiul dosarului lui GHIULSEN AMET de pe același număr, iar agentul a insistat pe „Ahmed" pentru că nimic nu i-a contrazis rezultatul.

Fix

Un nod Code de verificare între căutare și mapare. Nume fuzzy, dată exactă. Dacă nu trece, întoarce {"identity_match": false, "message": "..."} și fluxul nu mai atinge datele dosarului.

nod nou „Verifica identitate" — după get-client, înainte de mapare
const norm = s => (s||'').toString().toLowerCase()
  .normalize('NFD').replace(/[\u0300-\u036f]/g,'')
  .replace(/[^a-z]/g,'');

// distanta Levenshtein
const lev = (a,b) => {
  const m=[...Array(a.length+1)].map((_,i)=>[i,...Array(b.length).fill(0)]);
  for(let j=0;j<=b.length;j++) m[0][j]=j;
  for(let i=1;i<=a.length;i++) for(let j=1;j<=b.length;j++)
    m[i][j]=Math.min(m[i-1][j]+1, m[i][j-1]+1,
                     m[i-1][j-1]+(a[i-1]===b[j-1]?0:1));
  return m[a.length][b.length];
};

const spus   = norm($('GetLead').first().json.body.name);
const dobSpus= ($('GetLead').first().json.body.birthday||'').trim();

const client = $json.client || {};
const dinCrm = norm(client.lastname);
const dobCrm = (client.birthdate||'').slice(0,10); // AAAA-LL-ZZ
const [a,l,z] = dobCrm.split('-');
const dobCrmRo = z && l && a ? `${z}/${l}/${a}` : '';

// numele de familie apare oriunde in ce a dictat clientul, cu maxim 2 litere diferenta
const numeOk = dinCrm && [...spus.matchAll(/[a-z]+/g)]
  .concat([[spus]])
  .some(() => lev(spus, dinCrm) <= 2 || spus.includes(dinCrm) || dinCrm.includes(spus));

const dobOk = dobSpus && dobCrmRo && dobSpus === dobCrmRo;

if (!(numeOk && dobOk)) {
  return [{ json: {
    identity_match: false,
    client_id: null,
    message: 'Nu reușesc să vă identific cu aceste date.'
  }}];
}
return [{ json: { ...$json, identity_match: true } }];

Data nașterii rămâne verificarea tare, fără toleranță. Numele are voie să difere — de asta se ocupă distanța Levenshtein, care acceptă Globa pentru GLOABA, Colan pentru CIOLAN și Mihal pentru MIHART.

CriticN2

Trei noduri caută după telefonul 000000000

getIdLead1, getIdLead2 și getIdLead5 au parametrul phone scris literal 000000000. Nu e o expresie, e text.

  • getIdLead5 e pe ramura GetClient fără cod de client — deci orice apel de identificare fără cod caută clientul de test.
  • getIdLead2 alimentează client_id pentru fiecare sarcină creată. Toate cele 14 sarcini din perioada testată sunt atașate clientului TEST AGENT, nu clienților reali.
  • getIdLead1 e pe ramura de notiță.
Fix

Înlocuiți valoarea cu expresia care ia telefonul din webhook-ul corespunzător, la fel ca în getIdLead4, care e singurul făcut corect.

CriticN3

Un id de client este trimis ca lead_id

get-client-id-by-phone întoarce identificatorul clientului. Nodurile HTTP Request2 și HTTP Request5 îl pasează mai departe la get-lead pe parametrul lead_id. În înregistrarea reală citită din platformă, clientul are clients_id: 43692 iar dosarul id: 63766. Sunt numere diferite.

În plus, aceleași două noduri citesc {{ $json.id }}, în timp ce HTTP Request8 și HTTP Request10 citesc {{ $json.client.id }} din același răspuns. Cel puțin una dintre cele două forme trimite undefined.

Fix

Uniformizați citirea la forma reală a răspunsului și cereți în CRM un endpoint care întoarce toate dosarele unui client: get-leads-by-client. Fără el, N4 nu se poate repara.

CriticN4

Maparea de status citește doar primul dosar

În toate cele patru copii ale nodului de mapare:

Code in JavaScript 11 / 14 / 15 / 17 — linia problemă
const lead = src.lead ?? (Array.isArray(src.leads) ? src.leads[0] : src.leads) ?? {};

src.leads[0]. Un client cu opt dosare este redus la unul singur, iar dacă acela e finalizat, clientul aude că totul e gata.

CIOLAN (EZ234): 8 dosare, 7 finalizate + 1 nou → „urmează să primiți banii". GLOABA (PY247): 4 dosare, 3 finalizate + 1 în procesare → „un singur dosar, finalizat".

Fix
înlocuire — alege dosarul relevant, nu primul
const leads = Array.isArray(src.leads) ? src.leads
            : (src.lead ? [src.lead] : []);

// dosarele nefinalizate au prioritate; intre ele, cel mai recent
const DESCHISE = [1,2,3,4,5,6,7,8];
const deschise = leads.filter(l => DESCHISE.includes(Number(l.status)));
const lead = (deschise.length ? deschise : leads)
  .sort((a,b) => new Date(b.created_at) - new Date(a.created_at))[0] ?? {};

const total     = leads.length;
const finalizate= leads.filter(l => Number(l.status) === 9).length;

// prefix rostit inaintea mesajului de status, cand exista mai multe dosare
const prefix = total > 1
  ? `Aveți ${total} dosare la noi, dintre care ${finalizate} finalizate. Despre cel aflat în lucru: `
  : '';

Apoi message: prefix + message la final. Maparea celor zece stări este scrisă corect și nu trebuie atinsă — problema e doar selecția dosarului.

CriticN5

Fiecare lead nou primește același număr de telefon

În nodul HTTP Request13 care apelează send-form:

HTTP Request13 — parametri codați fix
phone                       →  +40740779788      ← acelasi la toti
uuid                        →  550e8400-e29b-41d4-a716-446655440000
notes                       →  "express daca este primul lead"
next_leave                  →  1
next_leave_date             →  0000-00-00
no_jobs                     →  0
no_visits_for_taxes_request →  0
postal_office_send          →  0
iban / sort_code / account_number / account_holder / signature / referral
                            →  sirul "null"
language                    →  1        (specificatia cere "ro")

Consecințele, în ordinea gravității: fiecare client nou intră în CRM cu telefonul altcuiva, deci SMS-ul cu linkul de documente nu poate ajunge la el niciodată; toate lead-urile împart același UUID; no_jobs și numărul de perioade sunt zero deși agentul le colectase; iar câmpul de observații conține o notă de dezvoltare ajunsă în producție.

Apelul PETRU MERLAN: agentul a trimis corect leaves_arr cu perioada 20/01/2026 – 18/08/2026 și un job. Nodul a suprascris no_jobs cu 0 și telefonul cu +40740779788.

Fix

Toate cele de mai sus devin expresii care citesc din $('CreareLead').item.json.body. Pentru uuid, generați-l în flux. Pentru phone, adăugați parametrul în schema uneltei — momentan nu există deloc (vezi P2).

CriticN6

Ramura de notiță nu e conectată, iar nodul ei scrie o notiță fixă

Webhook-ul CreareNotita are conexiunile goale — "CreareNotita": {"main": [[]]}. Nimic nu pleacă din el. Chiar dacă ar fi legat, nodul HTTP Request6 trimite către store-note:

HTTP Request6
client_id  →  43692          (clientul de test, codat fix)
details    →  "AgentVocal"   (text fix, nu rezumatul apelului)

Notița e moartă pe trei niveluri simultan: unealta nu e înregistrată pe agent, webhook-ul nu e conectat, iar nodul final ar scrie oricum același text pe același client.

Fix

Legați CreareNotita → Code (login) → getIdLead1 → HTTP Request6 → Respond, faceți client_id și details expresii, și înregistrați unealta pe agent. Vezi și E1.

CriticN7

Termenul fiecărei sarcini este 25/08/2026

Nodul CreareTask1 trimite task_deadline literal. Agentul calculează termenul corect — două, una sau trei zile lucrătoare, după tipul solicitării — îl trimite, iar fluxul îl aruncă. Toate sarcinile ajung cu aceeași dată, deci coada de lucru nu se poate prioritiza.

Fix
CreareTask1
task_deadline → {{ $('CreareTask').first().json.body.task_deadline }}
CriticN8

Referință între fluxuri: HTTP Request12 citește dintr-un nod care nu a rulat

Nodul e pe ramura GetLead (cazul „clientul are cod de client"), dar citește data nașterii din webhook-ul celuilalt flux:

HTTP Request12 — pe ramura GetLead
unique_id  →  {{ $('GetLead').first().json.body.unique_nr }}      corect
birthdate  →  {{ $('GetClient').first().json.body.birthdate }}    gresit

GetClient nu se execută în acest traseu. Rezultă undefined sau eroare de expresie — iar get-client are nevoie de ambii parametri. Aceasta este ramura pe care ajung exact clienții care au făcut efortul să dicteze codul.

Fix

{{ $('GetLead').first().json.body.birthday }}. Atenție și la numele câmpului: unealta GetLeadTaxeUK îl numește birthday, nu birthdate.

MajorN9

Nodurile de răspuns aruncă tot în afară de message

Maparea produce client_id, lead_id, status_code, status_label, next_step și internal_note. Cele patru noduri Respond to Webhook trimit înapoi doar textul:

Respond to Webhook 6 / 8 / 9 / 10
={ "message": "{{ $json.message }}" }

Agentul nu primește niciodată un client_id, deci nu poate lega o sarcină de un client — indiferent ce scrie promptul despre asta. Și interpolarea directă a unui text în JSON se rupe la prima ghilimea sau linie nouă din mesaj.

Fix
înlocuire — răspuns structurat
{{ JSON.stringify({
     found: $json.identity_match !== false && $json.status_code != null,
     identity_match: $json.identity_match !== false,
     client_id: $json.client_id,
     status_code: $json.status_code,
     status_text: $json.message
   }) }}

Un câmp found explicit este important: în 41 de cazuri agentul a primit un corp gol, iar un corp gol nu îi spune dacă e „nu există dosar" sau „a picat ceva".

MajorN10

Două noduri de răspuns nu au corp configurat

Respond to Webhook (ramura sarcini) și Respond to Webhook1 (ramura lead nou) nu au responseBody. n8n întoarce atunci elementul curent, adică cererea primită — cu tot cu antetele Cloudflare. În cinci apeluri agentul a primit înapoi propriul HTTP request ca rezultat al uneltei.

Fix

Setați un corp explicit, de exemplu { "ok": true, "id": {{ $json.id }} }. Iar în cazul sarcinilor, folosiți răspunsul ca semnal către model — vezi E2.

MajorN11

Telefonul nu este normalizat nicăieri

Unealta declară numarTelefon ca număr, iar descrierea ei cere formatul 07xxxxxxxx. Un tip numeric nu poate păstra zeroul din față, deci formatul cerut e imposibil de trimis. În practică modelul trimite 40764132983, iar getIdLead4 pune un plus în față și caută +40764132983.

Din 89 de căutări, exact 0 au fost în formatul pe care îl cere descrierea uneltei. Am observat și valori corupte, precum 4037644101085 — treisprezece cifre.

Peste asta se suprapune o ambiguitate reală: 07… este prefix de mobil și în România, și în Marea Britanie. Clienții voștri au numere din ambele țări.

Fix
  • Schimbați tipul parametrului în string și cereți-l ca +40… — același format și în prompt, și în descrierea uneltei.
  • În CRM, căutați după ultimele nouă cifre, ignorând prefixul. O singură linie care elimină toată clasa asta de erori.
MajorN12

Câmpurile goale ajung în CRM ca textul „null"

Promptul îi cere modelului să trimită null pentru orice câmp neobținut. Schema uneltei declară toate câmpurile ca string și obligatorii, deci modelul trimite șirul "null". Fluxul folosește apoi {{ … || null }}, iar în JavaScript "null" || null este "null" — șirul trece mai departe.

Lead-ul lui PETRU MERLAN a plecat spre CRM cu email: "null", nino: "null", uk_address: "null", current_city: "null".

Fix

Un nod Set înainte de send-form care curăță: v => (v==null || v==='null' || v==='') ? null : v. Și scoateți câmpurile opționale din lista required a uneltei, ca modelul să le poată omite pur și simplu.

MajorN13

Parola contului de serviciu este scrisă în clar în opt noduri

Fiecare nod Code conține email-ul și parola contului ai.agent@taxeuk.com direct în sursă. Sunt vizibile oricui are acces la n8n și pleacă în orice export al workflow-ului — inclusiv în cel pe care mi l-ați trimis.

Fix
  • Mutați-le într-o credențială n8n de tip Header Auth sau într-o variabilă de environment.
  • Rotiți parola — a circulat deja în afara sistemului.
  • Extrageți login-ul într-un sub-workflow cu token pus în cache. Acum fiecare apel de unealtă face un login separat, iar pe ramura cu cod de client se lanțuiesc patru cereri HTTP într-un timeout de 20 de secunde, în timp ce clientul așteaptă pe linie.
MajorN14

Maparea de status e duplicată în patru noduri identice

Code in JavaScript 11, 14, 15 și 17 conțin exact același cod, copiat. Orice corecție — inclusiv cea de la N4 — trebuie făcută de patru ori, iar dacă una scapă, doi clienți în situații identice primesc răspunsuri diferite.

Fix

Un singur sub-workflow „Mapare status dosar", apelat din ambele ramuri.

MinorN15

country_id și apl sunt fixe

country_id e 1 — corect pentru Anglia, dar blochează Germania, care e în ofertă. apl primește apelativul „Dl" / „Dna", în timp ce specificația voastră spune că apl este întotdeauna 1. Înregistrarea reală din CRM arată "apl":"dl", deci CRM-ul acceptă forma actuală — dar specificația și implementarea spun lucruri diferite și una dintre ele trebuie corectată.

E · Configurația ElevenLabs

5 defecte
CriticE1

create_notitaTaxeUK nu este înregistrat pe agent

Agentul are patru unelte proprii: CreareLeadTaxeUK, create_taskTaxeUK, GetLeadTaxeUK, GetclientTaxeUK. Notița nu e printre ele. Promptul o declară obligatorie la fiecare apel, o pune în lista de verificare de la Pasul 6 și o listează în criteriile de evaluare.

Efectul nu e doar că notița lipsește. O instrucțiune insistentă către o unealtă inexistentă degradează respectarea întregului bloc de acțiuni finale — modelul „bifează" pasul și trece la următorul. Cele 13 promisiuni fără sarcină din 25 se explică parțial așa.

Fix

Creați unealta către webhook-ul 740807ea-… cu parametrii client_id și details, după ce reparați N6. Sau, dacă preferați să nu depindeți de model deloc, ștergeți-o din prompt și generați notița dintr-un post-call webhook — e o acțiune complet deterministă, nu are nevoie de judecată în timp real.

MajorE2

Descrierea uneltei contrazice regula R5 din prompt

descrierea actuală a uneltei CreareLeadTaxeUK
CÂND SĂ APELEZI:
Doar când clientul este complet nou și a furnizat toate datele obligatorii:
nume, contact, NINO, adresele, datele bancare și istoricul perioadelor de
muncă în UK.

Promptul spune exact invers: „Fără excepție. Chiar dacă ai doar numele." Descrierea uneltei stă lipită de schema funcției și cântărește mai mult decât un paragraf de la mijlocul unui system prompt de 36.659 de caractere. Modelul o urmează pe ea. Doar 2 apeluri din 68.

Fix
descriere nouă
Înregistrează în sistem un dosar nou.

CÂND SĂ APELEZI:
La finalul ORICĂREI discuții de aplicare nouă, indiferent câte date ai
obținut. Nu există prag minim. Dacă ai doar numele, apelezi cu numele.
Câmpurile neobținute se trimit goale și vor fi completate de un coleg.
Un dosar incomplet în sistem este util; un dosar necreat nu există.

Și scoateți din lista required tot ce nu e strict necesar, ca schema să nu mai sugereze că totul e obligatoriu.

MajorE3

Lista de cuvinte pentru transcriere este goală

ASR-ul rulează pe Scribe v2 Realtime cu keywords: []. Numele proprii românești sunt exact locul unde orice motor de transcriere cedează, iar aici nu e ajutat cu nimic.

GLOABA → Globa · CIOLAN → Colan · MIUTESCU → Sălescu · MIHART → Mihal · AMET → Ahmed · TRIFU și RĂDUFCAN — nerecunoscute după patru-cinci încercări.

Fix

Exportați numele de familie distincte din CRM și încărcați-le ca listă de keywords. Este intervenția cu cel mai bun raport efort/rezultat din tot raportul, și e independentă de toate celelalte. Combinată cu potrivirea fuzzy de la N1, problema numelor dispare practic.

MajorE4

Modelul este qwen35-397b-a17b

Propria voastră fișă de configurare cere „model puternic, nu cel mai mic disponibil". Qwen nu e cel mai mic, dar pe română, pe disciplină strictă de apelare a uneltelor și pe un system prompt de 36.659 de caractere e sub ce vă trebuie.

Un detaliu util: temperatura e 0.0. De aceea mesajul fix al backend-ului a fost repetat aproape cuvânt cu cuvânt la toți clienții — modelul e determinist, deci reproduce fidel ce primește. Nu schimbați temperatura; e setarea corectă. Schimbați modelul.

Fix

Treceți pe un model mai capabil și re-rulați aceleași teste. Reparați însă întâi N1–N8 — altfel veți plăti mai mult pentru același răspuns greșit primit de la backend.

MinorE5

Baza de cunoștințe e goală, iar promptul are 36.659 de caractere

RAG este dezactivat și nu există niciun document atașat. Tot ce promptul numește „Knowledge" — tarife, termene, condiții — stă ca text simplu spre finalul unui prompt foarte lung. De aceea a apărut afirmația că cele optzeci de lire „acoperă tot": informația corectă există, dar e diluată.

Tot aici: turn_timeout e 7 secunde, sub cele 8–10 din fișa voastră. Pentru vorbitori care se exprimă greu, mai ales la dictarea unei date sau a unui cod, marginea de 2–3 secunde contează.

Fix

Mutați Knowledge într-un document atașat și activați RAG. Promptul scade cu câteva mii de caractere, iar informația se regăsește mai fidel. Urcați turn_timeout la 9.

P · Prompt și scheme de unelte

5 defecte
MajorP1

create_taskTaxeUK nu are parametrul client_id

Schema are doar task_description și task_deadline. Promptul dedică o secțiune întreagă regulilor de completare a client_id, cu trei ramuri de decizie. Nu are unde să ajungă. Fluxul îl completează singur din getIdLead2 — care caută telefonul 000000000, vezi N2.

Fix

Adăugați client_id în schemă, faceți-l opțional, și în flux folosiți-l când vine completat, cu revenire la căutarea după telefon când lipsește.

CriticP2

CreareLeadTaxeUK nu are parametru pentru telefon

Nu există phone în schemă. Nici pentru cont bancar: lipsesc iban, sort_code, account_number, account_holder. Lipsesc și postal_office_send, referral, no_visits_for_taxes_request, country_id.

Promptul instruiește agentul să ceară IBAN-ul, iar echipa a semnalat corect că „contul se trimite ulterior doar prin SMS". Are dreptate — dar chiar dacă ar fi corect să-l ceară, nu are unde să-l pună.

Absența telefonului e cea gravă. Fără el, nu se poate trimite linkul de atașare documente și semnare contract, deci dosarul nu poate avansa. Este exact ce a observat echipa după apelul MERLAN.

Fix
  • Adăugați phone în schemă și legați-l în send-form.
  • Scoateți din prompt cererea de IBAN și cont bancar la aplicarea nouă. Înlocuiți cu o informare: „Contul bancar nu vi-l cer la telefon. Vă trimitem un mesaj și ni-l transmiteți acolo."
  • Adăugați o întrebare obligatorie de confirmare a numărului, imediat după identificare — nu la final, unde riscă să fie sărită.
MajorP3

Nu există unealtă de trimitere SMS

Promptul spune „nu poți trimite SMS-uri, lași sarcină". Dar sarcina ajunge pe clientul de test cu termen fix, deci nu o vede nimeni. Trimiterea unui SMS cu un link este o acțiune complet deterministă — nu are motiv să treacă printr-un om.

Fix

O unealtă trimite_sms_link, apelată direct după CreareLeadTaxeUK, cu numărul confirmat. Iar în post-call webhook: lead nou fără SMS trimis → SMS-ul pleacă automat.

MajorP4

Nu confirmă înapoi ce a auzit, înainte de a căuta

Observația echipei, exact: „Ideal ar fi să și repete numele și data nașterii după client." O replică de confirmare prinde eroarea de transcriere înainte să ajungă în API. Se repetă ce a spus clientul, nu ce scrie în sistem — deci nu e o divulgare.

La fel pentru codul de client: agentul a afirmat la un moment dat că e format doar din litere, ceea ce e fals. Iar codul a fost trimis gol în 66 din 89 de căutări, chiar și după ce clientul îl dictase.

Fix
de adăugat la Pasul 2, înainte de apelul uneltei
După ce clientul îți spune numele și data nașterii, le repeți ÎNAPOI o
singură dată, înainte de a apela orice instrument:
  „Am notat Ciolan Letiția, doisprezece martie o mie nouă sute optzeci
   și șapte. Am înțeles corect?"

Codul de client are exact cinci caractere și poate conține atât litere
cât și cifre. Nu afirmi niciodată că e format doar din litere. Îl ceri
fonetic — „A ca Ana, B ca Barbu" — și îl confirmi tot fonetic înainte
de apel. Dacă nu ai obținut cinci caractere, nu apelezi instrumentul.
Dacă ai obținut codul, îl trimiți — nu îl trimiți niciodată gol.
MinorP5

Renunță după o singură încercare, sau insistă la nesfârșit

Într-un apel, agentul a apelat end_call la secunda 19, cu motivul „utilizatorul nu a furnizat datele de identificare", după o singură cerere. În altul a cerut același nume de patru-cinci ori la rând fără să schimbe metoda.

Fix

Pragul se leagă de canale diferite, nu de număr de încercări: telefonul de pe care sună → nume și dată de naștere → alt număr → cod de client. Maxim două încercări per canal, apoi treci la următorul; a doua oară ceri pe litere. Abandonezi doar după ce toate patru au eșuat.

Tot aici, două corecții mici de conținut: cele optzeci de lire sunt comisionul pentru trimiterea dosarului, nu „acoperă tot" — interziceți explicit formulările „acoperă tot", „comision final", „nu mai plătiți nimic". Și: dacă întrebarea e despre comision, nu răspundeți despre stadiul dosarului.

PlanOrdinea reparațiilor

Primele trei etape se fac în n8n și rezolvă majoritatea listei. Etapa 1 este singura care e urgentă indiferent de restul: până la ea, agentul spune clienților reali că au primit bani pe care nu i-au primit.

1

Opriți mesajul fals de dosar finalizat

Reparați selecția dosarului, referința între fluxuri și traseul client_idlead_id. Până la finalizare, scoateți agentul de pe traficul real de verificare stadiu.

N3 N4 N8
urgent · ~4 ore
2

Verificarea identității în flux

Nodul de potrivire nume fuzzy + dată exactă, plus răspuns structurat cu found, identity_match și client_id.

N1 N9
~4 ore
3

Scoateți valorile de test din producție

Telefoanele 000000000, telefonul fix din send-form, termenul fix al sarcinilor, notița fixă, UUID-ul comun.

N2 N5 N6 N7
~3 ore
4

Schemele uneltelor

phone și conturile bancare pe lead, client_id pe sarcină, descrierea corectată a CreareLeadTaxeUK, unealta de notiță, unealta de SMS.

E1 E2 P1 P2 P3
~3 ore
5

Lista de cuvinte ASR din CRM

Export al numelor de familie distincte, încărcate ca keywords. Independentă de restul, se poate face oricând.

E3
~2 ore
6

Igienă și securitate în flux

Rotiți parola contului de serviciu, mutați-o în credențiale, unificați maparea de status într-un sub-workflow, curățați șirurile „null", normalizați telefonul.

N10 N11 N12 N13 N14 N15
~4 ore
7

Prompt, model, Knowledge

Confirmarea înapoi, pragul de abandon, comisionul, fluxul pentru client existent. Apoi model mai capabil, Knowledge în RAG, turn_timeout la 9.

E4 E5 P4 P5
~5 ore
8

Post-call webhook ca plasă de siguranță

Verifică transcriptul: promisiune fără sarcină, aplicare fără lead, lead fără SMS, apel fără notiță. Le creează el. Cu conversation_id pentru deduplicare.

acoperă ce scapă modelul
~1 zi

RegresieCele nouă teste care trebuie să treacă

Rulați-le după fiecare etapă, cu aceiași clienți. Sunt scrise ca să pice dacă defectul revine.

TestTrece dacă
Client inexistent — nume inventat plus datăAgentul spune că nu reușește să identifice. Nu rostește niciun status.
Dată de naștere greșită intenționatIdentificare eșuată. Nu „v-am identificat".
DALCRAN AMET de pe numărul comun cu GHIULSEN AMETNu comunică nimic despre celălalt dosar.
CIOLAN (EZ234) — 8 dosareMenționează numărul de dosare, vorbește despre cel nefinalizat.
TRANCA (FHNX5) — dosar anulatSpune „anulat". Nu „finalizat", nu „transferat".
MACELARU (EW345) — cec primit, transfer neefectuatSpune că cecul a ajuns și transferul urmează.
GLOABA / CIOLAN / MIHART, doar cu nume și datăIdentificare din prima, fără telefon și fără cod.
Aplicare nouă completăÎn CRM: lead cu telefonul real, sarcini cu termene diferite, notiță, SMS trimis.
Două sarcini create în același apelAmbele atașate clientului corect, cu termene distincte.

Ce nu am atins

Nu am modificat nimic — nici agentul, nici fluxul, nici CRM-ul. Tot ce e mai sus vine din citirea celor 68 de conversații prin API-ul ElevenLabs, a configurației agentului și a exportului de workflow. Nu am apelat niciun webhook de producție, ca să nu creez înregistrări false. Fișierul cu workflow-ul pe care mi l-ați trimis conține parola contului de serviciu în clar, în opt locuri — rotiți-o, indiferent ce decideți despre restul raportului.