laptop_mac macOS Sonoma
Intermediate
schedule 8 min read
by Alex Rivera • May 14, 2024
Step 1 Cos'è MLX e Perché è Importante?
Se hai mai eseguito un modello linguistico di grandi dimensioni su un Mac e hai visto le ventole della CPU girare a pieno regime mentre la GPU era inattiva, hai già compreso il problema che MLX è stato progettato per risolvere.
MLX è un framework open-source per array sviluppato dal team di ricerca in machine learning di Apple, rilasciato alla fine del 2023. Nella sua essenza, MLX è progettato per un unico scopo: rendere il machine learning su Apple Silicon veloce. Non semplicemente "accettabilmente" veloce — genuinamente competitivo con workstation GPU dedicate per i carichi di lavoro di inferenza.
Il Vantaggio della Memoria Unificata
L'intuizione architetturale fondamentale di MLX è la unified memory architecture (UMA) di Apple Silicon. Nelle configurazioni di calcolo tradizionali, CPU e GPU mantengono pool di memoria separati. I dati devono essere copiati esplicitamente tra di essi — un collo di bottiglia che consuma sia tempo che energia.
Apple Silicon elimina questo problema completamente:
Terminal
Traditional Architecture:
┌──────────┐ PCIe Bus ┌──────────┐
│ CPU RAM │ ◄────────────► │ GPU RAM │
│ (DDR5) │ ~50 GB/s │ (GDDR6) │
└──────────┘ └──────────┘
Apple Silicon (M-Series):
┌─────────────────────────────────────┐
│ Unified Memory Pool │
│ ┌──────────┐ ┌─────────────┐ │
│ │ CPU │ │ GPU Cores │ │
│ │ Cores │ │ (up to 76) │ │
│ └──────────┘ └─────────────┘ │
│ ~400 GB/s bandwidth │
└─────────────────────────────────────┘
MLX è costruito dalle fondamenta per sfruttare questa topologia. I tensori risiedono in un unico spazio di indirizzi accessibile simultaneamente da ogni unità di calcolo — core CPU, core GPU e Neural Engine — senza alcun overhead di copia.
Perché Questo è Rilevante per l'Inferenza LLM
L'esecuzione di un modello linguistico di grandi dimensioni è fondamentalmente un problema di banda di memoria, non di potenza di calcolo. Il passaggio forward di un transformer è limitato dalla velocità con cui si possono caricare i pesi dalla memoria nelle unità di calcolo, non dal conteggio grezzo dei FLOP.
| Hardware |
Banda di Memoria |
Peak TOPS |
| MacBook Pro M4 Max |
~546 GB/s |
38.4 |
| RTX 4090 (discrete) |
1.008 GB/s |
165.6 |
| MacBook Pro M3 Pro |
~153 GB/s |
18 |
| MacBook Air M2 |
~100 GB/s |
15.8 |
Ciò che la tabella sopra non cattura è che una RTX 4090 richiede un sistema desktop con un TDP di 450W. Un MacBook Pro M4 Max assorbe circa 60W sotto pieno carico ML. La storia del rapporto prestazioni/watt è straordinaria.
MLX vs. Le Alternative
Prima di MLX, la soluzione dominante per eseguire LLM localmente su Mac era llama.cpp — un'eroica implementazione in C++ che ottimizzava manualmente i kernel Metal e le operazioni vettoriali della CPU. Funziona bene, ma è fondamentalmente un workaround costruito su hardware per cui non è stato progettato.
MLX, al contrario, è stato progettato dalle stesse persone che hanno progettato l'hardware. Gli ingegneri di Apple hanno scritto MLX con piena conoscenza del sottosistema di memoria della serie M, della gerarchia di cache e della microarchitettura GPU. Il risultato è un framework in cui operazioni come matmul, quantized_matmul e i kernel di attenzione sono elementi di prima classe con shader di calcolo Metal nativi, non considerazioni accessorie.
Ulteriori decisioni architetturali che rendono MLX eccezionale:
- Valutazione lazy: I calcoli non vengono eseguiti finché i risultati non sono esplicitamente necessari, abilitando la fusione automatica dei kernel e l'ottimizzazione del grafo.
- Differenziazione automatica: Supporto completo sia per la modalità forward che reverse-mode AD, rendendo MLX adatto al fine-tuning, non solo all'inferenza.
- API Pytonica: L'interfaccia è deliberatamente compatibile con NumPy, riducendo drasticamente la curva di apprendimento per i professionisti del ML.
- Ecosistema
mlx-lm: Una libreria di alto livello costruita su MLX specificamente per l'inferenza di modelli linguistici, la quantizzazione e il fine-tuning LoRA.
La conclusione: Se possiedi hardware Apple Silicon e non stai usando MLX per l'inferenza AI locale, stai lasciando sul tavolo una quantità sostanziale di prestazioni. Il resto di questa guida ti mostrerà esattamente come catturarle.
Step 2 Prerequisiti e Configurazione dell'Ambiente Python
Prima di immergerti in MLX, assicurati che il tuo hardware e il tuo stack software soddisfino i requisiti minimi. MLX è esclusivo per Apple Silicon — questo non è negoziabile. Il framework è progettato architetturalmente dalle fondamenta per sfruttare l'architettura a memoria unificata e il Neural Engine presenti solo nei chip della serie M.
Requisiti Hardware
| Componente |
Minimo |
Raccomandato |
| Chip |
Apple M1 |
Apple M2 Pro / M3 Max |
| RAM |
8 GB di memoria unificata |
32 GB+ di memoria unificata |
| Storage |
20 GB liberi |
50 GB+ liberi (per i modelli) |
| macOS |
Ventura 13.5 |
Sonoma 14.x o successivo |
⚠️ Importante: MLX non funzionerà su Mac basati su Intel. Se si tenta l'installazione su un Mac x86_64, il pacchetto verrà installato ma il backend Metal non riuscirà a inizializzarsi a runtime.
Verifica del Tuo Silicon
Prima di toccare qualsiasi gestore di pacchetti, conferma di essere su Apple Silicon:
Output atteso:
Puoi anche recuperare informazioni dettagliate sul chip:
Terminal
system_profiler SPHardwareDataType | grep "Chip"
Requisiti della Versione di Python
MLX richiede Python 3.9 o successivo. Python 3.11 è attualmente il punto ottimale — offre le migliori prestazioni con il minimo overhead dell'interprete su Apple Silicon, e tutte le principali dipendenze di MLX mantengono wheel stabili per esso.
Terminal
python3 --version
# Python 3.11.x preferred
Configurazione di un Ambiente Virtuale Dedicato
Non installare mai MLX nel tuo Python di sistema. I conflitti di dipendenze con il Python incluso in macOS possono causare guasti subdoli e frustranti. Usa un ambiente virtuale pulito.
Opzione A: Utilizzo di venv (Leggero, Integrato)
Terminal
# Create the environment
python3.11 -m venv ~/envs/mlx-env
# Activate it
source ~/envs/mlx-env/bin/activate
# Confirm the Python path
which python
# ~/envs/mlx-env/bin/python
Opzione B: Utilizzo di conda / miniforge (Raccomandato per i Workflow ML)
Miniforge include conda nativo per ARM ed è la scelta preferita per lo sviluppo ML serio su Apple Silicon:
Terminal
# Install Miniforge (if not already installed)
brew install miniforge
# Create a dedicated MLX conda environment
conda create -n mlx-env python=3.11 -y
# Activate
conda activate mlx-env
Pro Tip: Usa conda-forge come canale primario. Fornisce build native ARM64 per la maggior parte dei pacchetti di calcolo scientifico, evitando l'overhead di traduzione Rosetta 2 che può penalizzare silenziosamente le prestazioni.
Aggiornamento di pip e degli Strumenti Core
Una volta all'interno dell'ambiente attivato, aggiorna il toolchain fondamentale prima di installare qualsiasi pacchetto ML:
Terminal
pip install --upgrade pip setuptools wheel
Questo è particolarmente importante perché MLX occasionalmente distribuisce wheel binarie che richiedono una versione recente di pip (≥23.x) per essere risolte correttamente sul tag di piattaforma arm64.
MLX si affida all'API GPU Metal di Apple e al framework Accelerate per le operazioni BLAS. Questi sono inclusi con macOS e non richiedono installazioni separate, ma puoi verificare che Metal sia accessibile tramite Python:
Terminal
python3 -c "import subprocess; subprocess.run(['system_profiler', 'SPDisplaysDataType'])"
In alternativa, dopo aver installato MLX nella sezione successiva, il seguente one-liner confermerà che il backend Metal è attivo:
Terminal
import mlx.core as mx
print(mx.default_device()) # Device(gpu, 0) — confirms Metal backend
Se vedi Device(cpu, 0), i tuoi driver Metal non vengono rilevati correttamente — questo indica tipicamente una mancata corrispondenza della versione di macOS o un'installazione corrotta degli Xcode Command Line Tools.
Diverse dipendenze di MLX compilano estensioni native al momento dell'installazione. Assicurati che gli Xcode Command Line Tools siano presenti:
Verifica l'installazione:
Terminal
xcode-select -p
# /Library/Developer/CommandLineTools
Con il tuo ambiente pulito, Python fissato a 3.11, Metal confermato e pip aggiornato, sei pronto per installare MLX.
Step 3 Passo 1: Installazione di MLX e MLX-LM
Con il tuo ambiente Python correttamente configurato, è il momento di installare le librerie core. MLX è distribuito come pacchetto Python standard, ma ci sono alcune sfumature che vale la pena comprendere prima di procedere ciecamente con pip install rischiando di compromettere l'ambiente.
Struttura dei Pacchetti Core
L'ecosistema MLX di Apple è suddiviso in diversi pacchetti mirati. Per l'inferenza LLM, sono necessari due componenti primari:
| Pacchetto |
Scopo |
mlx |
Framework core per il calcolo su array (operazioni GPU/CPU su memoria unificata) |
mlx-lm |
Interfaccia LLM di alto livello — generazione, quantizzazione, fine-tuning |
huggingface-hub |
Download dei modelli e gestione della cache |
transformers |
Supporto per i tokenizer (incluso come dipendenza) |
Il pacchetto mlx-lm non installa automaticamente mlx alla versione esatta con cui è stato testato, quindi il pinning è importante. Maggiori dettagli di seguito.
Installazione
Attiva prima il tuo ambiente virtuale. Se hai saltato la sezione Prerequisiti, il requisito minimo è Python 3.9+ su un Mac Apple Silicon (serie M1/M2/M3/M4). MLX non funzionerà su Mac Intel — il framework è architetturalmente accoppiato all'Unified Memory Architecture.
Terminal
# Upgrade pip first — older pip versions mishandle Apple's binary wheels
pip install --upgrade pip
# Install the core MLX framework
pip install mlx
# Install the LLM interface layer
pip install mlx-lm
Per gli utenti che desiderano le build nightly all'avanguardia (utili per testare il supporto a modelli non ancora rilasciati):
Terminal
pip install mlx-nightly mlx-lm
⚠️ Non mescolare mlx stabile con mlx-nightly. L'ABI tra i due è incompatibile e produrrà errori di importazione criptici a runtime.
Verifica dell'Installazione
Esegui questo blocco di verifica immediatamente dopo l'installazione. Se uno qualsiasi di questi fallisce, il tuo ambiente ha problemi che si amplificheranno in errori più difficili da diagnosticare in seguito.
Terminal
# verify_mlx.py
import mlx.core as mx
import mlx_lm
# Check MLX version
print(f"MLX version: {mx.__version__}")
# Confirm we're targeting the GPU (not CPU fallback)
print(f"Default device: {mx.default_device()}")
# Confirm mlx-lm loaded
print(f"mlx-lm version: {mlx_lm.__version__}")
# Quick tensor operation on GPU
a = mx.array([1.0, 2.0, 3.0])
b = mx.array([4.0, 5.0, 6.0])
print(f"Dot product (GPU): {mx.inner(a, b).item()}")
Output atteso:
Terminal
MLX version: 0.16.x
Default device: Device(gpu, 0)
mlx-lm version: 0.19.x
Dot product (GPU): 32.0
Checkpoint critico: Se Default device restituisce Device(cpu, 0), MLX non sta accedendo al backend GPU Metal. Questo significa tipicamente che stai eseguendo un binario Python non nativo (ad esempio, Python x86 tradotto da Rosetta). Verifica con:
Terminal
python -c "import platform; print(platform.machine())"
# Must output: arm64
Opzionale: Installazione per lo Sviluppo
Se intendi contribuire a MLX o hai bisogno di modificare gli internals, installa dal sorgente:
Terminal
git clone https://github.com/ml-explore/mlx.git
cd mlx
pip install -e .
git clone https://github.com/ml-explore/mlx-lm.git
cd mlx-lm
pip install -e .
La compilazione dal sorgente richiede Xcode Command Line Tools e CMake ≥ 3.26:
Terminal
xcode-select --install
brew install cmake
Snapshot delle Dipendenze
Ecco un requirements.txt pulito per un ambiente di inferenza riproducibile a partire da metà 2025:
Terminal
mlx>=0.16.0
mlx-lm>=0.19.0
huggingface-hub>=0.23.0
transformers>=4.41.0
sentencepiece>=0.2.0
protobuf>=3.20.0
Fissa queste versioni nei carichi di lavoro in produzione. Il team di MLX introduce cambiamenti API incompatibili frequentemente dato il ritmo rapido di sviluppo del framework, e un aggiornamento silenzioso può invalidare i tuoi parametri di generazione o le configurazioni di quantizzazione.
Con le librerie confermate e operative, il passo successivo è scaricare modelli in formato MLX correttamente formattati da HuggingFace — il che richiede di comprendere perché non tutti i modelli GGUF o Safetensors sono compatibili con MLX out of the box.
Step 4 Passo 2: Download di Modelli MLX Ottimizzati da HuggingFace
Prima di poter eseguire l'inferenza, hai bisogno di modelli specificamente formattati e quantizzati per il runtime MLX. Sebbene MLX possa convertire modelli standard on-the-fly, il percorso più performante è scaricare direttamente da HuggingFace modelli pre-convertiti e pre-quantizzati nativi per MLX. La community MLX — guidata in gran parte dalla prolifica organizzazione mlx-community su HuggingFace — ha svolto il lavoro pesante di conversione e quantizzazione di centinaia di modelli popolari.
I modelli MLX sono archiviati come file safetensors abbinati a un config.json e un tokenizer_config.json. Ciò che li distingue è il formato di quantizzazione. A differenza di GGUF (usato da llama.cpp), MLX utilizza il proprio schema di quantizzazione interno con le seguenti configurazioni comuni:
| Quantizzazione |
Bit per Peso |
Qualità |
Velocità (Tok/s est.) |
Dimensione (modello 7B) |
mlx-4bit |
4-bit |
Buona |
⚡⚡⚡⚡ |
~4 GB |
mlx-8bit |
8-bit |
Migliore |
⚡⚡⚡ |
~8 GB |
bf16 |
16-bit (bfloat) |
Ottima |
⚡⚡ |
~14 GB |
fp16 |
16-bit (float) |
Ottima |
⚡⚡ |
~14 GB |
Per la maggior parte degli utenti su macchine M1/M2/M3, i modelli quantizzati a 4-bit offrono il miglior compromesso tra throughput e qualità.
Metodo 1: Utilizzo della CLI huggingface_hub (Raccomandato)
L'approccio più pulito è utilizzare la CLI di HuggingFace Hub, che gestisce automaticamente la ripresa in caso di interruzione, la cache e la verifica dell'integrità.
Terminal
# Install the hub CLI if you haven't already
pip install huggingface_hub
# Download a 4-bit quantized Llama 3.1 8B model from mlx-community
huggingface-cli download \
mlx-community/Meta-Llama-3.1-8B-Instruct-4bit \
--local-dir ./models/llama-3.1-8b-4bit \
--local-dir-use-symlinks False
Pro Tip: Il flag --local-dir-use-symlinks False garantisce che i file effettivi vengano scritti nella tua directory anziché symlink nella cache di HuggingFace. Questo è fondamentale per la portabilità e i riferimenti diretti ai percorsi nei tuoi script.
Metodo 2: Utilizzo di mlx_lm.convert per la Conversione Personalizzata
Se il modello di cui hai bisogno non è stato pre-convertito dalla community, puoi convertirlo tu stesso direttamente da un checkpoint standard di HuggingFace:
Terminal
# Convert and quantize a standard model to MLX 4-bit format
python -m mlx_lm.convert \
--hf-path mistralai/Mistral-7B-Instruct-v0.3 \
--mlx-path ./models/mistral-7b-instruct-4bit \
-q \
--q-bits 4 \
--q-group-size 64
Spiegazione dei flag principali:
-q — Abilita la quantizzazione durante la conversione
--q-bits — Bit target per peso (4 o 8)
--q-group-size — Dimensione del gruppo per la quantizzazione a gruppi; 64 è standard, 32 offre qualità leggermente superiore a fronte di dimensioni maggiori
Metodo 3: Download Snapshot tramite Python
Per workflow programmatici e pipeline CI/CD, usa l'API Python:
Terminal
from huggingface_hub import snapshot_download
model_path = snapshot_download(
repo_id="mlx-community/Mistral-7B-Instruct-v0.3-4bit",
local_dir="./models/mistral-7b-4bit",
ignore_patterns=["*.md", "*.txt"] # Skip non-essential files
)
print(f"Model downloaded to: {model_path}")
Modelli Raccomandati da cui Iniziare
Ecco modelli MLX collaudati e ad alte prestazioni disponibili ora su HuggingFace:
| Modello |
Repository HuggingFace |
VRAM Richiesta |
Ideale Per |
| Llama 3.1 8B (4-bit) |
mlx-community/Meta-Llama-3.1-8B-Instruct-4bit |
~5 GB |
Uso generale |
| Mistral 7B (4-bit) |
mlx-community/Mistral-7B-Instruct-v0.3-4bit |
~4.5 GB |
Inferenza veloce |
| Llama 3.1 70B (4-bit) |
mlx-community/Meta-Llama-3.1-70B-Instruct-4bit |
~38 GB |
Alta qualità |
| Phi-3.5 Mini (4-bit) |
mlx-community/Phi-3.5-mini-instruct-4bit |
~2.5 GB |
Mac a bassa memoria |
| Qwen2.5 14B (4-bit) |
mlx-community/Qwen2.5-14B-Instruct-4bit |
~9 GB |
Task di coding |
Verifica del Modello Scaricato
Prima di eseguire l'inferenza, valida che la struttura del modello sia intatta:
Terminal
# List the expected files in a valid MLX model directory
ls -lh ./models/llama-3.1-8b-4bit/
# Expected output should include:
# config.json
# tokenizer.json
# tokenizer_config.json
# special_tokens_map.json
# model.safetensors (or sharded: model-00001-of-00004.safetensors, etc.)
Se vedi file .safetensors insieme alle configurazioni del tokenizer, sei pronto. Un config.json o tokenizer_config.json mancante è la causa più comune di errori di caricamento — riesegui il comando di download se uno dei due è assente.
Step 5 Passo 3: Esecuzione dell'Inferenza tramite CLI
Con il tuo modello ottimizzato per MLX scaricato e disponibile localmente, sei pronto per eseguire l'inferenza direttamente dal terminale. MLX-LM include un potente comando mlx_lm.generate che elimina completamente il boilerplate Python, offrendoti un'interfaccia pulita e riproducibile per il benchmarking e la sperimentazione rapida.
Comando di Generazione Base
La chiamata di inferenza più semplice possibile si presenta così:
Terminal
mlx_lm.generate \
--model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
--prompt "Explain the unified memory architecture of Apple Silicon in three sentences."
MLX caricherà i pesi del modello direttamente nel pool di memoria unificata, compilerà il grafo di calcolo tramite il suo motore di valutazione lazy, e trasmetterà i token in streaming su stdout. Tipicamente vedrai il primo token entro 1–2 secondi sui chip della serie M — una diretta conseguenza dell'eliminazione totale della latenza di trasferimento PCIe.
Analisi dei Flag CLI Principali
Comprendere i flag disponibili ti permette di spingere il framework ai suoi limiti:
| Flag |
Tipo |
Default |
Descrizione |
--model |
str |
obbligatorio |
Percorso locale o ID repository HuggingFace |
--prompt |
str |
obbligatorio |
Stringa del prompt di input |
--max-tokens |
int |
256 |
Numero massimo di token da generare |
--temp |
float |
0.0 |
Temperatura di campionamento (0 = decodifica greedy) |
--top-p |
float |
1.0 |
Soglia di campionamento nucleus |
--seed |
int |
None |
Seed RNG per la riproducibilità |
--repetition-penalty |
float |
1.0 |
Penalizza la ripetizione dei token |
--verbose |
bool |
True |
Stampa il throughput token/sec e la latenza |
Comando di Inferenza di Livello Produzione
Per benchmarking serio o valutazione di prompt in produzione, usa la forma completamente parametrizzata:
Terminal
mlx_lm.generate \
--model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
--prompt "You are an expert systems programmer. Write a zero-copy ring buffer implementation in Rust." \
--max-tokens 1024 \
--temp 0.7 \
--top-p 0.9 \
--repetition-penalty 1.1 \
--seed 42 \
--verbose
Il flag --verbose produce un riepilogo delle prestazioni simile a questo al completamento:
Terminal
==========
Prompt: 47 tokens, 823.14 tokens-per-second
Generation: 1024 tokens, 68.42 tokens-per-second
Peak memory: 5.21 GB
Presta molta attenzione ai due distinti numeri di throughput. L'elaborazione del prompt (prefill) è un'operazione matriciale altamente parallelizzabile e sarà sempre significativamente più veloce della generazione autoregressiva di token (decode). Su un M3 Max con 128 GB di memoria unificata, puoi aspettarti un throughput di decode di 60–90 token/sec su modelli 8B quantizzati a 4-bit — competitivo o superiore all'inferenza GPU-accelerata su schede NVIDIA discrete che costano molte volte di più.
Utilizzo di un Template di Chat
Molti modelli instruction-tuned richiedono un template di chat strutturato per comportarsi correttamente. MLX-LM gestisce questo automaticamente quando si usa il flag --chat-template o si invoca l'interfaccia di chat:
Terminal
mlx_lm.generate \
--model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
--prompt "[INST] What is the time complexity of the Aho-Corasick algorithm? [/INST]" \
--max-tokens 512
In alternativa, per i modelli con template di chat tokenizer_config.json integrati (come Llama 3 e Mistral v0.3), puoi usare direttamente la modalità chat interattiva:
Terminal
mlx_lm.chat --model mlx-community/Meta-Llama-3-8B-Instruct-4bit
Questo avvia un'interfaccia in stile REPL con gestione completa della cronologia della conversazione, applicando automaticamente i token corretti <|begin_of_text|>, <|user|> e <|assistant|>. La sessione mantiene la KV cache nella memoria unificata tra i turni, il che significa che le risposte successive in una lunga conversazione diventano progressivamente più veloci man mano che la cache si scalda.
Piping dei Prompt da File
Per pipeline automatizzate e harness di valutazione, fai il pipe dei prompt da stdin o da file:
Terminal
cat system_prompt.txt | mlx_lm.generate \
--model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
--prompt "$(cat complex_query.txt)" \
--max-tokens 2048 \
>> outputs/results_$(date +%Y%m%d_%H%M%S).txt
Questo pattern si integra perfettamente nei framework di valutazione basati su shell, permettendoti di elaborare in batch suite di prompt senza avviare un interprete Python per ogni chiamata. L'entry point CLI è leggero e rapido da inizializzare — tipicamente meno di 500ms prima che inizi il caricamento del modello — rendendolo pratico anche in contesti di scripting con molti loop.
Step 6 Benchmarking MLX vs Llama.cpp
Ora arriva la parte che conta davvero — i numeri reali. Mettiamo MLX a confronto diretto con Llama.cpp, il campione uscente dell'inferenza LLM on-device, e vediamo dove ciascun framework vince, perde e perché.
Ambiente di Test
Tutti i benchmark sono stati eseguiti sulla seguente configurazione hardware e software:
| Parametro |
Valore |
| Dispositivo |
MacBook Pro M3 Max |
| RAM |
128 GB di memoria unificata |
| macOS |
Sonoma 14.5 |
| Python |
3.11.9 |
| MLX |
0.16.1 |
| mlx-lm |
0.16.1 |
| llama.cpp |
b3467 |
| Modello |
Llama-3.1-8B-Instruct (Q4_K_M / MLX 4-bit) |
Metodologia
A ogni framework è stato sottoposto lo stesso input ed è stato chiesto di generare esattamente 512 token. Abbiamo eseguito 5 passaggi di riscaldamento prima di registrare le misurazioni per eliminare l'overhead di compilazione JIT a freddo. La metrica riportata è token al secondo (tok/s) mediata su 10 esecuzioni.
Comando benchmark MLX:
```bash
python -m mlx_lm.generate \
--model mlx-community/Meta-Llama-3.1-8B-Instruct-4bit \
--prompt "Explain