Premessa: il 70% dei sistemi RAG che vedo nelle aziende sono "PoC che hanno funzionato abbastanza da finire in produzione". Reggono finché ci sono 10 utenti, poi cominciano a dare risposte sbagliate, lente, o entrambe.
Questa è l'architettura che uso dal terzo progetto in poi, dopo aver capito cosa rompe quando la scala aumenta. È un template — vanno adattati nomi e parametri al tuo caso — ma le decisioni chiave sono le stesse.
1. Ingest pipeline (offline)
Loader
Estrae testo da PDF, HTML, database, file Office. Errore comune: usare un loader generico
per tutti i tipi. PDF complessi (tabelle, layout multicolonna) richiedono loader dedicati come
unstructured.io o docling di IBM.
Chunker
Splitta i documenti in pezzi indicizzabili. Non usare chunk fissi di 512 token: rompi le frasi a metà. Usa chunking semantic (basato su similarity tra frasi consecutive) o almeno recursive character splitter con overlap del 10-15%.
Embedder
Trasforma testo in vettori. Per italiano + inglese consiglio BAAI/bge-m3 (multilingual,
1024 dim) o nomic-embed-text-v1.5. Evita text-embedding-ada-002 di OpenAI:
debole sull'italiano e costoso a scala.
Vector DB
Per < 10M chunk: pgvector su PostgreSQL — meno componenti, meno problemi. Per > 10M o se serve filtering complesso: Qdrant (production-ready, gestione filter potente). Pinecone va bene solo se vuoi managed e accetti il lock-in.
2. Query pipeline (online)
Query rewriter — il pezzo che il 90% degli sviluppatori salta
La query dell'utente ("come si imposta il timeout?") è quasi sempre peggiore della query ottimale per la ricerca. Usa un LLM piccolo (Llama 3.1 8B, Mistral 7B) per:
- HyDE: genera una finta risposta plausibile, embedda quella invece della query → recall +15-30%
- Step-back: chiedi al LLM "qual è la domanda più generale dietro questa?" e cerca quella
- Query expansion: aggiungi sinonimi e termini correlati
Hybrid retrieval
Combinare vector search (semantica) con BM25 (keyword exact-match) batte sempre il solo vector search. Implementabile in pgvector con un join, in Qdrant via API. Peso tipico: 0.7 vector + 0.3 BM25.
Re-ranker
Recupera 30-50 candidati dal retriever, poi riordinali con un re-ranker cross-encoder
(BAAI/bge-reranker-v2-m3). Prendi i top 5. Costo: +200ms di latenza, +20% di accuracy.
Senza questo step, le risposte sono mediocri.
3. Generation
LLM Generator
Qui pesa relativamente poco la scelta del modello rispetto al lavoro fatto nelle fasi precedenti. Tre opzioni:
- Llama 3.3 70B Q4 su A100 80GB → privacy garantita, costo predicibile, italiano ottimo
- Mistral Large 2 via API mistral.ai → ospitato in UE (GDPR-friendly)
- GPT-4o / Claude 3.5 via API → migliore qualità ma dati lasciano l'UE
Citation Layer (obbligatorio per produzione)
Il prompt deve forzare il modello a citare quale chunk ha usato per ogni affermazione. Pattern:
ogni chunk passato al modello ha un ID, il modello deve scrivere [1], [2]
nelle citazioni. Permette validazione, debugging, trust dell'utente.
4. Validator (il safety net)
Risposta deve passare almeno 2 check prima di andare all'utente:
- Citation check: ogni affermazione fattuale ha una citazione? Se no → "non ho informazioni sufficienti"
- Hallucination check: usa un altro LLM (più piccolo, più economico) per verificare che la risposta sia supportata dal contesto. Pattern NLI (Natural Language Inference): contesto + risposta → entails/contradicts/neutral.
5. Observability
Devi loggare ogni: query, query riscritta, chunk recuperati, score di re-ranking, risposta, feedback utente. Setup minimo:
- Tracing: LangSmith, Phoenix (Arize), o stack custom (OpenTelemetry → Tempo)
- Eval automatica: dataset di 50-200 query con risposte attese, regression test ad ogni deploy
- Eval umana: campione settimanale di 20 risposte → rating 1-5 → trend nel tempo
Checklist pre-deploy
Non andare in produzione senza aver risposto sì a tutte queste:
- ☐ Recall @ 5 sul retriever > 80% sul dataset di test?
- ☐ Latency p95 < 3 secondi end-to-end?
- ☐ Citation rate > 95% (quasi ogni affermazione cita una fonte)?
- ☐ Hallucination rate < 5% sul test set?
- ☐ Fallback configurato per ogni componente (LLM down, DB down, embedder down)?
- ☐ Rate limiting per utente?
- ☐ Cost monitoring con alert se > 150% del budget mensile?
- ☐ PII detection sui log (non loggare dati personali)?
- ☐ Re-indexing job schedulato (i documenti cambiano)?
- ☐ User feedback loop (thumbs up/down → dataset di re-training)?
Cosa non c'è in questo template (e perché)
Agentic RAG / ReAct. Sono pattern utili ma aumentano la latenza 3-5× e la complessità di debugging 10×. Vai diretto solo se il caso d'uso lo richiede davvero (es. multi-step reasoning con tool use).
Knowledge graph. Promette molto ma in pratica fa fatica a superare un buon hybrid retrieval + re-ranker su domini generici. Vale la pena solo su domini molto strutturati (es. legale, medico).
Multi-modal RAG. Se devi gestire immagini, schemi, tabelle complesse, il setup raddoppia. Parti text-only, aggiungi multi-modal solo se necessario.