Salta al contenuto principale

01 - RAG: Retrieval-Augmented Generation Spiegato

Guida completa a RAG: Retrieval-Augmented Generation Spiegato: architettura, implementazione pratica e best practices per developer e team tecnici.

Cosa ne pensi di questo articolo?

01 - RAG: Retrieval-Augmented Generation Spiegato
AI EngineeringFoto:Tara WinsteadPexels

In Breve

Guida completa a RAG: Retrieval-Augmented Generation Spiegato: architettura, implementazione pratica e best practices per developer e team tecnici.

RAG: Retrieval-Augmented Generation Spiegato

I Large Language Model (LLM) rappresentano una delle innovazioni tecnologiche più dirompenti degli ultimi anni: GPT-4, Claude, Gemini e Llama possono scrivere codice, riassumere documenti, rispondere a domande complesse e persino ragionare su problemi astratti. Eppure, soffrono di un difetto strutturale che ne limita drasticamente l'applicabilita in contesti professionali: le allucinazioni.

Quando un LLM non conosce la risposta, non dice "non lo so". Invece, genera testo plausibile ma completamente falso, con la stessa sicurezza con cui presenta fatti verificabili. In ambito aziendale, legale o medico, questo comportamento è inaccettabile. La soluzione più efficace e matura a questo problema si chiama Retrieval-Augmented Generation (RAG).

In questo primo articolo della serie AI Engineering e RAG Avanzato, partiremo dalle basi: cos'è RAG, come funziona, perchè risolve il problema delle allucinazioni e come costruire un sistema RAG funzionante da zero. Al termine, avrai una comprensione solida dell'intera architettura e sarai pronto ad approfondire ogni singolo componente negli articoli successivi.

Panoramica della Serie

# Articolo Focus
1Sei qui - RAG SpiegatoFondamenti e architettura completa
2Embeddings e Ricerca SemanticaCome i testi diventano vettori
3Vector Database in ProfonditàStorage, indexing, similarity search
4RAG con LangChain e PythonImplementazione pratica end-to-end
5Hybrid Retrieval e RerankingRicerca ibrida keyword + semantica
6Context Window e Prompt EngineeringOttimizzare il contesto per l'LLM
7RAG in ProduzioneScaling, monitoring, evaluation
8Knowledge Graphs e RAGGrafi di conoscenza + retrieval
9Multi-Agent SystemsAgenti AI collaborativi
10Il Futuro del RAGTrend, ricerca e next steps

Cosa Imparerai

  • Cos'è RAG e quale problema fondamentale risolve per gli LLM
  • L'architettura completa: dalla preparazione dei documenti alla generazione della risposta
  • Come funzionano embeddings, vector store e similarity search
  • Le strategie di chunking e i loro trade-off
  • Come costruire un sistema RAG minimo funzionante con Python
  • Le differenze tra Naive RAG e Advanced RAG
  • Quando usare RAG vs fine-tuning vs prompt engineering

1. Il Problema delle Allucinazioni nei LLM

Per comprendere perchè RAG è necessario, dobbiamo prima capire il problema che risolve. I Large Language Model sono essenzialmente modelli probabilistici di linguaggio: dato un testo di input, predicono la sequenza di token più probabile come continuazione. Questa architettura, basata sul meccanismo di attention dei Transformer, produce risultati straordinari ma ha un limite intrinseco: il modello non "sa" nulla nel senso umano del termine. Genera testo statisticamente plausibile basandosi sui pattern appresi durante l'addestramento.

I Tre Problemi Strutturali degli LLM

Problema Descrizione Impatto Pratico
Knowledge Cutoff La conoscenza è congelata alla data di addestramento Nessuna informazione su eventi recenti o dati proprietari
Allucinazioni Genera risposte plausibili ma completamente inventate Informazioni false presentate con alta confidenza
No Citazioni Non può indicare la fonte delle proprie affermazioni Impossibile verificare la correttezza delle risposte
No Dati Privati Non conosce la documentazione interna dell'azienda Inutile per casi d'uso specifici senza contesto

Le allucinazioni non sono un bug occasionale: sono una conseguenza diretta dell'architettura. Quando il modello non ha informazioni sufficienti per rispondere, non restituisce un errore. Invece, genera la continuazione più probabile del testo, che può essere completamente inventata. Il modello è stato addestrato per produrre testo fluente e coerente, non per essere fattualmente accurato.

Esempi Concreti di Allucinazione

Per capire la gravita del problema, consideriamo scenari reali dove le allucinazioni hanno conseguenze significative:

  • Ambito legale: Un LLM potrebbe citare sentenze inesistenti o leggi mai promulgate con numeri di articolo credibili ma inventati
  • Ambito medico: Potrebbe suggerire dosaggi di farmaci errati o interazioni farmacologiche non documentate
  • Documentazione tecnica: Potrebbe descrivere API con parametri che non esistono o funzionalità mai implementate
  • Supporto clienti: Potrebbe inventare policy aziendali, procedure di reso o garanzie inesistenti

Le statistiche confermano la portata del problema: i tassi di allucinazione variano significativamente per dominio, con ambiti specialistici come medicina e diritto che registrano tassi del 10-20% anche con i modelli più avanzati. RAG rappresenta la tecnica più efficace per mitigare questo problema, con riduzioni documentate fino al 71%.

2. Cos'è RAG: Definizione e Origini

Retrieval-Augmented Generation (RAG) è un paradigma architetturale che combina un sistema di information retrieval (recupero documenti) con un modello generativo (LLM) per produrre risposte fondate su dati reali. Il concetto è stato formalizzato nel 2020 da Patrick Lewis e colleghi di Meta AI nel paper seminale "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks".

L'intuizione fondamentale è semplice: invece di chiedere al modello di "ricordare" tutte le informazioni dal suo addestramento, gli forniamo i documenti rilevanti al momento della generazione. Questo processo si chiama grounding: ancorare la generazione a fonti concrete e verificabili.

RAG vs LLM Tradizionale - Confronto Architetturale

LLM TRADIZIONALE:
  Domanda utente ──────────────────> [LLM] ──> Risposta
                                       |
                            Basata SOLO su training data
                            Rischio allucinazione: ALTO

RAG (Retrieval-Augmented Generation):
  Domanda utente ──> [RETRIEVAL] ──> Documenti rilevanti
                         |                    |
                         |                    v
                         └───────> [LLM + Contesto] ──> Risposta con citazioni
                                       |
                            Basata su DATI REALI recuperati
                            Rischio allucinazione: BASSO
    

Analogia: L'Esame Open-Book

Immagina un esame universitario. L'LLM tradizionale è come uno studente che deve rispondere a memoria: conosce molto, ma può confondersi o inventare dettagli. RAG è come un esame open-book: lo studente può consultare i propri appunti e libri prima di rispondere. La risposta sarà più precisa e verificabile perchè fondata su fonti concrete.

Il concetto di grounding è cruciale: ogni affermazione nella risposta generata può essere ricondotta a un documento specifico nella knowledge base. Questo significa che:

  • Le risposte sono verificabili: puoi controllare il documento sorgente
  • Le risposte sono aggiornabili: aggiornando i documenti, cambiano automaticamente le risposte
  • Le risposte sono controllabili: decidi tu quali documenti il sistema può consultare
  • Le risposte sono tracciabili: puoi includere citazioni con riferimento alla fonte

3. Come Funziona RAG: La Pipeline Completa

Un sistema RAG si compone di due macro-fasi: la pipeline di indicizzazione, che prepara i documenti una tantum (o periodicamente), e la pipeline di query, che gestisce le domande degli utenti in tempo reale.

3.1 Pipeline di Indicizzazione (Fase Offline)

La fase di indicizzazione trasforma i documenti grezzi in una struttura ottimizzata per la ricerca semantica. Si compone di quattro step sequenziali:

Pipeline di Indicizzazione - Flusso Completo

[Documenti Sorgente]
    |  PDF, HTML, Markdown, CSV, database, API, email...
    v
[1. DOCUMENT LOADING]
    |  Estrazione del testo grezzo dai formati sorgente
    |  Preservazione dei metadati (autore, data, titolo)
    v
[2. CHUNKING (Text Splitting)]
    |  Divisione in frammenti di dimensione gestibile
    |  Strategie: fixed-size, semantic, recursive
    |  Overlap tra chunk per preservare contesto
    v
[3. EMBEDDING]
    |  Trasformazione di ogni chunk in un vettore numerico
    |  Modelli: OpenAI, Sentence Transformers, Cohere
    |  Dimensioni tipiche: 384, 768, 1536, 3072
    v
[4. VECTOR STORE]
    |  Salvataggio dei vettori in un database specializzato
    |  Indexing per ricerca veloce (HNSW, IVF)
    |  ChromaDB, Pinecone, Weaviate, Milvus, Qdrant
    v
[Knowledge Base Pronta per le Query]
    

3.2 Pipeline di Query (Fase Online)

Quando un utente pone una domanda, la pipeline di query entra in azione per trovare i documenti più rilevanti e generare una risposta fondata:

Pipeline di Query - Flusso in Tempo Reale

[Domanda dell'Utente]
    |  "Come configuro l'autenticazione OAuth nella nostra app?"
    v
[1. QUERY EMBEDDING]
    |  La domanda viene trasformata in vettore
    |  Stesso modello usato nell'indicizzazione!
    v
[2. SIMILARITY SEARCH]
    |  Ricerca dei chunk più simili nel vector store
    |  Metriche: cosine similarity, L2, dot product
    |  Restituisce i top-k risultati (tipicamente k=3..10)
    v
[3. CONTEXT ASSEMBLY]
    |  I chunk recuperati vengono assemblati in un contesto
    |  Ordinamento per rilevanza, deduplicazione
    v
[4. PROMPT CONSTRUCTION]
    |  Costruzione del prompt con contesto + domanda
    |  Template: "Basandoti sui seguenti documenti, rispondi..."
    v
[5. LLM GENERATION]
    |  Il modello genera la risposta basandosi sul contesto
    |  Può includere citazioni ai documenti sorgente
    v
[Risposta Fondata + Citazioni]
    

Regola Fondamentale: Coerenza degli Embeddings

È obbligatorio usare lo stesso modello di embedding sia nella fase di indicizzazione che nella fase di query. Modelli diversi producono spazi vettoriali incompatibili: i vettori generati da un modello non sono confrontabili con quelli di un altro. Cambiare modello di embedding richiede la re-indicizzazione completa di tutti i documenti.

4. Document Processing: Chunking e Preparazione

Il chunking è una delle fasi più critiche dell'intera pipeline RAG. La qualità dei risultati dipende in larga misura da come i documenti vengono suddivisi. Chunk troppo grandi diluiscono il segnale semantico e sprecano spazio nella context window dell'LLM. Chunk troppo piccoli perdono il contesto necessario per essere comprensibili.

4.1 Fixed-Size Chunking

La strategia più semplice: divide il testo in blocchi di dimensione fissa (es. 500 token) con un overlap opzionale tra chunk consecutivi.

Parametri del Fixed-Size Chunking

Parametro Descrizione Valore Tipico
chunk_size Dimensione massima di ogni chunk in token o caratteri 300-500 token
chunk_overlap Sovrapposizione tra chunk consecutivi 10-20% del chunk_size
separator Carattere/stringa usato per dividere "\n\n", "\n", " "
Esempio di Fixed-Size Chunking

Documento originale (1500 token):
"Lorem ipsum dolor sit amet... [1500 token di testo]"

Con chunk_size=500 e overlap=50:

Chunk 1: token 1-500     ────────────┐
Chunk 2: token 451-950   ──┐ overlap │
Chunk 3: token 901-1400  ──┘         │
Chunk 4: token 1351-1500             │
                          ────────────┘
L'overlap garantisce che il contesto ai bordi non venga perso.
    

4.2 Recursive Character Splitting

Strategia più sofisticata che prova a dividere rispettando la struttura del documento. Usa una gerarchia di separatori: prima prova a dividere per paragrafi ("\n\n"), poi per righe ("\n"), poi per frasi (". "), infine per parole (" "). Questo preserva meglio il contesto semantico rispetto al fixed-size.

4.3 Semantic Chunking

La strategia più avanzata: usa gli embeddings stessi per determinare dove dividere. Calcola la similarità tra frasi consecutive e crea un nuovo chunk quando la similarità scende sotto una soglia, indicando un cambio di argomento. Produce chunk di dimensione variabile ma semanticamente coerenti.

Confronto Strategie di Chunking

Strategia qualità Complessità Quando Usarla
Fixed-Size Base Minima Prototipazione, documenti omogenei
Recursive Buona Bassa Uso generale, documenti strutturati
Semantic Ottima Alta Alta qualità richiesta, documenti eterogenei

L'Importanza dei Metadati

Ogni chunk dovrebbe portare con se dei metadati: titolo del documento, autore, data, sezione, pagina. Questi metadati sono fondamentali per il filtraggio durante la ricerca e per generare citazioni accurate nella risposta. Un chunk senza metadati è come un paragrafo senza contesto.

5. Embeddings: Trasformare il Testo in Vettori

Gli embeddings sono il cuore matematico di RAG. Un embedding è una rappresentazione numerica (un vettore di numeri decimali) che cattura il significato semantico di un testo. Due frasi con significato simile avranno vettori "vicini" nello spazio multidimensionale, indipendentemente dalle parole usate.

Come Funzionano gli Embeddings - Concetto

INPUT: Frase di testo
OUTPUT: Vettore di numeri decimali (es. 1536 dimensioni)

Esempio:
"Il gatto dorme sul divano"  --> [0.23, -0.45, 0.67, 0.12, -0.89, ...]
"Il felino riposa sul sofa"  --> [0.22, -0.44, 0.68, 0.11, -0.88, ...]
                                   ^^ Vettori molto SIMILI (stesso significato)

"Il prezzo dell'oro sale"    --> [-0.56, 0.78, -0.12, 0.91, 0.34, ...]
                                   ^^ Vettore molto DIVERSO (significato diverso)
    

Il modello di embedding è una rete neurale addestrata su enormi quantità di testo per apprendere le relazioni semantiche tra parole, frasi e concetti. Non produce semplicemente una rappresentazione sintattica (come il bag-of-words o TF-IDF), ma cattura il significato profondo del testo.

Modelli di Embedding Principali (2025-2026)

Modello Dimensioni Provider Costo Indicativo
text-embedding-3-small 1536 OpenAI ~$0.02 / 1M token
text-embedding-3-large 3072 OpenAI ~$0.13 / 1M token
voyage-3-large 1024 Voyage AI ~$0.06 / 1M token
all-MiniLM-L6-v2 384 HuggingFace Gratuito (self-hosted)
nomic-embed-text 768 Ollama (locale) Gratuito (locale)
embed-v4 1024 Cohere ~$0.10 / 1M token

La scelta del modello di embedding dipende dal caso d'uso: i modelli più grandi (3072 dimensioni) offrono una rappresentazione più ricca ma costano di più in termini di storage e computazione. Per molti casi d'uso, modelli a 768-1536 dimensioni offrono un ottimo compromesso tra qualità e costo.

6. Vector Store: Il Database per gli Embeddings

Un vector store (o vector database) è un database specializzato per memorizzare, indicizzare e cercare vettori ad alta dimensionalità. A differenza dei database tradizionali che cercano corrispondenze esatte (SQL WHERE), un vector store cerca i vettori più simili a quello della query.

6.1 Metriche di Similarità

La ricerca nel vector store si basa su metriche di distanza/similarità tra vettori. Le tre metriche più comuni sono:

Metriche di Similarità a Confronto

Metrica Range Descrizione Quando Usarla
Cosine Similarity [-1, 1] Misura l'angolo tra due vettori, ignora la magnitudine Default per la maggior parte dei casi (scelta consigliata)
Distanza Euclidea (L2) [0, +inf) Distanza geometrica nello spazio, sensibile alla magnitudine Quando la magnitudine dei vettori è significativa
Dot Product (-inf, +inf) Prodotto scalare, combina direzione e magnitudine Vettori già normalizzati, Maximum Inner Product Search

6.2 Panoramica dei Vector Database

Il mercato dei vector database è esploso con l'adozione di RAG. Ecco una panoramica dei principali strumenti disponibili:

Vector Database a Confronto

Database Tipo Linguaggio Ideale Per
ChromaDB Embedded / Server Python Prototipazione, sviluppo locale, piccoli dataset
Pinecone Cloud managed Multi-lang Produzione, scalabilità automatica, zero-ops
Weaviate Self-hosted / Cloud Go Hybrid search, multi-tenancy, GraphQL
Milvus Self-hosted / Cloud Go / C++ Grandi volumi, alte performance, enterprise
Qdrant Self-hosted / Cloud Rust Performance, filtering avanzato, API REST
pgvector Estensione PostgreSQL C Stack esistente PostgreSQL, dati relazionali + vettoriali
FAISS Libreria in-memory C++ / Python Ricerca, benchmark, ottimizzazione massima

Per iniziare, ChromaDB è la scelta più semplice: si installa con pip, funziona in-memory o persistente su disco, e si integra nativamente con LangChain. Per la produzione, Pinecone (managed) e Qdrant (self-hosted) sono tra le opzioni più popolari.

7. Retrieval: La Ricerca dei Documenti Rilevanti

La fase di retrieval è il momento in cui la domanda dell'utente viene trasformata in un vettore e confrontata con tutti i vettori nel vector store per trovare i chunk più rilevanti. Questo processo avviene in millisecondi anche con milioni di documenti indicizzati, grazie agli algoritmi di indicizzazione approssimata come HNSW (Hierarchical Navigable Small World).

Flusso del Retrieval

Query: "Come configuro OAuth nella nostra app?"
  |
  v
[1] Embedding della query ──> [0.34, -0.21, 0.56, ...]
  |
  v
[2] Similarity Search nel Vector Store
  |   Confronta il vettore della query con tutti i vettori salvati
  |   Usa cosine similarity come metrica
  |
  v
[3] Top-K Results (es. k=5)
  |
  |   Score: 0.92 - "Configurazione OAuth 2.0 per applicazioni web..."
  |   Score: 0.87 - "Guida ai flussi di autenticazione OAuth..."
  |   Score: 0.83 - "Impostazione dei redirect URI per OAuth..."
  |   Score: 0.76 - "Confronto tra OAuth e SAML per SSO..."
  |   Score: 0.71 - "Sicurezza delle API con token JWT..."
  |
  v
[4] Filtering e Reranking (opzionale)
  |   Filtra per metadati (data, categoria, fonte)
  |   Reranking con modello cross-encoder
  |
  v
[Chunk Rilevanti Pronti per il Prompt]
    

7.1 Il Parametro Top-K

Il parametro top-k determina quanti chunk vengono recuperati. La scelta è un trade-off:

  • K troppo basso (1-2): Rischio di perdere informazioni rilevanti
  • K troppo alto (20+): Troppo rumore nel contesto, spreco di token, rischio di confondere il modello
  • K ottimale (3-7): Buon bilanciamento tra copertura e precisione

7.2 Relevance Scoring

Ogni risultato ha un relevance score (punteggio di rilevanza). I chunk con score basso dovrebbero essere filtrati perchè aggiungono rumore senza valore. Una soglia comune è 0.7 per la cosine similarity: tutto sotto viene scartato. In pratica, il threshold ottimale dipende dal dominio e va calibrato sperimentalmente.

8. Generation: Costruire la Risposta con l'LLM

La fase finale della pipeline RAG: i chunk recuperati vengono assemblati in un contesto strutturato e inseriti nel prompt dell'LLM insieme alla domanda dell'utente. Il modello genera la risposta basandosi esclusivamente (o prevalentemente) sul contesto fornito.

8.1 Il Prompt Template

Un buon prompt template per RAG deve istruire il modello a:

  • Usare solo le informazioni dal contesto fornito
  • Ammettere quando non trova la risposta nei documenti
  • Citare le fonti quando possibile
  • Non inventare informazioni non presenti nel contesto
Esempio di Prompt Template RAG
Sei un assistente tecnico. Rispondi alle domande SOLO basandoti
sul contesto fornito. Se la risposta non è presente nel contesto,
rispondi "Non ho trovato informazioni sufficienti nei documenti
disponibili."

CONTESTO:
---
{context}
---

DOMANDA: {question}

ISTRUZIONI:
1. Rispondi in modo chiaro e conciso
2. Cita il documento sorgente tra parentesi quadre [Fonte: nome_doc]
3. Se il contesto non contiene la risposta, dillo esplicitamente
4. Non inventare informazioni non presenti nel contesto

RISPOSTA:

8.2 Citation Tracking

Una delle funzionalità più preziose di RAG è la possibilità di tracciare le citazioni. Ogni chunk nel contesto può essere etichettato con un identificatore (es. [DOC-1], [DOC-2]) e il modello viene istruito a riferirsi a questi identificatori nella risposta. Questo permette all'utente di verificare ogni affermazione consultando il documento originale.

Context Window e Limiti

La quantità di contesto che puoi inserire è limitata dalla context window del modello LLM. Se i chunk recuperati superano il limite, dovrai selezionare solo i più rilevanti o riassumerli. Modelli moderni come GPT-4o (128K token) e Claude 3.5 (200K token) hanno context window molto ampie, ma anche cosi, inserire troppo contesto irrilevante degrada la qualità delle risposte (il cosiddetto "lost in the middle" problem).

9. Architettura RAG Completa: Visione d'Insieme

Ora che abbiamo esaminato ogni componente individualmente, assembliamo l'architettura completa di un sistema RAG end-to-end:

Architettura RAG End-to-End

                    FASE OFFLINE (Indicizzazione)
    ┌──────────────────────────────────────────────────────┐
    │                                                      │
    │  [Documenti]  ──>  [Loader]  ──>  [Chunker]          │
    │   PDF, HTML        Estrazione      Divisione         │
    │   MD, CSV          testo           in frammenti      │
    │                                       │              │
    │                                       v              │
    │                    [Embedding Model]                  │
    │                     Testo ──> Vettore                 │
    │                          │                           │
    │                          v                           │
    │                    [Vector Store]                     │
    │                     ChromaDB, Pinecone                │
    │                     Weaviate, Qdrant                  │
    │                                                      │
    └──────────────────────────────────────────────────────┘

                    FASE ONLINE (Query)
    ┌──────────────────────────────────────────────────────┐
    │                                                      │
    │  [Domanda Utente]                                    │
    │       │                                              │
    │       v                                              │
    │  [Query Embedding] ──> [Similarity Search]           │
    │       Stesso modello       Top-K chunk               │
    │       dell'indicizzazione       │                    │
    │                                 v                    │
    │                    [Context Assembly]                 │
    │                     Chunk + Metadati                  │
    │                          │                           │
    │                          v                           │
    │  [Prompt Template + Contesto + Domanda]              │
    │                          │                           │
    │                          v                           │
    │                       [LLM]                          │
    │                    GPT-4, Claude                      │
    │                    Llama, Gemini                      │
    │                          │                           │
    │                          v                           │
    │              [Risposta con Citazioni]                 │
    │                                                      │
    └──────────────────────────────────────────────────────┘
    

Componenti e Responsabilità

Componente Responsabilità Strumenti Tipici
Document Loader Caricare documenti da diverse sorgenti LangChain loaders, Unstructured, LlamaIndex
Text Splitter Dividere documenti in chunk ottimali RecursiveCharacterTextSplitter, SemanticChunker
Embedding Model Trasformare testo in vettori semantici OpenAI Embeddings, Sentence Transformers, Cohere
Vector Store Memorizzare e indicizzare vettori ChromaDB, Pinecone, Qdrant, pgvector
Retriever Cercare i chunk più rilevanti Similarity search, MMR, hybrid retrieval
LLM Generare la risposta finale dal contesto GPT-4o, Claude 3.5, Llama 3, Gemini Pro

10. Esempio Pratico: RAG Minimo con Python

Costruiamo un sistema RAG funzionante con il minimo codice necessario. Useremo LangChain come framework di orchestrazione, OpenAI per embeddings e generazione, e ChromaDB come vector store locale.

10.1 Setup del Progetto

Installazione delle Dipendenze
# Crea un ambiente virtuale
python -m venv rag-env
source rag-env/bin/activate  # Linux/Mac

# Installa le dipendenze
pip install langchain langchain-openai langchain-community
pip install chromadb
pip install pypdf  # Per caricare PDF

10.2 Pipeline di Indicizzazione

indexing.py - Preparazione dei Documenti
import os
from langchain_community.document_loaders import (
    PyPDFLoader,
    TextLoader,
    DirectoryLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

# Configura la API key
os.environ["OPENAI_API_KEY"] = "sk-..."

# 1. DOCUMENT LOADING
# Carica tutti i PDF da una cartella
loader = DirectoryLoader(
    "./documenti/",
    glob="**/*.pdf",
    loader_cls=PyPDFLoader
)
documents = loader.load()
print(f"Caricati {len(documents)} documenti")

# 2. CHUNKING
# Divisione ricorsiva con overlap
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,       # 500 caratteri per chunk
    chunk_overlap=50,     # 50 caratteri di overlap
    length_function=len,
    separators=["\n\n", "\n", ". ", " ", ""]
)
chunks = text_splitter.split_documents(documents)
print(f"Creati {len(chunks)} chunk")

# 3. EMBEDDING + 4. VECTOR STORE
# Crea gli embeddings e salvali in ChromaDB
embedding_model = OpenAIEmbeddings(
    model="text-embedding-3-small"
)

vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embedding_model,
    persist_directory="./chroma_db",
    collection_name="documenti_aziendali"
)
print("Vector store creato e salvato su disco")

10.3 Pipeline di Query

query.py - Interrogazione del Sistema RAG
import os
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

os.environ["OPENAI_API_KEY"] = "sk-..."

# Carica il vector store esistente
embedding_model = OpenAIEmbeddings(
    model="text-embedding-3-small"
)
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embedding_model,
    collection_name="documenti_aziendali"
)

# Configura il retriever
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 5}  # Recupera i 5 chunk più simili
)

# Definisci il prompt template
prompt_template = PromptTemplate(
    template="""Sei un assistente tecnico esperto.
Rispondi alla domanda basandoti SOLO sul contesto fornito.
Se non trovi la risposta nel contesto, dillo esplicitamente.

CONTESTO:
{context}

DOMANDA: {question}

RISPOSTA (con citazioni ai documenti fonte):""",
    input_variables=["context", "question"]
)

# Crea la chain RAG
llm = ChatOpenAI(
    model="gpt-4o",
    temperature=0  # Deterministic per risposte fattuali
)

rag_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # Inserisci tutti i chunk nel prompt
    retriever=retriever,
    return_source_documents=True,
    chain_type_kwargs={
        "prompt": prompt_template
    }
)

# Esegui una query
result = rag_chain.invoke(
    {"query": "Come configuro l'autenticazione OAuth?"}
)

# Stampa la risposta
print("RISPOSTA:")
print(result["result"])
print("\nFONTI:")
for doc in result["source_documents"]:
    print(f"  - {doc.metadata.get('source', 'N/A')}"
          f" (pagina {doc.metadata.get('page', 'N/A')})")

Output Atteso


RISPOSTA:
Per configurare l'autenticazione OAuth nella nostra applicazione,
segui questi passaggi:
1. Registra l'app nel provider OAuth (Google, GitHub, etc.)
2. Configura i redirect URI nel file config.yaml [Fonte: guida-oauth.pdf]
3. Implementa il flusso Authorization Code [Fonte: architettura-auth.pdf]
...

FONTI:
  - documenti/guida-oauth.pdf (pagina 12)
  - documenti/architettura-auth.pdf (pagina 5)
  - documenti/faq-sicurezza.pdf (pagina 3)
      

10.4 Struttura del Progetto

Struttura Cartelle del Progetto RAG

rag-project/
  ├── documenti/           # I tuoi documenti sorgente
  │   ├── guida-oauth.pdf
  │   ├── architettura.pdf
  │   └── faq.pdf
  ├── chroma_db/           # Vector store persistente (generato)
  ├── indexing.py           # Script di indicizzazione
  ├── query.py              # Script di query
  ├── requirements.txt      # Dipendenze
  └── .env                  # API keys (mai committare!)
    

11. Naive RAG vs Advanced RAG

Il sistema che abbiamo costruito finora è quello che la comunita chiama Naive RAG: un'implementazione lineare e semplice che funziona sorprendentemente bene per molti casi d'uso. Tuttavia, esistono limitazioni che le tecniche di Advanced RAG cercano di superare.

11.1 Limitazioni del Naive RAG

  • Query-Document Mismatch: La domanda dell'utente potrebbe usare termini diversi dai documenti. "Come resettare la password?" vs documento "Procedura di ripristino credenziali"
  • Chunk Boundary Issues: L'informazione rilevante potrebbe essere spezzata tra due chunk consecutivi
  • Lost in the Middle: L'LLM tende a dare più peso ai chunk all'inizio e alla fine del contesto, trascurando quelli centrali
  • Single-Hop Limitation: Non può rispondere a domande che richiedono sintesi da più documenti

11.2 Tecniche di Advanced RAG

Evoluzione da Naive a Advanced RAG

Tecnica Problema Risolto Come Funziona
Query Rewriting Query ambigue o mal formulate L'LLM riscrive la query in una forma più adatta al retrieval
HyDE Query-Document mismatch Genera un documento ipotetico dalla query, poi cerca documenti simili
Reranking Risultati non ottimalmente ordinati Un modello cross-encoder ri-ordina i risultati per rilevanza
Multi-Query Una sola prospettiva di ricerca Genera varianti della query per ampliare la copertura
Self-RAG Quando il retrieval non è necessario Il modello decide autonomamente se e quando fare retrieval
Multi-Hop RAG Domande complesse multi-step Catena di retrieval iterativi per costruire ragionamenti composti
Hybrid Search Limiti della sola ricerca semantica Combina ricerca semantica (vettoriale) con keyword (BM25)
Graph RAG Relazioni complesse tra entità Usa knowledge graph per navigare relazioni e contesti strutturati
Naive RAG vs Advanced RAG - Flusso a Confronto

NAIVE RAG:
  Query ──> Embedding ──> Search ──> Top-K ──> LLM ──> Risposta

ADVANCED RAG:
  Query ──> [Query Analysis]
              │
              ├──> Query Rewriting ──> Embedding ──> Search ─┐
              ├──> HyDE Generation ──> Embedding ──> Search ─┤
              └──> Multi-Query ──────> Embedding ──> Search ─┘
                                                       │
                                        [Merge + Deduplica]
                                               │
                                        [Reranker Model]
                                               │
                                        [Context Compression]
                                               │
                                            [LLM + Citazioni]
                                               │
                                        [Risposta Verificata]
    

Approfondiremo ciascuna di queste tecniche negli articoli successivi della serie, in particolare nell'articolo su Hybrid Retrieval e Reranking.

12. Quando Usare RAG: Decision Framework

RAG non è la risposta a tutti i problemi. Esistono tre approcci principali per personalizzare il comportamento di un LLM, ciascuno con vantaggi e limiti distinti. La scelta dipende dal caso d'uso specifico.

RAG vs Fine-Tuning vs Prompt Engineering

Criterio Prompt Engineering RAG Fine-Tuning
Costo iniziale Minimo Medio Alto
Dati necessari Nessuno Knowledge base Dataset di training
Aggiornamento Immediato (cambio prompt) Veloce (aggiorna documenti) Lento (re-training)
Latenza Bassa Media (retrieval + generation) Bassa
Accuratezza fattuale Dipende dal modello Alta (fondata su documenti) Media (dipende dal training)
Citabilità Nessuna Alta (traccia le fonti) Nessuna
Complessità Bassa Media Alta

12.1 Decision Tree Pratico

Albero Decisionale: Come Scegliere l'Approccio

Hai bisogno di personalizzare un LLM?
│
├── I dati cambiano frequentemente? (documenti, policy, catalogo)
│   └── SI ──> RAG
│         (I dati si aggiornano senza re-training)
│
├── Serve citare le fonti?
│   └── SI ──> RAG
│         (Tracciabilita delle risposte)
│
├── Il dominio è stabile e ben definito?
│   ├── Hai un grande dataset di training?
│   │   └── SI ──> Fine-Tuning
│   │         (Personalizzazione profonda del comportamento)
│   └── NO ──> RAG oppure Prompt Engineering
│
├── Serve solo cambiare tono/formato/stile?
│   └── SI ──> Prompt Engineering
│         (Nessuna infrastruttura aggiuntiva)
│
└── Serve ragionamento complesso su dati proprietari?
    └── SI ──> RAG + Fine-Tuning (Approccio Ibrido)
          (Il meglio di entrambi i mondi)
    

La Regola d'Oro

L'approccio consigliato dalla comunita AI engineering segue una scala di complessità crescente: inizia con il prompt engineering, poi passa a RAG se servono dati esterni o citazioni, e considera il fine-tuning solo quando i primi due approcci risultano insufficienti. Questa progressione minimizza il costo e la complessità, massimizzando il ROI.

12.2 Casi d'Uso Ideali per RAG

  • Chatbot aziendali: Rispondono sulla base della documentazione interna
  • Ricerca semantica: Trovare documenti rilevanti per significato, non solo keyword
  • Q&A su knowledge base: FAQ dinamiche che si aggiornano con i documenti
  • Assistenti legali: Risposte fondate su normative e giurisprudenza
  • Supporto tecnico: Risoluzioni basate su ticket precedenti e manuali
  • Analisi documentale: Estrarre insight da report, contratti, paper scientifici

12.3 Quando NON Usare RAG

  • Task creativi: Scrittura creativa, brainstorming, generazione di idee (il modello deve essere libero)
  • Conversazione generica: Chatbot sociali dove non servono dati specifici
  • Task con pochi dati: Se hai solo pochi documenti, il prompt engineering potrebbe bastare
  • Risposte in tempo reale stretto: Se la latenza del retrieval e inaccettabile (sotto i 50ms)

13. Il Mercato RAG: Numeri e Tendenze

RAG non e più un concetto accademico: e diventato un'architettura di produzione adottata su larga scala. I numeri del mercato confermano la sua importanza strategica.

RAG in Numeri (2024-2030)

Metrica Dato
Mercato globale RAG (2024) ~1.2 miliardi USD
Proiezione mercato (2030) ~11 miliardi USD
Tasso di crescita annuo (CAGR) 49.1% (2025-2030)
Adozione enterprise 30-60% dei casi d'uso LLM utilizza RAG
Riduzione allucinazioni Fino al 71% con RAG ben implementato
Framework dominanti 80.5% usa FAISS o Elasticsearch

I settori che guidano l'adozione sono legale, medico, supporto clienti e servizi finanziari, cioe tutti quei domini dove l'accuratezza fattuale e la citabilità delle fonti sono requisiti non negoziabili. La tendenza nel 2025-2026 è il passaggio dalla sperimentazione alla produzione su larga scala, con un'enfasi crescente su compliance, monitoraggio e qualità dei dati.

14. Conclusioni e Prossimi Passi

In questo articolo abbiamo costruito una comprensione completa di RAG: dal problema che risolve (le allucinazioni degli LLM) all'architettura end-to-end, passando per ogni singolo componente della pipeline. Abbiamo visto un'implementazione pratica funzionante e abbiamo confrontato RAG con le alternative (fine-tuning, prompt engineering).

Riepilogo dei Concetti Chiave

  • RAG combina retrieval e generation per produrre risposte fondate su dati reali
  • La pipeline di indicizzazione trasforma documenti in vettori: Loading, Chunking, Embedding, Storage
  • La pipeline di query trova e usa i documenti rilevanti: Embedding, Search, Assembly, Generation
  • Il chunking è una delle decisioni più critiche: influenza direttamente la qualità del retrieval
  • Gli embeddings catturano il significato semantico del testo in vettori numerici
  • I vector store rendono possibile la ricerca per similarità su milioni di documenti
  • Advanced RAG introduce tecniche come reranking, HyDE e multi-hop per superare i limiti del Naive RAG
  • RAG è ideale quando servono risposte aggiornate, verificabili e citabili

Prossimo Articolo: Embeddings e Ricerca Semantica

Nel prossimo articolo della serie approfondiremo il componente più affascinante di RAG: gli embeddings. Vedremo come funzionano internamente, come scegliere il modello giusto, come valutarne la qualità e come ottimizzare la ricerca semantica. Esploreremo anche le metriche di valutazione e le tecniche di benchmarking per misurare le performance del tuo sistema di retrieval.

Serie AI Engineering e RAG Avanzato

Articolo Argomento
01 - Sei quiRAG: Retrieval-Augmented Generation Spiegato
02 - ProssimoEmbeddings e Ricerca Semantica in Profondità
03Vector Database: Architettura e Best Practices
04Costruire un Sistema RAG con LangChain e Python
05Hybrid Retrieval: Keyword + Semantica + Reranking
06Context Window e Prompt Engineering per RAG
07RAG in Produzione: Monitoring, Evaluation, Scaling
08Knowledge Graphs e Retrieval Strutturato
09Multi-Agent Systems e RAG Orchestrato
10Il Futuro del RAG: Tendenze e Ricerca

Se ti interessa come questi pattern di AI engineering si traducono in workflow quotidiano su un codebase reale, ho documentato il mio setup (skill design + planning fasato + sub-agent orchestration) in Claude Code Workflow: Superpowers + GSD framework.

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti