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_endpoint esiste 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.