Skip to content

Latest commit

 

History

33 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laboratorio di Prompting

Un laboratorio didattico offline per far vivere ai ragazzi (scout, campo estivo) i concetti fondamenti dell'ingegneria dei prompt: contesto e memoria, system prompt, skill, workflow — con un modello linguistico locale, in LAN, senza Internet e senza account.

Il percorso guidato è una pagina web a quattro tappe — ① Context Injection, ② System Prompt, ③ Skills, ④ Workflow — più il laboratorio codice su pagina dedicata (code.html): il modello genera una pagina HTML completa e il ragazzo se la porta via. Il laboratorio codice è aperto solo dalle postazioni che l'educatore abilita.

Architettura in tre righe

browser dei ragazzi ──▶ nginx (statici + /api/*) ──▶ gateway (business logic)
                                                        ├── skill service
                                                        ├── llama-server (modello, tappe ①–④)
                                                        └── llama-coder (coder dedicato, laboratorio codice)

Tutto gira su un mini PC (o un Raspberry Pi 3 host con modello 0.5B) in LAN cablata; i ragazzi usano browser kiosk su Raspberry Pi 3. Zero dipendenze esterne a runtime: solo Python stdlib. Il coder dedicato (qwen2.5-coder-1.5b, ~1,9 GB di picco) esiste solo sul mini PC: sul Pi 3 non si attiva e la generazione ricade sul modello principale (fallback dichiarato in pagina).

Provarlo su una macchina sola

Tutti i comandi partono dalla cartella laboratory/ e usano make (vedi make help). Requisito: Python 3.11+ per i test; Docker + compose per lo stack.

Percorso 1 — senza modello, zero download (make demo)

cd laboratory
make demo      # skill ON con backend mock, chat OFF (nessun modello)

Apri http://localhost:8090 : il percorso si naviga, la tappa ③ (skill) funziona col backend simulato. È il modo più rapido per vedere tutto senza scaricare nulla. Il pannello educatore sta su http://localhost:8090/admin.

Percorso 2 — con il modello vero

Le dipendenze da scaricare sono l'immagine Docker di llama.cpp e i modelli (file GGUF).

cd laboratory
make pull      # immagine llama.cpp (server CPU, compatibile OpenAI)

# i modelli: GGUF quantizzati q4_k_m da HuggingFace, in laboratory/models/
#   1.5B (consigliato, ~1 GB)  — target del mini PC
curl -L -o models/qwen2.5-1.5b-instruct-q4_k_m.gguf \
  "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF/resolve/main/qwen2.5-1.5b-instruct-q4_k_m.gguf"
#   0.5B (più leggero, per Raspberry Pi 3)
curl -L -o models/qwen2.5-0.5b-instruct-q4_k_m.gguf \
  "https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q4_k_m.gguf"
#   coder 1.5B (~1 GB) — per il laboratorio codice, richiesto da make up
curl -L -o models/qwen2.5-coder-1.5b-instruct-q4_k_m.gguf \
  "https://huggingface.co/Qwen/Qwen2.5-Coder-1.5B-Instruct-GGUF/resolve/main/qwen2.5-coder-1.5b-instruct-q4_k_m.gguf"

make up        # UN comando, DUE llama: main (tappe ①–④) + coder (laboratorio codice)

Apri http://localhost:8090 e rifai le tappe col modello vero; il banner in pagina dice se il modello è attivo. (MODEL_FILE=.../CODER_FILE=... per cambiare GGUF; senza il GGUF del coder make up non parte — il fallback senza coder resta make demo.)

Comandi utili

Comando Cosa fa
make demo stack senza modello (mock)
make up / make down stack col modello / ferma tutto
make rebuild ricostruisce le immagini e riparte col modello
make status il modello risponde? quanti ragazzi collegati?
make admin URL del pannello educatore (/admin)
make logs log live (grep '#<cid>' segue un ragazzo)
make test suite di test (unittest)
make loadtest N=8 TURNS=4 simula 8 ragazzi in chat (vedi sotto)
make clean-sessions azzera lo storico delle sessioni

Simulare un'aula piena

make loadtest N=8 TURNS=4 lancia 8 "ragazzi" sintetici, ognuno con una conversazione a più turni sulle chat del gateway (sessioni load-*, visibili nel pannello educatore come quelle vere). Utile per vedere come lo stack regge il carico: nel pannello, il grafico token/secondo mostra il ritmo di generazione nel tempo — se degrada con tanti ragazzi contemporanei, si vede.

Consumi: locale vs modello di frontiera

La pagina del laboratorio mostra a ogni ragazzo, sotto il banner, il costo della propria sessione: i consumi stimati qui, sul mini PC (energia, costo, acqua ≈ 0) accanto a quelli della stessa sessione su un modello di frontiera (costo e acqua). Sono stime didattiche semplificate — i dati di partenza (watt, €/kWh, prezzo e acqua del modello di frontiera) stanno in un unico file modificabile, laboratory/backend/costi.py. La lezione: in locale non hai modelli di frontiera, ma ogni domanda ti costa quasi niente; la frontiera la paghi in acqua e denaro anche per le domande semplici.

Laboratorio codice (code.html)

La vecchia tappa ⑤ Prompt Engineering è un laboratorio autonomo su pagina dedicata: il modello scrive una pagina HTML completa — CSS incluso, in un file unico — e il ragazzo se la porta via con Copia, Scarica .html o Apri, con anteprima in sandbox. Dalla pagina del percorso (①–④) non ci sono link: l'accesso lo dà l'educatore, che abilita gli IP delle postazioni dal pannello /admin (allowlist persistente, vale da subito senza riavvii).

Policy nel gateway: tetto dedicato di 4096 token, una generazione alla volta (429 con retry alle concorrenti), niente backpressure su questa tappa. I dettagli stanno in laboratory/README.md.

Flotta llama: più nodi dietro lo stesso ingresso

Quando una classe intera fa accodare le generazioni su un unico nodo, si aggiungono mini PC solo-inferenza alla flotta: pagina, CLI e pannello non cambiano indirizzo né contratto — il gateway instrada ogni chat sul nodo con meno generazioni in corso, evita i nodi spenti e devia quelli lenti; il 429 di sovraccarico arriva solo quando TUTTI i nodi sono in affanno.

Configurazione

LLAMA_URL accetta una lista di endpoint separati da virgola (gateway e skill leggono la stessa variabile); il valore singolo di sempre resta identico:

# laboratory/.env
LLAMA_URL=http://192.168.1.50:8081,http://192.168.1.51:8081,http://localhost:8081

Poi un riavvio di gateway e skill (make rebuild, oppure docker compose restart gateway skill). Nel pannello /admin compare la sezione flotta (per nodo: stato sano / affanno / giù, generazioni in corso, modello servito), il badge della pagina dichiara «Modello locale (2/3 nodi)» e il grafico token/s guadagna un pannello per nodo accanto all'aggregato.

Aggiungere un nodo solo-inferenza (mini PC su LAN)

Sul mini PC serve SOLO il servizio modello, col GGUF condiviso e la porta :8081 pubblicata sulla LAN:

docker run -d --name llama \
  -p 8081:8081 \
  -v /home/lab/models:/models \
  ghcr.io/ggml-org/llama.cpp:server \
  -m /models/qwen2.5-1.5b-instruct-q4_k_m.gguf -c 2048 --host 0.0.0.0

La flotta è omogenea: stesso GGUF e stesso -c del compose principale su tutti i nodi — nome del modello e contesto dichiarati ai ragazzi non devono dipendere da quale nodo risponde. Le porte dirette :8081 dei nodi restano esposte a consumer fidati, stessa convenzione del llama locale. Per aggiungere o togliere un node basta aggiornare la lista negli ambienti server.

Sincronizzare i GGUF sui nodi

L'host del laboratorio resta la fonte: i modelli si allineano con rsync.

cd laboratory
rsync -av --progress models/*.gguf lab@192.168.1.50:/home/lab/models/
rsync -av --progress models/*.gguf lab@192.168.1.51:/home/lab/models/

Un nodo con GGUF diverso o mancante si vede subito nel pannello (nome modello per nodo): meglio ri-sincronizzare prima dell'aula.

Rollback

Rimettere il valore singolo precedente (o togliere la variabile) e riavviare gateway e skill: la flotta si svuota e tutto torna monolite.

LLAMA_URL=http://localhost:8081   # com'era prima della flotta

Verifica manuale della flotta

Senza hardware extra, la procedura si prova anche con un nodo finto (indirizzo di una macchina spenta):

# 1) config a due nodi, uno SPENTO: nessun errore all'avvio
LLAMA_URL=http://localhost:8081,http://192.168.1.99:8081 make rebuild

# 2) una chat: parte sul nodo vivo, risposta regolare
curl -s localhost:8090/api/chat -H 'Content-Type: application/json' \
  -d '{"messages":[{"role":"user","content":"ciao"}]}'

# 3) sotto carico (make loadtest N=4) il meno caro vince: i pannelli per nodo
#    del /admin mostrano serie distinte e il nodo spento risulta «giù»

# 4) stato della flotta coerente (healthy/total, stati per nodo)
curl -s localhost:8090/api/model-status | python3 -m json.tool

La suite automatizzata copre gli stessi casi (make test: instradamento sul nodo meno caro, nodo spento aggirato, nodo in affanno deviato, model-status).

Test

cd laboratory && make test

Licenza

Vedi LICENSE.

About

Laboratorio di Prompting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages