Cum am construit un agent AI care înlocuiește 4 ore de muncă manuală pe zi
Introducere
Unul dintre clienții noștri petrecea în jur de 4 ore pe zi procesând rapoarte: descărca fișiere din trei surse diferite, le normaliza, le compara și scria un rezumat pentru echipă. Un workflow repetat identic, în fiecare zi lucrătoare. Exact tipul de problemă pentru care un agent AI nu este over-engineering — ci soluția evidentă.
În acest articol îți arăt exact cum l-am construit: arhitectura, codul, capcanele și ce am schimbat după primele două săptămâni în producție.
01. Ce face agentul, concret
La fiecare dimineață, la ora 7:30, agentul rulează automat și:
Descarcă rapoartele din Google Drive, un FTP intern și un API REST
Le parsează și normalizează într-un format comun
Identifică anomalii și discrepanțe folosind un LLM
Generează un rezumat în română, trimis pe Slack și email
Salvează un audit trail în baza de date
Timpul total: 3–4 minute. Față de 4 ore. Cu zero intervenție umană dacă totul decurge normal.
“Notă importantă: Nu orice workflow merită un agent. Dacă pașii sunt simpli și deterministici, un script clasic este mai fiabil și mai ușor de debugat. Agentul strălucește când apar decizii ambigue — și exact asta era cazul nostru: rapoartele veneau în formate inconsistente care se schimbau periodic.”
02. Arhitectura în 3 straturi
Am ales o arhitectură simplă: un orchestrator central care primește un obiectiv, decide ce tool-uri să apeleze și iterează până finalizează task-ul.
typescript
plain text// Structura principală a agentului
interface AgentConfig {
model: 'claude-sonnet-4-20250514';
tools: Tool[];
maxIterations: 10;
systemPrompt: string;
}
async function runAgent(task: string, config: AgentConfig) {
const messages: Message[] = [
{ role: 'user', content: task }
];
for (let i = 0; i < config.maxIterations; i++) {
const response = await callLLM(messages, config);
// Dacă nu mai are tool calls, a terminat
if (!response.toolUse) return response.text;
// Execută tool-ul și adaugă rezultatul
const result = await executeTool(response.toolUse);
messages.push(response, { role: 'tool', content: result });
}
}Tool-urile definite
Fiecare tool este o funcție TypeScript cu un JSON Schema pentru parametri. LLM-ul primește lista de tool-uri disponibile și decide singur când și în ce ordine le apelează.
typescript
plain textconst tools = [
{
name: 'download_report',
description: 'Descarcă un raport din sursa specificată',
input_schema: {
type: 'object',
properties: {
source: { type: 'string', enum: ['gdrive', 'ftp', 'api'] },
date: { type: 'string', description: 'YYYY-MM-DD' }
}
}
},
{
name: 'analyze_discrepancies',
description: 'Analizează datele și identifică anomalii',
input_schema: { /* ... */ }
},
{
name: 'send_summary',
description: 'Trimite rezumatul pe Slack și email',
input_schema: { /* ... */ }
}
];03. Capcanele în care am căzut
Aș minți dacă ți-aș spune că a funcționat perfect din prima. Iată ce am schimbat după primele două săptămâni:
Prompt-ul inițial era prea vag
LLM-ul lua decizii creative pe care nu le voiam. Am adăugat exemple negative explicite: "Nu inventa date. Dacă un raport lipsește, raportează eroarea."
Fără timeout pe tool calls, agentul putea bloca la nesfârșit
Am adăugat un timeout de 30s per tool și retry cu exponential backoff.
Costul per rulare exploda când rapoartele erau mari
Am adăugat un pas de pre-procesare care extrage doar câmpurile relevante înainte de a trimite datele la LLM.
04. Rezultatele după 6 săptămâni
Clientul a economisit efectiv cele 4 ore zilnice. Dar beneficiul neașteptat a fost altul: agentul a identificat o discrepanță în rapoarte care trecea neobservată de luni de zile — o eroare de calcul care genera diferențe mici dar constante. Valoare totală recuperată: câteva mii de euro.
Concluzie
Dacă ai un workflow repetat, cu date inconsistente sau decizii semi-ambigue, probabil merită să vorbim. Scrie-ne la [email protected] și îți facem o evaluare gratuită.