Salta al contenuto principale

Buone pratiche

Ancora ogni risposta e consenti un esplicito "non lo so"

Il valore di un sistema RAG è che le risposte sono tracciabili alle fonti, quindi il prompt deve istruire il modello a rispondere solo dal contesto fornito e a dichiarare chiaramente quando il contesto è insufficiente. Senza una via d'uscita, il modello colma i vuoti con la memoria e allucina con sicurezza. Fai: includi "Se il contesto non contiene la risposta, dichiaralo" nel system prompt. Non fare: lasciare il modello libero di "essere utile" indovinando quando il retrieval non restituisce nulla di rilevante.

Suddividi sulla struttura, non su conteggi arbitrari di caratteri

Suddividere puramente per finestra fissa di caratteri taglia frasi e tabelle a metà di un'idea e produce passaggi che mescolano argomenti non correlati, e ciò rovina il retrieval. Preferisci un chunking consapevole della struttura su titoli, sezioni o confini di frase, con un piccolo overlap per preservare la continuità. Fai: suddividi un documento Markdown sui suoi titoli, poi sotto-suddividi le sezioni lunghe. Non fare: affettare ciecamente ogni documento in blocchi da 1000 caratteri ignorando dove cadono i confini.

Usa il retrieval ibrido di default

La ricerca vettoriale cattura il significato ma sfuma identificatori esatti, codici e termini rari; il BM25 lessicale centra quelli ma manca le parafrasi. Eseguire entrambi e fondere i risultati (la Reciprocal Rank Fusion è un default robusto) supera con affidabilità ciascuno da solo con poco sforzo extra. Fai: combina hit BM25 e vettoriali con RRF. Non fare: rilasciare retrieval solo vettoriale e poi chiederti perché codici prodotto o codici di errore esatti non vengono mai trovati.

Recupera ampio, poi fai re-rank stretto

Il retrieval di prima fase è veloce ma impreciso, quindi gettare una rete ampia e fare re-rank con un cross-encoder dà risultati di vertice molto migliori che fidarsi dell'ordine vettoriale grezzo. Passa al generatore solo i migliori pochi ri-rankati per mantenere il contesto stretto. Fai: recupera top-50, fai re-rank, invia top-5. Non fare: inviare i top-20 vettoriali grezzi direttamente al modello e pagare token su passaggi perlopiù irrilevanti.

Valuta retrieval e generazione separatamente

Accorpare tutto in un unico giudizio "la risposta sembra buona" nasconde da dove vengono i fallimenti. Misura il retrieval con context recall e precision e la generazione con faithfulness e answer relevancy, così sai se correggere il retriever o il prompt. Fai: mantieni un golden eval set e valuta i due stadi in modo indipendente. Non fare: regolare i prompt per mascherare un retriever che non ha mai recuperato il passaggio giusto.

Presidia i rilasci con un eval set in CI

I controlli manuali a campione non colgono le regressioni, e la qualità RAG deriva quando cambiano dati, modelli e prompt. Un golden eval set valutato automaticamente con una soglia minima di faithfulness trasforma la qualità in un gate di merge. Fai: fai fallire la CI quando la faithfulness media scende sotto la tua soglia calibrata. Non fare: modificare le risposte del golden set per far passare un sistema regredito, il che vanifica l'intero scopo del set.

Filtra sempre per tenant, livello di accesso e freschezza

Un retrieval che ignora chi sta chiedendo può far trapelare i dati di un cliente nella risposta di un altro o restituire contenuto obsoleto o non autorizzato. Imponi filtri di metadati obbligatori (tenant, ACL, lingua, data) su ogni query, applicati insieme alla ricerca per similarità. Fai: rendi il filtro tenant non opzionale nell'interfaccia del retriever. Non fare: affidarti a una promessa di "aggiungeremo il filtro nel layer applicativo più tardi" che un percorso di codice inevitabilmente dimentica.

Rendi l'ingestion incrementale e idempotente

La re-indicizzazione completa a ogni cambiamento è lenta, costosa e fonte di duplicati e drift. Dai ai chunk come chiave un id documento stabile più un hash di contenuto, così rieseguire l'ingestion aggiorna solo ciò che è cambiato ed elimina i chunk del contenuto rimosso. Fai: salta i documenti invariati confrontando gli hash di contenuto e fai upsert per id esterno. Non fare: accodare a ogni esecuzione e accumulare chunk stale e duplicati che inquinano il retrieval.

Tratta il contenuto recuperato come dati non fidati, mai come istruzioni

I documenti nel tuo corpus possono contenere testo che tenta di sovrascrivere le istruzioni del modello (prompt injection), e nella RAG quel testo finisce direttamente nel prompt. Delimita chiaramente il contesto, istruisci il modello a ignorare istruzioni trovate al suo interno, limita tool e privilegi che il modello può usare e valida gli output prima di agire. Fai: racchiudi il contesto in marcatori espliciti e tieni le azioni sensibili dietro un'autorizzazione separata. Non fare: lasciare che la riga "ignora le istruzioni precedenti" di un documento recuperato cambi il comportamento del sistema o inneschi un'azione reale.

Aggiungi contesto a livello di chunk prima dell'embedding

Un chunk isolato spesso perde il contesto del documento che lo rende trovabile ("la tariffa" non significa nulla senza "la tariffa di importazione 2026"). Anteporre un breve riassunto specifico del chunk della sua fonte prima dell'embedding (contextual retrieval) migliora il recall in modo misurabile. Fai: genera un'intestazione di contesto di una riga per chunk in fase di ingestion. Non fare: embeddare frammenti nudi spogliati di ogni indizio su quale documento e sezione provengano.

Mantieni la generazione deterministica e cita le fonti

Le risposte con grounding dovrebbero essere riproducibili e verificabili, quindi esegui il generatore a temperatura bassa e richiedi che attribuisca le affermazioni ai passaggi usati. Ciò rende gli output stabili tra le esecuzioni e permette agli utenti di controllare le prove. Fai: imposta la temperatura vicina a 0 e mostra citazioni a ciascun URL di fonte. Non fare: usare una temperatura alta per risposte fattuali e rilasciare affermazioni non citate che gli utenti non possono verificare.

Fai caching deliberato con invalidazione esplicita

Embedding, risultati di retrieval e risposte generate sono tutti cachabili e possono ridurre drasticamente costo e latenza, ma una cache senza invalidazione serve risposte stale dopo il cambiamento della fonte. Lega la durata di ogni cache alla freschezza della sua fonte, con chiavi tali che gli aggiornamenti sfrattino le voci giuste. Fai: invalida le cache di embedding e retrieval con lo stesso id/hash documento usato nell'ingestion. Non fare: mettere in cache le risposte finali a tempo indeterminato e continuare a servire la policy del trimestre scorso dopo la sua revisione.

Ispeziona i chunk effettivamente recuperati quando fai debug

Quando una risposta è sbagliata, la causa radice è molto più spesso un retrieval cattivo che una generazione cattiva, ma non lo vedi leggendo la sola risposta. Registra e rivedi i chunk esatti recuperati per le domande che falliscono per distinguere un fallimento di recall da uno di generazione. Fai: cattura query, id dei chunk recuperati e punteggi per ogni richiesta che debughi. Non fare: continuare a riscrivere il prompt per correggere risposte quando il passaggio giusto non è mai stato recuperato.