Corso
Docker ti permette di creare ambienti coerenti, portabili e isolati, rendendolo essenziale per le LLMOps (Large Language Models Operations). Incapsulando diverse applicazioni LLM e le loro dipendenze in container, Docker semplifica la distribuzione, assicura la compatibilità tra sistemi e snellisce i test.
In questo tutorial imparerai a creare un'applicazione chatbot di “domande e risposte su documenti” e a distribuirla sul cloud usando Docker. Useremo Gradio per l'interfaccia utente, LlamaIndex per l'orchestrazione, LlamaParse per il parsing dei documenti, Mixedbread AI per gli embedding, Groq per accedere ai modelli linguistici di grandi dimensioni, Docker per impacchettare l'applicazione e le sue dipendenze, e Hugging Face Spaces per distribuire l'app sul cloud.
Questo tutorial è pensato per essere semplice, così chiunque, anche con conoscenze limitate su come funzionano le applicazioni di AI, può costruirlo gratuitamente.
Descrizione del progetto
Ci sono due approcci principali per sviluppare e distribuire applicazioni di AI:
- Completamente open source: Questo approccio enfatizza privacy e protezione dei dati.
- Completamente closed source: Questo metodo prevede l'integrazione di più API e servizi cloud.
Entrambi gli approcci hanno pro e contro. Nel nostro caso, abbiamo scelto il secondo, integrando più servizi di AI. Questo ci permette di costruire un'app veloce che richiede solo pochi secondi per essere creata e distribuita. Il nostro obiettivo principale è ridurre la dimensione dell'immagine Docker, cosa che può essere ottenuta efficacemente integrando più servizi di AI.
Dai un'occhiata al tutorial Local AI con Docker, n8n, Qdrant e Ollama per costruire un'app LLM usando strumenti e framework open source per una privacy maggiore!
Costruiremo un chatbot di Q&A generico che consente agli utenti di caricare documenti e chattarci in tempo reale. È piuttosto simile al NotebookLM di Google.

Diagramma del progetto. Immagine dell'autore
Ecco gli strumenti che useremo in questo progetto:
- Gradio Blocks: Per creare un'interfaccia utente che consente di caricare qualsiasi documento di testo e chattare facilmente con il documento.
- LlamaCloud: Serve per eseguire il parsing dei file ed estrarre i dati testuali in stile markdown.
- MixedBread AI: Viene utilizzato per convertire i documenti caricati e i messaggi in embedding per il recupero del contesto.
- Groq Cloud: Serve per ottenere risposte LLM veloci. In questo progetto useremo il modello llama-3.1-70b.
- LlamaIndex: Per creare la pipeline RAG (Retrieval Augmented Generation) che orchestra tutti i servizi di AI. La pipeline userà il file caricato e i messaggi dell'utente per generare risposte contestuali.
- Docker: Viene utilizzato per incapsulare app, dipendenze, ambiente e configurazioni.
- Hugging Face Cloud: Spingeremo tutti i file nel repository Spaces e Hugging Face costruirà automaticamente l'immagine usando il Dockerfile e la distribuirà sul server.
Se sei alle prime armi con gli LLM, valuta il corso Padroneggia i concetti dei Large Language Models (LLM) per imparare terminologia di base, metodologie, considerazioni etiche e le ricerche più recenti.
1. Configurazione dell'ambiente
Prima di costruire l'app LLM, dobbiamo scaricare e installare Docker dal sito ufficiale.
- Installa Docker sul tuo sistema locale usando le opzioni predefinite.
- Poi crea una directory di progetto con il tuo IDE preferito e aggiungi un file
.env. Useremo questo file per memorizzare le chiavi API di LlamaCloud, MixedBread AI e Groq Cloud. - Dopodiché, registrati su LlamaCloud e genera la tua chiave API. Useremo LlamaCloud per eseguire il parsing di vari formati di testo, inclusi Excel, txt, Word e PDF.

Generazione di una nuova chiave in LlamaCloud. Fonte immagine: LlamaCloud
- Poi registrati su MixedBread AI e genera la tua chiave API. Useremo questa chiave per accedere gratuitamente al loro modello di embedding di punta.

Creazione di una chiave API in MixedBread. Fonte immagine: MixedBread
- Vai su GroqCloud e registrati per generare gratuitamente la tua chiave API. Useremo GroqCloud per accedere a LLM ad alta velocità.

Creazione di una chiave API in GroqCloud. Fonte immagine: GroqCloud
Scopri tutto su GroqCloud leggendo l'articolo sul motore di inferenza Groq LPU. Imparerai le API Groq e le loro funzionalità con esempi di codice. Inoltre, scoprirai come creare applicazioni di AI contestuali usando Groq API e LlamaIndex.
Ecco come dovrebbe apparire il tuo file .env:
LLAMA_CLOUD_API_KEY=llx-XXXXXX
GROQ_API_KEY=gsk_XXXXXXX
MXBAI_API_KEY=emb_XXXXXX
Ricordati di aggiungere il file .env al tuo .gitignore per evitare di esporre accidentalmente le chiavi API al pubblico.
2. Creazione dell'applicazione LLM
Ora creeremo uno script Python chiamato app.py e aggiungeremo i componenti dell'interfaccia utente integrando tutti i servizi di AI tramite LlamaParser per sviluppare la pipeline Retrieval-Augmented Generation (RAG) con LlamaIndex.
Lo script app.py farà quanto segue:
- Caricare tutti i pacchetti Python necessari.
- Caricare in modo sicuro tutte le chiavi API dal file
.env. - Inizializzare LlamaParser usando la chiave API di LlamaCloud.
- Definire un estrattore di file che gestisca varie estensioni comuni.
- Inizializzare il modello di embedding usando la chiave API di MixedBread AI, nello specifico il modello
mixedbread-ai/mxbai-embed-large-v1. - Inizializzare il large language model usando la chiave API di Groq Cloud e il modello
llama-3.1-70b-versatile.
Successivamente implementerà le seguenti funzioni Python:
load_files(): Questa funzione caricherà i file, li analizzerà con LlamaParser, li convertirà in embedding e li salverà nel vector store. Sarà incluso l'handling delle eccezioni per gestire casi in cui vengano caricati oggetti non file o formati non supportati.respond(): Questa funzione prenderà l'input dell'utente, recupererà contenuti dal vector store e li userà per generare una risposta tramite il modello Groq. La generazione sarà in formato streaming e verrà gestita l'eccezione se non sono stati caricati file.
Infine, costruirà i componenti UI, inclusi un uploader di file, pulsanti, una chat box e l'interfaccia di chat complessiva.
Scopri di più sul framework LlamaIndex seguendo il tutorial più semplice su LlamaIndex.
Ecco lo script app.py:
import os
import gradio as gr
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.embeddings.mixedbreadai import MixedbreadAIEmbedding
from llama_index.llms.groq import Groq
from llama_parse import LlamaParse
# API keys
llama_cloud_key = os.environ.get("LLAMA_CLOUD_API_KEY")
groq_key = os.environ.get("GROQ_API_KEY")
mxbai_key = os.environ.get("MXBAI_API_KEY")
if not (llama_cloud_key and groq_key and mxbai_key):
raise ValueError(
"API Keys not found! Ensure they are passed to the Docker container."
)
# models name
llm_model_name = "llama-3.1-70b-versatile"
embed_model_name = "mixedbread-ai/mxbai-embed-large-v1"
# Initialize the parser
parser = LlamaParse(api_key=llama_cloud_key, result_type="markdown")
# Define file extractor with various common extensions
file_extractor = {
".pdf": parser,
".docx": parser,
".doc": parser,
".txt": parser,
".csv": parser,
".xlsx": parser,
".pptx": parser,
".html": parser,
".jpg": parser,
".jpeg": parser,
".png": parser,
".webp": parser,
".svg": parser,
}
# Initialize the embedding model
embed_model = MixedbreadAIEmbedding(api_key=mxbai_key, model_name=embed_model_name)
# Initialize the LLM
llm = Groq(model="llama-3.1-70b-versatile", api_key=groq_key)
# File processing function
def load_files(file_path: str):
global vector_index
if not file_path:
return "No file path provided. Please upload a file."
valid_extensions = ', '.join(file_extractor.keys())
if not any(file_path.endswith(ext) for ext in file_extractor):
return f"The parser can only parse the following file types: {valid_extensions}"
document = SimpleDirectoryReader(input_files=[file_path], file_extractor=file_extractor).load_data()
vector_index = VectorStoreIndex.from_documents(document, embed_model=embed_model)
print(f"Parsing completed for: {file_path}")
filename = os.path.basename(file_path)
return f"Ready to provide responses based on: {filename}"
# Respond function
def respond(message, history):
try:
# Use the preloaded LLM
query_engine = vector_index.as_query_engine(streaming=True, llm=llm)
streaming_response = query_engine.query(message)
partial_text = ""
for new_text in streaming_response.response_gen:
partial_text += new_text
# Yield an empty string to cleanup the message textbox and the updated conversation history
yield partial_text
except (AttributeError, NameError):
print("An error occurred while processing your request.")
yield "Please upload the file to begin chat."
# Clear function
def clear_state():
global vector_index
vector_index = None
return [None, None, None]
# UI Setup
with gr.Blocks(
theme=gr.themes.Default(
primary_hue="green",
secondary_hue="blue",
font=[gr.themes.GoogleFont("Poppins")],
),
css="footer {visibility: hidden}",
) as demo:
gr.Markdown("# DataCamp Doc Q&A 🤖📃")
with gr.Row():
with gr.Column(scale=1):
file_input = gr.File(
file_count="single", type="filepath", label="Upload Document"
)
with gr.Row():
btn = gr.Button("Submit", variant="primary")
clear = gr.Button("Clear")
output = gr.Textbox(label="Status")
with gr.Column(scale=3):
chatbot = gr.ChatInterface(
fn=respond,
chatbot=gr.Chatbot(height=300),
theme="soft",
show_progress="full",
textbox=gr.Textbox(
placeholder="Ask questions about the uploaded document!",
container=False,
),
)
# Set up Gradio interactions
btn.click(fn=load_files, inputs=file_input, outputs=output)
clear.click(
fn=clear_state, # Use the clear_state function
outputs=[file_input, output],
)
# Launch the demo
if __name__ == "__main__":
demo.launch()
- Esegui il file Python sopra per avviare il server Gradio con il seguente comando nel terminale:
$ python app.py
Output:

- Puoi accedere all'interfaccia di Grodio copiando e incollando l'URL generato nel browser. Quindi puoi caricare un file e iniziare a fare domande al riguardo.

Accesso all'app Gradio dal browser. Immagine dell'autore
In questo tutorial usiamo LlamaIndex per creare e distribuire la nostra applicazione LLM. Puoi creare un'app simile con LangChain seguendo il corso breve Sviluppare applicazioni LLM con LangChain.
3. Creazione del Dockerfile
- Nel tuo progetto, crea un
Dockerfileper impacchettare lo script dell'applicazione, le dipendenze Python e le configurazioni del server, inizializzando il server Gradio.
Il Dockerfile eseguirà le seguenti attività:
- Impostare un ambiente Python 3.9.
- Definire la directory di lavoro.
- Copiare il file
requirements.txtnella directory/app. Questo file contiene i nomi di tutti i pacchetti Python richiesti. - Installare tutte le dipendenze specificate in
requirements.txt. - Copiare il file
app.pynella directory/app. - Esporre la porta e impostare l'URL del server Gradio.
- Eseguire il file dell'applicazione per avviare il server.
Ecco come dovrebbe apparire il Dockerfile:
# Dockerfile
# Use the official Python image with the desired version
FROM python:3.9-slim
# Set the working directory inside the container
WORKDIR /app
# Copy the requirements file to the working directory
COPY requirements.txt /app
# Install the dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code to the working directory
COPY app.py /app
# Expose the port that Gradio will run on (default is 7860)
EXPOSE 7860
ENV GRADIO_SERVER_NAME="0.0.0.0"
# Command to run your application
CMD ["python", "app.py"]
- E così appare il file
requirements.txt. Aggiungilo anche al tuo progetto:
gradio
llama-index-embeddings-mixedbreadai
llama-index-llms-groq
llama-index
4. Creazione dell'immagine Docker ed esecuzione del container
- Digita il seguente comando nel terminale per costruire l'immagine docker
docqa. Userà ilDockerfileper creare l'immagine Docker.
$ docker build -t docqa .
Possiamo vedere i log dei processi in corso durante la creazione dell'immagine Docker:

Creazione dell'immagine Docker LLM. Immagine dell'autore
- Una volta creata l'immagine, vai su Docker Desktop, clicca sulla scheda Images e seleziona l'immagine Docker per vedere i log e le varie istruzioni per eseguirla.

Visualizzazione dell'immagine Docker su Docker Desktop. Immagine dell'autore
Ora eseguiremo il container Docker in locale usando l'immagine. Gli forniremo il numero di porta, un file .env per impostare le variabili d'ambiente, il nome del container Docker e il tag dell'immagine Docker.
- Esegui il seguente comando nel tuo terminale:
$ docker run -p 7860:7860 --env-file .env --name docqa-container docqa
Una volta avviato il container, puoi accedere all'app Gradio incollando l'URL, in questo caso http://0.0.0.1:7860/ nel browser.

Test dell'applicazione LLM nel container Docker. Immagine dell'autore
- Per visualizzare le informazioni su tutti i container in esecuzione in locale, digita il seguente comando:
$ docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ff2a11da13d7 docqa "python app.py" 17 seconds ago Up 16 seconds 0.0.0.0:7860->7860/tcp docqa-container
- Puoi fermare il container Docker con il comando
stop:
$ docker stop docqa-container
- Puoi anche rimuoverlo con il comando
rm:
$ docker rm docqa-container
Una volta che abbiamo un'immagine Docker, possiamo distribuire la nostra applicazione LLM ovunque: GCP, AWS, Azure o qualsiasi server cloud che supporti la distribuzione con Docker.
5. Distribuire l'applicazione LLM su Hugging Face usando Docker
Per semplificare le cose ai principianti, distribuiremo l'app usando Docker su Hugging Face Cloud (Spaces).
- Vai alla dashboard di Hugging Face, clicca sull'immagine del profilo e seleziona + New Space.
- Dai un nome al tuo Space, aggiungi una breve descrizione, seleziona la licenza e l'SDK, e crea il repository dello Space.

Creazione del nuovo Hugging Face Space usando Docker. Fonte immagine: Hugging Face
Una volta creato il repository dello Space, riceverai le istruzioni su come clonarlo e aggiungere i file necessari.
- Per clonare il repository, usa il seguente comando (aggiorna l'URL con quello del tuo Space):
$ git clone https://huggingface.co/spaces/kingabzpro/doc-qa-docker
- Copia e incolla tutti i file dalla directory del progetto nel nuovo repository:
Ecco come dovrebbe apparire la directory del progetto con tutti i file. Assicurati sempre di non fare push del file .env, quindi aggiungilo al .gitignore.

Struttura dei file del progetto. Immagine dell'autore
- Metti in stage i file, fai il commit con un messaggio e poi fai push sullo Space di Hugging Face:
$ git add .
$ git commit -m "Deploying the App"
$ git push
Output:
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 16 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 7.60 KiB | 7.60 MiB/s, done.
Total 7 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://huggingface.co/spaces/kingabzpro/doc-qa-docker
afb20ad..5ca6388 main -> main
- Vai sul tuo Hugging Face Space per accedere all'applicazione. Costruirà l'immagine Docker e poi servirà l'applicazione:

Creazione dell'immagine Docker su Hugging Face Cloud. Fonte immagine: Doc Qa Docker
Se vedi un errore come quello sotto, non preoccuparti. È dovuto alla mancanza di variabili d'ambiente. Dobbiamo solo impostarle nello Space di Hugging Face.

Errore a runtime sull'app distribuita. Fonte immagine: Doc Qa Docker
- Per aggiungere una nuova variabile d'ambiente nel tuo Space, vai su Settings, scorri in basso e clicca sul pulsante New secret. Poi fornisci nome e valore per la variabile, come mostrato sotto. In questo caso, aggiungiamo le chiavi API necessarie:

Aggiunta dei secret all'app distribuita. Fonte immagine: Impostazioni Doc Qa Docker.
Ecco come dovrebbero apparire i tuoi secret dopo aver aggiunto tutte le chiavi API necessarie come variabili d'ambiente:

Secret per l'app distribuita. Fonte immagine: Impostazioni Doc Qa Docker.
Una volta impostati i secret, l'app si riavvierà automaticamente e dovresti vederla in esecuzione. Usala e goditi la tua applicazione di Q&A sui documenti nel cloud!

App LLM su Hugging Face Spaces. Fonte: Doc Qa Docker
Per riprodurre i risultati, tutti i file e le configurazioni sono disponibili nel repository GitHub: kingabzpro/Deploy-Doc-QA.
6. Monitoraggio dell'applicazione distribuita
Usare servizi di AI ha vantaggi: non devi distribuire o gestire servizi, ottieni throughput elevato e hai una dashboard con i log.
La tua dashboard LlamaCloud registra tutti i documenti che sono stati analizzati. Puoi consultare la cronologia o le richieste e confrontare l'utilizzo.

Dashboard Llama Cloud. Fonte: LlamaCloud
Allo stesso modo, puoi anche verificare il numero di token usati per il modello di embedding e il numero di richieste generate.

Dashboard Mixedbread. Fonte: Mixedbread
I log più dettagliati di ciascuna API si trovano su GroqCloud, con informazioni su latenza, numero di token, chiave AI e ID richiesta per effettuare il debug del sistema.

Log GroqCloud. Fonte: GroqCloud
Considerazioni finali
Questa guida ci ha mostrato come combinare più servizi per costruire un'applicazione di Q&A su documenti efficiente con un uso minimo di risorse e overhead computazionale. Tutti i servizi e gli strumenti utilizzati sono disponibili gratuitamente per testare e costruire la tua applicazione.
Abbiamo ridotto la dimensione dell'immagine Docker di 600 MB usando più servizi di AI pronti all'uso. Se avessimo distribuito tutto in autonomia, la dimensione sarebbe stata intorno ai 20 GB o più.
Ti consiglio, come prossimo passo del tuo percorso di apprendimento, il corso Concetti di LLMOps: dall'ideazione alla distribuzione. Questo corso ti aiuterà a comprendere il ciclo di vita di sviluppo degli LLM e le sfide della distribuzione delle applicazioni. Ti insegnerà anche come applicare efficacemente questi concetti.
In quanto data scientist certificato, sono appassionato di sfruttare tecnologie all’avanguardia per creare applicazioni di machine learning innovative. Con una solida esperienza in riconoscimento vocale, analisi e reportistica dei dati, MLOps, AI conversazionale e NLP, ho affinato le mie competenze nello sviluppo di sistemi intelligenti in grado di avere un impatto concreto. Oltre alla mia expertise tecnica, sono anche un comunicatore efficace, con il talento di rendere chiari e sintetici concetti complessi. Di conseguenza, sono diventato un blogger molto seguito in ambito data science, condividendo idee ed esperienze con una community in crescita di professionisti dei dati. Attualmente mi concentro sulla creazione e sull’editing di contenuti, lavorando con large language model per sviluppare contenuti potenti e coinvolgenti che possano aiutare aziende e singoli a valorizzare al meglio i propri dati.


