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