În 2017 un grup de cercetători Google publică articolul care lansează arhitectura Transformer. În câțiva ani, această arhitectură este scalată atât în dimensiunea modelului, cât și a datelor cu care sunt antrenate modelele, devenind rapid etalonul în domeniul procesării lingvistice. În noiembrie 2022, OpenAI lansează oficial ChatGPT care cucerește atenția întregii lumi în timp record și introduce în vocabularul comun termenul de model lingvistic mare (LLM).
Noul val de soluții GenAI este cel al agenților. Un agent este definit ca un LLM care are libertate de decizie și acces la funcții pentru a îndeplini un scop, ulterior fiind adăugat și conceptul de planificare și de utilizator în buclă.
Soluțiile GenAI pot lua multe forme și nivele de complexitate (a se vedea Figura 1), dar toate au la bază aceste modele lingvistice mari care realizează diverse taskuri în diverse modele de design precum: generarea îmbunătățită prin recuperare (RAG, un LLM cu recuperare date), agent cu funcții, sisteme flow-agent, sistem multi-agenți ierarhici, sistem distribuit multi-agent (swarm). Din punct de vedere arhitectural, toate exemplele de mai sus pot fi implementate prin intermediul grafurilor aciclice care permit control asupra pașilor de la întrebare la răspuns.
Sistemele GenAI în producție pot lua multe forme, cele mai cunoscute arhetipuri fiind sisteme tip chatbot, tip copilot, și agenți ambientali (deep agents).
Din această categorie fac parte necesitățile non negociabile care țin de axa securitate și confidențialitate, respectiv evaluare și observabilitate, ambele fiind esențiale pentru succesul oricărui proiect GenAI.
Securitatea și confidențialitatea datelor este un aspect de multe ori puțin important în proiecte demonstrative sau de tip produs minim viabil. Pentru sistemele de producție autentificarea utilizatorului (bazată pe roluri) de-a lungul întregului lanț de servicii (interfață grafică, API agenți și API funcții) este obligatorie. Acest lucru asigură evitarea situațiilor de escaladare privind accesul la date la care utilizatorul nu are acces (de exemplu, autentificare pe bază de conturi funcționale tipică pentru aplicații demonstrație) sau utilizarea nepermisă a API-urilor din sistem.
Figura 1. Exemple de soluții GenAI în funcție de caracteristici
Din punctul de vedere al confidențialității datelor trebuie asigurat faptul că atât comunicația între serviciile sistemului, cât și informația stocată (documente, tabele, imagini și date utilizator) sunt criptate pentru a preveni interceptarea în tranzit sau accesarea la sursă. Fiecare API din sistem poate fi accesat prin autentificarea SSO (single sign on).
În aceeași categorie intră și funcționalitățile de tip "guardrails" pentru siguranța conținutului, menite să prevină utilizarea sistemului în scopuri nepermise. Aceste mecanisme trebuie să verifice atât solicitările utilizatorului, cât și răspunsurile generate, astfel încât ele să nu includă informații care încalcă termenii de utilizare sau prevederile legale. Astfel de protecții sunt incluse, de regulă, în pachetul standard de securitate al serviciilor GenAI din cloud, precum Azure OpenAI, Google Gemini sau Anthropic Claude. În schimb, în cazul unei infrastructuri de inferență auto-găzduite, fie on-premises, fie în cloud, aceste "guardrails" trebuie proiectate și implementate în mod explicit.
Evaluarea și observabilitatea soluției, precum și feedbackul utilizatorilor reprezintă mecanisme principale de îmbunătățire, debugging și de verificare a sistemului înainte de punerea în funcțiune într-un mediu superior (de exemplu, UAT în producție).
Principiul de funcționare general este următorul: mecanismul de feedback permite utilizatorilor să evalueze ca fiind pozitiv sau negativ fiecare răspuns al sistemului și să adauge opțional anumite observații/ comentarii. Această evaluare este asociată urmei (eng. trace) de observație. Urma de observație salvează tot parcursul sistemului de la întrebare la răspuns și permite depanarea ulterioară a sistemului pentru orice interacțiune, realizând practic un jurnal complet al acțiunilor și răspunsurilor întregului sistem. În acest fel, interacțiunile pozitive sunt agregate și păstrate într-un set de date etalon al sistemului, utilizat pentru evaluarea înainte de punerea în funcțiune (pre-deployment evaluation) a unei versiuni noi în mediul superior, pentru a putea identifica eventuale regresii ale noii versiuni, dar și pentru a evalua îmbunătățirile prin intermediul setului de metrici utilizate (BLEU, ROUGE, METEOR, LLM as a judge etc.) Selecția setului de metrici se realizează în concordanță cu tipul de soluție implementat dar și pe sub-componente, de exemplu subcomponenta de traducere sau recuperare se evaluează distinct de întreg sistemul. Ideal este ca fiecare sub-sistem care realizează o funcționalitate importantă să fie evaluat cu setul potrivit de metrici și date de evaluare.
În mod asemănător evaluările negative împreună cu urmele de observație asociate sunt agregate în setul de date de îmbunătățire din răspunsurile utilizatorilor pentru a fi ulterior analizate și reparate problemele care au condus la rezultate inadecvate conform feedbackului utilizatorului.
De asemenea, mai există setul de date delta realizat manual pentru a putea evalua funcționalități nou adăugate cu o versiune nouă. De exemplu, un set de întrebări pentru a evalua capacitatea de planificare a soluției prin întrebări cu rezolvare multi-pas care nu funcționează în versiunea actuală. Acest tip de set delta poate fi utilizat și în procesul de dezvoltare a funcționalității. Ulterior, setul de îmbunătățire și cel delta se alătură datelor etalon de evaluare pre-deployment, acesta fiind legat de versiunea care urmează să fie pusă în funcțiune.
Observabilitatea poate fi descrisă ca un jurnal al tuturor pașilor realizați de sistem pentru o singură interacțiune întrebare-răspuns. Acest jurnal trebuie să cuprindă eventuale decizii de orchestrare a altor agenți sau funcții, răspunsuri intermediare sau ale serviciilor auxiliare apelate (DBs, tools etc.), starea globală a sistemului, conversația anterioară, și feedbackul primit de la utilizator dacă este cazul. Fără acest jurnal unificat, care menține atât starea sistemului, cât și parcursul apelurilor de la întrebare până la răspuns, depanarea rapidă a eventualelor probleme (buguri în codul agenților sau al funcțiilor, erori în stratul de date, schimbări ale schemelor API ale serviciilor auxiliare sau ale LLM-urilor, lipsa accesului utilizatorului, erori de tip gateway timeout, servicii oprite etc.) devine dificilă. Pentru funcționalitatea de observabilitate se poate utiliza una dintre librăriile: OpenTelemetry, Langfuse, Weave și Langsmith. De menționat că librăriile de agenți încă nu au soluții native pentru acest scop.
Ultimul punct obligatoriu pentru sistemul de producție este cel al protocoalelor. Acesta este important pentru a oferi modularitate și un cadru bine definit în partea de comunicare a unui sistem GenAI.
Deși aceste protocoale specifice domeniului încă nu au doi ani de existență, dintre ele s-au remarcat drept cele mai cunoscute următoarele: comunicare sistem - UI AG-UI și A2UI, comunicare agent-agent A2A (Agent to Agent), comunicare agent-funcții MCP Model Context Protocol. API-urile de agenți și funcții folosesc fie protocolul SSE (Server Sent Event), fie WebSockets [^9]care permit streaming (de sus în jos, respectiv bidirecțional) și update al stării către interfața utilizator. Stabilirea protocoalelor de comunicare permite extinderea și adăugarea de noi agenți sau funcții într-un mod robust și modular fără efecte secundare sau probleme de formatare. ( A se vedea Figura 2).
O practică importantă este separarea serviciilor AI (endpointurile LLM) în mediile aferente (dev, UAT și prod), astfel încât traficul din fiecare mediu să fie izolat și serviciile să poată fi scalate dinamic în mod corespunzător cu numărul de utilizatori activi concomitent din fiecare mediu. În mod ideal, serviciul LLM din producție nu este împărțit cu alte proiecte pentru a evita supra-încărcarea prin trafic încrucișat cu alte proiecte. Acest lucru este esențial pentru a minimiza timpul de răspuns în mediul de producție și pentru a evita așteptarea aferentă mecanismului back-off response, atunci când serviciile sunt saturate de apeluri de la utilizatori, care măresc substanțial timpul de așteptare.
Figura 2. Exemplu de organizare stratificată a unui sistem GenAI
Un alt mecanism des întâlnit este cel de folosire a unui Gateway care are rolul de rutare a traficului către endpointurile separate pe mediu și/sau proiecte. Acesta oferă, de asemenea, posibilitatea echilibrării încărcăturii de apeluri, respectiv cea de apel de rezervă către alt serviciu de inferență LLM, când cel principal nu funcționează. Unele server gateway pentru LLMs pot fi, de asemenea, configurate să realizeze filtrarea pe bază de guardrails de siguranță prin apeluri de verificare a întrebării și răspunsului tranzitate de gateway către un LLM diferit specializat în evaluarea siguranței, guvernării și conformității, precum și a respectării termenilor de utilizare etc.
Cea mai des întâlnită axă de optimizare a sistemelor GenAI este cea a costului și latenței, acestea fiind strâns legate. Aceasta se realizează mai nou prin intermediul disciplinei de inginerie a contextului. LLM-urile de frontieră actuale permit ferestre de context de milioane de tokenuri (un fel de silabe), dar asta nu înseamnă că este o practică bună să folosești întreaga capacitate a LLM-ului din cauză că: timpul de inferență crește cvadratic cu lungimea contextului, iar costul este liniar. Pentru sisteme optimizate pentru interacțiune continuă cu utilizatorul, contextul trebuie administrat în așa fel încât să fie trimis strictul necesar pentru pasul respectiv din graful de rulare al sistemului. Acesta este un principiu bun de design, întrucât un graf de rulare poate avea un număr considerabil de apeluri LLM și, în general, sunt de preferat mai multe apeluri cu context relativ mic decât câteva apeluri cu context mare. (Divide et impera). Totuși trebuie să existe un echilibru între numărul de apeluri către LLM și complexitatea problemei, respectiv timpul total de răspuns, de o parte, și acuratețea respectiv utilitatea răspunsurilor, de cealaltă parte. Mai clar, complexitatea și numărul de apeluri din flow pot fi incrementate ulterior pentru a ajunge la metricile și utilitatea răspunsurilor dorite.
Un alt considerent de optimizare important este cel al deciziei de apelare sau de delegare a responsabilității către un agent sau funcții specializat(e). Primul principiu este cel al separării distincte a funcțiilor sau sub-agenților. Scopul principal este gruparea după funcționalitate și descrieri, astfel încât selecția unei căi corecte să fie cât mai probabilă. Scopul separării este de a evita căi/rute care au descrieri care se suprapun, acest principiu se aplică atât la agenți sub orchestrator, cât și pentru un agent cu diverse funcții. O problemă des întâlnită în sistemele de producție este selecția unei căi/rute de apel incorecte pentru întrebarea utilizatorului. Descrierile de sub-agenți sau funcții cu descrieri asemănătoare se grupează împreună (de exemplu, un sub-agent de date care răspunde despre KPI-uri de performanță va avea acces la o colecție de funcții KPI distincte cu descrieri apropiate).
În sprijinul acestui principiu vine optimizarea deciziilor de alegere a căii/rutei de delegare pentru situații în care suprapunerea funcționalităților (și prin extensie a descrierii sale) nu poate fi rezolvată prin delegare. În aceste cazuri se aplică una din sau ambele soluții: limitarea posibilelor decizii prin selecție pe bază de similaritate semantică a descrierii agentului/funcției și/sau cu exemple corecte întrebare-rută agent/funcție și a clasificării unei întrebări către o rută de delegare (clasificarea rutei putând fi realizată cu LLM sau cu metode clasice de machine learning).
Prima și cea mai frecvent întâlnită funcționalitate este cea de personalizare specifică utilizatorului. În termeni tehnici este vorba de memorarea conversațiilor, respectiv a datelor încărcate de utilizator (care nu sunt legate de datele la care are acces sistemul prin agenți și funcții). Personalizarea depinde de memoria sistemului, aceasta poate fi de termen scurt (conversația activă), dar și de termen lung (conversațiile anterioare). Această memorie este salvată separat pentru fiecare utilizator în parte și trebuie gestionată din punct de vedere al recuperării din partiția de date de termen lung, adică selectare/filtrare din cea de termen scurt pentru a ancora asistentul la conversațiile fiecărui utilizator în parte.
O altă funcționalitate recomandată este cea de caching care optimizează timpul de răspuns în cazul în care întrebarea unui utilizator a fost deja rezolvată anterior pentru alt utilizator, bineînțeles cu un timp de resetare potrivit al cache-ului. Este important de luat în considerare următorul fapt: cache-ul poate să fie realizat prin similaritate semantică a întrebărilor utilizatorilor sau în mod clasic prin potrivire exactă. Acest mecanism permite răspunsuri rapide pentru întrebări comune și poate reduce timpul de așteptare respectiv costul. Cache-ul poate fi implementat atât la nivel global al agentului orchestrator, cât și la nivelurile inferioare unde se află sub-agenți respectiv funcții (tools).
Un design bun necesită decizii corecte privind protocoalele de comunicații, cadrul tehnologic și potrivirea cu nivelul de complexitate a cerințelor și necesităților soluției și tipului de cloud disponibil.
Din punct de vedere tehnic, o soluție GenAI poate fi scrisă în mai multe limbaje (Python, Java, C# și TypeScript) folosind diverse librării schelet pentru agenți (LangGraph, Google ADK, Pydantic AI, OpenAI Agents SDK, Microsoft Agent Framework, Strands Agents SDK, Crew AI, Mastraetc.) și încapsulată prin API-uri pentru modularizare oferind un spectru larg de posibilități. Totuși, de cele mai multe ori, soluțiile GenAI nu sunt de sine stătătoare și trebuie integrate cu sisteme și servicii existente, încorporate în aplicații noi sau existente.
Din punct de vedere arhitectural, stratul GenAI este poziționat ca ultimul strat de automatizare dintr-o stivă tehnologică, înaintea interfețelor cu utilizatorul și integrat cu stratul de servicii și cel de date.
Acest strat realizează automatizarea anumitor sarcini cum ar fi: căutare de informații, suport tehnic, analiză date, generare și testare cod. Aceste exemple sunt cunoscute acum, putând fi realizate și gestionate de utilizatori non-tehnici care fie nu au cunoștințele tehnice necesare (SQL și limbaje de programare) pentru a realiza aceste sarcini, fie aleg să utilizeze soluții GenAI pentru a accelera procesele și a delega, până la un punct, sarcini de cercetare și suport unui asistent AI. Designul este centrat pe utilizator, acesta fiind un concept esențial de design care conduce la succes, întrucât utilizatorul ghidează și direcționează activitățile sistemelor GenAI și, în același timp, evaluează sistemul cu care interacționează.
de Ovidiu Mățan
de Laura Dioşan , Andrei Olar , Mózes Császár