Khóa học
Docker cho phép bạn tạo môi trường nhất quán, di động và tách biệt, khiến nó trở nên thiết yếu cho LLMOps (vận hành mô hình ngôn ngữ lớn). Bằng cách đóng gói các ứng dụng LLM và các phụ thuộc trong container, Docker đơn giản hóa việc triển khai, đảm bảo khả năng tương thích đa hệ thống và tối ưu quy trình kiểm thử.
Trong hướng dẫn này, bạn sẽ học cách xây dựng một ứng dụng chatbot “Hỏi & Đáp theo tài liệu” và triển khai lên đám mây bằng Docker. Chúng ta sẽ dùng Gradio cho giao diện người dùng, LlamaIndex để điều phối, LlamaParse để phân tích cú pháp tài liệu, Mixedbread AI để tạo embedding, Groq để truy cập các mô hình ngôn ngữ lớn, Docker để đóng gói ứng dụng và các phụ thuộc, và Hugging Face Spaces để triển khai ứng dụng lên đám mây.
Hướng dẫn này được thiết kế đơn giản, để bất kỳ ai có kiến thức hạn chế về cách thức hoạt động của ứng dụng AI cũng có thể tự xây dựng miễn phí.
Mô tả dự án
Có hai cách tiếp cận chính để phát triển và triển khai ứng dụng AI:
- Hoàn toàn mã nguồn mở: Cách này nhấn mạnh quyền riêng tư và bảo vệ dữ liệu.
- Hoàn toàn đóng: Cách này tích hợp nhiều API và dịch vụ đám mây.
Cả hai đều có ưu và nhược điểm. Trong trường hợp của chúng ta, chúng ta chọn cách thứ hai, tích hợp nhiều dịch vụ AI. Cách này giúp xây dựng ứng dụng AI nhanh, chỉ mất vài giây để dựng và triển khai. Trọng tâm chính là giảm kích thước image Docker, điều có thể đạt được hiệu quả nhờ tích hợp nhiều dịch vụ AI.
Hãy xem hướng dẫn Local AI với Docker, n8n, Qdrant và Ollama để xây dựng một ứng dụng LLM bằng công cụ và nền tảng mã nguồn mở nhằm tăng cường quyền riêng tư!
Chúng ta sẽ xây dựng một chatbot Hỏi & Đáp đa dụng cho phép người dùng tải tài liệu lên và trò chuyện với tài liệu theo thời gian thực. Nó khá giống với NotebookLM của Google.

Sơ đồ dự án. Ảnh: Tác giả
Các công cụ sẽ dùng trong dự án này:
- Gradio Blocks: Tạo giao diện cho phép người dùng tải mọi tài liệu văn bản và dễ dàng trò chuyện với tài liệu.
- LlamaCloud: Dùng để phân tích tệp và trích xuất dữ liệu văn bản ở dạng markdown.
- MixedBread AI: Chuyển đổi tài liệu đã nạp và tin nhắn chat thành embedding để truy hồi ngữ cảnh.
- Groq Cloud: Truy cập phản hồi LLM tốc độ cao. Trong dự án này, chúng ta sẽ dùng mô hình llama-3.1-70b.
- LlamaIndex: Tạo pipeline RAG (Retrieval Augmented Generation) để điều phối tất cả dịch vụ AI. Pipeline sẽ dùng tệp đã tải lên và tin nhắn người dùng để tạo câu trả lời theo ngữ cảnh.
- Docker: Đóng gói ứng dụng, phụ thuộc, môi trường và cấu hình.
- Hugging Face Cloud: Chúng ta sẽ đẩy toàn bộ tệp lên kho Spaces, và Hugging Face sẽ tự động build image bằng Dockerfile và triển khai lên máy chủ.
Nếu bạn mới làm quen với LLM, hãy cân nhắc học khóa Master Large Language Models (LLMs) Concepts để nắm các thuật ngữ cơ bản, phương pháp, cân nhắc đạo đức và nghiên cứu mới nhất.
1. Thiết lập môi trường
Trước khi xây dựng ứng dụng LLM, chúng ta cần tải và cài đặt Docker từ trang chính thức.
- Cài Docker trên máy cục bộ của bạn với các tùy chọn mặc định.
- Tiếp theo, tạo thư mục dự án bằng IDE ưa thích và thêm tệp
.env. Chúng ta sẽ dùng tệp này để lưu API key cho LlamaCloud, MixedBread AI và Groq Cloud. - Sau đó, đăng ký LlamaCloud và tạo API key. Chúng ta sẽ dùng LlamaCloud để phân tích nhiều định dạng văn bản, gồm Excel, txt, Word và PDF.

Tạo khóa mới trong LlamaCloud. Nguồn ảnh: LlamaCloud
- Tiếp theo, đăng ký MixedBread AI và tạo API key. Chúng ta sẽ dùng khóa này để truy cập miễn phí mô hình embedding hàng đầu của họ.

Tạo API key trong MixedBread. Nguồn ảnh: MixedBread
- Truy cập GroqCloud và đăng ký để tạo API key miễn phí. Chúng ta sẽ dùng GroqCloud để truy cập các LLM tốc độ cao.

Tạo API key trong GroqCloud. Nguồn ảnh: GroqCloud
Tìm hiểu mọi thứ về GroqCloud bằng cách đọc bài viết về Groq LPU Inference Engine. Bạn sẽ học về Groq API và các tính năng kèm ví dụ mã. Ngoài ra, tìm hiểu cách xây dựng ứng dụng AI theo ngữ cảnh bằng Groq API và LlamaIndex.
Tệp .env của bạn sẽ trông như sau:
LLAMA_CLOUD_API_KEY=llx-XXXXXX
GROQ_API_KEY=gsk_XXXXXXX
MXBAI_API_KEY=emb_XXXXXX
Hãy nhớ thêm tệp .env vào .gitignore để tránh vô tình lộ API key ra công khai.
2. Xây dựng ứng dụng LLM
Giờ chúng ta sẽ tạo script Python tên app.py và thêm các thành phần giao diện người dùng, đồng thời tích hợp tất cả dịch vụ AI bằng LlamaParser để phát triển pipeline RAG (Retrieval-Augmented Generation) với LlamaIndex.
Script app.py sẽ thực hiện:
- Nạp tất cả gói Python cần thiết.
- Nạp an toàn tất cả API key từ tệp
.env. - Khởi tạo LlamaParser bằng API key của LlamaCloud.
- Định nghĩa bộ trích xuất tệp xử lý nhiều phần mở rộng phổ biến.
- Khởi tạo mô hình embedding bằng API key MixedBread AI, cụ thể là mô hình
mixedbread-ai/mxbai-embed-large-v1. - Khởi tạo mô hình ngôn ngữ lớn bằng API key Groq Cloud và mô hình
llama-3.1-70b-versatile.
Tiếp theo, nó sẽ triển khai các hàm Python sau:
load_files(): Hàm này nạp tệp, phân tích bằng LlamaParser, chuyển thành embedding và lưu vào vector store. Có xử lý ngoại lệ cho trường hợp tải lên không phải tệp hoặc định dạng không được hỗ trợ.respond(): Hàm này nhận đầu vào của người dùng, truy xuất nội dung từ vector store và dùng nó để tạo phản hồi bằng mô hình Groq. Phản hồi được stream và có xử lý ngoại lệ nếu chưa có tệp nào được tải lên.
Cuối cùng, nó sẽ xây dựng các thành phần UI, gồm bộ tải tệp, nút bấm, hộp chat và giao diện chat tổng thể.
Tìm hiểu thêm về framework LlamaIndex qua hướng dẫn LlamaIndex dễ theo dõi hơn.
Đây là 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()
- Chạy tệp Python trên để khởi động máy chủ Gradio bằng lệnh sau trong terminal:
$ python app.py
Kết quả:

- Bạn có thể truy cập giao diện Grodio bằng cách sao chép và dán URL được tạo vào trình duyệt. Sau đó, tải tệp lên và bắt đầu đặt câu hỏi về tài liệu.

Truy cập ứng dụng Gradio trên trình duyệt. Ảnh: Tác giả
Chúng ta dùng LlamaIndex để xây dựng và triển khai ứng dụng LLM trong hướng dẫn này. Bạn có thể xây dựng ứng dụng tương tự với LangChain qua khóa học ngắn Developing LLM Applications with LangChain.
3. Tạo Dockerfile
- Trong dự án của bạn, tạo
Dockerfileđể đóng gói script ứng dụng, các phụ thuộc Python và cấu hình máy chủ, đồng thời khởi tạo máy chủ Gradio.
Tệp Dockerfile sẽ thực hiện các tác vụ sau:
- Thiết lập môi trường Python 3.9.
- Định nghĩa thư mục làm việc.
- Sao chép tệp
requirements.txtvào thư mục/app. Tệp này chứa tên tất cả các gói Python cần thiết. - Cài đặt toàn bộ phụ thuộc được chỉ định trong
requirements.txt. - Sao chép tệp
app.pyvào thư mục/app. - Mở cổng và thiết lập URL máy chủ Gradio.
- Chạy tệp ứng dụng để khởi động máy chủ.
Tệp Dockerfile nên như sau:
# 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"]
- Và đây là nội dung tệp
requirements.txt. Hãy thêm vào dự án của bạn:
gradio
llama-index-embeddings-mixedbreadai
llama-index-llms-groq
llama-index
4. Build Docker image và chạy container
- Gõ lệnh sau trong terminal để build image docker
docqa. Nó sẽ dùngDockerfileđể tạo Docker image.
$ docker build -t docqa .
Chúng ta có thể xem log của các tiến trình diễn ra trong khi build Docker image:

Build Docker image cho LLM. Ảnh: Tác giả
- Sau khi image được build thành công, vào Docker Desktop, nhấp vào tab Images, rồi nhấp vào Docker image để xem log và các hướng dẫn chạy image.

Xem Docker image trên Docker Desktop. Ảnh: Tác giả
Giờ chúng ta sẽ chạy container Docker cục bộ từ image. Chúng ta sẽ cung cấp số cổng, tệp .env để thiết lập biến môi trường, tên container và thẻ image.
- Chạy lệnh sau trong terminal:
$ docker run -p 7860:7860 --env-file .env --name docqa-container docqa
Khi container bắt đầu chạy, bạn có thể truy cập ứng dụng Gradio bằng cách dán URL, ở đây là http://0.0.0.1:7860/ vào trình duyệt.

Kiểm thử ứng dụng LLM trong container Docker. Ảnh: Tác giả
- Để xem thông tin về tất cả container đang chạy cục bộ, gõ lệnh sau:
$ docker ps
Kết quả:
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
- Bạn có thể dừng container Docker bằng lệnh
stop:
$ docker stop docqa-container
- Bạn cũng có thể xóa nó bằng lệnh
rm:
$ docker rm docqa-container
Khi đã có Docker image, chúng ta có thể triển khai ứng dụng LLM ở bất cứ đâu: GCP, AWS, Azure, hoặc bất kỳ máy chủ đám mây nào hỗ trợ triển khai Docker.
5. Triển khai ứng dụng LLM lên Hugging Face bằng Docker
Để đơn giản cho người mới bắt đầu, chúng ta sẽ triển khai ứng dụng bằng Docker trên Hugging Face Cloud (Spaces).
- Vào bảng điều khiển Hugging Face, nhấp vào ảnh hồ sơ và chọn + New Space.
- Đặt tên cho Space, thêm mô tả ngắn, chọn giấy phép và SDK, rồi tạo kho Space.

Tạo Hugging Face Space mới bằng Docker. nguồn ảnh: Hugging Face
Khi kho Space được tạo, bạn sẽ nhận hướng dẫn cách clone và thêm các tệp cần thiết.
- Để clone kho, dùng lệnh sau (cập nhật URL trỏ đến Space của bạn):
$ git clone https://huggingface.co/spaces/kingabzpro/doc-qa-docker
- Sao chép toàn bộ tệp từ thư mục dự án sang kho mới:
Thư mục dự án của bạn sẽ như sau với đầy đủ tệp. Luôn đảm bảo không đẩy tệp .env lên, hãy thêm nó vào .gitignore.

Cấu trúc tệp dự án. Ảnh: Tác giả
- Stage tệp, commit với thông điệp, rồi push lên Hugging Face Space:
$ git add .
$ git commit -m "Deploying the App"
$ git push
Kết quả:
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
- Vào Hugging Face Space của bạn để truy cập ứng dụng. Nó sẽ build Docker image rồi phục vụ ứng dụng:

Build Docker image trên Hugging Face Cloud. Nguồn ảnh: Doc Qa Docker
Nếu bạn thấy lỗi như dưới đây, đừng lo. Nguyên nhân do thiếu biến môi trường. Chúng ta chỉ cần thiết lập các biến đó trong Hugging Face Space.

Lỗi runtime trên ứng dụng đã triển khai. Nguồn ảnh: Doc Qa Docker
- Để thêm biến môi trường mới trong Space, vào Settings, cuộn xuống và nhấp nút New secret. Sau đó cung cấp tên và giá trị cho biến môi trường như bên dưới. Ở đây, chúng ta thêm các API key cần thiết:

Thêm secrets cho ứng dụng đã triển khai. Nguồn ảnh: Doc Qa Docker settings.
Secrets của bạn sẽ trông như sau sau khi thêm đầy đủ API key làm biến môi trường:

Secrets cho ứng dụng đã triển khai. Nguồn ảnh: Doc Qa Docker settings.
Sau khi thiết lập secrets, ứng dụng sẽ tự động khởi động lại và bạn sẽ thấy ứng dụng chạy. Hãy sử dụng và tận hưởng ứng dụng Hỏi & Đáp tài liệu trên đám mây!

Ứng dụng LLM trên Hugging Face Spaces. Nguồn ảnh: Doc Qa Docker
Để tái lập kết quả, tất cả tệp và cấu hình có trong kho GitHub: kingabzpro/Deploy-Doc-QA.
6. Giám sát ứng dụng đã triển khai
Việc dùng dịch vụ AI có ưu điểm: bạn không phải tự triển khai hay quản lý dịch vụ, có thông lượng cao, và có bảng điều khiển kèm log.
Bảng điều khiển LlamaCloud ghi log mọi tài liệu đã được phân tích. Bạn có thể xem lịch sử yêu cầu và so sánh mức sử dụng.

Bảng điều khiển Llama Cloud. Nguồn: LlamaCloud
Tương tự, bạn cũng có thể kiểm tra số token đã dùng cho mô hình embedding và số lượng yêu cầu đã tạo.

Bảng điều khiển Mixedbread. Nguồn ảnh: Mixedbread
Log chi tiết nhất cho từng API có trên GroqCloud, với thông tin về độ trễ, số token, khóa AI và ID yêu cầu để bạn debug hệ thống.

Log GroqCloud. Nguồn: GroqCloud
Lời kết
Hướng dẫn này cho thấy cách kết hợp nhiều dịch vụ để xây dựng ứng dụng Hỏi & Đáp theo tài liệu hiệu quả với mức sử dụng tài nguyên và chi phí tính toán tối thiểu. Tất cả dịch vụ và công cụ chúng ta dùng đều miễn phí để bạn thử nghiệm và tự xây dựng ứng dụng.
Chúng ta đã giảm kích thước Docker image khoảng 600MB nhờ dùng nhiều dịch vụ AI sẵn có. Nếu tự triển khai mọi thứ, kích thước image có thể khoảng 20GB hoặc hơn.
Tôi khuyến nghị học khóa LLMOps Concepts: From Ideation to Deployment như bước tiếp theo trên hành trình học tập. Khóa học sẽ giúp bạn hiểu vòng đời phát triển LLM và các thách thức khi triển khai ứng dụng, cũng như cách áp dụng hiệu quả các khái niệm này.
Là một nhà khoa học dữ liệu được chứng nhận, tôi đam mê tận dụng công nghệ tiên tiến để tạo ra các ứng dụng học máy đổi mới. Với nền tảng vững chắc về nhận dạng giọng nói, phân tích và báo cáo dữ liệu, MLOps, AI hội thoại và NLP, tôi đã rèn giũa kỹ năng phát triển các hệ thống thông minh có thể tạo ra tác động thực sự. Bên cạnh chuyên môn kỹ thuật, tôi cũng là một người truyền đạt tốt, có khả năng chắt lọc các khái niệm phức tạp thành ngôn ngữ rõ ràng, súc tích. Nhờ đó, tôi trở thành một blogger được nhiều người quan tâm trong lĩnh vực khoa học dữ liệu, chia sẻ góc nhìn và kinh nghiệm với cộng đồng các chuyên gia dữ liệu ngày càng lớn. Hiện tại, tôi tập trung vào sáng tạo và biên tập nội dung, làm việc với các mô hình ngôn ngữ lớn để phát triển nội dung mạnh mẽ và hấp dẫn, giúp doanh nghiệp và cá nhân tận dụng tối đa dữ liệu của mình.
