1. Home
  2. iThink
  3. AI Locale & Agenti
  4. Ollama su GPU e CPU: setup e risoluzione dei problemi
AI Locale & Agenti Il Mio Primo Agente Digitale · Appendice

Ollama su GPU e CPU: setup e risoluzione dei problemi

Robot bianco, simbolo di un assistente digitale
Foto: StockSnap · Pixabay · Licenza dei contenuti Pixabay

VRAM calculator: la formula esatta

VRAM_GB = (Parametri_Miliardi × Bit_Per_Parametro) / 8 + KV_Cache_GB + Overhead_GB

Componenti

| Componente | Formula | Note | | ------------ | --------- | ------ | | Pesi modello | Params_B × Quant_Bits / 8 | Es. 7B × 4.5bit / 8 = 3.9 GB | | KV Cache | 2 × Layers × Hidden_Dim × Context × Bytes_Per_Param | Cresce linearmente con num_ctx | | Attention Overhead | ~10-20% pesi | Flash Attention riduce | | Attivazioni/Buffer | ~0.5-1 GB | Fisso per architettura | | OS/Driver | 1-2 GB | Riservato GPU |

Calcolo della KV cache (preciso)

def calculate_kv_cache_gb(
    num_layers: int,
    hidden_dim: int,
    num_kv_heads: int,  # GQA: spesso < num_attention_heads
    context_length: int,
    bytes_per_param: int = 2,  # fp16 = 2, fp8 = 1
) -> float:
    """Calcola KV cache in GB."""
    # 2 tensori (K + V) per layer
    # Shape per tensor: [batch, num_kv_heads, context, head_dim]
    # head_dim = hidden_dim / num_attention_heads
    head_dim = hidden_dim // 32  # Assumiamo 32 attention heads standard
    elements_per_layer = 2 * num_kv_heads * context_length * head_dim
    total_bytes = elements_per_layer * num_layers * bytes_per_param
    return total_bytes / (1024**3)


# Esempi reali
MODEL_SPECS = {
    "mistral-7b": {"layers": 32, "hidden": 4096, "kv_heads": 8},
    "llama-3.1-8b": {"layers": 32, "hidden": 4096, "kv_heads": 8},
    "gemma-2-9b": {"layers": 42, "hidden": 3584, "kv_heads": 8},
    "qwen-2.5-14b": {"layers": 48, "hidden": 5120, "kv_heads": 8},
    "llama-3.1-70b": {"layers": 80, "hidden": 8192, "kv_heads": 8},
}

for name, spec in MODEL_SPECS.items():
    for ctx in [4096, 8192, 16384, 32768, 131072]:
        kv = calculate_kv_cache_gb(**spec, context_length=ctx)
        print(f"{name} ctx={ctx}: KV Cache = {kv:.2f} GB")

Output tipico:

mistral-7b ctx=4096:   KV Cache = 0.52 GB
mistral-7b ctx=8192:   KV Cache = 1.04 GB
mistral-7b ctx=32768:  KV Cache = 4.17 GB
llama-3.1-70b ctx=4096: KV Cache = 4.19 GB
llama-3.1-70b ctx=131072: KV Cache = 134 GB (!) → Usa QLORA o sliding window

Quantizzazione GGUF: guida completa

| Quant | Bit/Param | Size 7B | Qualità | Speed | VRAM 7B | Uso Consigliato | | ------- | ----------- | --------- | --------- | ------- | --------- | ----------------- | | Q2_K | 2.5 | 2.1 GB | ⭐⭐ | ⚡⚡⚡⚡⚡ | 2.8 GB | Solo test, CPU vecchie | | Q3_K_S | 3.0 | 2.5 GB | ⭐⭐⭐ | ⚡⚡⚡⚡ | 3.2 GB | RAM 8GB limitata | | Q3_K_M | 3.4 | 2.8 GB | ⭐⭐⭐⭐ | ⚡⚡⚡⚡ | 3.5 GB | CPU-only, laptop | | Q3_K_L | 3.8 | 3.1 GB | ⭐⭐⭐⭐ | ⚡⚡⚡ | 3.8 GB | Qualità > velocità | | Q4_0 | 4.0 | 3.5 GB | ⭐⭐⭐⭐ | ⚡⚡⚡ | 4.2 GB | Legacy, compatibilità | | Q4_K_S | 4.2 | 3.7 GB | ⭐⭐⭐⭐⭐ | ⚡⚡⚡ | 4.4 GB | Alternativa Q4_K_M | | Q4_K_M | 4.5 | 3.8 GB | ⭐⭐⭐⭐⭐ | ⚡⚡⚡ | 4.5 GB | DEFAULT PRODUZIONE | | Q5_0 | 5.0 | 4.2 GB | ⭐⭐⭐⭐⭐ | ⚡⚡ | 4.9 GB | Qualità superiore | | Q5_K_S | 5.2 | 4.4 GB | ⭐⭐⭐⭐⭐ | ⚡⚡ | 5.1 GB | Sweet spot qualità | | Q5_K_M | 5.5 | 4.6 GB | ⭐⭐⭐⭐⭐⭐ | ⚡⚡ | 5.3 GB | Produzione alta qualità | | Q6_K | 6.5 | 5.4 GB | ⭐⭐⭐⭐⭐⭐ | ⚡ | 6.2 GB | Near-lossless | | Q8_0 | 8.0 | 6.7 GB | ⭐⭐⭐⭐⭐⭐⭐ | ⚡ | 7.5 GB | Benchmark, fine-tune base | | F16 | 16.0 | 13.5 GB | Originale | 🐢 | 14.5 GB | Solo training/export | | F32 | 32.0 | 27.0 GB | Originale | 🐢🐢 | 28 GB | Mai per inferenza |

Regole pratiche sulla quantizzazione

  1. Inizia sempre con Q4_K_M: è il miglior equilibrio tra qualità, velocità e VRAM
  2. Scendi a Q3_K_M se: OOM, CPU-only, RAM < 16GB
  3. Sali a Q5_K_M/Q6_K se: qualità insufficiente, VRAM abbondante
  4. Q8_0/F16 solo per: benchmark, merge LoRA, export per fine-tuning
  5. K-quants (K_S, K_M, K_L) > legacy (Q4_0, Q5_0) — migliori per stesso bitrate

Modelli consigliati per hardware (settembre 2026)

Laptop / Entry GPU (VRAM 6-8 GB / RAM 16 GB)

| GPU | Modello | Quant | Context | Note | | ----- | --------- | ------- | --------- | ------ | | RTX 3050/3060 6-8GB | Phi-3.5 Mini | Q4_K_M | 128k | Migliore per VRAM bassa | | RTX 3060 8GB | Mistral 7B / Llama 3.1 8B | Q4_K_M | 8k-32k | Standard | | RTX 3060 8GB | Gemma 2 9B | Q4_K_M | 8k | Safety built-in | | M1/M2/M3 8GB Unified | Phi-3.5 Mini / Mistral 7B | Q4_K_M | 128k/32k | Metal acceleration | | M1/M2/M3 16GB Unified | Llama 3.1 8B / Qwen 2.5 14B | Q4_K_M | 32k/128k | Best value Mac |

Mid-Range Desktop (VRAM 10-12 GB / RAM 32 GB)

| GPU | Modello | Quant | Context | Note | | ----- | --------- | ------- | --------- | ------ | | RTX 3070/3080 10-12GB | Qwen 2.5 14B | Q4_K_M | 32k-128k | Top coding/math | | RTX 3080 12GB | Llama 3.1 8B (128k ctx) | Q4_K_M | 128k | Long context RAG | | RTX 4070 12GB | Nemotron 3 Ultra 53B | Q3_K_M | 8k | Reasoning avanzato | | M2/M3 Pro 16-18GB | Qwen 2.5 14B / Llama 3.1 8B | Q4_K_M | 128k | Unified memory |

High-End Desktop (VRAM 24 GB / RAM 64 GB)

| GPU | Modello | Quant | Context | Note | | ----- | --------- | ------- | --------- | ------ | | RTX 3090/4090 24GB | Llama 3.1 70B | Q4_K_M | 8k-32k | Qualità GPT-4o tier | | RTX 4090 24GB | Nemotron 3 Ultra 53B | Q4_K_M | 16k | NVIDIA optimized | | RTX 4090 24GB | Qwen 2.5 72B | Q4_K_M | 8k | Top multilingue | | 2× RTX 3090 24GB (NVLink) | Llama 3.1 70B | Q5_K_M | 32k | Multi-GPU | | M2/M3 Max 48-96GB | Llama 3.1 70B / Nemotron 3 Ultra | Q4_K_M | 128k | Best price/perf |

Workstation / Server (VRAM 48-80 GB+)

| Config | Modello | Quant | Note | | -------- | --------- | ------- | ------ | | 2× RTX 4090 48GB | Llama 3.1 70B / 405B | Q6_K / Q2_K | Multi-GPU tensor parallel | | 4× RTX 4090 96GB | Llama 3.1 405B | Q4_K_M | Qualità piena | | 8× A100 80GB | Qualsiasi modello | Qualsiasi | Scala di produzione | | Mac Studio M2 Ultra 192GB | Llama 3.1 405B | Q4_K_M | Massimo su una sola macchina |


Errori comuni: i 20 più frequenti con le soluzioni

| # | Errore | Causa | Soluzione Rapida | | --- | -------- | ------- | ------------------ | | 1 | connection refused: localhost:11434 | Ollama daemon non avviato | ollama serve in terminale separato | | 2 | CUDA out of memory | Modello > VRAM | export OLLAMA_NUM_GPU_LAYERS=20, usa Q3_K_M | | 3 | Error: model not found | Tag sbagliato / non pullato | ollama list → verifica nome esatto → ollama pull | | 4 | Inferenza lentissima (>10s/token) | Swapping RAM↔Disk / CPU-only | Chiudi app, usa modello più piccolo, SSD NVMe | | 5 | ollama pull timeout / lento | Registry lento / rete | export OLLAMA_MAX_PARALLEL=1, mirror HF | | 6 | JSONDecodeError streaming | Chunk troncato / connessione rotta | Wrap in try/except, retry logic | | 7 | Context window exceeded | num_ctx default 4096 piccolo | Aumenta num_ctx (8192, 16384, 32768) | | 8 | Output troncato / ripetitivo | num_predict limitato / temp alta | num_predict: -1, temperature: 0.7 | | 9 | Modello non usa GPU | Driver mancanti / env var | nvidia-smi verifica, OLLAMA_NUM_GPU_LAYERS=999 | | 10 | sqlite3.OperationalError: locked | Multi-processo stesso DB | WAL mode: sqlite:///db.sqlite?journal_mode=WAL | | 11 | ChromaDB ID already exists | Re-index senza clear | collection.delete(ids=...) prima di add | | 12 | Embedding dimension mismatch | Modello embedding ≠ collection | Ricrea collection con nuovo embedding model | | 13 | Agent loop infinito | Tool non termina / parsing error | max_iterations=10, handle_parsing_errors=True | | 14 | Gradio Address already in use | Porta 7860 occupata | GUI_SERVER_PORT=7861 o kill processo | | 15 | File upload non funziona | gr.File type mismatch | gr.File(file_types=[".pdf", ".txt", ".md"]) | | 16 | Fine-tuning OOM | Batch troppo grande / seq length | batch_size=1, grad_accum=8, max_seq_length=2048 | | 17 | LoRA merge fallisce | Version mismatch PEFT/transformers | pip install -U peft transformers, stesso base model | | 18 | ImportError: flash_attn | Flash attention non installato | pip install flash-attn --no-build-isolation (richiede CUDA) | | 19 | Mac Metal malloc error | Unified memory pressure | Chiudi browser/app, OLLAMA_NUM_GPU_LAYERS=-1 (CPU) | | 20 | WSL2 GPU non rilevato | Driver Windows non passati | nvidia-smi in WSL verifica, aggiorna driver Windows |


Performance tuning avanzato

1. Flash Attention (Speed + Memory)

# Installa (richiede CUDA 11.8+ / 12.x)
pip install flash-attn --no-build-isolation

# Verifica supporto modello
# Llama 3.1, Mistral, Qwen 2.5, Gemma 2 supportano nativamente
# Attiva via: `OLLAMA_FLASH_ATTENTION=1 ollama serve`

Guadagni tipici:

  • Velocità: +20-40% throughput
  • VRAM: -30-50% KV cache (con num_ctx lungo)
  • Requisiti: GPU Ampere+ (RTX 30xx/40xx), CUDA 11.8+

2. KV Cache Quantization (fp8 / int8)

# Ollama 0.3+ supporta KV cache quantizzato
export OLLAMA_KV_CACHE_QUANT=fp8  # o int8, q4_k_m
ollama serve

Trade-off: fp8 ≈ lossless, int8 piccolo calo qualità, q4_k_m risparmio max VRAM.

3. Parallel Decoding (Speculative Decoding)

# Usa modello draft piccolo (es. 68M param) per predire token
# Ollama: non ancora nativo, usa vLLM o TGI per produzione
# vLLM example:
# vllm serve meta-llama/Llama-3.1-8B-Instruct --speculative-model draft-model

4. Batch Inference (Throughput)

# Per multiple query indipendenti
from ollama import Client
client = Client()

# Batch via async
import asyncio
async def batch_infer(prompts: list[str]):
    tasks = [client.async_generate(model="mistral", prompt=p) for p in prompts]
    return await asyncio.gather(*tasks)

5. Optimal num_gpu_layers per Modello

| Modello | Layers Totali | VRAM 8GB | VRAM 12GB | VRAM 24GB | | --------- | -------------- | ---------- | ----------- | ----------- | | Mistral 7B / Llama 8B | 32 | 20-24 | 32 (tutti) | 32 | | Gemma 2 9B | 42 | 24-28 | 42 | 42 | | Qwen 2.5 14B | 48 | 16-20 | 32-40 | 48 | | Llama 3.1 70B | 80 | ❌ CPU | ❌ CPU | 40-60 (multi-GPU) |

Regola: num_gpu_layers = min(total_layers, VRAM_GB × 1.5) approssimativo.

6. Context window e velocità

# Benchmark veloce per trovare sweet spot
import time
from ollama import Client

client = Client()
for ctx in [2048, 4096, 8192, 16384, 32768]:
    start = time.time()
    client.generate(
        model="mistral",
        prompt="Test " * 100,
        options={"num_ctx": ctx, "num_predict": 100},
    )
    elapsed = time.time() - start
    print(f"ctx={ctx}: {elapsed:.2f}s")

Checklist pre-deploy (produzione)

Infrastruttura

  • [ ] Ollama daemon come systemd service / launchd / Windows service
  • [ ] OLLAMA_HOST=0.0.0.0:11434 per accesso rete (se serve)
  • [ ] Firewall: porta 11434 solo LAN/VPN, mai pubblico
  • [ ] Reverse proxy (nginx/Caddy) con TLS per Gradio
  • [ ] Monitoring: ollama ps, GPU metrics (nvidia-smi / dcgmi), disk space
  • [ ] Backup: /root/.ollama/models + ChromaDB ./chroma_db + SQLite memory
  • [ ] Log rotation: journalctl --vacuum-time=30d

Modelli

  • [ ] Modelli pullati e testati: ollama run modello "test"
  • [ ] Quantizzazione Q4_K_M validata per qualità
  • [ ] num_ctx settato per use case (RAG = 8192+, chat = 4096)
  • [ ] num_gpu_layers ottimizzato per GPU target
  • [ ] Modelli fine-tunati merged e testati standalone

Applicazione

  • [ ] Gradio share=False, server_name="0.0.0.0" (LAN) o 127.0.0.1 (localhost only)
  • [ ] HTTPS via Caddy/ngrok/cloudflared se accesso remoto
  • [ ] Auth se multi-utente (Gradio auth, OAuth2 proxy, VPN)
  • [ ] Rate limiting per IP/sessione
  • [ ] Input validation/sanitization su tutti i tool
  • [ ] Read-only mode per tool distruttivi se non serve scrittura

Sicurezza

  • [ ] AGENT_ALLOWED_DOMAINS configurato per HTTP tool
  • [ ] AGENT_ALLOWED_COMMANDS per shell tool
  • [ ] AGENT_WORK_DIR isolato, no symlink escape
  • [ ] AGENT_READ_ONLY=true se solo consulta
  • [ ] Nessun segreto in codice / env / log (API keys, password)
  • [ ] Audit log: chi ha chiesto cosa, quando, risposta

Performance

  • [ ] Load test: 10 concurrent users, misura p50/p95/p99 latency
  • [ ] KV cache sizing per context window max
  • [ ] Queue config: max_size, concurrency_limit per carico atteso
  • [ ] Fallback: modello più piccolo se OOM / timeout

Per approfondire


Risorse della community (aggiornate al 2026)

Ufficiali

Modelli & Benchmark

Fine-Tuning

RAG & Agent Frameworks

Hardware & Optimization

Newsletter & Aggregatori


Schede di riferimento rapido

Comandi Ollama essenziali

# Modelli
ollama pull mistral:7b-instruct-q4_k_m
ollama list
ollama show mistral:7b-instruct-q4_k_m --modelfile
ollama cp mistral mio-mistral
ollama rm mistral

# Runtime
ollama serve
ollama run mistral "prompt"
ollama ps                    # Modelli caricati in VRAM
ollama stop mistral          # Scarica da VRAM

# Debug
ollama run mistral "test" --verbose 2>&1 | grep -i "metal\|cuda\|gpu"

Variabili d'ambiente di Ollama

export OLLAMA_HOST=0.0.0.0:11434          # Bind address
export OLLAMA_NUM_GPU_LAYERS=999          # Layer su GPU (default: auto)
export OLLAMA_MAX_LOADED_MODELS=3         # Modelli contemporanei in VRAM
export OLLAMA_MAX_QUEUE=512               # Request queue size
export OLLAMA_FLASH_ATTENTION=1           # Enable flash attention
export OLLAMA_KV_CACHE_QUANT=fp8          # KV cache quantization
export OLLAMA_MODELS_DIR=/mnt/models      # Custom models directory
export OLLAMA_KEEP_ALIVE=30m              # Tempo keep model in VRAM

Client Python minimale (senza dipendenze extra)

import requests, json

def chat(model, messages, stream=True, **options):
    resp = requests.post(
        "http://localhost:11434/api/chat",
        json={"model": model, "messages": messages, "stream": stream, "options": options},
        stream=stream,
        timeout=300,
    )
    if stream:
        for line in resp.iter_lines():
            if line:
                yield json.loads(line)["message"]["content"]
    else:
        return resp.json()["message"]["content"]

Fine serie: roadmap futura

| Topic | Descrizione | Priorità | | ------- | ------------- | ---------- | | LangGraph Agents | Orchestrazione multi-agente, human-in-the-loop, state machines | Alta | | Multi-Modal | LLaVA, Qwen-VL, Pixtral per vision + text | Media | | Function Calling Native | Tool calling strutturato su tutti i modelli supportati | Alta | | Distributed Inference | Petals, Exo per modelli >70B su cluster consumer | Bassa | | Guardrails & Safety | NeMo Guardrails, Llama Guard per produzione enterprise | Alta | | Observability | LangSmith, Arize, custom metrics per agenti in produzione | Media | | Edge Deployment | ollama su Raspberry Pi 5, Jetson Orin, mobile (llama.cpp) | Media |


Repository completo

Tutto il codice della serie in un unico repo:

git clone https://github.com/roccobalzama/agente-digitale.git
cd agente-digitale
pip install -r requirements.txt

# Struttura
src/
  ├── config.py              # Pydantic settings
  ├── llm_setup.py           # ChatOllama factory
  ├── ollama_client.py       # Cap. 3 - Client HTTP robusto
  ├── agent_memory.py        # Cap. 4 - Memory management
  ├── rag_pipeline.py        # Cap. 5 - RAG completo
  ├── agent_tools.py         # Cap. 6 - Tools + Agent
  ├── gui_app.py             # Cap. 7 - Gradio UI
  ├── specialization.py      # Cap. 8 - Domain adaptation
  └── utils.py               # Helpers comuni

data/
  ├── docs/                  # Documenti per RAG
  └── models/                # Modelli fine-tuned

scripts/
  ├── index_docs.py          # Indexing pipeline
  ├── train_lora.py          # Unsloth training
  ├── eval_model.py          # Evaluation suite
  └── doctor.py              # Diagnostica sistema

notebooks/
  ├── 01_quickstart.ipynb
  ├── 02_rag_demo.ipynb
  ├── 03_agent_demo.ipynb
  └── 04_finetune_demo.ipynb

Grazie per aver seguito "Il Mio Primo Agente Digitale" (Vibe Pro Vol.2).

Hai ora tutto per costruire, deployare, specializzare agenti AI completamente locali, privacy-first, zero costi ricorrenti.

Il prossimo passo è tuo: scegli un dominio, raccogli documenti, addestra il tuo agente speciale.
Condividi i risultati: GitHub Discussions | Twitter @roccobalzama


Serie completa: 9 post | ~15.000 righe codice | 8 capitoli + appendix | Testato su Ollama 0.3+, LangChain 0.2+, Gradio 4.44+, Python 3.11+, RTX 3060/4090, Mac M2/M3.

Condividi LinkedIn Facebook X WhatsApp
Continua a leggere

Tutti gli articoli del blog

Strumenti gratuiti