Text-to-SQL in locale: interrogare il proprio database in linguaggio naturel
Il text-to-SQL con un LLM locale permette di porre una domanda in francese (« qual è il fatturato per regione del mese scorso? ») e di ottenere una query SQL eseguibile sul tuo PostgreSQL o MySQL — senza che né lo schema né i dati lascino la tua infrastruttura. Questa guida illustra il funzionamento concreto: inserire lo schema nel contesto, costruire una pipeline Python con Ollama e soprattutto predisporre le misure di protezione (sola lettura, validazione, limiti) senza le quali nessun sistema text-to-SQL può essere messo in produzione.
#Perché usare text-to-SQL con un LLM locale
Le soluzioni cloud di text to SQL (assistenti BI, copiloti di data warehouse) inviano il tuo schema — nomi di tabelle e colonne, talvolta campioni di righe — a un server di terzi. Per un database di clienti, risorse umane o dati finanziari, questo è spesso inaccettabile: lo schema da solo rivela già la struttura della tua attività e i campioni contengono dati personali.
Un LLM locale risolve questo problema alla radice: il modello gira sulla tua macchina tramite Ollama, lo schema rimane nella memoria locale e la query generata viene eseguita sul tuo database senza che un solo byte transiti su internet. È anche gratuito da usare e non è soggetto ad alcun limite di frequenza delle richieste API.
- Privacy
- Lo schema e i dati non lasciano mai la tua rete — è più facile rispettare il GDPR e tutelare i segreti commerciali.
- Costo
- Nessun costo per richiesta. Un analista dati può iterare centinaia di volte senza pagare.
- Accessibilità
- Gli utenti aziendali che non conoscono SQL interrogano il database in linguaggio naturale.
- Controllo
- Sei tu a scegliere il modello, il prompt e le misure di salvaguardia: nessuna scatola nera remota.
#Come funziona concretamente
Questa guida ti porta al modello. Il kit ti porta al copilota che scrive codice nel tuo editor.
- Spazio online a vita
- PDF + file
- Aggiornamenti a vita
Il principio del text to SQL con un LLM si articola in tre fasi. Prima si descrive al modello lo schema del database (il DDL delle tabelle pertinenti). Poi gli si trasmette la domanda dell'utente con un'istruzione rigorosa: produrre esclusivamente una query SQL nel dialetto di destinazione. Infine si recupera la query, la si valida e la si esegue in sola lettura.
- 01Introspezione dello schemaSi estrae la struttura delle tabelle (colonne, tipi, chiavi) dal database — automaticamente anziché a mano, per mantenerla sincronizzata.
- 02Costruzione del promptSi costruisce un prompt di sistema contenente il dialetto SQL, lo schema pertinente e le regole (solo SELECT, LIMIT obbligatorio, nessun commento).
- 03GenerazioneIl LLM locale restituisce una query. La ripuliamo (rimuovendo gli eventuali delimitatori Markdown ```sql).
- 04Validazione + esecuzioneVerifichiamo che sia un SELECT, lo eseguiamo con un ruolo di database in sola lettura, e restituiamo le righe.
#Prerequisiti
- Ollama installato
- Il daemon deve ascoltare su http://localhost:11434. Verifica con « ollama ps ».
- Un modello capace
- Un modello recente specializzato nella programmazione (Qwen3-Coder 30B-A3B, Devstral 24B) dà risultati molto migliori in SQL rispetto a un piccolo modello generalista (vedi la sezione modelli).
- Python 3.10+
- Con il client database adatto: psycopg2-binary (PostgreSQL) o PyMySQL (MySQL).
- Un accesso al database in sola lettura
- Idealmente un ruolo SQL dedicato che possa eseguire solo SELECT — la misura di protezione più importante.
#Fornire al modello lo schema del proprio database
È la fase che determina l'80 % della qualità del risultato. Il modello può generare una query corretta solo se conosce i nomi esatti delle tabelle e delle colonne, i loro tipi e le relazioni tra di esse. Due approcci: incollare il DDL grezzo oppure esaminare la struttura del database tramite introspezione per costruire una descrizione compatta.
Per un database piccolo (meno di una ventina di tabelle), si può inserire tutto. Oltre questa dimensione, lo schema supera il contesto utile e sommerge il modello di informazioni: occorre quindi selezionare le tabelle pertinenti alla domanda (tramite una prima fase di ricerca o una mappatura del dominio aziendale). Ecco un'introspezione PostgreSQL che produce uno schema leggibile dal LLM.
#Pipeline Python completa con Ollama
Ecco una pipeline minima ma funzionale: schema → prompt → generazione → pulizia → validazione → esecuzione. Utilizza il client Python ufficiale di Ollama e un ruolo del database con accesso in sola lettura.
La parte dedicata all'esecuzione separa volutamente la validazione dalla chiamata al database. Si rifiuta tutto ciò che non è una singola istruzione SELECT prima ancora di aprire il cursore.
#Rendere affidabile e sicuro il SQL generato
È la sezione che distingue una demo da un deployment reale. Un LLM può generare una query distruttiva se gli viene chiesto — oppure accidentalmente, tramite un'iniezione nella domanda. La difesa non deve mai basarsi soltanto sul prompt: deve essere strutturata su più livelli, sul lato del database.
- 01Ruolo del database con accesso in sola lettura (difesa principale)Crea un ruolo SQL che abbia SOLO il privilegio SELECT. Anche se il modello genera un DROP TABLE, il database lo rifiuta. È il solo sistema veramente affidabile: 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;' e niente di più.
- 02Validazione applicativaPrima dell'esecuzione, analizza il codice SQL con sqlparse e rifiuta tutto ciò che non è una singola istruzione SELECT. Insieme al ruolo nel database, questo crea una doppia barriera.
- 03Timeout della richiestaL'istruzione SET statement_timeout impedisce a una query mal formata (prodotto cartesiano su milioni di righe) di saturare il database.
- 04LIMIT forzatoImposta un LIMIT sia sul lato prompt che sul lato codice, per non caricare mai intere tabelle in memoria.
- 05Ciclo di correzioneSe l'esecuzione restituisce un errore SQL, restituisci il messaggio di errore al modello e chiedi una query corretta (1 o 2 tentativi massimi).
Il ciclo di correzione migliora notevolmente il tasso di successo. Molti errori sono banali (nome di colonna leggermente errato, funzione per le date specifica del dialetto) e il modello li corregge al secondo tentativo se vede il messaggio di errore del motore.
#Quali modelli locali eccellono in SQL
Il SQL è un'attività di programmazione: i modelli specializzati «coder» superano nettamente quelli generalisti della stessa dimensione. Nel 2026, un modello recente per la programmazione come Qwen3-Coder 30B-A3B cambia tutto — i piccoli modelli da 2B a 8B mettono insieme alla meglio query semplici, ma falliscono non appena servono più join o un'aggregazione con funzioni finestra. (Codestral 22B, a lungo citato per il SQL, è ora soggetto a una licenza che non consente l'uso in produzione: da escludere in azienda.)
- Qwen3-Coder 30B-A3B
- La scelta predefinita per il 2026. Modello MoE per il codice con 3B parametri attivi: veloce, 256k di contesto per schemi di grandi dimensioni, ≈19 GB in Q4 su una RTX 4090 o un Mac recente. Licenza Apache 2.0.
- Devstral 24B
- Specialista del codice firmato Mistral AI (Apache 2.0), ≈14 GB in Q4 — entra nella memoria di una scheda da 16 GB come la RTX 4080. Il miglior compromesso per SQL su una workstation modesta.
- Qwen 3.8 27B
- Modello generalista recente, con solide capacità di ragionamento sui join complessi (≈18 GB, 262k di contesto, visione). Imposta il livello di ragionamento su «low»: su un compito così strutturato come SQL, tende a ragionare troppo con l'impostazione predefinita.
- Modelli piccoli 2B–8B (Qwen 3.5 4B, Granite 4.2 8B)
- Solo per schemi molto semplici e domande dirette. Da evitare quando il database presenta relazioni non banali.
#Risoluzione dei problemi
- Il modello inventa colonne
- Lo schema è incompleto o troppo grande. Limitane il contenuto alle tabelle pertinenti e aggiungi commenti che spiegano il significato aziendale delle colonne ambigue.
- Risposte con testo intorno al SQL
- Rafforza l'istruzione «Solo SQL, nessuna spiegazione» e mantieni in clean_sql la rimozione dei delimitatori dei blocchi di codice Markdown.
- Errori nelle funzioni per le date
- Specifica il dialetto nel prompt di sistema (PostgreSQL e MySQL differiscono per DATE_TRUNC, YEAR(), ecc.). Il ciclo di correzione corregge gli errori rimanenti.
- Query lente o che vanno in timeout
- statement_timeout funziona. Aggiungi «filtrare sempre su un intervallo di date ragionevole» al prompt per le grandi tabelle.
- « Connection refused » Ollama
- Il servizio non è avviato. Verifica « ollama ps » e assicurati che il servizio ascolti su http://localhost:11434.
#Per approfondire
Il text-to-SQL riutilizza diversi componenti già trattati sul sito. Queste guide approfondiscono questa guida:
- Integrare Ollama in un'applicazione Python tramite l'API REST
- Per esporre questa pipeline tramite un'API FastAPI, gestire lo streaming e la modalità JSON.
- Function calling e output JSON strutturati con Ollama
- Un'alternativa per garantire la struttura dell'output (query + spiegazione), anziché ottenerla ripulendo il testo.
- Scegliere la quantizzazione (Q4, Q5, Q8, FP16)
- Per trovare il compromesso tra la dimensione del modello SQL e la VRAM disponibile sulla tua scheda.
Un feedback, un errore, una precisazione? Facci sapere, così la guida migliora per tutti.