Chiedi a Claude informazioni sulla tua azienda, i tuoi appunti o i tuoi file, e lui non sa cosa siano. Non li ha mai visti. Conosce solo ciò che ha imparato durante l'addestramento, e la tua roba non ne faceva parte.
Un sistema RAG risolve questo problema. Invece di rispondere a memoria, Claude prima cerca nei tuoi documenti, prende le parti che contano e risponde basandosi su ciò che ha effettivamente trovato. I tuoi dati, la sua fonte, niente supposizioni.
Perché è meglio che incollare file nella chat:
Scala. L'intera base di conoscenza non ci sta in una singola chat. RAG memorizza tutto e recupera solo ciò che serve per ogni domanda.
Costa meno. Incollare un file significa che Claude lo rilegge per intero a ogni domanda. RAG lo legge una volta, poi recupera solo la parte rilevante. Invece di inviare un manuale da 10.000 token ogni volta, potrebbe inviare 500 token della sezione esatta che ti serve. Le configurazioni reali tagliano l'uso dei token dell'80% o più.
È più preciso. Dai a un modello un muro di testo e perde i dettagli nel mezzo. Dagli pochi pezzi precisi e le risposte diventano più accurate.
Rimane aggiornato. Aggiorna i tuoi file una volta e il sistema usa la versione nuova. Niente da reincollare.
Alla fine di questa guida, ne avrai uno funzionante sui tuoi file, passo dopo passo, senza bisogno di un dottorato.
Cosa ti servirà
Prima di toccare codice, ecco la lista completa. Buona notizia: questa versione ha bisogno di una sola chiave API, e tutto il resto gira gratis sulla tua macchina.
1. Python 3.9 o superiore. Per controllare se ce l'hai, apri il terminale (Terminale su Mac, Prompt dei comandi su Windows) e digita python --version. Se vedi qualcosa tipo 3.11, sei a posto. Altrimenti, scaricalo da python.org ed esegui l'installer. Su Windows, spunta la casella "Add Python to PATH" durante l'installazione, altrimenti i comandi qui sotto non funzioneranno.
2. Una chiave API di Claude, più un piccolo credito. Questa è l'unica chiave e l'unico denaro di cui ha bisogno tutta la guida. Ecco il percorso esatto, click per click:
Vai su platform.claude.com, e accedi (o registrati) lì.
L'API ha bisogno di un saldo positivo per funzionare, quindi aggiungi fondi prima. Quando richiesto, scegli se i crediti sono per te o per un'azienda, poi arrivi alla schermata di pagamento. Scegli l'opzione $5 "Starting out". È più che sufficiente: tutto il resto in questa guida è gratuito e locale, quindi Claude è l'unica cosa che costa denaro, e ogni domanda ti costa una frazione di centesimo. I crediti scadono un anno dopo l'acquisto.
Dopo il pagamento, atterrerai sulla dashboard della Console. Dovresti vedere il tuo saldo (ad esempio $5.00) in alto a sinistra sotto "Organization credits."
Ora prendi la chiave. Clicca Get API key (in alto a destra), poi Create Key. Dalle un nome qualsiasi (ad esempio my-rag-key) e lascia il workspace come Default. Clicca crea, poi copia la stringa che ti mostra. Inizia con sk-ant- e la vedi solo una volta, quindi incollala da qualche parte al sicuro per un minuto.
Questo è l'intero setup.
Passo 1: Aggiungi la tua chiave e carica i tuoi file
1. Crea la cartella del progetto. Crea una nuova cartella sul Desktop e chiamala rag-project. Tutto va qui.
2. Apri il tuo terminale. Su Mac: Cmd+Spazio, digita Terminale, Invio. Su Windows: pulsante Start, digita cmd, Invio.
3. Punta il terminale alla tua cartella. Digita cd e uno spazio, poi trascina la cartella rag-project sulla finestra del terminale e premi Invio. Ogni comando qui sotto viene eseguito dall'interno di questa cartella.
1cd Desktop/rag-project
4. Installa gli strumenti. Incolla questo nel terminale e premi Invio (la prima esecuzione potrebbe richiedere un minuto):
1pip install anthropic chromadb sentence-transformers pypdf python-dotenv
Se ottieni pip: command not found, usa pip3 al posto di pip. Quando il terminale mostra una riga nuova senza errori rossi, è fatto.
5. Crea il tuo file di codice. All'interno di rag-project, crea un file vuoto chiamato esattamente rag.py. Aprilo con qualsiasi editor di testo.
6. Crea il file della chiave. Nella stessa cartella, crea un file chiamato esattamente .env (inizia con un punto, nessun nome prima). Incolla questo dentro, con la chiave reale che hai creato durante il setup dopo il =, senza spazi, senza virgolette:
1ANTHROPIC_API_KEY=sk-ant-paste-your-real-key-here
Tenere la chiave in .env invece che nel codice significa che non perderai se condividi lo script o lo metti su GitHub.
7. Carica la chiave. Metti questo all'inizio di rag.py:
1import os2from dotenv import load_dotenv34load_dotenv() # legge il tuo file .env5api_key = os.getenv("ANTHROPIC_API_KEY")
8. Crea la tua base di conoscenza. All'interno di rag-project, crea una cartella chiamata documents. Metti lì qualsiasi file .txt, .md, o .pdf: i tuoi appunti, un documento di prodotto, riepiloghi di riunioni, qualsiasi cosa.
8.1. Se non hai ancora file, usa questo file di test. Crea notes.txt all'interno della cartella documents e incolla questo:
Project Northstar è il nostro strumento interno per tracciare il feedback dei clienti. È stato lanciato a marzo 2026 ed è gestito dal team della piattaforma. L'ingegnere capo è Dana Reyes. Il feedback viene revisionato ogni venerdì. Northstar ha sostituito il vecchio sistema di fogli di calcolo che abbiamo usato fino al 2025.
Alla fine chiederai a Claude informazioni su Northstar e lo vedrai rispondere usando proprio questo file.
9. Aggiungi il codice che legge i tuoi file. Sotto il codice del passo 7, in rag.py:
1from pathlib import Path2from pypdf import PdfReader34def load_documents(folder="documents"):5 docs = []6 for file in Path(folder).iterdir():7 if file.suffix in [".txt", ".md"]:8 text = file.read_text(encoding="utf-8")9 docs.append({"source": file.name, "text": text})10 elif file.suffix == ".pdf":11 reader = PdfReader(str(file))12 text = "\n".join(page.extract_text() or "" for page in reader.pages)13 docs.append({"source": file.name, "text": text})14 return docs1516documents = load_documents()17print(f"Caricati {len(documents)} documento/i.")
10. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Dovresti vedere:
Caricato 1 documento.
Se vedi Caricato 0 documento/i, la cartella documents è vuota o nel posto sbagliato. Deve stare direttamente dentro rag-project, accanto a rag.py.
Passo 2: Dividi i tuoi file in chunk
Al momento ogni file è un unico grande blocco di testo. Prima di poterlo cercare, dobbiamo tagliarlo in pezzi più piccoli chiamati chunk. Ecco perché: quando qualcuno fa una domanda, il sistema trova i chunk che corrispondono e invia solo quelli a Claude. Se i tuoi chunk sono interi documenti da 50 pagine, invii troppo. Se sono frasi singole, perdono contesto. I paragrafi brevi sono il punto giusto.
1. Aggiungi il codice per il chunking. Sotto il codice del passo 10, in rag.py:
1def chunk_text(text, chunk_size=500, overlap=100):2 words = text.split()3 chunks = []4 start = 05 while start < len(words):6 end = start + chunk_size7 chunk = " ".join(words[start:end])8 chunks.append(chunk)9 start = end - overlap # torna indietro un po' così i chunk si sovrappongono10 return chunks
Due numeri da capire qui, in parole semplici:
- chunk_size=500 significa che ogni chunk è di circa 500 parole. Abbastanza grande per contenere un'idea completa, abbastanza piccolo per rimanere preciso.
- overlap=100 significa che ogni chunk ripete le ultime 100 parole di quello precedente. Questo è importante perché una risposta potrebbe trovarsi proprio sul confine tra due chunk. Senza sovrapposizione, una frase tagliata a metà potrebbe perdersi. La sovrapposizione garantisce che nessuna idea cada nel vuoto.
2. Trasforma ogni documento in chunk. Aggiungi questo sotto:
1all_chunks = []2for doc in documents:3 for chunk in chunk_text(doc["text"]):4 all_chunks.append({"source": doc["source"], "text": chunk})56print(f"Creati {len(all_chunks)} chunk(s) da {len(documents)} documento/i.")
Nota che ogni chunk porta con sé la sua source (il nome del file da cui proviene). Lo teniamo attaccato per tutto il percorso, così quando Claude risponderà più tardi, potrà dirti da quale file proviene la risposta.
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Dovresti vedere qualcosa come:
Caricati 1 documento/i.
Creati 1 chunk(s) da 1 documento/i.
Il piccolo file di test diventa un solo chunk perché è breve. I documenti veri ne produrranno molti. Se hai messo un lungo PDF nella cartella, potresti vedere decine o centinaia di chunk, che è esattamente quello che vuoi.
Passo 3: Trasforma i tuoi chunk in embedding
Questo è il passaggio che permette al computer di cercare per significato invece che per parole esatte. Ogni chunk viene convertito in un elenco di numeri (un embedding) che cattura di cosa parla. I chunk con significati simili finiscono con numeri simili. Più tardi, quando arriva una domanda, trasformiamo anche la domanda in numeri e troviamo le corrispondenze più vicine.
Il modello che fa questo gira localmente sulla tua macchina. Si scarica una volta, poi funziona offline e gratuitamente, e i tuoi file non lasciano mai il tuo computer.
1. Carica il modello di embedding. Sotto il codice del passo 2, in rag.py:
1from sentence_transformers import SentenceTransformer23print("Caricamento del modello di embedding (primo download, circa 90 MB)...")4embedder = SentenceTransformer("all-MiniLM-L6-v2")
La primissima volta che esegui questo, scarica il modello, quindi concedigli un momento. Ogni esecuzione successiva è immediata perché è già sulla tua macchina.
2. Trasforma ogni chunk in un embedding. Aggiungi questo sotto:
1chunk_texts = [chunk["text"] for chunk in all_chunks]2embeddings = embedder.encode(chunk_texts)34print(f"Creati {len(embeddings)} embedding(s).")5print(f"Ogni embedding è un elenco di {len(embeddings[0])} numeri.")
embedder.encode(...) prende la tua lista di testi dei chunk e restituisce un embedding per ogni chunk. Tutto qui.
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
La prima esecuzione si ferma mentre il modello si scarica, poi dovresti vedere qualcosa come:
Caricati 1 documento/i.
Creati 1 chunk(s) da 1 documento/i.
Caricamento del modello di embedding (primo download, circa 90 MB)...
Creati 1 embedding(s).
Ogni embedding è un elenco di 384 numeri.
Quella riga "384 numeri" è l'intera idea resa visibile: il tuo testo è ora una riga di numeri che il computer può confrontare. Non devi leggere o capire quei numeri tu stesso. Il database nel prossimo passaggio gestisce tutti i confronti per te.
Se il download fallisce con un errore di connessione, esegui di nuovo il comando. Riprende da dove si era interrotto.
Passo 4: Memorizza tutto nel tuo database vettoriale
Ora mettiamo i chunk e i loro embedding in Chroma, il tuo database locale. Questo è ciò che rende la ricerca veloce: invece di confrontare la tua domanda con ogni chunk manualmente ogni volta, Chroma li memorizza pronti all'uso e fa la corrispondenza per te. Salva in una cartella sulla tua macchina, quindi lo costruisci solo una volta.
1. Configura il database. Sotto il codice del passo 3, in rag.py:
1import chromadb23client = chromadb.PersistentClient(path="chroma_db")4collection = client.get_or_create_collection("my_documents")
PersistentClient(path="chroma_db") dice a Chroma di salvare in una cartella chiamata chroma_db (la crea automaticamente, proprio accanto al tuo script). Poiché è salvato su disco, i tuoi dati sopravvivono dopo che lo script termina. Una collection è semplicemente la scatola con nome in cui vivono i tuoi chunk.
2. Aggiungi i tuoi chunk al database. Aggiungi questo sotto:
1collection.add(2 ids=[str(i) for i in range(len(all_chunks))],3 embeddings=[emb.tolist() for emb in embeddings],4 documents=[chunk["text"] for chunk in all_chunks],5 metadatas=[{"source": chunk["source"]} for chunk in all_chunks],6)78print(f"Memorizzati {collection.count()} chunk(s) nel database.")
Ecco cosa ogni riga passa a Chroma, in parole semplici: ids dà a ogni chunk un'etichetta univoca (0, 1, 2...), embeddings sono i numeri del passo 3, documents è il testo effettivo del chunk, e metadatas porta il nome del file così possiamo mostrare la fonte in seguito. Chroma tiene tutte e quattro le cose legate insieme.
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Dovresti vedere:
Memorizzati 1 chunk(s) nel database.
Una cosa da sapere per dopo. Ogni volta che esegui lo script ora, aggiunge di nuovo i chunk, quindi i conteggi possono salire (1, poi 2, poi 3...) su esecuzioni ripetute. Va bene mentre stiamo costruendo. Per ricominciare da zero, elimina la cartella chroma_db ed esegui di nuovo. Nella versione finale gestiremo questo correttamente in modo che non si duplichi.
Passo 5: Cerca nei tuoi documenti
Questa è la parte di "recupero" (retrieval) della RAG, la R nel nome. Prendiamo una domanda, la trasformiamo in un embedding come abbiamo fatto con i chunk, e chiediamo a Chroma i chunk il cui significato è più vicino. Quei chunk corrispondenti sono ciò che passeremo a Claude nel prossimo passaggio.
1. Aggiungi la funzione di ricerca. Sotto il codice del passo 4, in rag.py:
1def search(question, n_results=3):2 question_embedding = embedder.encode([question])[0]3 results = collection.query(4 query_embeddings=[question_embedding.tolist()],5 n_results=n_results,6 )7 return results
Cosa fa questo, riga per riga in parole semplici: trasforma la domanda in numeri con lo stesso modello che hai usato sui tuoi chunk (questo è importante, entrambi devono parlare lo stesso "linguaggio numerico"), poi chiede a Chroma le corrispondenze più vicine. n_results=3 significa "dammi i 3 chunk più rilevanti." Tre è un buon default: abbastanza contesto, non così tanto da sprecare token.
2. Prova una ricerca. Aggiungi questo sotto per testarlo:
1question = "Chi gestisce Northstar e quando viene revisionato il feedback?"2results = search(question)34for i, doc in enumerate(results["documents"][0]):5 source = results["metadatas"][0][i]["source"]6 print(f"\n--- Match {i+1} (da {source}) ---")7 print(doc)
Questo esegue una domanda reale contro il tuo database e stampa i chunk che ha trovato, ciascuno con il nome del file da cui proviene.
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Con il file di test Northstar, dovresti vederlo restituire il chunk corrispondente, qualcosa come:
--- Match 1 (da notes.txt) ---
Project Northstar è il nostro strumento interno per tracciare il feedback dei clienti. È stato lanciato a marzo 2026 ed è gestito dal team della piattaforma. L'ingegnere capo è Dana Reyes. Il feedback viene revisionato ogni venerdì. Northstar ha sostituito il vecchio sistema di fogli di calcolo che abbiamo usato fino al 2025.
Nota cosa è appena successo: la tua domanda usava le parole "chi gestisce" e "revisionato", ma il file dice "ingegnere capo" e "revisionato ogni venerdì". Ha comunque funzionato, perché la ricerca si basa sul significato, non sulle parole esatte. Questo è il punto centrale degli embedding, ed è il motivo per cui questo batte una semplice ricerca per parole chiave (Ctrl+F) nei tuoi file.
Se hai più file, vedrai i primi 3 chunk da tutti loro, ordinati per quanto corrispondono.
Passo 6: Fai rispondere Claude basandosi su ciò che ha trovato
Questa è la parte di "generazione", la G in RAG. Prendiamo i chunk del passo 5, li passiamo a Claude Opus 4.8 insieme alla domanda, e gli diciamo di rispondere usando solo quel contesto. Questo è ciò che impedisce di indovinare: Claude risponde dai tuoi file, non dalla propria memoria, e ti dice quale file ha usato.
1. Aggiungi la funzione di risposta. Sotto il codice del passo 5, in rag.py:
1import anthropic23claude = anthropic.Anthropic(api_key=api_key)45def answer(question):6 results = search(question)7 chunks = results["documents"][0]8 sources = [m["source"] for m in results["metadatas"][0]]910 context = ""11 for i, chunk in enumerate(chunks):12 context += f"[Da {sources[i]}]\n{chunk}\n\n"1314 message = claude.messages.create(15 model="claude-opus-4-8",16 max_tokens=1024,17 system=(18 "Rispondi alle domande usando solo il contesto fornito. "19 "Se la risposta non è nel contesto, di' che non lo sai. "20 "Menziona sempre da quale file proviene la tua risposta."21 ),22 messages=[23 {24 "role": "user",25 "content": f"Contesto:\n{context}\nDomanda: {question}",26 }27 ],28 )29 return message.content[0].text
Cosa succede qui, in parole semplici: cerchiamo i chunk rilevanti, li incolliamo insieme in un blocco di contesto (ciascuno etichettato con il nome del file), poi inviamo quel blocco più la domanda a Claude. L'istruzione system è la parte chiave. Dice a Claude tre cose: rispondi solo dal contesto, ammetti quando la risposta non c'è, e nomina il file di origine. Queste tre regole sono ciò che rende le risposte affidabili invece che inventate.
model="claude-opus-4-8" è il nome esatto del modello (trattini, non punti). max_tokens=1024 limita la lunghezza della risposta.
2. Fai una domanda. Aggiungi questo sotto:
1question = "Chi gestisce Northstar e quando viene revisionato il feedback?"2print(answer(question))
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Dovresti ottenere una risposta reale costruita dal tuo file, qualcosa come:
Dana Reyes è l'ingegnere capo che gestisce Project Northstar, e il feedback viene revisionato ogni venerdì. (Fonte: notes.txt)
Questo è un sistema RAG completo funzionante. Claude non ha mai visto questo file durante l'addestramento, non può sapere chi sia Dana Reyes, eppure ha risposto correttamente e ti ha detto esattamente da dove proveniva la risposta. Chiedigli qualcosa che non è nei tuoi file e dirà che non lo sa, invece di inventare una risposta. Quel "non lo so" è una caratteristica, non un fallimento: è la differenza tra uno strumento di cui ti puoi fidare e uno che indovina.
Passo 7: Trasformalo in qualcosa di effettivamente utilizzabile
Al momento devi modificare il codice e rieseguire l'intero script ogni volta che vuoi chiedere qualcosa. Peggio ancora, ogni esecuzione rilegge i tuoi file e li riaggiunge al database, quindi i chunk si accumulano. Risolviamo entrambi: costruisci il database solo una volta, poi lascia che tu faccia domande in un ciclo, digitandole direttamente nel terminale.
1. Risolvi il problema della doppia aggiunta. Trova il blocco del passo 4 che aggiunge i chunk (la parte collection.add(...)) e sostituiscilo con questa versione, che costruisce il database solo se è vuoto:
1if collection.count() == 0:2 collection.add(3 ids=[str(i) for i in range(len(all_chunks))],4 embeddings=[emb.tolist() for emb in embeddings],5 documents=[chunk["text"] for chunk in all_chunks],6 metadatas=[{"source": chunk["source"]} for chunk in all_chunks],7 )8 print(f"Memorizzati {collection.count()} chunk(s) nel database.")9else:10 print(f"Database ha già {collection.count()} chunk(s), ricostruzione saltata.")
Ora il lavoro pesante (leggere file, creare embedding, riempire il database) avviene solo la prima volta. Le esecuzioni successive saltano direttamente alla risposta.
2. Aggiungi il ciclo delle domande. In fondo a rag.py, sostituisci la singola domanda di test del passo 6 con questo:
1print("\nFai una domanda sui tuoi documenti (o digita 'quit' per uscire).\n")23while True:4 question = input("Tu: ")5 if question.lower() in ["quit", "exit"]:6 break7 print("\nClaude: " + answer(question) + "\n")
input("Tu: ") aspetta che tu scriva una domanda e premi Invio. while True lo mantiene attivo così puoi farne quante ne vuoi. Digitare quit lo ferma.
3. Eseguilo. Salva rag.py, poi nel tuo terminale:
1python rag.py
Ora puoi semplicemente parlare con i tuoi file:
Fai una domanda sui tuoi documenti (o digita 'quit' per uscire).
Tu: chi è l'ingegnere capo di Northstar?
Claude: L'ingegnere capo di Project Northstar è Dana Reyes. (Fonte: notes.txt)
Tu: cosa ha sostituito?
Claude: Northstar ha sostituito il vecchio sistema di fogli di calcolo usato fino al 2025. (Fonte: notes.txt)
Tu: quit
Questo è il tuo sistema RAG finito. Legge i tuoi file una volta, li ricorda e risponde alle domande su di essi a richiesta, con la fonte ogni volta.
Una cosa da sapere quando aggiungi nuovi file. Poiché il database ora viene costruito solo una volta, inserire nuovi file in documents non verrà mostrato automaticamente. Per caricare nuovi file, elimina la cartella chroma_db ed esegui lo script una volta. Ricostruisce da zero con tutto ciò che è nella cartella.
Opzionale: dagli una finestra chat nel tuo browser
Il terminale funziona, ma se vuoi una vera finestra chat, Streamlit ne aggiunge una in circa 20 righe.
1. Installalo. Nel tuo terminale:
1pip install streamlit
2. Crea app.py nella stessa cartella e incolla questo. Riutilizza la funzione answer dal tuo rag.py:
1import streamlit as st2from rag import answer34st.title("Chatta con i tuoi documenti")56if "history" not in st.session_state:7 st.session_state.history = []89question = st.chat_input("Chiedi qualcosa sui tuoi file...")1011if question:12 reply = answer(question)13 st.session_state.history.append((question, reply))1415for q, a in st.session_state.history:16 st.chat_message("user").write(q)17 st.chat_message("assistant").write(a)
3. Eseguilo. Nel tuo terminale (nota: streamlit run, non python):
1streamlit run app.py
Apre automaticamente una finestra chat nel tuo browser. Scrivi una domanda, ottieni una risposta con la sua fonte, proprio come il terminale ma più bello da vedere.
Una nota: affinché funzioni, il ciclo delle domande del passo 7 non deve essere eseguito all'importazione. Avvolgi quel ciclo in fondo a rag.py in if __name__ == "__main__": in modo che si attivi solo quando esegui rag.py direttamente, non quando app.py lo importa.
Permettere di rispondere anche a domande generali
Se vuoi che risponda anche a domande generali. Al momento il sistema risponde solo dai tuoi file, quindi una domanda come "qual è la capitale del Venezuela?" ottiene "non è nei documenti", anche se Claude conosce la risposta. Se vuoi che ricada sulle proprie conoscenze, apri rag.py, trova il blocco system=(...) nel passo 6 e sostituisci questa riga:
1"Se la risposta non è nel contesto, dì che non lo sai."
per questo:
1"Se la risposta non è nel contesto, rispondi usando la tua conoscenza generale ma dichiara che lo stai facendo."
Salva ed esegui di nuovo. Ora risponde prima dai tuoi file e, se questi non coprono la domanda, ricorre alla conoscenza generale, indicandoti quale fonte ha usato.
Conclusione
Hai appena costruito un sistema RAG funzionante. Legge i tuoi file, trova le parti che contano e fa rispondere Claude attingendo da esse, indicando ogni volta la fonte esatta. La stessa configurazione scala da poche note all'intera base di conoscenza.
Da qui è tuo da indirizzare dove vuoi: il tuo vault Obsidian, i tuoi documenti di lavoro, le tue ricerche salvate. Carica i file, ricostruisci una volta e inizia a chiedere. Tutto ciò che hai imparato qui, i chunk, gli embedding, la ricerca, la risposta, è la stessa base dietro ogni strumento "chatta con i tuoi documenti" che hai visto.
Se questo ti è stato utile, vai sul mio profilo e seguimi. Scrivo di tecnologia, IA e sistemi che funzionano davvero.





