HomeModelli AIRAGMCP OrchestrazionePrompt EngineeringQuando (Non) Usare AIChipsBotNews

RAG — Retrieval Augmented Generation

Come dare ai modelli AI accesso a conoscenza specifica, aggiornata e verificabile. L'architettura, i componenti e le best practices per sistemi RAG in produzione.

Cos'è il RAG e perché serve

I Large Language Model hanno una conoscenza impressionante, ma con limiti fondamentali: le informazioni sono "congelate" al momento del training, non citano le fonti, e possono inventare fatti (hallucination). Il Retrieval Augmented Generation (RAG) risolve questi problemi combinando due capacità:

  1. Retrieval — cercare informazioni rilevanti in una base di conoscenza
  2. Generation — usare quelle informazioni come contesto per generare una risposta

In pratica, invece di chiedere al modello "cosa sai su X?", gli dici "ecco i documenti rilevanti su X, rispondi basandoti su questi". Il risultato è una risposta ancorata a dati reali, aggiornati e verificabili.

Quando usare il RAG: Ogni volta che il modello deve rispondere con informazioni specifiche del tuo dominio — documentazione interna, FAQ, knowledge base, cataloghi prodotti, normative, manuali tecnici.

Architettura: il pipeline completo

Un sistema RAG ha due fasi: l'indicizzazione (offline, una tantum) e la query (online, ad ogni richiesta).

INDICIZZAZIONE (offline): Documenti ──▶ Chunking ──▶ Embedding ──▶ Vector Store QUERY (online): Domanda ──▶ Embedding ──▶ Ricerca ──▶ Top-K chunks ──▶ LLM ──▶ Risposta ▲ ▲ Vector Store Prompt + Contesto

Ogni fase ha le sue scelte architetturali e trade-off. Vediamole nel dettaglio.

Strategie di chunking

Il chunking è il processo di dividere i documenti in frammenti gestibili. È forse la fase più sottovalutata del RAG, ma ha un impatto enorme sulla qualità del retrieval.

Fixed-size chunking

Il metodo più semplice: dividere il testo in blocchi di dimensione fissa (es. 512 token) con un overlap (es. 50 token) per non perdere informazioni ai confini.

# Chunking a dimensione fissa con overlap
def fixed_chunk(text, chunk_size=512, overlap=50):
    words = text.split()
    chunks = []
    i = 0
    while i < len(words):
        chunk = " ".join(words[i:i + chunk_size])
        chunks.append(chunk)
        i += chunk_size - overlap
    return chunkspython

Pro: semplice, prevedibile, veloce. Contro: ignora la struttura del testo — può tagliare a metà una frase o un concetto.

Semantic chunking

Divide il testo in base al significato, non alla dimensione. Usa gli embedding per identificare dove il tema cambia: quando la similarità tra frasi consecutive scende sotto una soglia, si crea un nuovo chunk.

Pro: ogni chunk è semanticamente coerente. Contro: più lento, dimensioni variabili (alcuni chunk possono essere molto grandi o molto piccoli).

Recursive chunking

L'approccio usato da LangChain: prova a dividere prima per paragrafi (\n\n), poi per frasi (.\n), poi per spazi, fino a ottenere chunk della dimensione target. Rispetta la struttura naturale del testo.

# RecursiveCharacterTextSplitter di LangChain
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", ". ", " ", ""]
)
chunks = splitter.split_text(document)python

Document-aware chunking

Per documenti strutturati (Markdown, HTML, codice), usare parser specifici che rispettano la struttura: dividere per sezioni, funzioni, classi. Un chunk che contiene una funzione intera è molto più utile di uno che ne contiene metà.

Best practice Inizia con chunk da 500-1000 caratteri con overlap del 10-20%. Poi testa: se il retrieval non trova le informazioni giuste, prova chunk più piccoli. Se le risposte mancano di contesto, prova chunk più grandi.

Embedding models

Gli embedding trasformano il testo in vettori numerici che catturano il significato semantico. Due testi con significato simile avranno vettori vicini nello spazio. Questo è il fondamento del retrieval semantico.

Modello Dimensioni Max token Note
text-embedding-3-large (OpenAI) 3072 8191 Ottima qualità, API semplice
embed-v4 (Cohere) 1024 512 Multilingue eccellente
jina-embeddings-v3 1024 8192 Lungo contesto, multilingue
BGE-M3 (BAAI) 1024 8192 Open source, dense+sparse
nomic-embed-text 768 8192 Open source, efficiente
Voyage 3 1024 32000 Ottimizzato per RAG, lungo contesto
# Generare embedding con OpenAI
from openai import OpenAI
client = OpenAI()

response = client.embeddings.create(
    model="text-embedding-3-large",
    input=["Come funziona il retrieval augmented generation?"]
)
vector = response.data[0].embedding  # lista di 3072 floatpython

Vector databases

I vector database sono ottimizzati per memorizzare e cercare vettori ad alta dimensionalità. Usano algoritmi di Approximate Nearest Neighbor (ANN) come HNSW o IVF per cercare i vettori più simili in millisecondi, anche su milioni di documenti.

Pinecone

Fully managed, serverless. Zero infrastruttura. Ottimo per iniziare. Pricing basato su storage + query.

Weaviate

Open source, hybrid search nativa (dense+BM25). GraphQL API. Moduli di vectorizzazione integrati.

Qdrant

Open source, scritto in Rust. Eccellente performance. Filtri avanzati, payload ricchi. API REST e gRPC.

Chroma

Open source, embedding-first. Semplicissimo per prototipi. Gira in-memory o persistente.

pgvector

Estensione PostgreSQL. Perfetto se hai già Postgres. Niente infrastruttura aggiuntiva. Buono fino a ~1M vettori.

Milvus

Open source, scalabile. Supporta miliardi di vettori. Architettura distribuita. Più complesso da gestire.

# Esempio: RAG con pgvector e psycopg2
import psycopg2
from pgvector.psycopg2 import register_vector

conn = psycopg2.connect("dbname=myapp")
register_vector(conn)

# Cercare i 5 chunk più simili alla query
cur = conn.cursor()
cur.execute("""
    SELECT content, 1 - (embedding <=> %s) AS similarity
    FROM documents
    ORDER BY embedding <=> %s
    LIMIT 5
""", (query_embedding, query_embedding))

chunks = cur.fetchall()python

La ricerca puramente semantica (dense) ha un punto debole: può mancare match esatti su termini tecnici, nomi propri, codici prodotto. La ricerca ibrida combina:

  • Dense retrieval (embedding) — cattura il significato semantico
  • Sparse retrieval (BM25/TF-IDF) — cattura le corrispondenze lessicali esatte

I risultati vengono combinati con Reciprocal Rank Fusion (RRF) o un semplice punteggio pesato:

score_finale = alpha * score_dense + (1 - alpha) * score_sparse

Un valore di alpha = 0.7 (favorire il semantico) è un buon punto di partenza. Ma il valore ottimale dipende dal dominio: per documentazione tecnica con molti acronimi, alpha = 0.5 funziona meglio.

Reranking

Il retrieval iniziale è veloce ma approssimativo (usa embedding compressi). Il reranking prende i top-K risultati e li ri-ordina con un modello più sofisticato che esamina query e documento insieme (cross-encoder), non solo i loro vettori.

  • Cohere Rerank — API managed, eccellente qualità, multilingue
  • Cross-encoder (Hugging Face) — modelli come ms-marco-MiniLM, self-hosted
  • ColBERT — approccio ibrido late-interaction, buon compromesso velocità/qualità
# Reranking con Cohere
import cohere
co = cohere.Client("YOUR_API_KEY")

results = co.rerank(
    query="Come configurare il RAG con pgvector?",
    documents=[chunk.text for chunk in retrieved_chunks],
    model="rerank-v3.5",
    top_n=5
)

for r in results.results:
    print(f"Score: {r.relevance_score:.3f} | {r.document.text[:80]}")python

Evaluation: misurare la qualità

Un sistema RAG va valutato su più dimensioni:

Metrica Cosa misura Come
Context Relevance I chunk recuperati sono pertinenti alla domanda? LLM-as-judge o annotazione umana
Faithfulness La risposta è fedele ai chunk (non inventa)? Verifica claim-by-claim
Answer Relevance La risposta risponde effettivamente alla domanda? LLM-as-judge
Recall@K Il chunk giusto è nei top-K risultati? Set di valutazione con ground truth

Framework come RAGAS e DeepEval automatizzano queste metriche usando un LLM come giudice.

Software e framework

LangChain

Il framework più popolare per applicazioni LLM. Offre astrazioni per document loaders, text splitters, embedding, vector stores e chain di RAG. Enorme ecosystem con centinaia di integrazioni. Criticato per l'eccesso di astrazione, ma ottimo per prototipi rapidi.

LlamaIndex

Focalizzato specificamente sul RAG. Offre "data connectors" per decine di fonti dati, strategie di indicizzazione avanzate (tree index, keyword index, knowledge graph), e un query engine sofisticato con sub-question decomposition.

Haystack (deepset)

Framework enterprise per NLP/RAG. Pipeline component-based, ottimo per sistemi di produzione complessi. Supporto nativo per hybrid retrieval e evaluation.

Best practices e anti-pattern

Best practices
  • Includi metadati nei chunk (titolo del documento, sezione, data) — usali per filtrare il retrieval
  • Testa con domande reali dei tuoi utenti, non domande inventate
  • Usa il reranking sempre — il costo è minimo e la qualità migliora significativamente
  • Monitora le query senza risultati — rivelano buchi nella knowledge base
  • Considera query rewriting — riformulare la domanda dell'utente prima del retrieval
Anti-pattern da evitare
  • Chunk troppo grandi — diluiscono il segnale e sprecano context window
  • Nessun overlap — informazioni ai confini dei chunk vengono perse
  • Ignorare il preprocessing — header, footer, boilerplate degradano la qualità degli embedding
  • Un unico indice per tutto — separare per tipo di documento migliora il retrieval
  • Fidarsi ciecamente del RAG — il modello può ancora allucinare anche con contesto; usa guardrails

Tecniche avanzate

Query Decomposition

Per domande complesse, scomporle in sotto-domande e fare retrieval separato per ognuna. Esempio: "Confronta i prezzi e le performance di Pinecone e Qdrant" diventa due query separate, una per i prezzi e una per le performance.

Parent Document Retrieval

Indicizzare chunk piccoli (per precisione nel retrieval) ma passare al modello il documento genitore più grande (per contesto completo). Il meglio di entrambi i mondi.

Self-RAG

Il modello decide autonomamente se ha bisogno di fare retrieval, valuta la rilevanza dei documenti recuperati, e giudica se la sua risposta è fedele al contesto. Un ciclo di auto-miglioramento.

Collegamento con altri temi

Il RAG non esiste in isolamento. Per costruire sistemi completi: