Intermedio 20 minPython

Creare un agente IA locale in Python con LangChain e Ollama

Un agente IA locale in Python con LangChain e Ollama non è semplicemente un chatbot: è un programma che decide da solo quando chiamare una funzione, leggere un file o eseguire più passaggi in sequenza per rispondere. Questa guida realizza passo dopo passo un agente funzionante in una ventina di minuti, con un modello Qwen 3.5 9B che gira interamente sul tuo computer. Zero chiavi API, zero dati inviati a terzi.

Di Mohamed Meguedmi·Agg. 2026-08-27·Testato su Windows, macOS e Linux

#Perché un agente IA locale in Python?

Un agente, nel senso di LangChain, è un semplice ciclo: il LLM riceve una domanda e la lista dei suoi strumenti, sceglie di chiamarne uno (oppure no), legge il risultato e ricomincia finché non può rispondere. Tutto il meccanismo di "decisione" si basa sulla capacità del modello di generare una chiamata strutturata a uno strumento.

Farlo in locale, con Ollama, cambia due cose concrete: i tuoi dati non escono mai dalla macchina e ogni chiamata costa zero euro. È la differenza tra creare prototipi con OpenAI e ritrovarsi una fattura di 50 € a fine settimana, e iterare senza badare al numero di chiamate.

Privacy
I file letti dall'agente (contratti, codice proprietario, note mediche) non escono dal computer. Nessun DPA da firmare, nessun trasferimento al di fuori dell'UE.
Costo marginale nullo
Una volta scaricato il modello, puoi iterare centinaia di volte al giorno senza che la fattura aumenti.
Riproducibilità
Fissi la versione esatta del modello (qwen3.5:9b, granite4.2:8b, ecc.). Nessun drift silenzioso come con gpt-4o-2024-11-20 che diventa un'altra cosa un mese dopo.
Latenza prevedibile
Nessun viaggio di andata e ritorno sulla rete. Su una GPU adeguata, il primo token arriva in meno di un secondo.
i
Non è magico nemmeno questo
Un modello locale 9B resta più debole di GPT-5 o Claude 4.7 su compiti molto complessi. Per l'80% degli agenti utili (leggere un file, chiamare un'API interna, eseguire un calcolo, classificare un'email), è ampiamente sufficiente. Per il resto, è un ottimo terreno di apprendimento prima di pagare per i token.

#Prerequisiti

Il kit Copilota Locale

Questa guida ti porta al modello. Il kit ti porta al copilota che scrive codice nel tuo editor.

  • Spazio online a vita
  • PDF + file
  • Aggiornamenti a vita
Python 3.10+
LangChain non è più testato su 3.9. Verifica con python --version.
Ollama installato e avviato
Deve essere in ascolto su http://localhost:11434. Consultare le guide di installazione di Ollama (Windows, macOS, Linux) se non è già stato installato e avviato.
Un modello che sa chiamare strumenti
Non tutti i LLM ne sono capaci. Qwen 3.5, Granite 4.2, Gemma 4, Devstral e GLM 4.7 Flash supportano nativamente il tool calling. Evita i modelli ormai obsoleti (Llama 2/3, Qwen 2.5, Mistral 7B).
Hardware
Qwen 3.5 9B Q4 occupa circa 6,6 GB di VRAM. Una GPU da 8 GB (RTX 3060, 4060) basta, una da 12 GB (4070) offre un margine. Su Mac, considera 16 GB di memoria unificata per avere un po' di respiro.
→
La scelta del modello è critica
Con un modello che non sa chiamare correttamente gli strumenti, il tuo agente genererà argomenti inventati o risponderà in testo libero invece di produrre un tool call. Se sei alle prime armi, rimani su qwen3.5:9b — è il punto ottimale qualità / VRAM nel 2026.

#1. Inizializzare il progetto Python

Un ambiente virtuale, tre pacchetti e basta. Evitiamo di installare LangChain nell'ambiente Python di sistema: cambia rapidamente e ingombra l'ambiente.

Creare e attivare il venv
mkdir agent-local && cd agent-local
python -m venv .venv

# macOS / Linux
source .venv/bin/activate

# Windows PowerShell
# .venv\Scripts\Activate.ps1
Installare le dipendenze
pip install --upgrade pip
pip install langchain langchain-ollama langgraph
langchain
Il cuore: astrazioni dei prompt, degli strumenti, dei messaggi.
langchain-ollama
Integrazione ufficiale Ollama. Mantenuta dal team LangChain dal 2024.
langgraph
Per il ciclo degli agenti. È il motore consigliato oggi, più stabile dei vecchi AgentExecutor.
i
Perché langgraph piuttosto che AgentExecutor?
I vecchi tutorial di LangChain utilizzano AgentExecutor + create_react_agent (da langchain.agents). Questa API è in modalità manutenzione. La documentazione ufficiale indica ora langgraph.prebuilt.create_react_agent — è questo che utilizzeremo qui. Più semplice, con una migliore tipizzazione e streaming gratuito.

#2. Collegare Ollama da Python

Prima di creare un agente, si verifica che si stia effettivamente comunicando con il modello. Scarica il modello se non l'hai già fatto, poi prova la chiamata più semplice possibile.

Scarica Qwen 3.5 9B
ollama pull qwen3.5:9b

Il download è di circa 6,6 GB in Q4_K_M (la quantizzazione predefinita di Ollama). Una volta installato il modello, crea il primo script:

test_ollama.py
from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen3.5:9b",
    temperature=0,
    # base_url="http://localhost:11434",  # par défaut, à changer si Ollama est ailleurs
)

reponse = llm.invoke("En une phrase : qu'est-ce qu'un agent IA ?")
print(reponse.content)
Avviare il test
python test_ollama.py

Se vedi una frase coerente, la connessione Python ↔ Ollama funziona. Se ottieni una ConnectionError, verifica che Ollama sia in esecuzione (ollama ps deve elencare un servizio attivo).

→
temperature=0 per gli agenti
Vogliamo un comportamento deterministico quando il modello sceglie uno strumento. Una temperatura elevata fa variare le chiamate agli strumenti da un'esecuzione all'altra — è un inferno da sottoporre a debug. Per le risposte creative, aumenta di nuovo la temperatura a 0.7 in seguito.

#3. Definire gli strumenti dell'agente

Un tool di LangChain è semplicemente una funzione Python decorata con @tool. La docstring diventa la descrizione che vede il LLM — il modello la usa per decidere quando chiamare il tool. Sii preciso: una docstring vaga genera chiamate casuali.

Creeremo due strumenti rappresentativi: un valutatore di espressioni aritmetiche e un lettore di file.

tools.py
from pathlib import Path
from langchain_core.tools import tool


@tool
def calculer(expression: str) -> str:
    """Évalue une expression arithmétique simple.

    Args:
        expression: une expression contenant uniquement des chiffres,
                    des espaces et les opérateurs + - * / ( ).

    Returns:
        Le résultat numérique sous forme de chaîne, ou un message d'erreur.
    """
    autorise = set("0123456789+-*/(). ")
    if not all(c in autorise for c in expression):
        return "Erreur : caractère non autorisé. Seuls 0-9 et + - * / ( ) sont permis."
    try:
        resultat = eval(expression, {"__builtins__": {}}, {})
        return str(resultat)
    except Exception as e:
        return f"Erreur de calcul : {e}"


@tool
def lire_fichier(chemin: str) -> str:
    """Lit le contenu d'un fichier texte du répertoire courant.

    Args:
        chemin: chemin relatif ou absolu vers un fichier texte (.txt, .md, .py, etc.).

    Returns:
        Le contenu du fichier, ou un message d'erreur si introuvable.
    """
    p = Path(chemin)
    if not p.exists():
        return f"Fichier introuvable : {chemin}"
    if not p.is_file():
        return f"Ce n'est pas un fichier : {chemin}"
    try:
        return p.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        return "Fichier binaire ou encodage non UTF-8."
    except Exception as e:
        return f"Erreur de lecture : {e}"
!
eval() è pericoloso in produzione
L'uso di eval(), anche con __builtins__ vuoto, non è una vera sandbox. Per un agente che funziona sul tuo computer e che tu controlli, è accettabile. Per qualsiasi cosa esposta a utenti esterni, usa ast.parse con una whitelist degli operatori, o la libreria simpleeval.

Tre regole per strumenti che il modello usa correttamente:

Nome esplicito
calculer anziché process, lire_fichier anziché get. Il LLM sceglie innanzitutto in base al nome.
Docstring dettagliata
Descrivi cosa fa lo strumento, quali input si aspetta e cosa restituisce. Le annotazioni di tipo Python vengono lette da LangChain ed esposte al modello.
Restituire una stringa
Sempre. Se la funzione restituisce un dict o un oggetto, LangChain lo serializza, ma il risultato è meno leggibile per il modello.

#4. Assemblare l'agente

Abbiamo un LLM, abbiamo degli strumenti. La funzione create_react_agent di langgraph collega i due e gestisce il ciclo: finché il modello vuole chiamare strumenti, continuiamo; quando risponde con del testo, ci fermiamo.

agent.py
from langchain_ollama import ChatOllama
from langgraph.prebuilt import create_react_agent
from tools import calculer, lire_fichier

llm = ChatOllama(model="qwen3.5:9b", temperature=0)

SYSTEM_PROMPT = (
    "Tu es un assistant en français. Tu disposes d'outils pour calculer "
    "et lire des fichiers. Utilise-les dès que c'est pertinent, sans jamais "
    "inventer un résultat. Réponds toujours en français."
)

agent = create_react_agent(
    model=llm,
    tools=[calculer, lire_fichier],
    prompt=SYSTEM_PROMPT,
)

if __name__ == "__main__":
    question = (
        "Combien fait 1234 * 5678 ? "
        "Ensuite, lis le fichier notes.txt et résume-le en deux phrases."
    )
    reponse = agent.invoke({"messages": [("user", question)]})

    # Le dernier message est la réponse finale du modèle
    print(reponse["messages"][-1].content)

Crea un piccolo file notes.txt accanto per testare:

File di test
echo "Réunion projet Hermes : on garde Ollama comme runtime principal, on évalue vLLM pour la prod, RAG sur ChromaDB. Décision : POC en 2 semaines." > notes.txt

#5. Eseguire e osservare il ciclo

Avviare l'agente
python agent.py

Dovresti vedere una risposta che contiene sia il risultato del calcolo (7 006 652) sia un riassunto del file. Ma è più istruttivo vedere cosa accade durante l'esecuzione. Aggiungi questa modalità verbose per seguire il ciclo passo passo:

Modalità streaming dettagliata
for evenement in agent.stream(
    {"messages": [("user", question)]},
    stream_mode="values",
):
    dernier = evenement["messages"][-1]
    dernier.pretty_print()
    print("---")

Osserverai la sequenza tipica di un agente: il modello genera una chiamata a calculer, riceve il risultato, genera una chiamata a lire_fichier, riceve il contenuto e poi genera la risposta finale. Tre iterazioni per una sola domanda dell'utente.

i
Se il modello non richiama gli strumenti
Due cause frequenti: (1) il modello non ha il tool calling attivato lato Ollama — esegui di nuovo ollama pull qwen3.5:9b per ottenere la versione più recente. (2) Il prompt di sistema è troppo vago. Specifica esplicitamente "usa gli strumenti per i calcoli" invece di sperare che lo intuisca.

#Suggerimenti e risoluzione dei problemi

Contesto troppo breve
Per impostazione predefinita, Ollama tronca a 2048 token. Se il tuo agente esegue più strumenti in sequenza, questo limite viene superato rapidamente. Imposta num_ctx=8192 in ChatOllama(model="...", num_ctx=8192).
Modello che inventa strumenti
Se l'agente inventa nomi di funzioni, abbassa la temperatura a 0 e riformula il prompt di sistema elencando esplicitamente gli strumenti disponibili.
Loop infinito
Imposta un limite: create_react_agent(..., recursion_limit=10). Superato questo limite, l'agente si arresta correttamente.
Latenza troppo alta
Su CPU, un 9B fa 5-10 tok/s. Passa a qwen3.5:4b (3,4 GB VRAM, 30+ tok/s su GPU modesta) se la qualità rimane accettabile per il tuo caso.
Errore "context length exceeded"
Il riassunto di un file lungo supera num_ctx. Aggiungi uno strumento intermedio che suddivida il file in blocchi oppure aumenta num_ctx fino a 32768 se la tua VRAM lo permette.
→
Tracciare i propri agenti con LangSmith
Per debuggare seriamente, LangSmith traccia ogni chiamata, ogni token, ogni strumento. È gratuito in sviluppo. Imposta LANGSMITH_TRACING=true e LANGSMITH_API_KEY nell'ambiente e avrai una timeline completa. Nessun dato viene inviato se non definisci la chiave.

#Per approfondire

Hai un agente che calcola, legge, ragiona localmente. Tre direzioni naturali per approfondire:

Dargli accesso ai tuoi documenti
Collegare l'agente a un database vettoriale affinché possa rispondere sulla base di un corpus interno — è esattamente l'argomento della guida introduttiva al RAG locale.
Lavorare dalla CLI per programmare
Aider è un agente di sviluppo che modifica direttamente i tuoi file dal terminale. Puoi collegarlo allo stesso Ollama e sfruttare Qwen3-Coder 30B o Devstral per modificare i file con assistenza.
Regolare la quantizzazione del modello
Se trovi Qwen 3.5 9B Q4 troppo lento o appena sufficiente in termini di qualità, la guida alla quantizzazione spiega quando passare a Q5_K_M o scegliere un modello più piccolo.
Questa guida ti è stata utile?

Un feedback, un errore, una precisazione? Facci sapere, così la guida migliora per tutti.