import OpenAI from 'openai';
const openai = new OpenAI();
const tools = [{
type: 'function' as const,
function: {
name: 'getUserOrders',
description: 'Aduce ultimele comenzi ale unui utilizator din baza de date.',
parameters: {
type: 'object',
properties: {
userId: { type: 'string', description: 'ID-ul unic al userului' },
limit: { type: 'number', description: 'Numar de rezultate, default 5' }
},
required: ['userId']
}
}
}];
async function handleAgentRequest(userPrompt: string) {
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: userPrompt }],
tools
});
const toolCall = response.choices[0].message.tool_calls?.[0];
if (toolCall && toolCall.function.name === 'getUserOrders') {
const args = JSON.parse(toolCall.function.arguments);
// Aici rulezi query-ul tau securizat in DB
const dbResult = await db.query('SELECT * FROM orders WHERE user_id = $1 LIMIT $2', [args.userId, args.limit || 5]);
return dbResult;
}
}Am pus la punct un agent simplu cu OpenAI function calling care interoghează direct baza de date pentru un tool intern. Vă arăt mai jos pattern-ul care m-a salvat de la scris API endpoint-uri redundante și cum să-l securizați. Merită implementat dacă vreți să scăpați de formulare de filtrare inutile.
De ce SQL direct din LLM e o idee proastă
Am văzut mulți entuziaști care dau prompt-uri de genul „Uite schema bazei de date, scrie un query SQL și rulează-l”. Sincer, asta e rețetă sigură pentru SQL injection sau, mai probabil, un drop table accidental dacă modelul o ia pe arătură. Plus că LLM-urile sunt slabe la join-uri complexe pe scheme customizate.
Soluția curată e function calling. Practic, noi îi dăm LLM-ului o listă de funcții (tool-uri) pe care le poate apela, cu parametri stricți. El doar decide când și cu ce argumente să le apeleze, iar codul nostru Node.js rulează query-ul real în DB.
Cum arată fluxul în producție
La un proiect recent cu vreo 8.500 de utilizatori activi, am avut nevoie de un asistent care să caute comenzi și statusuri de livrare. În loc să scriu 10 filtre în UI, am mapat 3 funcții de citire în backend.
Modelul primește întrebarea utilizatorului, analizează definițiile de funcții pe care i le trimitem și returnează un JSON cu numele funcției și argumentele. Noi executăm funcția local, luăm rezultatul din PostgreSQL și îl trimitem înapoi la OpenAI ca să-i formateze un răspuns uman.
Am redus timpul de dezvoltare cu cel puțin 3 zile pentru că n-am mai stat să construiesc ecrane complexe de raportare.
Trade-off-uri de care te lovești rapid
Nimic nu e moca pe lumea asta. Primul minus major e latența. Ai nevoie de cel puțin două apeluri API către OpenAI: primul ca să-ți zică ce funcție să apelezi, al doilea ca să-i dai rezultatul din DB și să-ți genereze textul final. Asta înseamnă lejer 2-3 secunde de așteptare pentru user.
Al doilea e costul de tokeni. Descrierea funcțiilor (schema JSON) este trimisă la fiecare request. Dacă ai 20 de funcții cu descrieri detaliate, consumi mii de tokeni doar pe context, înainte ca userul să scrie un singur cuvânt. Sfatul meu: grupați funcțiile pe module și trimiteți doar tool-urile relevante pentru contextul curent.
Voi cum gestionați permisiunile când lăsați un LLM să interogheze date sensibile? Mergeți pe roluri de DB separate pentru agent sau filtrați totul din cod?