Sari la conținut
megapromoting
Hai să discutăm

Soluții · Servicii financiare

Un agent care clasifică mișcări de bani alegând dintr-o listă închisă, nu scriind o propoziție pe care apoi o interpretează cineva.

Într-o organizație financiară, un agent util nu dă sfaturi și nu aprobă nimic: citește documente și tranzacții, le încadrează într-o categorie dintr-un set fix, spune cât de sigur e și are voie să răspundă „nu știu”. Restul — decizia, aprobarea, politica — rămâne la oameni.

Ofertă, cu condițiiNu scriem „livrat”, pentru că nu avem un agent de acest fel pus în producție la un client din sectorul financiar. Ce avem, și arătăm exact ca atare, e o conductă proprie de ingestie care rulează pe datele noastre: cinci module Python, 1.526 de linii, care citesc notificări bancare din e-mail și extrase în PDF, clasifică fiecare tranzacție prin unelte și o scriu în PostgreSQL cu dedublare, plus patru fluxuri de automatizare pentru webhookuri de la trei procesatori de plăți. Starea reală, spusă în aceeași frază: depozitul nu e sub git, directoarele `tests/` și `webhook-server/` sunt goale, iar potrivirea aproximativă a numelor de contrapartidă folosește o euristică de n-grame marcată în cod ca „de înlocuit cu un serviciu de înglobare înainte de producție”. Partea de platformă financiară în producție — flux de cerere, contract, grafic de plăți, audit — e o lucrare separată, cu dovezile ei, și acolo scriem „livrat”.

Cererile de agenți AI în servicii financiare vin aproape întotdeauna în forma „să răspundă clienților la întrebări despre produsele noastre”. E o cerere legitimă, dar nu acolo se câștigă timp. Timpul se pierde în altă parte: cineva deschide zilnic zeci de notificări bancare și de extrase, se uită la o descriere de tipul unui șir de majuscule cu un cod și decide dacă e o încasare de la client, un salariu, un impozit, o rată către un creditor sau o cheltuială de exploatare. Munca asta e repetitivă, plictisitoare și, exact de aceea, plină de greșeli.

Un model lingvistic e bun la ea, cu o condiție: să nu i se ceară să scrie un răspuns în text liber. Dacă îi ceri o propoziție, o vei parsa tu, iar parsarea o vei greși. În conducta noastră, modelul nu scrie: primește șapte unelte și trebuie să cheme exact una — încasare de la client, salariu, impozit, plată către creditor, cheltuială de exploatare, comision bancar sau necunoscut. Fiecare unealtă cere, pe lângă numele contrapartidei sau categoria, un scor de încredere între 0 și 1. „Necunoscut” cere un motiv scris. Ieșirea e o structură, nu o părere.

A doua regulă e că nimic nu intră de două ori. Fiecare tranzacție extrasă dintr-o notificare sau dintr-un extras primește un identificator extern calculat ca prefix de 16 caractere dintr-o amprentă SHA-256 peste câmpurile ei, coloana e unică în tabel, iar inserarea se face cu `ON CONFLICT (external_id) DO NOTHING`. Consecința practică: cutia poștală poate fi recitită de câte ori vrei, iar soldul nu se dublează. Fără regula asta, orice conductă de ingestie financiară ajunge, în a treia săptămână, să producă dubluri pe care cineva le curăță manual.

Ce nu face un asemenea agent, și de ce e important să scriem asta pe pagină: nu aprobă o plată, nu ia o decizie de creditare, nu dă recomandări de investiție și nu răspunde clientului în numele instituției. Scorul de încredere pe care îl întoarce e evaluarea modelului despre el însuși, nu o măsurătoare a acurateței făcută de noi — distincția asta e diferența dintre un instrument și o iluzie de control.

Ce cuprinde

Ce se schimbă concret în servicii financiare

Documentul intră o singură dată, chiar dacă îl citim de zece ori

Notificările se citesc din cutia poștală prin IMAP, extrasele din PDF. Fiecare tranzacție primește un identificator extern din amprentă SHA-256 peste câmpurile ei, coloana `external_id` e `NOT NULL UNIQUE` în tabel, iar inserarea se face cu `ON CONFLICT (external_id) DO NOTHING`, cu jurnal separat pentru rândul inserat și pentru cel sărit ca duplicat. Recitirea aceleiași cutii nu produce nicio dublură.

Clasificarea se face prin unelte, cu o listă închisă de rezultate

Șapte unelte, nu text liber: încasare de la client, salariu, impozit, plată către creditor, cheltuială de exploatare, comision bancar, necunoscut. Modelul trebuie să cheame una singură. Primele șase cer obligatoriu, pe lângă nume sau categorie, un scor de încredere între 0,0 și 1,0, declarat în schema uneltei; a șaptea cere un motiv. Modelul folosit e declarat în cod, nu ascuns în configurație.

„Necunoscut” e o ieșire legitimă, cu motiv

Un clasificator care nu are voie să spună „nu știu” va încadra greșit, cu încredere mare, exact tranzacțiile neobișnuite — adică pe cele care contează. De aceea unealta de necunoscut e la fel de disponibilă ca celelalte și cere un motiv scris, care ajunge în rând. Rândurile necunoscute sunt lista de lucru a omului, nu un eșec al sistemului.

Potrivirea aproximativă a numelor de contrapartidă, cu starea ei reală

Aceeași firmă apare în extrase sub trei ortografii. Peste clasificare există o potrivire după asemănare cosinus între vectori. Spunem exact ce sunt acei vectori azi: o euristică de n-grame de caractere, scrisă în cod cu comentariul că pentru producție trebuie înlocuită cu un apel real la un serviciu de înglobare. Funcționează pentru variații de scriere; nu e o potrivire semantică.

Webhookurile de la procesatorii de plăți intră în același tabel

Patru fluxuri de automatizare, câte unul pentru trei procesatori de plăți și unul de reconciliere zilnică, cu 7 până la 10 noduri fiecare. Ideea de arhitectură e că sursele diferite — e-mail, PDF, webhook — nu produc trei tabele care trebuie apoi împăcate, ci rânduri în același tabel, cu aceeași regulă de dedublare.

Consumul de model stă sub buget pe cheie, nu sub factură

Apelurile trec printr-un gateway propriu la `api.megapromoting.com/v1`, cu 44 de modele configurate, fiecare cu cost pe token și limită de context. Cheia de proiect are listă albă de modele, buget și perioadă, se poate roti păstrând istoricul, iar consumul se consolidează zilnic pe utilizator × cheie × model. Detaliul care surprinde pe toată lumea: modelele de raționament produc pași interni pe care sistemul de urmărire nu-i vede, dar furnizorul îi facturează — deci bugetul brut pe cheie se setează sub plafonul dorit.

Ce se poate rula fără ca datele să plece de pe mașină

Pentru pașii care nu cer un model mare — extragerea câmpurilor dintr-un format cunoscut, potrivirea de nume, verificările de coerență — nu e nevoie de niciun furnizor extern; sunt cod obișnuit. Modelul se cheamă doar pentru pasul de încadrare. Când politica ta interzice ieșirea datelor, discuția e ce anume se trimite la model, nu dacă se folosește AI: se poate trimite descrierea tranzacției fără identificatorii de cont.

Ce nu face și nu va face un agent de acest fel

Nu aprobă o plată și nu execută un transfer. Nu ia decizia de creditare — regulile, pragurile și aprobarea sunt politica instituției. Nu dă recomandări de investiție și nu răspunde clientului în numele tău fără un traseu separat de aprobare. Și nu îți garantează acuratețea: scorul de încredere e ieșirea modelului despre sine, nu o măsurătoare independentă.

Traseul

Cum trece o cerere prin sistem.

01

Fixăm lista închisă de rezultate, înainte de orice cod

Prima livrare nu e un agent, ci o listă: categoriile în care are voie să încadreze, ce câmpuri obligatorii cere fiecare, și ce înseamnă „necunoscut” la tine. Dacă lista nu se poate scrie pe o pagină, sarcina nu e potrivită pentru un agent — și e mai ieftin să afli asta acum.

02

Construim ingestia și dedublarea, fără model

Citirea din e-mail, PDF sau webhook, extragerea câmpurilor, calculul identificatorului extern și scrierea în bază se fac și se verifică fără niciun apel la un model. Livrăm o conductă care ingerează corect și nu dublează. Dacă pasul ăsta nu e solid, un model deasupra lui doar produce greșeli mai convingătoare.

03

Adăugăm încadrarea și o măsurăm pe cazurile tale

Peste conducta care merge punem uneltele de clasificare și rulăm pe un set de tranzacții reale ale tale, cu rezultatul corect stabilit de omul care face azi munca. Livrăm tabelul cu acordul și dezacordurile, nu o afirmație despre acuratețe. Pragul de la care rândul merge la om se alege din acel tabel.

04

Punem bugetul, jurnalul și porțile

Cheie de proiect cu listă albă de modele și buget, consolidare zilnică a consumului, jurnal cu unealta chemată și scorul, și o poartă care trimite la om tot ce e sub prag sau necunoscut. Livrăm accesele, documentul de punere în funcțiune și lista scrisă a ce face agentul singur și ce nu.

1E-mail, PDF sauwebhook2extragerea câmpurilor3amprentă SHA-2564scriere cu ONCONFLICT DO NOTHING5încadrare prin unadin șapte unelte, cuscorrândurile„necunoscut” către om
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 servicii financiare.

Ce fel de date atinge, concret
Mișcări de bani, cu dată, sumă, monedă, descriere și contrapartidă. O parte dintre contrapartide sunt persoane fizice — un salariu poartă numele angajatului — deci tabelul conține date cu caracter personal ale angajaților, nu doar date comerciale. Asta schimbă cine are voie să deschidă tabelul.
Ce ajunge la model și ce rămâne acasă
La model ajunge textul descrierii tranzacției și suma. Identificatorii de cont, IBAN-urile și restul câmpurilor nu au ce căuta în cerere pentru ca încadrarea să funcționeze, deci se pot lăsa în afara ei. Regula pe care o aplicăm în general: ce nu e necesar pentru pasul respectiv nu se trimite, pentru că ce nu pleacă nu poate fi reținut de nimeni.
Unde stau datele extrase
PostgreSQL, cu `external_id` unic și index pe el. Baza rămâne a ta, pe infrastructura ta sau pe una pe care ți-o operăm noi. Nu există un depozit comun peste clienți, pentru că nu există motiv tehnic pentru care ar exista.
Urma deciziei automate
Fiecare rând păstrează ce unealtă a fost chemată, cu ce scor și, când e cazul, motivul de „necunoscut”. E minimul necesar ca peste șase luni cineva să poată răspunde la întrebarea „de ce a fost pusă tranzacția asta la cheltuieli de exploatare” — cu un răspuns, nu cu o ridicare din umeri.
Termenul de păstrare, care aici nu îl alegi tu singur
Documentele financiare au termene de păstrare stabilite de legislația contabilă și fiscală, nu de preferința noastră sau a ta. Într-un proiect financiar termenul se ia din acele reguli, se scrie în registrul de prelucrări și abia apoi se implementează ștergerea. Ordinea inversă — se implementează întâi, se verifică după — produce sisteme care șterg ce trebuia păstrat.

Un caz

O conductă de ingestie care poate fi repornită fără frică

Situația

Notificările bancare și extrasele lunare ajungeau într-o cutie poștală și erau citite de un om, care le încadra pe categorii. Prima variantă evidentă — un script care citește cutia și scrie în bază — are o problemă care se vede abia în a treia săptămână: la orice repornire sau recitire, aceleași tranzacții intră din nou.

Ce am construit

Am scris cinci module, 1.526 de linii de Python: două analizoare de notificări prin IMAP, un extractor de extrase PDF, clasificatorul prin unelte și scrierea în PostgreSQL. Regula centrală e identificatorul extern — un prefix de 16 caractere dintr-o amprentă SHA-256 peste câmpurile tranzacției — cu coloana unică în tabel și inserare `ON CONFLICT DO NOTHING`. Clasificarea nu întoarce text: modelul cheamă una din șapte unelte, cu scor de încredere obligatoriu, iar „necunoscut” cere motiv.

Ce a ieșit

Cutia poștală poate fi recitită oricând, iar rândurile deja procesate se sar și se notează ca duplicat în jurnal. Tranzacțiile pe care modelul nu le poate încadra apar ca listă de lucru, cu motivul lângă ele, în loc să fie împinse într-o categorie ca să pară că totul a mers.

Ce nu spune cazul

E o conductă internă, nu un sistem livrat unui client financiar: nu e sub git, directoarele de teste sunt goale, iar potrivirea aproximativă a numelor folosește o euristică de n-grame pe care codul o marchează explicit ca provizorie. Am descris-o aici pentru că arată metoda, nu pentru că e un produs.

Întrebări

Ce întreabă cineva din servicii financiare

Agentul aprobă plăți sau credite?

Nu, și nu e o limitare tehnică pe care o vom depăși în versiunea următoare. Aprobarea e o decizie cu consecințe juridice, care aparține unei persoane autorizate din instituție. Agentul pregătește: încadrează, completează, semnalează ce nu se potrivește. Un sistem care aprobă singur ar trebui să poată răspunde în fața unui controlor, iar un scor de încredere nu e un răspuns.

Cum știu că a încadrat corect?

Nu din scorul de încredere — acela e evaluarea modelului despre sine, nu o măsurătoare. Se știe din comparația cu deciziile omului care face azi munca, pe un set de tranzacții reale, făcută înainte de a porni ceva în regim automat. Rezultatul acelei comparații e un tabel pe care îl livrăm, inclusiv rândurile în care agentul a greșit.

Ce se întâmplă când nu e sigur?

Cheamă unealta de „necunoscut” și scrie motivul. Rândul ajunge în lista de lucru a omului, nu într-o categorie aleasă la întâmplare ca să pară că sistemul a funcționat. Un clasificator fără ieșire de „nu știu” greșește exact acolo unde greșeala costă: pe tranzacțiile neobișnuite.

Dacă citim de două ori aceeași notificare, se dublează suma?

Nu. Fiecare tranzacție are un identificator extern calculat ca amprentă peste câmpurile ei, coloana e unică, iar inserarea folosește `ON CONFLICT (external_id) DO NOTHING`. Rândul sărit se notează în jurnal ca duplicat, deci se vede că a fost recitit.

Datele noastre pleacă la un furnizor de model?

Pentru pasul de încadrare, da: descrierea tranzacției și suma pleacă la modelul ales, prin gateway-ul nostru, cu cheie de proiect, listă albă de modele și buget. Restul pașilor — citirea, extragerea, dedublarea, potrivirea de nume — sunt cod obișnuit și nu ies nicăieri. Ce anume are voie să plece se stabilește în scris înainte, nu se descoperă din jurnale după.

Puteți citi extrase în PDF, nu doar notificări prin e-mail?

Da, e unul dintre modulele conductei. Ce trebuie știut e că un extras PDF e un format fragil: se citește după structura pe care o produce banca respectivă, iar când banca schimbă șablonul, modulul trebuie ajustat. De aceea se scrie cu verificări care cad zgomotos, nu care ghicesc.

De ce scrie pe pagina asta „ofertă” și nu „livrat”?

Pentru că regula noastră cere minimum două implementări proprii ca să scriem „livrat”, iar conducta descrisă aici rulează pe datele noastre, nu în producție la un client din sectorul financiar. Are și lipsuri pe care le numim: nu e sub git, nu are teste, iar potrivirea de nume folosește o euristică marcată în cod ca provizorie. Când vom putea cita două implementări la clienți, schimbăm cuvântul.

Ce ne trebuie de la noi ca să înceapă lucrarea?

Trei lucruri: lista închisă a categoriilor în care are voie să încadreze, un set de tranzacții reale cu răspunsul corect dat de omul care face azi munca, și decizia scrisă despre ce câmpuri au voie să iasă din rețeaua voastră. Fără al treilea punct nu începem, pentru că e singurul care nu se poate repara ulterior.

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