Sari la conținut
syncra
Toate notele

Funcții AI care rezistă pe date reale

Unui demo îi ajunge un singur răspuns bun. O funcție în producție trebuie să dea un rezultat rezonabil pentru orice îi trimit utilizatorii reali. Iată ce am învățat construind funcții AI în produse pe care oamenii le folosesc.

De , fondator6 min de citit

În ultimii ani am construit funcții AI în produse pe care oameni reali le folosesc zilnic. Ca inginer senior pe contract la FreeLogo.com (se deschide într-o filă nouă), o platformă AI de logo-uri și branding din familia HostPapa, am construit generarea de logo-uri cu AI și editorul vectorial de lângă ea. Înainte de asta, la GWIN AI, am lucrat la o aplicație financiară cross-platform cu un asistent care completează widget-urile din aplicație cu date live.

Niciunul nu e un proiect Syncra. Ambele erau produse ale companiilor pentru care am lucrat, iar detaliile lor interne rămân la ele. Ce pot împărtăși e practica inginerească pe care o aplic acum în fiecare funcție AI pe care o construim la Syncra. Nimic din ea nu e exotic. Mare parte e disciplină obișnuită de software, aplicată unei componente lente, probabilistice și care, din când în când, greșește cu toată convingerea.

Diferența dintre un demo și o funcție

Un demo rulează pe inputuri alese de tine. Producția rulează pe orice vine: text copiat dintr-un PDF cu rândurile rupte, o cerere în trei limbi deodată, un câmp gol, un utilizator care apasă butonul de două ori, cineva care scrie „ignoră-ți instrucțiunile”. Un model care pare genial pe cele zece exemple ale tale le va întâlni pe toate în prima lui săptămână.

Așa că întrebarea nu e niciodată „poate modelul să facă asta?”, ci „ce face produsul când modelul nu reușește?”. Fiecare lecție de mai jos e o variantă a acestei întrebări.

1. Tratează răspunsul modelului ca input nesigur

Răspunsul modelului e input de la utilizator care se întâmplă să vină de pe propriul tău server. Validează-l la graniță, exact cum ai valida trimiterea unui formular.

Cere output structurat oriunde rezultatul ajunge în cod, nu la un cititor uman, și verifică-l după o schemă înainte ca orice altceva să-l atingă:

const ChartRequest = z.object({
  metric: z.enum(["revenue", "orders", "visitors"]),
  period: z.enum(["week", "month", "year"]),
});

const parsed = ChartRequest.safeParse(modelOutput);
if (!parsed.success) return showFallback();

Decide dinainte ce se întâmplă când validarea eșuează: o singură reîncercare, cu eroarea de validare inclusă în prompt, apoi o stare de rezervă bine definită, pe care UI-ul știe s-o afișeze. „Modelul a returnat ceva ciudat” trebuie să fie un caz tratat, cu un ecran gândit pentru el, nu o excepție în loguri.

2. Lasă modelul să aleagă. Faptele le aduce codul tău

Când răspunsul unui asistent ajunge în UI, de exemplu într-un grafic, un card sau un widget, împarte munca clar. Modelul decide ce se afișează și cu ce parametri. Codul tău ia cifrele reale din propriile date și le afișează.

Modelul n-ar trebui să scrie niciodată o cifră pe care baza ta de date o știe deja. Doar regula asta îți aduce multe:

  • Corectitudine. Cifrele vin din sursa de adevăr, nu din ce ghicește modelul despre ea.
  • Actualitate. Widget-ul arată datele așa cum sunt acum, nu cum erau într-un prompt.
  • Permisiuni. Stratul de date știe deja ce are voie să vadă utilizatorul respectiv. Un model fără acces direct la date nu poate scurge ce n-a primit niciodată.
  • Testabilitate. Poți testa „modelul a ales widget-ul potrivit” separat de „widget-ul arată datele corecte”.

Tool calling-ul face asta firesc. Dă-i modelului un set mic de unelte bine descrise, cu parametri stricți, și consideră că treaba lui e să aleagă direcția și formularea, nu să facă aritmetică.

3. Gândește așteptarea

Generarea durează secunde, nu milisecunde, iar durata variază de la o cerere la alta. Trateaz-o ca pe un job, nu ca pe un apel de funcție:

  • Pornește lucrul, răspunde imediat și arată un progres onest.
  • Lasă oamenii să anuleze și nu mai plăti pentru muncă pe care n-o mai așteaptă nimeni.
  • Salvează rezultatul, ca un refresh sau o conexiune căzută să nu-l arunce.
  • Fă reîncercările idempotente, ca un dublu clic să nu ruleze de două ori aceeași generare (și să nu o factureze de două ori).

Folosește streaming pentru text când are sens să citești și rezultatul parțial. Pentru imagini și alte rezultate de tip totul sau nimic, tratează starea de așteptare cu toată atenția de design. Face parte din funcție, iar într-o zi lentă e cea mai mare parte din ce vede utilizatorul.

4. Pune rezultatul acolo unde oamenii îl pot corecta

Rezultatul AI e rareori exact ce voia cineva. Dacă singura opțiune e „regenerează”, utilizatorii ajung să dea cu zarul până iese ceva destul de apropiat.

Abordarea mai solidă e ca rezultatul să ajungă într-o formă pe care oamenii o pot edita: un logo generat se deschide ca forme vectoriale editabile, un răspuns schițat apare într-un câmp de text, valorile sugerate completează un formular pe care utilizatorul îl trimite tot el. Generarea îl duce pe om repede la un punct de plecare bun. Interfața de editare e locul unde termină, și tot ea acoperă cazurile în care modelul a ratat.

Asta influențează și formatul rezultatului. Dacă oamenii îl vor edita, cere-i modelului ceva structurat și editabil, nu un artefact final aplatizat.

5. Ancorează răspunsurile în propriul conținut

Multe probleme de tipul „AI-ul a inventat ceva” sunt de fapt probleme de retrieval. Dacă răspunsul trebuie să vină din documentația, catalogul sau înregistrările tale, găsește mai întâi fragmentele relevante și dă-i modelului doar atât.

Embedding-urile și căutarea semantică fac cea mai mare parte din treabă și nu cer multă infrastructură la început: o coloană vectorială în Postgres-ul pe care îl rulezi deja, de exemplu pgvector, acoperă multe produse înainte să ai nevoie de ceva dedicat. Pune efortul în ce intră. Împarte conținutul în fragmente după structura lui reală, păstrează lângă fiecare fragment sursa lui, ca răspunsurile s-o poată cita, și reindexează când conținutul se schimbă.

6. Construiește un set de evaluare din inputuri reale

Înainte de lansare, adună un set de inputuri reale sau realiste și include intenționat cazurile urâte: gol, foarte lung, în limba greșită, ambiguu, adversarial. Pentru fiecare, notează proprietățile pe care trebuie să le aibă un răspuns bun, nu un șir exact așteptat: e valid conform schemei, menționează entitatea corectă, refuză când trebuie.

Rulează setul la fiecare schimbare de prompt și la fiecare schimbare de model. Prompturile sunt cod. Versionează-le, fă-le review și nu edita niciodată unul direct în producție doar pentru că un singur exemplu a ieșit mai bine. Upgrade-urile de model merită același tratament: un model mai nou poate fi mai bun în medie și totuși mai slab exact pe cazurile de care depinde produsul tău.

7. Pregătește-te pentru ziua proastă a furnizorului

Furnizorii dau timeout, ating rate limit-urile, au căderi și retrag modele. Pune furnizorul în spatele unei interfețe mici, a ta, ca restul codului să nu apeleze niciodată direct SDK-ul unui vendor. Setează timeout-uri. Decide care e soluția de rezervă: alt model, un rezultat din cache sau un mesaj clar, cu posibilitatea de a încerca din nou.

Loghează suficient cât să poți depana: versiunea promptului, modelul, latența, rezultatul validării. Ține datele personale în afara acestor loguri sau maschează-le, pentru că prompturile adună exact informațiile pe care oamenii ar prefera să nu le știe stocate. Și urmărește costul per cerere așa cum urmărești latența. Se schimbă la fiecare editare de prompt.

Cum arată asta la Syncra

Construim AI aplicat: asistenți, căutare semantică, retrieval și fluxuri de lucru cu AI, conectate la datele și uneltele clientului. Nu antrenăm modele. Fiecare funcție AI pe care o lansăm pornește de la practica de mai sus: răspuns validat, fapte din sistemele tale, o așteptare gândită, o interfață de editare acolo unde are sens, un set de evaluare și o soluție de rezervă pentru ziua în care furnizorul cade.

Nimic din toate astea nu face un demo mai impresionant. Toate decid însă dacă funcția mai merge la o lună după lansare.

Alte note