Costruire una semplice applicazione RAG con LLM moderni
La Retrieval-Augmented Generation (RAG) è diventata uno dei modi più pratici per rendere utili gli LLM con i propri dati. In questo post racconto come ho costruito da zero una app RAG open-source.
Cos'è la RAG?
La RAG combina la potenza dei grandi modelli linguistici con un sistema di retrieval che recupera contesto rilevante dai propri documenti prima di generare una risposta.
Invece di fare fine-tuning di un modello, che è costoso e lento, la RAG permette di:
- Ancorare le risposte ai dati reali
- Ridurre le allucinazioni fornendo contesto verificabile
- Aggiornare la conoscenza senza riaddestrare il modello
Panoramica dell'architettura
Query utente
│
▼
┌──────────┐ ┌──────────────┐
│ Embedding │────▶│ Vector Store │
│ Model │ │ (pgvector) │
└──────────┘ └──────┬───────┘
│ Risultati Top-K
▼
┌──────────────┐
│ Prompt LLM │
│ Query+Contesto│
└──────┬───────┘
│
▼
Risposta
Stack tecnico
| Componente | Tecnologia | Perché |
|---|---|---|
| Embedding | OpenAI text-embedding-3-small | Miglior rapporto costo/qualità |
| Vector DB | PostgreSQL + pgvector | Nessuna infrastruttura extra |
| LLM | GPT-4o / Claude | Intercambiabili tramite API |
| Backend | Python + FastAPI | Supporto async e type hints |
| Frontend | React + TypeScript | Familiare e rapido da iterare |
Strategia di chunking
Una delle decisioni più importanti nella RAG è come suddividere i documenti. Questa è la soluzione che ha funzionato meglio:
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=64,
separators=["
", "
", ". ", " ", ""]
)
chunks = splitter.split_documents(documents)
Perché 512 token?
- Troppo piccolo (128) — perde contesto e il retrieval diventa rumoroso
- Troppo grande (2048) — diluisce le informazioni rilevanti
- 512 con overlap di 64 — buon compromesso per la maggior parte dei casi
Lezioni imparate
- Il chunking conta più del modello — dati scarsi producono risultati scarsi
- La ricerca ibrida vince — combina similarità vettoriale e keyword BM25
- Il reranking vale la pena — un reranker economico sui primi 20 risultati batte una top-5 vettoriale
- Valutare è difficile — crea presto un set di test, anche piccolo
Prossimi passi
Sto sperimentando con:
RAG multimodale(immagini + testo) usando modelli vision- RAG agentica, in cui l'LLM decide quando e cosa recuperare
- Graph RAG per documenti con relazioni complesse tra entità
Il codice sorgente completo è disponibile su GitHub. Lascia una stella se lo trovi utile!
