Questo tutorial crea un agente con chiamate di funzioni in cui lo strumento esposto al modello non esegue mai SQL arbitrario. Combina due meccanismi già verificati nel codice Aurabase: il validatore NL2SQL e una transazione Postgres di sola lettura, due mattoni dell'intelligenza artificiale nativaintegrata nel backend. Prerequisiti: un progetto Aurabase, la sua chiave service_rolee un account con uno dei tre fornitori LLM nativi (OpenAI, Anthropic, Gemini).
L'essenziale
- Il rischio reale non è la funzione che chiama se stessa, ma lo strumento esposto al modello: un
execute_sql(query)grezzo gli fornisce pieno accesso SQL. - L'architettura sicura espone uno strumento
query_database(question)che delega a un validatore dell'albero della sintassi (solo SELECT, LIMIT limitato, schema isolato) anziché all'esecuzione diretta. - Aurabase espone questo validatore in modo nativo (
/nl2sql): riutilizzarlo come implementazione dello strumento evita di dover ricodificare personalmente la validazione SQL. - L'SQL impegnato viene quindi eseguito tramite
aura.db.sql()in modalitàreadOnly: true, un'effettiva transazione Postgres di sola lettura, non un semplice filtro testuale. - L'endpoint nativo
/chatdi Aurabase non accetta ancora un ruolotoolné un parametrotools(verificato nel codice): il loop dell'agente attualmente viene eseguito tramite l'SDK del provider LLM, non tramite il proxy Aurabase. - La chiave
service_roleignora la RLS in base alla progettazione: non deve mai lasciare il backend e l'agente eredita un accesso più ampio rispetto a un tipico utente autenticato.
Cosa costruirai
Costruirai un agente che risponde a domande in linguaggio naturale sui dati in un progetto Postgres, senza mai lasciare che il modello scriva SQL che viene eseguito così com'è. Il modello chiama uno strumento denominato query_database, questo strumento traduce la domanda in SQL convalidato tramite NL2SQL, quindi esegue questo SQL di sola lettura e restituisce le righe al modello in modo che formuli la sua risposta.
Questo tutorial utilizza @aurabase/aurabase-js JavaScript SDK sul lato server (mai sul lato browser, la chiave service_role non deve essere esposta al client) e la funzione OpenAI che chiama l'API per il loop dell'agente. Lo stesso principio si applica all'SDK Anthropic o Gemini.
Perché uno strumento "esegui questo SQL" è pericoloso
La maggior parte dei tutorial sugli agenti Postgres, incluse alcune guide ufficiali, definiscono un singolo strumento: una funzione execute_sql che accetta una stringa SQL come argomento e la esegue così com'è. Il modello scrive questa stringa da solo, in base alla domanda dell'utente e allo schema fornito nel contesto.
Questa scelta trasferisce al modello una responsabilità che non può adempiere in modo affidabile. Una pronta iniezione inserita nella domanda può produrre SQL distruttivo che lo strumento esegue indiscriminatamente, poiché non ha idea di come dovrebbe apparire una query "legittima". Il nostro articolo dedicato descrive in dettaglio questo vettore di attacco: proteggere NL2SQL dall'iniezione SQL.
L'alternativa creata in questo tutorial espone uno strumento più ristretto, query_database(question). Il modello non può più scrivere direttamente SQL: può solo porre una domanda nella propria chiamata allo strumento. È il motore Aurabase NL2SQL che traduce questa domanda in SQL, prima di passarla attraverso un validatore di albero sintattico (solo SELECT, nessuna sottoquery, dieci funzioni autorizzate, LIMITE limitato).
Uno strumento execute_sql(query: string) fornisce al modello l'accesso SQL completo, indipendentemente dalla qualità del prompt del sistema. Un'istruzione ("esegue solo SELECT") rimane un'istruzione che il modello può seguire, interpretare erroneamente o vedere aggirata da un'iniezione inserita nella domanda dell'utente.
Definire lo schema dello strumento esposto al modello
I tre fornitori LLM nativi di Aurabase (OpenAI, Anthropic, Gemini) accettano una tabella di definizioni di strumenti in formato JSON Schema. A questo agente basta un unico strumento: query_database, che accetta una domanda in linguaggio naturale e nient'altro. Il modello non vede né lo schema SQL né un campo query che potrebbe compilare da solo.
Implementare lo strumento: NL2SQL quindi di sola lettura
Il gestore dello strumento viene eseguito sul tuo backend, mai nel browser. Contiene la chiave del progetto service_role, che ignora RLS in base alla progettazione e pertanto non dovrebbe mai essere esposta a un client. Effettua due chiamate all'SDK di Aurabase.
La prima chiamata traduce la domanda in SQL convalidato tramite aura.ai.nl2sql(): solo SELECT, LIMIT limitato, nessun accesso al catalogo di sistema. Il secondo esegue questo SQL già convalidato tramite aura.db.sql(), con l'opzione readOnly: true: Postgres stesso rifiuta quindi qualsiasi scrittura in questa transazione, indipendentemente dalla convalida testuale già applicata da NL2SQL upstream.
readOnly: true innesca una vera e propria transazione Postgres di sola lettura: il motore rifiuta la scrittura, non è un filtro applicato al testo della richiesta. In combinazione con la convalida solo SELECT di NL2SQL, l'agente ha due livelli indipendenti: se uno presenta un difetto, l'altro è ancora valido.
Il ciclo dell'agente: funzione che richiama il lato SDK del fornitore
Aurabase espone tre provider LLM nativi, ma il suo endpoint /chat non inoltra ancora un parametro tools o un ruolo tool. ChatOptions trasporta solo temperature, max_tokens e modele i ruoli accettati sono limitati a system, user e assistant (verificati in llm/mod.rs e handlers/chat.rs). Il ciclo di chiamata delle funzioni viene quindi eseguito oggi direttamente tramite l'SDK del provider, non tramite il proxy Aurabase.
Finché Aurabase non orchestra nativamente le chiamate agli strumenti, il tuo backend deve gestire il loop stesso con OpenAI, Anthropic o Gemini SDK. NL2SQL e l'esecuzione SQL rimangono le classiche chiamate Aurabase all'interno di questo ciclo.
Il principio rimane lo stesso se si orchestra l'agente con LangChain o un servizio come Azure AI Agent: lo strumento dichiarato nel framework deve rimanere lo stesso query_database, mai un esecutore SQL grezzo. Il nostro confronto descrive in dettaglio dove LangChain e LlamaIndex forniscono valore reale su Postgres e dove aggiungono complessità in particolare: Agenti Postgres con LangChain o LlamaIndex.
Prova con una domanda reale
Domanda inviata all'agente: "Quanti clienti premium hanno effettuato un ordine questo mese?" ". Il modello chiama query_database con questa domanda così com'è, senza mai vedere o scrivere alcun codice SQL. Ecco il risultato delle due chiamate interne attivate dallo strumento.
La risposta finale del modello si basa su queste linee effettive, non su un'ipotesi. Se lo strumento restituisce zero righe, un'allucinazione numerica diventa significativamente meno probabile rispetto a un modello che risponderebbe senza dati verificati.
Proteggi l'agente prima di entrare in produzione
- La chiave
service_rolenon lascia mai il tuo backend: né nel prompt inviato al modello, né in un log, né in una variabile di ambiente lato client. readOnly: truerimane attivo suaura.db.sql()per questo strumento specifico, anche se il tuo progetto necessita di essere scritto altrove nell'applicazione.service_roleignora RLS in base alla progettazione. Se l'agente dovesse rispondere in modo diverso a seconda dell'utente che pone la domanda, filtrare esplicitamente l'SQL o ricorrere agli endpoint PostgREST classici, che rispettano la RLS. Vedere isolamento RLS multi-tenant.- Registra ogni chiamata dello strumento (domanda posta, SQL convalidato, numero di righe): questa è l'unica traccia utilizzabile se una domanda produce un risultato inaspettato.
- La limitazione della tariffa e la quota mensile di Aurabase si applicano già al progetto su
/nl2sql: un agente loquace non può superare silenziosamente il budget dell'IA.
Limiti attuali di cui essere consapevoli
Lo strumento query_database eredita tutte le limitazioni del validatore NL2SQL: nessuna sottoquery, nessuna CTE/WITH, nessuna UNION e un elenco chiuso di dieci funzioni SQL. Una domanda che richiede naturalmente una sottoquery (“clienti che non hanno mai ordinato”) deve essere riformulata o elaborata da un secondo strumento dedicato anziché forzata in NL2SQL.
Oggi non esiste alcuna orchestrazione delle chiamate agli strumenti all'interno del proxy Aurabase /chat: il loop dell'agente qui descritto risiede nel codice dell'applicazione, non in un servizio gestito. Se l'agente deve concatenare diversi strumenti (database e RAG documentari, ad esempio), è il tuo backend che orchestra le due chiamate.
RAG e chiamata di funzione combinati
Questo tutorial copre domande strutturate sui dati relazionali. Per domande su contenuti non strutturati (documenti, ticket, note), lo stesso agente può esporre un secondo strumento collegato al RAG nativo di Aurabase (pgvector, ricerca HNSW). Le due funzionalità e la loro articolazione sono dettagliate nella pagina Native AI on Postgres.