RAG dal database: perché e come
Retrieval-augmented generation (RAG) risolve il limite di fondo dei large language model: rispondono in base ai dati con cui sono stati addestrati e non conoscono i tuoi documenti aziendali. Con RAG recuperi i frammenti di testo pertinenti a una domanda e li passi al modello come contesto (grounding), così la risposta poggia su fatti verificabili invece che sulla memoria parametrica del modello.
Portare RAG dentro SQL ha un vantaggio preciso: dati, embedding e logica di retrieval vivono dove già risiedono governance, row-level security e backup. La pipeline tipica è: ingest dei documenti → chunking → generazione degli embedding chiamando un modello esterno → salvataggio dei vettori nel database (tipo di dato vector) → a runtime, embedding della domanda e ricerca dei chunk più simili tramite vector search → costruzione del prompt con i chunk recuperati → generazione della risposta. Attenzione a una distinzione che l’esame ama testare: sia l’indicizzazione sia la query di retrieval usano un modello di embedding, mentre solo la fase finale chiama un modello generativo (completion/chat).
Modelli esterni con sp_invoke_external_rest_endpoint
In Azure SQL Database (e in SQL database in Fabric) la stored procedure sp_invoke_external_rest_endpoint chiama un endpoint REST HTTPS direttamente da T-SQL: è il ponte verso Azure OpenAI per ottenere embedding o completion senza uscire dal database. Concettualmente passi URL, metodo, header e payload JSON e ricevi la risposta come JSON, che elabori poi con le funzioni JSON native.
Punti da ricordare a livello di prodotto, non di sintassi:
- È una feature di Azure SQL Database / Fabric, non di SQL Server on-premises: uno scenario “istanza SQL Server nel datacenter che deve chiamare un modello” ti obbliga a un layer applicativo esterno.
- L’autenticazione preferita è la managed identity, incapsulata in una DATABASE SCOPED CREDENTIAL; evita di incollare API key in chiaro nel codice.
- Solo HTTPS, con limiti su dimensione di payload e risposta e un timeout massimo: documenti grandi vanno spezzati (di nuovo il chunking) e le chiamate massive vanno gestite a batch.
Trade-off: chiamare il modello dal database semplifica l’architettura e tiene i dati vicini, ma accoppia il carico OLTP alle latenze di rete verso il modello. Per indicizzare grandi volumi conviene spesso un processo batch/ETL esterno, riservando la chiamata in-database al retrieval a runtime.
Chunking e grounding
Il chunking spezza i documenti in segmenti prima dell’embedding. Chunk troppo grandi diluiscono la similarità e sforano i limiti; chunk troppo piccoli perdono contesto. Il criterio di scelta: dimensioni moderate, con un overlap fra chunk contigui per non tagliare le frasi a metà, e rispetto dei confini semantici (paragrafi, sezioni). Accanto al vettore si conservano metadati (fonte, titolo, posizione) per poter citare la provenienza.
Il grounding è l’atto di iniettare i chunk recuperati nel prompt e istruire il modello a rispondere solo su quella base (“rispondi solo dai documenti forniti e dichiara se l’informazione non c’è”): riduce le allucinazioni e rende le risposte tracciabili. La qualità del retrieval — quindi di embedding e chunking — determina la qualità del grounding: se recuperi il chunk sbagliato, nemmeno il modello migliore ti salva.
Trappole tipiche d’esame
- SQL Server on-premises deve chiamare Azure OpenAI → soluzione:
sp_invoke_external_rest_endpointesiste in Azure SQL Database / Fabric, non nel box SQL Server; serve un layer applicativo esterno. Distrattore classico. - Documento più grande dei limiti della REST call → soluzione: non alzi il timeout all’infinito; applichi chunking e invii i segmenti, oppure sposti l’indicizzazione su un batch ETL esterno.
- Risposte inventate nonostante RAG → soluzione: il problema è quasi sempre il retrieval (chunking/embedding), non il modello generativo; rivedi dimensione chunk, overlap e modello di embedding, non solo il prompt.
- “Usa una external table per leggere i documenti in SQL database in Fabric” → soluzione: le external table NON sono supportate da SQL database in Fabric; è un distrattore, l’ingest va gestito diversamente.
- API key Azure OpenAI in chiaro nella stored procedure → soluzione: usa managed identity con DATABASE SCOPED CREDENTIAL, mai credenziali hard-coded.
- Confondere embedding e completion → soluzione: indicizzazione e query di retrieval usano un modello di embedding; solo la generazione finale usa un modello di completion/chat. Sono due deployment e due chiamate distinte.