Mục lục bài
Pipeline RAG gồm những gì
- Nạp: trích xuất văn bản sạch từ tài liệu, gắn metadata (nguồn, phòng ban, quyền xem, ngày hiệu lực).
- Chia đoạn (chunking) theo cấu trúc tài liệu.
- Embedding: biến mỗi đoạn thành vector, lưu vào vector DB cùng metadata.
- Truy vấn: embedding câu hỏi → lọc theo quyền → tìm đoạn gần nhất → rerank.
- Sinh câu trả lời: LLM đọc các đoạn đã chọn, trả lời kèm trích dẫn.
- Đánh giá và cập nhật liên tục khi tài liệu thay đổi.
Lưu ý: Phần lớn lỗi RAG nằm ở khâu nạp và chia đoạn, không phải ở LLM. Dành thời gian cho bước 1–2.
Các bước thực hiện
Tiến độ chỉ lưu trên trình duyệt này.
Bước 1: Trích xuất văn bản tiếng Việt, kể cả bản scan
Bash extract.py - Chuẩn hoá Unicode NFC — văn bản tiếng Việt từ nhiều nguồn hay lẫn kiểu dấu tổ hợp.
- Kiểm tra ngẫu nhiên văn bản OCR: bảng biểu, số tiền, mã hiệu hay bị nhận sai.
- Tài liệu nhiều bảng/bố cục phức tạp: cân nhắc công cụ chuyên phân tích bố cục (ví dụ Docling, Unstructured) và so sánh kết quả.
Bước 2: Chia đoạn theo cấu trúc tài liệu
- Ưu tiên cắt theo tiêu đề, điều khoản, mục — mỗi đoạn trọn một ý.
- Gắn tiêu đề mục cha vào đầu đoạn (ví dụ "Quy trình bảo hành > Bước 3") để đoạn tự đứng được.
- Quy tắc thô để bắt đầu: vài trăm token mỗi đoạn, chồng lấp khoảng 10–15%; điều chỉnh theo kết quả đánh giá ở bước 6.
- Lưu metadata:
doc_id, tên file, trang/mục, phòng ban, mức quyền, ngày hiệu lực.
chunk.py Bước 3: Dựng vector DB: pgvector (hoặc Qdrant)
Bash schema.sql Số chiều
1024khớp với mô hình embeddingBAAI/bge-m3dùng ở bước 4 — đổi mô hình thì đổi số chiều. Muốn dùng Qdrant:sudo docker run -d -p 127.0.0.1:6333:6333 -v qdrant_data:/qdrant/storage qdrant/qdrant, lọc quyền bằng payload filter.Bước 4: Embedding đa ngôn ngữ và nạp dữ liệu
Bash ingest.py Mẹo: Mô hình embedding khác (ví dụ
intfloat/multilingual-e5-large) có quy ước riêng như tiền tố "query: "/"passage: ". Đọc model card và kiểm thử trên câu hỏi tiếng Việt của bạn trước khi chốt.Bước 5: Truy vấn có lọc quyền, rerank và sinh câu trả lời
ask.py Cảnh báo: Phân quyền phải lọc ở câu truy vấn cơ sở dữ liệu (như
department = ANY(...)ở trên), dựa trên danh tính người dùng lấy từ hệ thống đăng nhập. Không bao giờ dựa vào câu lệnh trong prompt kiểu "đừng tiết lộ tài liệu X".Bước 6: Đánh giá chất lượng
- Lập bộ câu hỏi thật từ các phòng ban, mỗi câu kèm tài liệu/đoạn đúng và đáp án mong đợi.
- Đo khâu tìm kiếm: đoạn đúng có nằm trong top-k không (recall@k) — trước và sau rerank.
- Đo khâu trả lời: có bám tài liệu không, có trích dẫn đúng không, có bịa thêm không. Người có chuyên môn chấm, có thể hỗ trợ bằng công cụ như Ragas.
- Mỗi lần đổi chunking, mô hình embedding, prompt: chạy lại toàn bộ bộ câu hỏi và so sánh.
- Thu thập phản hồi người dùng (đúng/sai) trên giao diện để bổ sung bộ câu hỏi.
Bước 7: Đồng bộ tài liệu và quyền truy cập
- Đồng bộ định kỳ từ nguồn tài liệu (file server, SharePoint, Google Drive…): tài liệu sửa → nạp lại theo
doc_id; tài liệu xoá → xoá chunk. - Đồng bộ quyền cùng tài liệu; thay đổi quyền phải có hiệu lực ở lần truy vấn kế tiếp.
- Loại tài liệu hết hiệu lực hoặc đánh dấu ngày hiệu lực để LLM ưu tiên bản mới.
- Ghi nhật ký: ai hỏi gì, những tài liệu nào được truy xuất — lưu có kiểm soát (xem bài bảo mật dữ liệu AI).
- Đồng bộ định kỳ từ nguồn tài liệu (file server, SharePoint, Google Drive…): tài liệu sửa → nạp lại theo
Kiểm tra thành công
- Với bộ câu hỏi đánh giá, đa số câu tìm được đoạn đúng trong top-k và câu trả lời có trích dẫn khớp tài liệu.
- Người dùng phòng A hỏi về tài liệu chỉ phòng B được xem → hệ thống trả lời không tìm thấy.
- Sửa một tài liệu nguồn, chạy đồng bộ, câu trả lời phản ánh nội dung mới.
- Câu hỏi ngoài phạm vi tài liệu → hệ thống nói không có thông tin thay vì bịa.
Lỗi thường gặp & cách sửa
Tìm kiếm trả về đoạn không liên quan
Nguyên nhân thường gặp: Văn bản trích xuất bẩn (OCR sai, header/footer lặp), đoạn quá dài hoặc quá ngắn, lẫn NFC/NFD.
Kiểm tra mẫu văn bản trong extracted/, loại header/footer lặp, chuẩn hoá NFC, thử kích thước đoạn khác và bật rerank.
LLM trả lời đúng ý nhưng bịa thêm chi tiết
Nguyên nhân thường gặp: Prompt không ràng buộc, nhiệt độ cao, ngữ cảnh thiếu thông tin nên mô hình tự lấp.
Ràng buộc chỉ dùng tài liệu, yêu cầu trích dẫn, giảm temperature, trả lời "không có thông tin" khi điểm rerank thấp dưới ngưỡng bạn tự hiệu chỉnh.
expected 1024 dimensions, not ...
Nguyên nhân thường gặp: Số chiều cột vector khác số chiều mô hình embedding.
Đổi khai báo vector(n) theo mô hình, tạo lại bảng và nạp lại toàn bộ — không trộn vector từ hai mô hình embedding khác nhau.
Nạp kho tài liệu rất chậm
Nguyên nhân thường gặp: Embedding trên CPU, insert từng dòng không gom.
Chạy embedding trên GPU với batch_size lớn hơn, gom insert (COPY hoặc executemany), tạo chỉ mục HNSW sau khi nạp xong lượt đầu.
Bước tiếp theo
Nguồn chính chủ
Lệnh, tên gói và tham số thay đổi theo phiên bản. Trước khi chạy trên máy thật, hãy kiểm tra phiên bản mới nhất tại trang chính chủ:
- pgvector — GitHub
- Qdrant — Documentation
- BAAI/bge-m3 — Model card
- BAAI/bge-reranker-v2-m3 — Model card
- Sentence Transformers — Documentation
- OCRmyPDF — Documentation
Giới hạn của bài
- Bài không khẳng định mô hình embedding nào tốt nhất cho tiếng Việt — hãy đánh giá trên bộ câu hỏi của chính doanh nghiệp.
- Kích thước đoạn và số k trong ví dụ là điểm khởi đầu, không phải giá trị tối ưu.
- Mã mẫu lược bỏ xử lý lỗi, hàng đợi nạp và xác thực người dùng — cần bổ sung trước khi đưa vào sản xuất.
Kỹ sư HQG khảo sát, lên cấu hình, lắp đặt và bàn giao hạ tầng AI chạy được thật.