Immagina di poter fare domande in linguaggio naturale a una cartella di PDF — manuali, contratti, dispense, bilanci — e ricevere risposte precise con tanto di riferimento alla fonte, tutto sul tuo computer, senza mandare un solo documento su internet. È quello che permette la tecnica RAG (Retrieval-Augmented Generation): un modello linguistico che, prima di rispondere, recupera i passaggi rilevanti dai tuoi documenti. In questa guida costruiamo un sistema RAG gratuito e completamente locale con Ollama e Python.

Con la tecnica RAG puoi interrogare i tuoi PDF in linguaggio naturale, in locale.

A chi serve, cosa otterrai e i prerequisiti

Questa guida è pensata per chi ha una minima dimestichezza con il terminale e vuole un assistente che risponda sui propri documenti senza usare servizi cloud — utile per motivi di riservatezza (dati aziendali, sanitari, legali) o semplicemente per non pagare abbonamenti. Alla fine avrai uno script Python che carica i PDF di una cartella, li indicizza e risponde alle tue domande citando i brani usati.

Prerequisiti reali:

  • Un computer con Windows, macOS o Linux e almeno 8 GB di RAM (16 GB consigliati per modelli più grandi).
  • Python 3.10 o superiore installato.
  • Circa 5-6 GB di spazio libero per i modelli.
  • Nessun account e nessuna carta di credito: tutto gira in locale.

Quali strumenti IA useremo e perché

Il cuore del sistema è Ollama, il programma gratuito e open source che scarica ed esegue modelli linguistici in locale con un comando. Ci servono due modelli:

  • Un modello di generazione, che scrive le risposte. Consiglio come prima scelta llama3.1:8b (ottimo equilibrio qualità/risorse) o qwen2.5:7b; su macchine potenti si può salire di dimensione.
  • Un modello di embedding, che trasforma il testo in vettori numerici per la ricerca semantica: nomic-embed-text è leggero, veloce e gratuito.

Per la parte di codice useremo LangChain (che orchestra caricamento, suddivisione e interrogazione) e Chroma come database vettoriale locale. Perché questa combinazione e non un servizio cloud? Pro: gratis, privato, nessun limite d'uso. Contro: la qualità dipende dall'hardware e dal modello, e i modelli locali sono meno brillanti dei migliori modelli chiusi. Se ti serve la massima qualità e la privacy non è un vincolo, valuta in alternativa le API di OpenAI, Anthropic o Google; ma per iniziare, e per i dati sensibili, il locale è la scelta giusta.

Passo 1: installare Ollama e i modelli

Scarica Ollama dal sito ufficiale (ollama.com) e installalo. Poi, da terminale, scarica i due modelli:

ollama pull llama3.1:8b
ollama pull nomic-embed-text

Verifica che Ollama risponda:

ollama run llama3.1:8b "Dimmi ciao in italiano"

Se ricevi un saluto, sei pronto. Ollama resta attivo in background ed espone un servizio locale sulla porta 11434, che il nostro script userà.

Passo 2: installare le librerie Python

Crea una cartella per il progetto, mettici dentro i tuoi PDF in una sottocartella documenti/ e installa le dipendenze:

pip install langchain langchain-community langchain-ollama chromadb pypdf
Poche librerie Python bastano per indicizzare e interrogare i documenti.

Passo 3: indicizzare i PDF

Questo script legge tutti i PDF nella cartella, li divide in blocchi (chunk), calcola gli embedding e li salva in un database Chroma su disco. Salvalo come indicizza.py:

from langchain_community.document_loaders import PyPDFDirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_ollama import OllamaEmbeddings
from langchain_community.vectorstores import Chroma

# 1. Carica tutti i PDF della cartella
loader = PyPDFDirectoryLoader("documenti/")
pagine = loader.load()
print(f"Caricate {len(pagine)} pagine")

# 2. Dividi in blocchi con un po' di sovrapposizione
splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=150
)
blocchi = splitter.split_documents(pagine)
print(f"Creati {len(blocchi)} blocchi")

# 3. Calcola gli embedding e salvali in Chroma
embeddings = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma.from_documents(
    blocchi, embeddings, persist_directory="./chroma_db"
)
print("Indice creato in ./chroma_db")

Esegui con python indicizza.py. Alla fine avrai una cartella chroma_db con l'indice: va rifatto solo quando aggiungi o cambi i documenti.

Passo 4: fare domande ai documenti

Ora lo script che risponde. Recupera i blocchi più pertinenti, li passa al modello e stampa la risposta con le fonti. Salvalo come chiedi.py:

from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain_community.vectorstores import Chroma

embeddings = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
llm = ChatOllama(model="llama3.1:8b", temperature=0.1)

domanda = input("Domanda: ")

# Recupera i 4 blocchi piu' rilevanti
risultati = db.similarity_search(domanda, k=4)
contesto = "\n\n".join(d.page_content for d in risultati)

prompt = f"""Rispondi alla domanda usando SOLO il contesto qui sotto.
Se la risposta non e' nel contesto, di' che non e' presente nei documenti.
Rispondi in italiano e in modo conciso.

CONTESTO:
{contesto}

DOMANDA: {domanda}
"""

risposta = llm.invoke(prompt)
print("\nRISPOSTA:\n", risposta.content)
print("\nFONTI:")
for d in risultati:
    print("-", d.metadata.get("source"), "pag.", d.metadata.get("page"))

Esegui con python chiedi.py, digita una domanda e otterrai la risposta più il riferimento ai file e alle pagine usate. Il vincolo "usa solo il contesto" riduce le allucinazioni: se l'informazione non c'è, il modello lo dichiara invece di inventare.

Prompt di prova e risultato atteso

Supponiamo di aver caricato il manuale di un elettrodomestico. Una domanda tipo:

Qual è la temperatura massima consigliata per il lavaggio dei capi delicati e ogni quanto va pulito il filtro?

Il sistema recupererà i paragrafi pertinenti del manuale e risponderà con i valori esatti citati nel testo, indicando le pagine. Se chiedi qualcosa che il manuale non copre (per esempio "quanto consuma in standby?" quando il dato non c'è), risponderà che l'informazione non è presente nei documenti: esattamente il comportamento che vogliamo.

Varianti e casi avanzati

Alcuni miglioramenti utili quando prendi confidenza:

  • Modello più capace: se hai una buona GPU, sostituisci llama3.1:8b con un modello più grande (per esempio qwen2.5:14b) per risposte più accurate.
  • Interfaccia grafica: collega Open WebUI a Ollama per avere un'esperienza simile a ChatGPT con caricamento documenti dal browser, senza scrivere codice.
  • Citazioni più precise: aumenta k per recuperare più contesto, o riduci chunk_size per blocchi più mirati.
  • Molti documenti: con migliaia di pagine valuta un database vettoriale più robusto come Qdrant.

Errori comuni e soluzioni

  • ConnectionError o "connection refused": Ollama non è in esecuzione. Avvialo (l'app o il comando ollama serve) e riprova.
  • Risposte lente: normale su CPU; usa un modello più piccolo o abilita la GPU. La prima domanda è sempre più lenta perché il modello viene caricato in memoria.
  • Risposte "vuote" o fuori tema: probabilmente i PDF sono scansioni-immagine senza testo selezionabile. In quel caso serve un passaggio OCR (per esempio con Tesseract) prima dell'indicizzazione.
  • Chroma che non trova l'indice: assicurati di aver eseguito indicizza.py e che la cartella chroma_db esista.

Quando non usare questo approccio e come proseguire

Il RAG locale è ideale per documenti riservati e per un uso personale o di piccolo team. Non è la scelta migliore se hai bisogno della massima qualità di ragionamento su testi molto complessi, o se devi servire tanti utenti contemporaneamente: in quei casi conviene passare a modelli via API (OpenAI, Anthropic, Google) o a soluzioni gestite, accettando però che i dati escano dalla tua macchina. Come passo successivo puoi trasformare questi script in una piccola app web con Streamlit, aggiungere la cronologia della conversazione, o integrare un modello aperto più potente come GLM-5.2 via API. Il concetto resta lo stesso: recuperare prima, generare poi — è questa la ricetta che rende un modello davvero utile sui tuoi dati.

Comandi e nomi dei modelli sono aggiornati a luglio 2026; consulta la documentazione ufficiale di Ollama e LangChain, che vengono aggiornate di frequente.