Per iniziare
- Accedi alla console con le credenziali del cluster HPC (serve essere nel gruppo Hpc.Users).
- Guarda se il modello che ti serve è già in esecuzione: i modelli condivisi li può usare chiunque, senza avviarne un altro.
- Se no, usa il picker ("Quale modello?"): scegli il tipo di lavoro e avvia il primo suggerito.
- Usalo dalla console, oppure dai tuoi programmi con una API key (sezione Uso dai programmi).
- Quando hai finito, fermalo: le GPU sono poche e condivise.
Indirizzo unico: — compatibile OpenAI (/v1), Anthropic (/v1/messages) e Jev (/v1/systemone).
Concetti
Quota GPU
dgx01 ha 7 GPU Tesla V100 da 32 GB, condivise con tutto il cluster. Il servizio LLM può usarne al massimo 2 alla volta in totale
(non 2 per utente: la quota è unica, perché tutti i job girano come utente di servizio hpc.cluster).
Se la quota è piena, una nuova richiesta va in coda in SLURM finché una GPU si libera.
Job dedicato e pod
- Job dedicato: un modello con le sue 1 o 2 GPU tutte per sé. È la scelta per i modelli grandi e per i motori "esclusivi".
- Pod: un job con 1 o 2 GPU dentro cui si avviano più modelli, anche di utenti diversi, finché c'è memoria sulla GPU. Esempio: Qwen3.6 su llama.cpp (22 GB) + d1-3B (6 GB) sulla stessa V100, una sola GPU di quota. Avviare un modello dentro un pod esistente non consuma quota.
- Un pod rimasto senza modelli per 5 minuti si chiude da solo e restituisce le GPU.
- La GPU fisica di un pod o di un job dedicato la sceglie SLURM tra quelle libere; dentro i pod scegli tu pod e GPU, oppure "automatico" (la GPU più piena in cui il modello entra ancora, per lasciare libere le altre).
- Motori esclusivi (vLLM, strata, ds4) occupano tutta la memoria libera della scheda: vanno su una GPU vuota. llama.cpp, ollama, colibri e i modelli decisionali condividono.
Condiviso o privato
Un modello avviato è visibile a tutti. Se è condiviso (predefinito) chiunque sia loggato lo può usare; se lo avvii come privato lo usi solo tu (e gli amministratori); un modello privato può usare al massimo 1 GPU. Solo chi l'ha avviato, o un amministratore, lo può fermare.
Durata (walltime)
Avvio di giorno (08–20): massimo 4 ore. Avvio la sera o di notte: massimo 12 ore. Alla scadenza il job termina e il modello si spegne.
Quale modello usare
| Lavoro | Prima scelta | Alternative | Perché |
|---|---|---|---|
| Chat generale, assistente, traduzioni | Gemma 4 26B (llama.cpp) | gpt-oss-20b, Qwen3.6-35B | ~140 token/s su una GPU, buona qualità |
| Massima qualità, problemi difficili | Qwen3.8-Flash-Next (strata) | Qwen3.8-27B Q8 (2 GPU) | il modello più forte che sta su dgx01 (~50–64 token/s) |
| Codice | Qwen3.8-27B (llama.cpp) | Qwen3.8-Flash-Next, gpt-oss-20b | denso, preciso; Qwen3-Coder su colibri è lento |
| Ragionamento, matematica | gpt-oss-20b | Qwen3.8-Flash-Next | pensato per il ragionamento passo-passo, veloce |
| Documenti lunghi, RAG, riassunti | Qwen3.6-35B su strata | vLLM per modelli supportati | legge il prompt 5× più veloce degli altri motori (3400 token/s) |
| Immagini (grafici, documenti scansionati) | Qwen2.5-VL-7B (vLLM) | Gemma 4 | modello visione-linguaggio |
| Immagini cliniche, quesiti medici | Lingshu-7B (vLLM) | Qwen2.5-VL-7B | addestrato su dati medici; uso di ricerca, non diagnostico |
| Classificare, instradare, sì/no, estrarre campi | Liquid d1-3B | d1-2B (anche CPU), GLiNER, Laya (CPU) | una passata, probabilità calibrate, ~60 ms |
| Molti utenti insieme sullo stesso modello | un modello su vLLM | — | gli altri motori servono una richiesta alla volta |
| Nessuna GPU libera | Qwen3.6-35B su CPU (llama.cpp) | d1-2B su CPU | lento (~9 token/s) ma non usa quota GPU |
Velocità misurate su dgx01 con un utente alla volta: "prefill" è la lettura del prompt, "decode" la scrittura della risposta. Un token è circa ¾ di parola inglese, meno in italiano.
Schede dei modelli
Accedi alla console per vedere qui il catalogo aggiornato.
Motori
Lo stesso modello può girare su motori diversi, con prestazioni molto diverse (es. Qwen3.6-35B: prefill 3386 token/s su strata, 638 su llama.cpp, 17 su colibri). Il profilo scelto all'avvio decide il motore.
| Motore | Come lavora | Speculative decoding | Quantizzazioni | CPU | Condivide la GPU |
|---|
Uso dai programmi
Crea una API key nella console (sezione "Usarli da programmi" → Nuova API key) oppure con llm-serve key create <nome>.
La chiave si vede una sola volta: salvala. Non scade con i login; la revochi dalla console.
curl
Python (libreria openai)
opencode
Il campo model è l'id del modello in esecuzione (es. qwen3.8-27b), oppure id@profilo per un'istanza precisa,
oppure auto (il miglior modello di chat attivo). GET /v1/models elenca quelli che puoi usare.
Il certificato è per ora autofirmato: nei client va accettato (es. curl -k, verify=False).
Da terminale sul cluster
/opt/common/tools/llm-serve/bin/llm-serve login # credenziali del cluster HPC llm-serve gpus # le 7 GPU, chi le usa, i pod llm-serve pick documents # cosa usare per documenti lunghi llm-serve start gemma-4-26b-a4b # automatico: in un pod se c'è spazio, altrimenti job dedicato llm-serve start d1-3b --pod <id> --gpu 3 # in un pod/GPU preciso llm-serve start qwen3.8-27b --dedicated --private llm-serve status ; llm-serve stop <job> ; llm-serve logs <job> eval $(llm-serve env) # OPENAI_BASE_URL e OPENAI_API_KEY per altri programmi
Modelli decisionali (FDM)
d1, GLiNER2.5-Decide e Laya non scrivono testo: ricevono uno stato (testo, JSON, immagini per d1) e delle domande tipizzate,
e rispondono in una sola passata con probabilità calibrate. Ideali per classificare, instradare, fare triage, estrarre campi.
L'API è POST /v1/systemone, la stessa di Jev (TypeSafe): un client Jev funziona cambiando solo l'URL base.
| Tipo di domanda | Risposta | Modelli |
|---|---|---|
noul (sì/no) | probabilità che sia vero | tutti |
choice (anche multiple: true) | opzione scelta + probabilità di ciascuna | tutti |
score | livello su una scala data | tutti |
text, number, date | valore estratto dal testo | d1 |
box, boxes | posizione di oggetti in un'immagine | d1 |
Prefill e decode
Ogni risposta ha due fasi: il prefill (il modello legge tutto il prompt, conta per documenti lunghi e RAG) e il decode (scrive la risposta un token alla volta, conta per la velocità percepita). I motori sono più o meno bravi nelle due fasi.
Si possono usare due motori diversi, uno per fase?
Su una stessa richiesta no: lo stato interno prodotto dal prefill (la "KV cache") ha un formato diverso per ogni motore e non si passa da uno all'altro. Le alternative, in ordine di utilità su dgx01:
- Un motore bravo in entrambe le fasi. strata con Qwen3.6-35B ha il prefill migliore (3386 token/s) e un decode quasi pari al migliore
(98 contro 106 di llama.cpp). Per documenti lunghi è la scelta da fare: profilo
strata-1gpu. - strata con prefill e decode su due GPU (
--split-serve PREFILL,DECODE): lo stesso motore avvia due processi, uno legge il prompt su una scheda e l'altro scrive la risposta sull'altra; la sessione passa dall'uno all'altro in RAM, in automatico. Usa entrambe le GPU della quota per un solo modello. Profilostrata-split-2gpudi Qwen3.6-35B: in test. - Due istanze dello stesso modello e smistamento automatico. Se lo stesso modello è attivo due volte (es. Qwen3.6 su strata e su llama.cpp),
il gateway manda le richieste con prompt lunghi (oltre ~4000 token) all'istanza con il prefill più veloce e le altre a quella con il decode
più veloce. Ogni richiesta è servita per intero da un motore. Come fare: avvia lo stesso modello con due profili diversi e usa come
modell'id senza profilo (qwen3.6-35b-a3b). Costa 2 GPU di quota, oppure 1 GPU + CPU se la seconda istanza èllamacpp-cpu. - Speculative decoding: un modello piccolo "propone" i token e quello grande li verifica a gruppi; accelera il decode senza cambiare il risultato.
È già attivo, in automatico, su strata (MTP) per Qwen3.6 e Qwen3.8-Flash-Next. llama.cpp (
-md <modello-draft.gguf>) e vLLM lo supportano ma non sono ancora configurati nel catalogo.
Speculative decoding
Un modello piccolo (o le teste MTP già presenti nel modello) propone alcuni token; il modello grande li controlla tutti in una sola passata e tiene quelli giusti. La risposta è identica a quella senza speculazione: cambia solo la velocità con cui viene scritta (decode). Il prefill non cambia.
| Modello | Profilo | Senza | Con MTP | Guadagno |
|---|---|---|---|---|
| Qwen3.6-35B-A3B | llamacpp-1gpu-mtp | 99 tok/s | 150 tok/s | +51% |
| Qwen3.8-27B Q4 | llamacpp-q4-1gpu-mtp | 33 tok/s | 61 tok/s | +84% |
| Gemma-4-26B-A4B | llamacpp-1gpu-mtp | 109 tok/s | 151 tok/s | +39% |
Media su quattro testi (codice, riassunto, testo libero, traduzione), un utente. I profili -mtp usano 1–5 GB di VRAM in più.
Le altre tecniche provate servono poco sulle V100: EAGLE3 +10% su gpt-oss-20b e −10% su gpt-oss-120b (esperti in RAM); n-gram aiuta solo quando la risposta ripete il prompt;
vLLM 0.8.5 con un draft model +27% in media ma molto variabile. Dettagli: BENCHMARK-dgx01.md §14 e i test nel catalogo (clic sul modello).
Con più utenti insieme (MTP, 16 slot): il guadagno cala con il carico. Qwen3.6 +46% con 1 utente, +4% con 4, −38% con 16; Gemma +52% → +9% → −27%;
Qwen3.8-27B (denso) +88% → +33% → +25% con 8 utenti (con 16 utenti e MTP va fuori memoria GPU). Quindi: profili -mtp per uso privato o con pochi utenti (fino a ~4);
per un modello condiviso molto usato meglio il profilo senza speculazione.
Sottotipi
| Motore | Usabili | Attivo nei profili |
|---|---|---|
| llama.cpp | MTP, EAGLE3, draft model, DFlash, DSpark, n-gram | MTP nei profili -mtp |
| vLLM 0.8.5 | draft model, n-gram, EAGLE, Medusa, MLP speculator, MTP DeepSeek | nessuno |
| strata | MTP | MTP in tutti i profili strata |
| ds4 | MTP, DSpark | nessuno |
| colibri | MTP (solo GLM-5.2, Qwen3.8-Flash-Next) | nessuno |
| ollama, fdm | nessuno | — |
Nel catalogo la colonna Speculative indica il sottotipo attivo di ogni profilo.
Come sono misurati i dati
Tutte le misure sono state fatte su dgx01 tra il 27 ottobre e il 2 novembre 2026, con i comandi e i profili del catalogo. Il dettaglio completo
(comandi esatti, date, job SLURM) è nel file BENCHMARK-dgx01.md in /opt/common/tools/llm-serve/.
| Misura | Come |
|---|---|
| Prefill (token/s) | prompt di ~2000 token, risposta di 1 token: token del prompt ÷ tempo |
| Decode (token/s) | prompt breve, 256 token generati: token generati ÷ (tempo − tempo del solo prompt). I token di "ragionamento" contano |
| TTFT (s) | tempo al primo token: con prompt breve (misurato) e con ~2000 token (= 2000 ÷ prefill) |
| Avvio (s) | dal lancio del container a quando il modello risponde; "freddo" = file del modello tolti dalla RAM del nodo, "caldo" = ancora in RAM |
| Concorrenza | valori della tabella con 1 utente alla volta; prove separate con 1–16 utenti (vedi "Prefill e decode" e il file dei benchmark) |
| Finestra di contesto | durante le misure: 4096 token (vLLM, llama.cpp), 8192 (strata, colibri, ds4); in servizio vale la colonna "Contesto" del catalogo |
| VRAM | letta da nvidia-smi a modello caricato; per vLLM è la memoria riservata in anticipo |
Documenti lunghi (16k–256k token)
Ogni modello è stato provato con prompt da 16k, 32k, 64k, 128k token e fino al suo massimo: i risultati sono nella tendina che si apre cliccando sul nome del modello nel catalogo (riga "contesto lungo"). In sintesi: più il testo è lungo, più lenta è la lettura (un documento da 128k richiede da 1,5 a 6 minuti prima della risposta); per testi oltre 64k vanno meglio Qwen3.8-Flash-Next su strata (oltre 1100 token/s di lettura fino a 256k) e Lingshu / Qwen2.5-VL su vLLM con 2 GPU (fino a 128k); Qwen3.6 oltre 32k conviene su llama.cpp. Su una sola GPU i modelli vLLM arrivano a ~32k, i modelli decisionali d1 a 8k (d1-3B) e 32k (d1-2B).
Finestra di contesto
Ogni modello ha una finestra massima (letta dai suoi metadati: da 32k a 1M token) e ogni profilo una finestra configurata, cioè quanti token (prompt + risposta) può usare una richiesta in quel servizio: di solito 32k, perché finestre più grandi tolgono memoria alla GPU. Nel catalogo la colonna "Contesto" mostra configurata / massima. Una richiesta più lunga della finestra configurata viene rifiutata dal motore.
Avvio a freddo, avvio a caldo e primo token
"A freddo" si usa con due significati diversi; conviene tenerli separati.
1. Il modello non è in esecuzione: bisogna avviarlo
Se il modello che ti serve non è già attivo, prima di poterlo usare va avviato (dalla console o con llm-serve start): questo richiede
da pochi secondi a qualche minuto. Il servizio non avvia i modelli da solo alla prima richiesta: una chiamata a un modello spento riceve un errore
che dice di avviarlo. Se invece il modello è già attivo (anche avviato da un collega), la richiesta parte subito e conta solo il tempo al primo token.
2. Avvio "a freddo" o "a caldo": dove si trovano i file del modello
Nel catalogo le due colonne dell'avvio si riferiscono a questo:
- Avvio a freddo: i file del modello non sono nella memoria (RAM) del nodo e vanno letti dallo storage BeeGFS. Succede quando il modello non è stato usato da tempo, o quando la RAM è servita ad altro.
- Avvio a caldo: il modello è stato usato da poco, quindi il sistema operativo ne tiene ancora i file in RAM e li rilegge da lì, senza passare dallo storage. Avviene in automatico; i file restano in RAM finché la memoria non serve ad altri programmi.
Cosa succede durante un avvio
| Fase | Tempo tipico su dgx01 | Dipende da freddo/caldo? |
|---|---|---|
| attesa di una GPU libera in SLURM (solo se la quota di 2 GPU è occupata) | da 0 a ore | no (non inclusa nei tempi misurati) |
| avvio del container | 1–3 s | no |
| lettura dei pesi | freddo: ~1,5 GB/s (23 GB ≈ 15 s; 90 GB ≈ 60 s) caldo: ~4 GB/s (23 GB ≈ 6 s) | sì, è l'unica fase |
| copia dei pesi nella memoria della GPU | pochi secondi | no |
| inizializzazione del motore | llama.cpp: secondi · strata: preparazione della cache degli esperti · vLLM: 1–2 minuti (misura della memoria e preparazione dei "CUDA graph") · Qwen3.8-Flash-Next: blocco di 55 GB di esperti in RAM | no |
Risultato misurato: su dgx01 freddo e caldo differiscono di pochi secondi, e in qualche prova l'avvio a caldo è stato persino più lento, per il carico variabile del nodo. Il motivo è che lo storage BeeGFS è veloce e i suoi server hanno a loro volta una cache, mentre la parte lunga dell'avvio è l'inizializzazione del motore, che non dipende da dove stanno i file. La differenza diventa visibile solo con i modelli molto grandi (80–90 GB).
Tempo al primo token (TTFT)
Con il modello già attivo, una richiesta aspetta prima la lettura del prompt (prefill) e poi riceve la risposta un pezzo alla volta. Il TTFT è il tempo fino al primo pezzo: con una domanda breve è sotto il secondo per quasi tutti i modelli; con un documento di 2000 token va da 0,4 s (vLLM) e 0,7 s (strata) a 3–4 s (modelli grandi su llama.cpp). I valori sono nelle colonne "Avvio" e "TTFT" del catalogo.
In pratica: i modelli usati spesso conviene tenerli attivi e condivisi (nessun avvio, solo TTFT); un modello fermato e riavviato nella stessa giornata di solito parte "a caldo"; i tempi di avvio contano soprattutto per vLLM (2–3 minuti) e per i modelli più grandi.
Caricamento dei modelli e cache
I modelli si leggono direttamente da BeeGFS (/beegfs/datasets/models), senza copia sul disco locale. Misure su dgx01:
| Lettura di un modello | Velocità |
|---|---|
| BeeGFS, file mai letto di recente | 1,5 GB/s |
| BeeGFS, file letto di recente (cache dei server di storage) | 3,0–3,5 GB/s |
disco SSD locale di dgx01 (/raid, 7 TB) | 1,8 GB/s |
| RAM del nodo (file già letto) | 3,9 GB/s |
Una cache sul disco locale farebbe guadagnare al massimo pochi secondi (Qwen3.6, 23 GB: ~3 s su un avvio di 25–35 s) e richiederebbe la copia preventiva (~80 s per 23 GB). Per questo non c'è: la cache efficace esiste già ed è automatica — la RAM del nodo (503 GB) tiene i modelli usati di recente e libera da sola quelli non usati da più tempo, e i server BeeGFS fanno lo stesso.
Benchmark SWE (qualità sul codice)
Due classifiche pubbliche misurano quanto un modello sa risolvere compiti reali di sviluppo software:
- SWE-bench Verified (llm-stats.com): percentuale di 500 problemi reali di GitHub risolti; i valori sono dichiarati dai produttori, non verificati.
- DeepSWE (deepswe.datacurve.ai): pass@1 su 113 compiti lunghi, tutti con lo stesso agente (mini-swe-agent).
Nel catalogo la colonna "SWE %" riporta SWE-bench Verified / DeepSWE. Consultate il 2 novembre 2026, le due classifiche riportano solo Qwen3.6-35B-A3B (73,4 / n.d.), DeepSeek-V4-Flash (79,0 / 53) e GLM-5.3-Flash (n.d. / 63); gli altri modelli del pool non compaiono (le pagine mostrano solo una parte delle voci). Attenzione: sono i risultati dei modelli originali a piena precisione con agenti e impostazioni del produttore, non misure fatte su dgx01 né sulle versioni quantizzate che usiamo.
Caricare e testare un nuovo modello (LOAD/TEST)
Nella console, sezione Carica / testa un modello: si incolla l'indirizzo HuggingFace del modello (per i repository GGUF si può indicare la quantizzazione,
es. *Q4_K_M*; per i modelli riservati serve un token HuggingFace, usato solo per il download e non salvato).
- Analizza (senza scaricare nulla): legge dai metadati formato, architettura, dimensione, quantizzazione e contesto massimo, e per ogni motore dice se può funzionare sulle V100 e perché (architetture supportate da vLLM 0.8.5 e da llama.cpp, quantizzazioni non supportate, memoria necessaria).
- Scarica e testa: scarica il modello nel pool, lancia su ogni motore candidato lo stesso test e benchmark usato per il catalogo (un job SLURM per motore, fino a 45 minuti) e mostra esito, prefill, decode, TTFT, avvio, VRAM ed eventuali errori.
- I profili che superano il test vengono aggiunti al catalogo (segnati "utente") e il modello si può avviare come gli altri. I punteggi per tipo di uso sono provvisori finché un amministratore non li rivede.
Limiti: al massimo 2 test alla volta; modelli oltre 200 GB solo per gli amministratori; i test usano la stessa quota di 2 GPU dei modelli in servizio (se è piena vanno in coda). Per vLLM servono i file originali (safetensors), per llama.cpp e strata un repository GGUF.
Tecnologia
- Sito e API: un servizio Python (FastAPI + uvicorn, HTTPS) eseguito come
hpc.clustersu dgx01; pagine in HTML e JavaScript senza framework. Login del cluster HPC tramite PAM/AD. - Motori: tutti in container Singularity (
/beegfs/datasets/llm/images/*.sif), avviati come job SLURM: vLLM e ollama da immagini ufficiali, llama.cpp, strata, colibri, DwarfStar e il server dei modelli decisionali ricompilati per le V100 (CUDA 12.4, sm_70). Nessun motore è installato sul sistema. - Modelli: su BeeGFS,
/beegfs/datasets/models/{llm,fdm}. Catalogo:/opt/common/tools/llm-serve/catalog.yaml(+catalog.d/per i modelli aggiunti con LOAD/TEST).
Limiti delle V100
- Niente bf16 né FP8 in hardware: i modelli girano in fp16 o quantizzati; i pesi FP8/NVFP4 (es. Qwen3.6-27B-FP8) non sono utilizzabili.
- vLLM recente, SGLang e TGI non supportano più queste GPU: vLLM è fermo alla 0.8.5, quindi le architetture più nuove girano in GGUF (llama.cpp, strata).
- I modelli enormi (DeepSeek-V4, GLM-5.3) girano solo in modo sperimentale e molto lento.
Domande frequenti
Vedo un modello avviato da un collega: posso usarlo?
Sì, se è condiviso (non segnato "privato"): basta usarne l'id. Non puoi fermarlo tu.
Posso caricare un mio modello sulla GPU dove ne gira già un altro?
Sì, se è dentro un pod e c'è memoria: la finestra "Avvia" mostra le GPU dei pod dove il modello entra. Altrimenti puoi usare un'altra GPU (pod nuovo o job dedicato), se la quota di 2 GPU non è già piena.
Dov'è la mia API key?
La crei nella console (o con llm-serve key create) e la vedi solo in quel momento. Il servizio ne conserva solo un'impronta (hash), quindi non può mostrartela di nuovo: se la perdi, revocala e creane un'altra.
Perché il mio modello è "in coda"?
La quota di 2 GPU è occupata (da te o da altri utenti del servizio), oppure SLURM non ha GPU libere su dgx01. Si avvia appena una si libera; intanto controlla se ci sta in un pod esistente.
Quanto dura un modello avviato?
Fino al walltime (4 ore di giorno, 12 di sera/notte) o finché lo fermi. I pod vuoti si chiudono dopo 5 minuti.