Costruire un Chatbot RAG con LangChain in 1 Ora
RAG (Retrieval-Augmented Generation) permette all'AI di rispondere usando i tuoi documenti specifici invece che solo la conoscenza del modello. È la base di ogni chatbot aziendale utile: FAQ automatiche, assistenti documentali, knowledge base interattive. È anche, tecnicamente, il pattern dietro il "RAG agent" — uno dei tipi di agente AI più usati in produzione.
Il problema che risolve è concreto: un modello come GPT-4 conosce solo ciò su cui è stato addestrato, fino a una certa data, e non ha idea di cosa contenga il tuo manuale prodotto, i tuoi contratti o la tua knowledge base interna. Senza RAG, un chatbot aziendale o inventa risposte plausibili ma sbagliate (le cosiddette "allucinazioni") o ammette semplicemente di non sapere. Con RAG, prima di rispondere il sistema recupera i passaggi più rilevanti dai tuoi documenti e li passa al modello come contesto — la risposta diventa verificabile e ancorata a fonti reali.
Documenti → Chunking → Embedding → Vector Store → Retrieval → LLM → Risposta
RAG o fine-tuning? Come scegliere
Sono le due strade più comuni per "specializzare" un modello, e vengono confuse spesso. Il fine-tuning riaddestra il modello sui tuoi dati — utile per insegnargli uno stile, un formato di risposta o un dominio linguistico molto specifico, ma non è il modo giusto per dargli conoscenza aggiornabile: ogni volta che i dati cambiano, serve riaddestrare. Il RAG invece lascia il modello intatto e gli passa i documenti rilevanti al momento della domanda: aggiorni la knowledge base semplicemente aggiungendo o modificando i documenti, senza toccare il modello. Per la maggior parte dei casi aziendali — FAQ, supporto clienti, ricerca interna — RAG è la scelta giusta: più economico, più veloce da aggiornare, e le risposte restano verificabili tramite le fonti citate.
Setup iniziale
pip install langchain openai chromadb tiktoken pypdf
Step 1: Carica i documenti
Il primo passo è portare i tuoi documenti dentro il sistema. LangChain fornisce loader per la maggior parte dei formati (PDF, Word, CSV, pagine web, notion, Slack export): il loader estrae il testo grezzo e lo trasforma in oggetti Document che il resto della pipeline sa maneggiare.
from langchain.document_loaders import PyPDFLoader, DirectoryLoader
# Carica un PDF
loader = PyPDFLoader("manuale_prodotto.pdf")
documents = loader.load()
# Oppure carica una directory intera
loader = DirectoryLoader("./docs", glob="**/*.pdf")
documents = loader.load()Step 2: Chunking e Embedding
Un documento intero è troppo grande da passare al modello ogni volta — e la maggior parte non è nemmeno rilevante per una singola domanda. Il chunking divide i documenti in blocchi più piccoli e gestibili. L'embedding trasforma ogni blocco in un vettore numerico che ne rappresenta il significato: testi con significato simile finiscono "vicini" nello spazio vettoriale, il che permette di cercare per somiglianza semantica invece che per parole chiave esatte. Il vector store è il database che conserva questi vettori e li rende cercabili in millisecondi anche su migliaia di documenti.
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
# Suddividi in chunk
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200 # ~20% overlap riduce perdita di contesto
)
chunks = splitter.split_documents(documents)
# Crea vector store
vectorstore = Chroma.from_documents(
chunks,
OpenAIEmbeddings(),
persist_directory="./chroma_db"
)
vectorstore.persist()Step 3: Chain RAG completa
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
# Prompt template personalizzato
template = """Usa il seguente contesto per rispondere alla domanda.
Se non conosci la risposta, dì che non lo sai — non inventare.
Contesto: {context}
Domanda: {question}
Risposta:"""
prompt = PromptTemplate(
template=template,
input_variables=["context", "question"]
)
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 5}
),
chain_type_kwargs={"prompt": prompt},
return_source_documents=True
)
# Usa il chatbot
result = qa_chain("Qual è la policy sui resi?")
print(result["result"])
print(result["source_documents"]) # Mostra le fonti usateBest practices
- Chunk size ottimale: 500–1500 caratteri con 10–20% di overlap — abbastanza contesto per essere utile, abbastanza piccolo per essere preciso
- MMR retriever: Maximum Marginal Relevance riduce le risposte ridondanti privilegiando chunk diversi tra loro, non solo i più simili alla domanda
- Confidence threshold: se la similarity score dei documenti recuperati è bassa, meglio scalare a un umano che rispondere con un contesto debole
- Mostra le fonti: aumenta la fiducia degli utenti nelle risposte e ti permette di verificare rapidamente se il sistema sta recuperando i documenti giusti
- Testa con domande "trabocchetto": domande fuori contesto o fuori dominio devono ricevere "non so", mai una risposta inventata
- Aggiorna l'indice quando i documenti cambiano: un vector store non si aggiorna da solo — serve un processo (anche schedulato) che ricostruisca gli embedding dei documenti modificati
Chunk troppo grandi perdono precisione. Chunk troppo piccoli perdono contesto. Inizia con 1000 caratteri e ottimizza in base ai risultati reali — non in base alla teoria.
Quanto costa e quanto scala
I costi di un sistema RAG hanno due componenti: gli embedding (pagati una volta per documento, più ogni volta che lo aggiorni — con OpenAI, frazioni di centesimo per pagina) e le chiamate al modello per generare le risposte, che sono il costo ricorrente vero. Su volumi bassi (centinaia di query al giorno) un vector store locale come Chroma o FAISS è più che sufficiente. Oltre le decine di migliaia di documenti o quando serve alta disponibilità, conviene passare a soluzioni gestite come Pinecone, Weaviate o pgvector su Postgres — la logica della pipeline resta identica, cambia solo dove vivono i vettori.
Domande frequenti
RAG elimina completamente le allucinazioni?
Le riduce drasticamente, ma non le azzera del tutto: il modello può ancora interpretare male un documento recuperato correttamente. Per questo il confidence threshold e la citazione delle fonti restano fondamentali anche con RAG attivo.
Posso usare RAG con dati che cambiano spesso?
Sì, ed è uno dei suoi punti di forza rispetto al fine-tuning: basta ri-processare il documento aggiornato e ricalcolarne gli embedding. Per dati che cambiano ogni minuto (es. prezzi in tempo reale) è comunque meglio combinare RAG con una chiamata diretta a un'API, non solo con documenti statici.
Serve per forza LangChain?
No — LangChain è comodo perché astrae molti passaggi, ma un RAG minimale si costruisce anche direttamente con le API di embedding e un vector store, senza framework. LangChain conviene quando la pipeline cresce in complessità (più fonti, retriever multipli, agenti che decidono quando fare retrieval).
Costruisco chatbot personalizzati per la tua documentazione
Dal PDF del manuale al chatbot in produzione, con gestione delle fonti e escalation automatica a umano.
Contattami →