GUIDA Come creare un Chatbot con LLama

Pubblicità

Skills07

Head of Development
Staff Forum
Utente Èlite
Messaggi
39,219
Reazioni
13,231
Punteggio
253

Guida completa: costruire un chatbot LLaMA in Python e servire un'interfaccia web con Flask​


Scopo: questa guida è pensata per un lettore neofita che si avvicina per la prima volta ai modelli di linguaggio (LLM). Ti guiderò passo-passo: dai concetti base fino a un’app funzionante (backend Flask + frontend semplice), includendo istruzioni pratiche, script, Docker, e suggerimenti per addestrare e personalizzare il modello.


Nota importante sulle licenze
I pesi dei modelli LLaMA sono soggetti a licenze ufficiali di Meta. Prima di scaricarli o distribuirli assicurati di leggere e accettare i termini. Alcuni pesi non possono essere ridistribuiti pubblicamente.



Indice (rapido)​


  1. Concetti base — che cos'è LLaMA, tokenizer, pesi, inferenza
  2. Requisiti e ambiente di lavoro (Windows/macOS/Linux)
  3. Modalità d'esecuzione: llama.cpp vs transformers (pro/contro)
  4. Preparare l'ambiente passo-passo (virtualenv, dipendenze)
  5. Ottenere e preparare i pesi (avvisi, conversione in ggml)
  6. Script minimo per inferenza (llama-cpp-python)
  7. Inferenza con transformers (GPU) — esempio semplice
  8. Capire i prompt e progettare bot che rispettino regole e tono
  9. Personalizzazione: Few-shot, Instruction tuning, LoRA (PEFT)
  10. Backend: API REST con Flask (codice completo)
  11. Frontend: pagina HTML + Tailwind, miglioramenti UX
  12. WebSocket per chat in tempo reale (Flask-SocketIO)
  13. Docker e docker-compose per distribuire il servizio
  14. Sicurezza, privacy e considerazioni legali
  15. Debugging e risoluzione problemi comuni
  16. Checklist finale e suggerimenti per il post sul forum
  17. Risorse e link utili (cosa leggere dopo)



1) Concetti base (breve)​


  • LLM (Large Language Model): modello di deep learning addestrato su grandi quantità di testo. Genera testo predicendo la parola successiva.
  • LLaMA: famiglia di modelli rilasciata da Meta (es. LLaMA 2/3). Ha diversi formati e pesi.
  • Tokenizer: converte testo in numeri (token) che il modello elabora.
  • Pesi: i file che contengono i parametri del modello.
  • Inferenza: generare testo usando il modello già addestrato.

Per un principiante: pensa al modello come a una grande funzione che trasforma un prompt in una risposta; il tokenizer traduce il testo in input numerici che la funzione comprende.




2) Requisiti e ambiente di lavoro​


Requisiti minimi​


  • Python 3.10+ (consigliato 3.11)
  • 8+ GB RAM (per modelli piccoli/quantizzati con llama.cpp)
  • Per modelli grandi e training: GPU con CUDA (16GB+ consigliati)
  • Spazio su disco: 10–50 GB (a seconda dei pesi)

Sistema operativo​


  • Linux è più semplice per tool di ML; macOS va bene; Windows funziona ma alcune dipendenze (compilazione di llama.cpp) possono richiedere WSL.

Consigli pratici​


  • Usa un ambiente virtuale (venv) o Conda.
  • Lavora su una macchina dedicata se sperimenti con pesi grandi.



3) Modalità d'esecuzione: pro e contro​


llama.cpp​


  • Pro: esecuzione su CPU, supporto a modelli quantizzati (ggml), basso uso di memoria, ottimo per laptop/desktop senza GPU.
  • Contro: performance inferiore rispetto a GPU; conversione pesi richiesta.

transformers​


  • Pro: sfrutta GPU per inferenza veloce e training; ecosistema ricco (PEFT, Accelerate).
  • Contro: richiede GPU, più complesso da configurare.

Servizi gestiti (Hugging Face Inference, AWS, Replicate)​


  • Pro: zero setup hardware, produzione più semplice.
  • Contro: costi, dipendenza da servizi esterni.

Scelta per un neofita: cominciare con llama.cpp per sperimentare localmente, poi passare a GPU/transformers se necessario.




4) Preparare l'ambiente passo-passo​


Esempio su Linux / macOS.


Codice:
# crea e attiva venv<br>python -m venv venv<br>source venv/bin/activate<br>pip install --upgrade pip<br>

Installazioni principali (versione di base per llama-cpp-python):


Codice:
pip install flask flask-socketio llama-cpp-python<br>

Se prevedi GPU e transformers:


Codice:
pip install transformers accelerate peft datasets safetensors bitsandbytes torch<br>

Nota: l'installazione di torch dipende dalla tua versione di CUDA; segui la guida ufficiale di PyTorch.




5) Ottenere e preparare i pesi​


  1. Registrati (se richiesto) sulla pagina ufficiale di Meta/LLaMA e accetta la licenza.
  2. Scarica i pesi (spesso in formato safetensors o PyTorch).
  3. Per llama.cpp: è necessario convertire i pesi in formato ggml (quantizzato). I repository llama.cpp forniscono script di conversione. Tipicamente il comando è qualcosa del genere (semplificato):

Codice:
# clonare llama.cpp e usare script di conversione (esempio generico)<br>git clone https://github.com/ggerganov/llama.cpp<br>cd llama.cpp<br># copia i pesi in una cartella e segui il README per convertire a ggml<br>python convert.py --input model.safetensors --output model.ggml<br>

  1. Metti il file model.ggml in ./models/.

Attenzione: i nomi dei comandi e script cambiano col tempo; segui sempre il README del repo llama.cpp che hai clonato.




6) Script minimo per inferenza con​


File infer_llama.py:


Codice:
from llama_cpp import Llama<br><br># percorso al modello ggml<br>MODEL_PATH = "./models/llama-7b.ggml"<br>llm = Llama(model_path=MODEL_PATH)<br><br>prompt = "Scrivi una breve guida introduttiva su Flask in italiano."<br>res = llm.create(prompt=prompt, max_tokens=200, temperature=0.2)<br>print(res.choices[0].text)<br>

Esegui:


Codice:
python infer_llama.py<br>

Parametri utili:


  • max_tokens: lunghezza massima generata
  • temperature: casualità (0.0 = deterministico)
  • top_p: nucleus sampling
  • stop: lista di token per fermare la generazione



7) Inferenza con transformers (GPU)​


Installare le dipendenze necessarie (PyTorch compatibile con la tua GPU).


Esempio semplificato:


Codice:
from transformers import AutoTokenizer, AutoModelForCausalLM<br>import torch<br><br>model_name = "meta-llama/your-model-name"<br>tokenizer = AutoTokenizer.from_pretrained(model_name)<br>model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16, device_map='auto')<br><br>inputs = tokenizer("Ciao! Spiegami cosa è Flask.", return_tensors='pt').to(model.device)<br>outputs = model.generate(**inputs, max_new_tokens=150)<br>print(tokenizer.decode(outputs[0], skip_special_tokens=True))<br>

Questo approccio va bene se hai accesso ai pesi e una GPU.




8) Progettare prompt efficaci (prompt engineering)​


Concetti chiave​


  • System prompt: istruzioni a inizio prompt che definiscono comportamento (es. tono, lingua, formato).
  • Few-shot: includere alcuni esempi di domanda/risposta per indirizzare il modello.
  • Temperature e max_tokens determinano creatività e lunghezza.

Esempio di system prompt​


Codice:
Sei un assistente tecnico che risponde in italiano in modo chiaro e conciso. Fornisci esempi di codice quando necessario e non inventare fatti.<br>

Best practices​


  • Fornisci formato di output se necessario (JSON, elenco puntato).
  • Se il modello tende a inventare, abbassa temperature e aggiungi prompt che richiedano "se non sei sicuro, ammettilo".



9) Personalizzazione: Few-shot, Instruction-tuning, LoRA​


Few-shot​


  • Facile: inserisci esempi nel prompt. Non richiede training.
  • Limite: prompt più lungo, inferenza più costosa.

Instruction-tuning / Fine-tuning​


  • Addestrare il modello su coppie (prompt -> risposta) per ottenere comportamento persistente.
  • Richiede risorse (GPU, tempo).

LoRA (PEFT)​


  • Metodo efficiente che modifica pochi parametri.
  • Vantaggio: richiede poca memoria e salva solo i pesi adattati.

Esempio schematico per LoRA (concettuale):


Codice:
# librerie: transformers, accelerate, peft<br># carica modello in 4-bit o fp16<br># prepara dataset (JSONL con campi prompt, response)<br># configura LoraConfig e trainer<br># trainer.train()<br># salva i pesi LoRA<br>

Per un neofita: comincia con few-shot; passa a LoRA quando vuoi che le personalizzazioni siano persistenti senza dover mantenere grandi training runs.




10) Backend Flask: API REST completa​


Crea app.py con una API REST minima che serve il modello.


Codice:
# app.py<br>from flask import Flask, request, jsonify<br>from llama_cpp import Llama<br>import os<br><br>app = Flask(__name__)<br>MODEL_PATH = os.environ.get('MODEL_PATH','./models/llama-7b.ggml')<br>llm = Llama(model_path=MODEL_PATH)<br><br>@app.route('/api/chat', methods=['POST'])<br>def chat():<br>    data = request.json or {}<br>    prompt = data.get('prompt','')<br>    if not prompt:<br>        return jsonify({'error':'prompt mancante'}), 400<br>    # potresti costruire qui un prompt system integrando istruzioni persistenti<br>    resp = llm.create(prompt=prompt, max_tokens=256, temperature=0.2)<br>    text = resp.choices[0].text<br>    return jsonify({'reply': text})<br><br>if __name__ == '__main__':<br>    app.run(host='0.0.0.0', port=5000)<br>

Eseguire in sviluppo​


Codice:
export MODEL_PATH=./models/llama-7b.ggml<br>python app.py<br>

Migliorie consigliate​


  • Aggiungi gestione errori e timeout.
  • Aggiungi rate-limiting (es. flask-limiter).
  • Log delle richieste (evita di registrare dati sensibili).



11) Frontend semplice (HTML + Tailwind)​


File templates/index.html (Flask serve la cartella templates automaticamente):


Codice:
&lt;!doctype html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>  &lt;meta charset="utf-8"&gt;<br>  &lt;meta name="viewport" content="width=device-width,initial-scale=1"&gt;<br>  &lt;script src="https://cdn.tailwindcss.com"&gt;&lt;/script&gt;<br>  &lt;title&gt;Chatbot LLaMA&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body class="bg-gray-100 p-6"&gt;<br>  &lt;div class="max-w-3xl mx-auto bg-white rounded-2xl shadow p-6"&gt;<br>    &lt;h1 class="text-2xl font-bold mb-4"&gt;Chatbot LLaMA&lt;/h1&gt;<br>    &lt;div id="chat" class="h-96 overflow-y-auto border p-3 mb-3 rounded"&gt;&lt;/div&gt;<br>    &lt;div class="flex"&gt;<br>      &lt;input id="prompt" class="flex-1 border rounded p-2 mr-2" placeholder="Scrivi qui..."&gt;<br>      &lt;button id="send" class="px-4 py-2 bg-blue-600 text-white rounded"&gt;Invia&lt;/button&gt;<br>    &lt;/div&gt;<br>  &lt;/div&gt;<br>  &lt;script&gt;<br>    const chatEl = document.getElementById('chat')<br>    document.getElementById('send').onclick = async ()=&gt;{<br>      const prompt = document.getElementById('prompt').value<br>      if(!prompt) return<br>      chatEl.innerHTML += `&lt;div class='text-sm text-gray-700 mb-2'&gt;&lt;strong&gt;Tu:&lt;/strong&gt; ${prompt}&lt;/div&gt;`<br>      document.getElementById('prompt').value = ''<br>      const res = await fetch('/api/chat', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({prompt})})<br>      const j = await res.json()<br>      chatEl.innerHTML += `&lt;div class='text-sm text-gray-900 mb-4'&gt;&lt;strong&gt;Bot:&lt;/strong&gt; ${j.reply}&lt;/div&gt;`<br>      chatEl.scrollTop = chatEl.scrollHeight<br>    }<br>  &lt;/script&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;<br>

Miglioramenti UX:


  • visualizzare indicatori di "sta scrivendo..."
  • timestamp per i messaggi
  • supporto per prompt predefiniti



12) Chat in tempo reale con Flask-SocketIO​


File app_socket.py:


Codice:
from flask import Flask, render_template<br>from flask_socketio import SocketIO, emit<br>from llama_cpp import Llama<br><br>app = Flask(__name__)<br>socketio = SocketIO(app, cors_allowed_origins='*')<br>llm = Llama(model_path='./models/llama-7b.ggml')<br><br>@app.route('/')<br>def index():<br>    return render_template('index.html')<br><br>@socketio.on('user_message')<br>def handle_message(data):<br>    prompt = data.get('prompt','')<br>    emit('bot_typing', {'status': True})<br>    resp = llm.create(prompt=prompt, max_tokens=256)<br>    emit('bot_reply', {'reply': resp.choices[0].text})<br><br>if __name__ == '__main__':<br>    socketio.run(app, host='0.0.0.0', port=5000)<br>

Lato client usa socket.io per inviare messaggi e ricevere risposte in tempo reale.




13) Docker e docker-compose​


Dockerfile (esempio semplice)​


FROM python:3.11-slim<br>WORKDIR /app<br>COPY requirements.txt ./<br>RUN pip install --no-cache-dir -r requirements.txt<br>COPY . /app<br>ENV MODEL_PATH=/app/models/llama-7b.ggml<br>EXPOSE 5000<br>CMD ["python","app.py"]<br>

docker-compose.yml di esempio (per sviluppo locale):


Codice:
version: '3.8'<br>services:<br>  web:<br>    build: .<br>    volumes:<br>      - ./models:/app/models:ro<br>    ports:<br>      - "5000:5000"<br>

Costruisci e avvia:


Codice:
docker compose up --build<br>

Note: i file dei pesi sono molto grandi: montali come volume e non includerli nell'immagine.




14) Sicurezza, privacy e considerazioni legali​


  • Proteggi l'API: usa autenticazione (API key), HTTPS e rate-limiting.
  • Dati sensibili: evita di loggare informazioni personali; se necessario, anonimizza i log.
  • Licenze dei pesi: rispetta i termini di Meta e dei dataset usati per il fine-tuning.
  • Moderazione: implementa filtri per contenuti offensivi o pericolosi (prima di mostrare la risposta all'utente).



15) Debugging e problemi comuni​


  • Errore memoria GPU: riduci batch size, usa 4-bit quantization, o passa a llama.cpp.
  • Installazione difficile su Windows: prova WSL2 con Ubuntu.
  • Performance lente su CPU: usa modello quantizzato con llama.cpp.
  • Risposte inventate (hallucinations): specifica nel prompt di "ammettere se non si è sicuri", riduci temperature, fornisci fonti in prompt.



16) Checklist per il post sul forum​


  • Fornisci istruzioni chiare su come ottenere i pesi (link ufficiale e nota licenza).
  • Includi file essenziali: app.py, requirements.txt, templates/index.html, Dockerfile, docker-compose.yml.
  • Includi screenshot della UI e output di esempio.
  • Spiega limitazioni e possibili upgrade (GPU, LoRA, deploy su cloud).



17) Risorse e link utili (da aggiungere al post)​


  • Documentazione ufficiale LLaMA (Meta) — come ottenere i pesi e licenza
  • Repository llama.cpp — conversione ggml ed esecuzione CPU
  • llama-cpp-python — binding Python per llama.cpp
  • Hugging Face: transformers, accelerate, peft, datasets — per inferenza GPU e LoRA
  • Flask e Flask-SocketIO — guide ufficiali
  • TailwindCSS — guida rapida per styling
  • PyTorch — installazione corretta per la tua GPU


REPOSITORY GITHUB: https://github.com/Chry1911/LLamaChatbot
 
Ultima modifica:
Ottima guida come sempre👍
Non c'entra niente, ma io uso Ollama con Open WebUi. Recentemente ho creato un workflow in n8n e accedo alla chat sulla mia istanza di n8n pubblica.
Cosa ne pensi di questo approccio?
 
Ultima modifica:
è un approccio alternativo, che funziona bene.
Io ho provato giusto per dirla tutta dando informazioni migliori con:

- windows 11
- 16gb ram ddr3
- i7 4790
- gtx 970

E gira bene il modello, è un modello leggero che usa al massimo 8gb di ram.
Sicuramente se provassi su quello con l'i5 14600kf + 32gb di ram e la 5060 con i cuda core avrei ancora piu benefici.

Bello comunque che ne stiamo facendo una bella discussione
 
è un approccio alternativo, che funziona bene.
Io ho provato giusto per dirla tutta dando informazioni migliori con:

- windows 11
- 16gb ram ddr3
- i7 4790
- gtx 970

E gira bene il modello, è un modello leggero che usa al massimo 8gb di ram.
Sicuramente se provassi su quello con l'i5 14600kf + 32gb di ram e la 5060 con i cuda core avrei ancora piu benefici.
Sicuramente, io faccio girare tutto sulla 5070Ti, preferisco stare tutto sulla gpu. Uso docker desktop in win11 (che usa wsl comunque). Gli ho dato 6 cpu e 24 Gb di Ram.
Screenshot 2025-12-05 181728.webp
Ollama per gli LLM, open webUi per usarli (in realtà lo uso pochissimo ultimamente), piper per TTS e whisper per speech-to-text, questi due mi servono in home assistant per far parlare Home Assistant voice preview.

I modelli che ho attualmente
Screenshot 2025-12-05 181904.webp
Llama3.1 distillato lo uso proprio in home assistant. Da ieri però sto provando anche qwen3 con ottimi risultati perchè è thinking.
Bello comunque che ne stiamo facendo una bella discussione
Si finalmente qualcuno con cui parlarne seriamente, sono più di 6 mesi che smanetto e sono ancora alle basi, c'è tutto un mondo da scoprire.
 
Ottimo, bellissimo il fatto che hai dockerizzato tutto, in maniera tale da avere ambienti isolati e contenerizzati, questo implica il non installare librerie esterne.

Fondamentale se ti stai cimentando in python, usare sempre il Virtual Environement (venv) cosi col pip installi sempre librerie in un ambiente isolato e non in mezzo a windows.
 
Allego file con le dipendenze che sto usando io su windows 11 senza WSL.

Python:
flask
flask-cors
llama-cpp-python>=0.2.90
sentencepiece
pdfplumber
python-docx
pypdf
docx2txt
imapclient
requests
python-dotenv
datasets
pandas
numpy
scikit-learn
huggingface-hub
 
intanto mostro la mia demo in lavorazione che già funziona
 

Allegati

  • Screenshot 2025-12-06 090620.webp
    Screenshot 2025-12-06 090620.webp
    72.1 KB · Visualizzazioni: 1
L’intento del mio bot è renderlo disponibile a solo richieste di un argomento e fargli fare analisi documentale
 
Si tramite prompt ad esempio ho scritto questo:
Python:
@app.route("/start_stream", methods=["POST"])
def start_stream():
    data = request.json or {}
    conv_id = data.get("conv_id") or create_conversation()
    convs = load_conversations()
    history = convs.get(conv_id, {}).get("messages", [])

    # Prompt system aggiornato per ambito informatico
    SYSTEM_PROMPT = """
<<SYS>>
Sei un assistente specializzato **solo ed esclusivamente in argomenti di informatica**.

Puoi rispondere SOLO se la domanda riguarda:
- programmazione
- linguaggi di programmazione
- sviluppo software
- architetture software
- informatica generale
- server, reti, protocolli
- hardware, sistemi operativi
- cybersecurity
- database
- strumenti informatici
- troubleshooting tecnico
- AI / machine learning / modelli LLM
- cloud computing
- DevOps, Docker, Kubernetes

SE LA DOMANDA NON È DI NATURA INFORMATICA:
- NON devi rispondere alla domanda
- NON devi inventare nulla
- NON devi divagare

Devi rispondere esattamente con questo messaggio:

"Mi dispiace, posso rispondere solo a domande di ambito informatico."

Il messaggio deve essere IDENTICO senza variazioni.
<</SYS>>
"""

Questo vuol dire che ignora qualsiasi altra richiesta

Poi ho abbellito la UI

1765024554822.webp

E come vedi risponde solo con del codice
 
Si tramite prompt ad esempio ho scritto questo:
Python:
@app.route("/start_stream", methods=["POST"])
def start_stream():
    data = request.json or {}
    conv_id = data.get("conv_id") or create_conversation()
    convs = load_conversations()
    history = convs.get(conv_id, {}).get("messages", [])

    # Prompt system aggiornato per ambito informatico
    SYSTEM_PROMPT = """
<<SYS>>
Sei un assistente specializzato **solo ed esclusivamente in argomenti di informatica**.

Puoi rispondere SOLO se la domanda riguarda:
- programmazione
- linguaggi di programmazione
- sviluppo software
- architetture software
- informatica generale
- server, reti, protocolli
- hardware, sistemi operativi
- cybersecurity
- database
- strumenti informatici
- troubleshooting tecnico
- AI / machine learning / modelli LLM
- cloud computing
- DevOps, Docker, Kubernetes

SE LA DOMANDA NON È DI NATURA INFORMATICA:
- NON devi rispondere alla domanda
- NON devi inventare nulla
- NON devi divagare

Devi rispondere esattamente con questo messaggio:

"Mi dispiace, posso rispondere solo a domande di ambito informatico."

Il messaggio deve essere IDENTICO senza variazioni.
<</SYS>>
"""

Questo vuol dire che ignora qualsiasi altra richiesta

Poi ho abbellito la UI

Visualizza allegato 501283

E come vedi risponde solo con del codice
Ottimo veramente. Infatti quello che voglio imparare bene io e il prompt engineering, scrivere il giusto prompt è la cosa più difficile secondo me
 
Pubblicità
Pubblicità
Indietro
Top