Dạy RAG nhìn hình trong một buổi chiều
RAG của bạn chỉ đọc text? Tài liệu có bảng biểu, chart thì coi như mù. Đây là cách fine-tune multimodal embedding để RAG thấy cả hình.
Bụi WireKịch bản quen mà đau
Giả sử team bạn 4 người, vừa deploy xong hệ thống RAG cho 500 trang tài liệu nội bộ. Demo với sếp, hỏi câu text thuần — trả lời ngon lành. Sếp gật gù, rồi chỉ vào biểu đồ trang 14: "Doanh thu Q3 theo chart này thế nào?" Hệ thống im lặng hai giây, rồi nhả ra một đoạn văn hoàn toàn lạc đề. Phòng họp đột nhiên rất yên.
Lý do thì đơn giản đến đau lòng: RAG truyền thống chỉ "nhìn" text. Bảng biểu, chart, hình minh họa, layout phức tạp — với nó đều là vùng tối. Bạn có OCR cũng chỉ cứu được phần nào, vì cấu trúc bảng bị phá nát khi flatten thành text thuần. Cột nào thuộc hàng nào, model không biết — và nó sẽ đoán bừa.
Multimodal embedding — mở đèn cho vùng tối
Đây là lúc Visual Document Retrieval (VDR) vào cuộc. Thay vì ép tài liệu qua pipeline OCR → chunk text → encode, VDR encode nguyên cả trang tài liệu dạng ảnh thành vector. Khi user hỏi bằng text, query cũng được encode vào cùng không gian — và retrieval diễn ra trên cả nội dung chữ lẫn visual.
Nói thẳng ra thì: nếu RAG text-only là lái xe chỉ nhìn biển báo chữ, thì multimodal embedding là bật thêm camera 360 — bạn thấy cả vạch kẻ đường, biển hình, và cái ổ gà phía trước.
Sentence Transformers — thư viện mà dân làm semantic search đã quen — giờ hỗ trợ multimodal đầy đủ. Cụ thể, bạn có thể fine-tune model Qwen3-VL-Embedding-2B để nó hiểu tài liệu dạng ảnh theo đúng domain của mình. Kết quả từ Hugging Face: model sau fine-tune đạt NDCG@10 là 0.947, so với base model chỉ 0.888 — và vượt cả các model lớn gấp 4 lần kích thước. Nhỏ mà võ công thâm hậu.
Trước khi fine-tune — chuẩn bị gì?
Ba thứ bạn cần sắp xếp trước khi bắt tay vào:
1. Dataset đúng format
Sentence Transformers nhận dạng (query, positive) hoặc (query, positive, negative). Với VDR, "positive" là ảnh trang tài liệu chứa câu trả lời, "query" là câu hỏi text.
from datasets import Dataset
dataset = Dataset.from_dict({
"query": ["Doanh thu Q3 2025?", "Cấu trúc team AI?"],
"positive": ["path/to/page_14.png", "path/to/page_7.png"],
})
2. Loss function phù hợp
Hai cái tên cần nhớ:
- CachedMultipleNegativesRankingLoss: tiết kiệm memory, cho phép batch size lớn ngay cả trên GPU vừa phải.
- MatryoshkaLoss: cho phép model tạo embedding ở nhiều chiều khác nhau — chiều nhỏ cho tốc độ, chiều lớn cho độ chính xác. Một model phục vụ được cả hai use case mà không cần train lại.
3. Model base
Qwen3-VL-Embedding-2B là lựa chọn cân bằng — đủ nhỏ để fine-tune trên single GPU, đủ mạnh để cho kết quả production-ready.
Thử ngay trong một buổi chiều
Bước 1 — Cài đặt:
pip install sentence-transformers[vision] datasets
Bước 2 — Load model:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("Qwen/Qwen3-VL-Embedding-2B")
Bước 3 — Cấu hình loss (đây là phần quan trọng nhất):
from sentence_transformers.losses import (
CachedMultipleNegativesRankingLoss,
MatryoshkaLoss,
)
base_loss = CachedMultipleNegativesRankingLoss(model, mini_batch_size=16)
loss = MatryoshkaLoss(model, base_loss, matryoshka_dims=[256, 512, 1024])
Bước 4 — Train:
from sentence_transformers import SentenceTransformerTrainer
trainer = SentenceTransformerTrainer(
model=model,
train_dataset=dataset,
loss=loss,
)
trainer.train()
Bước 5 — Đo NDCG@10 trên tập test, so sánh trước và sau. Với khoảng 500–1000 cặp query-document chất lượng, bạn có thể thấy cải thiện rõ rệt chỉ sau vài epoch.
Mấy cái bẫy mình từng thấy
Bẫy 1: "50 cặp data, fine-tune luôn cho nóng!"
50 samples thì model chưa kịp học đã overfit. Tối thiểu nên có vài trăm cặp chất lượng. Chưa đủ data? Dùng base model trước — nó đã khá ngon rồi, đừng vội.
Bẫy 2: Quên MatryoshkaLoss rồi deploy bị chậm
Train xong embedding 1024 chiều, lúc serve mới thấy latency cao. Muốn giảm chiều? Train lại. MatryoshkaLoss giải quyết chuyện này từ đầu — cho phép cắt chiều lúc inference mà không mất nhiều chất lượng. Thiếu một dòng config, tốn thêm mấy ngày.
Bẫy 3: Fine-tune xong quên optimize inference
Model embedding ngon rồi, nhưng nếu pipeline của bạn còn có LLM generation phía sau, đừng quên phần serve. Với workload sinh nhiều token, speculative decoding — dùng draft model nhỏ đề xuất token, model lớn verify một lượt — có thể giảm latency đáng kể. Như dân đã dùng vLLM biết: tắc ở inference thì fine-tune bao đẹp cũng vô nghĩa.
Khi nào nên — và không nên — làm?
Nên fine-tune khi:
- Tài liệu domain-specific (y tế, pháp luật, tài chính) với nhiều bảng biểu, chart
- Base model retrieve sai quá nhiều trên tập test của bạn
- Team có ít nhất vài trăm cặp query-document chất lượng
Chưa cần khi:
- Tài liệu chủ yếu text thuần, ít visual
- Base model đã cho kết quả đủ tốt cho use case hiện tại
- Bạn chưa có evaluation pipeline — fine-tune mà không đo được thì như tập gym mà bỏ cân ở nhà
Đừng tin mình, thử đi rồi biết — chạy base model trên đúng dữ liệu của bạn, đo NDCG@10, rồi hẵng quyết có fine-tune hay không. Đôi khi câu trả lời là "base model đủ rồi" — và đó cũng là một thắng lợi.
---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng
Nguồn tham khảo
- Training and Finetuning Multimodal Embedding & Reranker Models with Sentence Transformers
- Accelerating decode-heavy LLM inference with speculative decoding on AWS Trainium and vLLM | Artificial Intelligence
- A Technical Deep Dive into the Essential Stages of Modern Large Language Model Training, Alignment, and Deployment - MarkTechPost