Modelli locali con Ollama: cosa ci fai davvero

Far girare un LLM sul proprio computer è diventato un comando da terminale. Ma cosa ci si può fare realisticamente, con quanta RAM, e quando conviene? Un tutorial pratico con codice Python, senza illusioni.

Sul laptop con cui sto scrivendo, un modello linguistico da otto miliardi di parametri risponde in italiano, riassume documenti e scrive codice. Non manda un solo byte fuori dalla macchina, non costa nulla a chiamata e funziona anche in aereo. Tre anni fa sarebbe sembrato un trucco; oggi è un comando da terminale. Il merito è di due cose: la quantizzazione, che comprime i modelli fino a farli stare in memorie normali, e strumenti come Ollama, che nascondono tutta la complessità dietro un’interfaccia da manuale.

Questo tutorial fa due cose: ti porta da zero a interrogare un modello locale da Python, e ti dice — senza illusioni — cosa puoi aspettarti davvero dal tuo hardware.

Installazione e primo modello

Ollama è un runtime open source che scarica, gestisce ed esegue modelli open weights (Llama, Qwen, Gemma, Mistral e molti altri) esponendoli su un server locale. Su Linux si installa con uno script, su macOS e Windows con un installer dal sito ufficiale:

curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3.2      # scarica un modello da 3B, ~2 GB
ollama run llama3.2       # chat interattiva nel terminale

Il comando pull funziona come per le immagini Docker: scarica il modello una volta sola e lo tiene in una cache locale. Da quel momento Ollama espone una API REST su localhost:11434, ed è lì che entra in gioco Python.

Parlare col modello da Python

Il pacchetto ufficiale si installa con pip install ollama. La chiamata di base ricalca il formato a messaggi ormai standard:

import ollama

risposta = ollama.chat(
    model="llama3.2",
    messages=[
        {"role": "system",
         "content": "Rispondi in italiano, in modo conciso."},
        {"role": "user",
         "content": "Spiega la quantizzazione in due frasi."},
    ],
)
print(risposta["message"]["content"])

Per un uso interattivo conviene lo streaming, che mostra i token man mano che vengono generati invece di far attendere la risposta completa:

stream = ollama.chat(
    model="llama3.2",
    messages=[{"role": "user",
               "content": "Tre usi sensati di un LLM locale?"}],
    stream=True,
)
for pezzo in stream:
    print(pezzo["message"]["content"], end="", flush=True)

E siccome il server locale parla HTTP, puoi anche fare a meno del pacchetto e usare requests: utile per capire che sotto non c’è nessuna magia, solo una API sulla tua macchina:

import requests

r = requests.post(
    "http://localhost:11434/api/generate",
    json={"model": "llama3.2",
          "prompt": "Completa: il vantaggio di un modello locale è",
          "stream": False},
)
print(r.json()["response"])

Personalizzare il modello con un Modelfile

Ripetere lo stesso prompt di sistema a ogni chiamata è scomodo. Ollama risolve con il Modelfile, un file di configurazione che ricorda il Dockerfile: parti da un modello esistente, gli cuci addosso istruzioni e parametri, e ne ottieni una versione tua pronta all’uso. Salva queste righe in un file chiamato Modelfile:

FROM llama3.2

# istruzioni permanenti, valide per ogni conversazione
SYSTEM """Sei un assistente editoriale italiano.
Rispondi in modo conciso e non inventare fonti."""

# temperatura bassa = risposte piu' prevedibili
PARAMETER temperature 0.3

Poi lo si registra una volta e lo si usa come qualsiasi altro modello, anche da Python passando il nuovo nome a model=:

ollama create redattore -f Modelfile
ollama run redattore "Riscrivi in modo piu' chiaro: ..."

È l’equivalente locale di un «assistente configurato»: il comportamento è fissato nel modello, non ripetuto a ogni richiesta. Utile quando lo stesso profilo serve a più script.

La domanda vera: quanta memoria hai?

Qui il tutorial diventa una questione di fisica. Un modello quantizzato a 4 bit occupa all’incirca mezzo gigabyte per miliardo di parametri, più un margine per il contesto: un 8B chiede circa 5-6 GB, un 70B oltre 40. La memoria che conta è quella accessibile alla GPU — la VRAM su PC con scheda dedicata, la memoria unificata sui Mac Apple Silicon. Se il modello non ci sta, Ollama lo fa girare (in tutto o in parte) su CPU: funziona, ma la velocità crolla da «conversazione» a «attesa».

L’analogia giusta è la cilindrata: non esiste il modello «migliore» in assoluto, esiste il più grande che il tuo motore muove a velocità accettabile.

Memoria GPU disponibile → modelli possibili (quantizzazione 4 bit) 8 GB fino a ~8B · chat, riassunti, codice semplice 16 GB fino a ~14B · RAG locale, buon coding 24 GB fino a ~32B · lavoro serio quotidiano 48+ GB ~70B · vicino ai modelli via API Regola pratica: ~0,5 GB per miliardo di parametri a 4 bit, più 1-3 GB di margine per il contesto.

Cosa puoi far girare in base alla memoria GPU (o unificata, sui Mac). Le soglie sono indicative e valgono per la quantizzazione a 4 bit, quella usata di default da Ollama.

Un esempio concreto: estrarre dati da testo, gratis e offline

Dove un modello locale rende di più non è la chat, ma l’elaborazione ripetitiva: classificare, estrarre, riformattare centinaia di testi senza pagare una API a chiamata e senza mandare dati fuori. Ecco un estrattore di informazioni strutturate che forza l’output in JSON:

import json
import ollama

recensioni = [
    "Consegna rapidissima ma il prodotto è arrivato graffiato.",
    "Ottimo rapporto qualità-prezzo, lo ricomprerei.",
    "Assistenza clienti inesistente, esperienza pessima.",
]

schema = {
    "type": "object",
    "properties": {
        "sentimento": {"type": "string",
                       "enum": ["positivo", "negativo", "misto"]},
        "tema": {"type": "string"},
    },
    "required": ["sentimento", "tema"],
}

for testo in recensioni:
    r = ollama.chat(
        model="llama3.2",
        messages=[{"role": "user",
                   "content": f"Analizza questa recensione: {testo}"}],
        format=schema,   # output vincolato allo schema JSON
    )
    print(json.loads(r["message"]["content"]))

Il parametro format vincola la generazione allo schema: niente parsing fragile di testo libero. Su un laptop con 8 GB questo giro processa qualche recensione al secondo — lento per un servizio pubblico, perfetto per un batch notturno sui tuoi dati.

Cosa ci fai davvero (e cosa no)

Dopo qualche settimana di uso reale, il bilancio onesto è questo. Un modello locale nella fascia 8-14B è genuinamente utile per: riassunti e bozze, estrazione e classificazione di testi, ricerca semantica sui propri documenti (gli embedding locali, via ollama.embed, sono ottimi), completamento di codice, e qualsiasi cosa coinvolga dati che non vuoi o non puoi mandare a terzi.

Dove invece i modelli piccoli deludono: ragionamento a più passaggi, domande di cultura generale molto specifiche (meno parametri significa letteralmente meno cose memorizzate), lingue diverse dall’inglese su modelli piccoli — l’italiano migliora sensibilmente salendo di taglia — e tutto ciò che richiede affidabilità da produzione. Un 8B locale non è un modello di frontiera compresso: è un altro strumento, con un altro punto di equilibrio.

Il modello locale non sostituisce l’API di frontiera: la complementa. Uno gestisce il volume e i dati sensibili, l’altra i casi difficili.

Perché ti riguarda

Provare Ollama costa mezz’ora e zero euro, e ti dà tre cose. La prima è un laboratorio personale: puoi sperimentare prompt, embedding e fine-tuning senza contatori che girano. La seconda è un’opzione strategica: sapere cosa gira in casa ti dice quanto sei davvero dipendente dai fornitori cloud, ed è la stessa domanda che si fanno le aziende quando valutano i costi dell’AI su larga scala. La terza è la comprensione: quando il modello gira sulla tua macchina, con la tua memoria e i tuoi limiti, smette di essere un oracolo remoto e diventa quello che è — un file di pesi, un runtime, e una quantità sorprendente di cose utili che puoi già fare oggi.

I commenti sono riservati agli iscritti.

Accedi per commentare