AleFeri

Una semplice applicazione RAG open-source con i nuovi LLM

Python9/5/2025

Una semplice applicazione RAG open-source con i nuovi LLM

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

ComponenteTecnologiaPerché
EmbeddingOpenAI text-embedding-3-smallMiglior rapporto costo/qualità
Vector DBPostgreSQL + pgvectorNessuna infrastruttura extra
LLMGPT-4o / ClaudeIntercambiabili tramite API
BackendPython + FastAPISupporto async e type hints
FrontendReact + TypeScriptFamiliare 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?

  1. Troppo piccolo (128) — perde contesto e il retrieval diventa rumoroso
  2. Troppo grande (2048) — diluisce le informazioni rilevanti
  3. 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!