Mở đầu — vì sao bài này quan trọng
Ở các bài trước, bạn đã hiểu RAG là gì, vì sao cần nó (Bài 19), embeddings hoạt động ra sao (Bài 20) và vector database nào phù hợp (Bài 21). Nhưng có một khoảng cách rất lớn giữa việc "hiểu từng mảnh ghép" và việc "ráp toàn bộ thành một hệ thống chạy được trong sản xuất". Đây chính là khoảng cách khiến nhiều đội AI loay hoay: demo trên laptop thì lung linh, nhưng đưa lên production thì chậm, sai, tốn kém và không ai dám tin.
Bài 22 này là bài "lắp ráp". Chúng ta sẽ đi qua toàn bộ kiến trúc RAG end-to-end — từ lúc một tài liệu thô được nạp vào hệ thống, cho đến khi người dùng nhận được câu trả lời có dẫn nguồn. Bạn sẽ thấy rõ luồng dữ liệu chạy qua từng tầng, hiểu được mỗi thành phần chịu trách nhiệm gì, và quan trọng nhất với vai trò Product Manager: biết được mỗi tầng có thể "vỡ" ở đâu, ảnh hưởng đến trải nghiệm người dùng và chi phí ra sao.
Tại sao một AI PM cần nắm kiến trúc này thay vì để engineer lo? Vì RAG không phải một feature kỹ thuật thuần túy — nó định hình trực tiếp chất lượng sản phẩm. Quyết định chunk to hay nhỏ, retrieve 3 hay 10 đoạn, có rerank hay không... đều là những đánh đổi giữa chất lượng câu trả lời, độ trễ và chi phí token. Đó là những quyết định sản phẩm, và bạn cần đủ hiểu để tham gia vào chúng một cách có cơ sở.
Khái niệm cốt lõi
RAG end-to-end gồm hai luồng tách biệt nhưng liên quan chặt chẽ: Indexing Pipeline (luồng offline, chuẩn bị dữ liệu) và Query Pipeline (luồng online, phục vụ câu hỏi của người dùng theo thời gian thực). Hiểu được sự tách biệt này là chìa khóa, vì hai luồng có yêu cầu hoàn toàn khác nhau về tốc độ và tần suất.
Luồng Indexing — chuẩn bị tri thức (offline)
Đây là luồng chạy ngầm, không cần real-time. Nó biến tài liệu thô thành dữ liệu mà hệ thống có thể tra cứu nhanh:
[Data Sources] → [Ingestion] → [Chunking] → [Embedding] → [Vector DB]
(PDF, web, (đọc, làm (cắt nhỏ (vector hóa (lưu cùng
Notion, DB) sạch text) tài liệu) từng chunk) metadata)
- Data Sources: nguồn tri thức của bạn — file PDF, trang web, Confluence, Notion, Google Drive, hoặc bảng trong database. Một sản phẩm thực tế thường phải nuốt nhiều loại nguồn cùng lúc.
- Ingestion Pipeline: đọc dữ liệu thô, trích xuất văn bản, làm sạch (bỏ header/footer, ký tự rác, HTML thừa), và gắn metadata (nguồn, ngày cập nhật, tác giả, quyền truy cập).
- Chunking: cắt tài liệu dài thành các đoạn nhỏ vừa với context window và đủ "đặc" về ngữ nghĩa. Đây là khâu quyết định chất lượng nhiều hơn người ta tưởng.
- Embedding: chuyển mỗi chunk thành một vector số học bằng model embedding (ví dụ OpenAI
text-embedding-3, hoặc model đa ngôn ngữ hỗ trợ tiếng Việt). - Vector DB: lưu vector cùng metadata và text gốc, đánh chỉ mục (index) để tra cứu tương đồng cực nhanh.
Luồng Query — phục vụ câu trả lời (online)
[User Query] → [Embed Query] → [Retrieve Top-K] → [Rerank] →
→ [Build Prompt + Context] → [LLM] → [Response + Citations]
- Embed Query: câu hỏi của người dùng được vector hóa bằng cùng một model embedding đã dùng ở luồng indexing — đây là điều bắt buộc, dùng lệch model là một lỗi kinh điển.
- Retrieve Top-K: tìm K chunk có vector gần nhất với câu hỏi (thường K = 5 đến 20).
- Rerank (tùy chọn nhưng rất nên có): dùng một model cross-encoder xếp hạng lại các chunk vừa lấy, đẩy đoạn thực sự liên quan lên đầu và lọc bớt nhiễu.
- Build Prompt: ghép các chunk được chọn vào một prompt template cùng câu hỏi và hướng dẫn cho LLM.
- LLM Generation: model sinh câu trả lời dựa trên context được cung cấp, kèm trích dẫn nguồn.
Tầng điều phối (Orchestration)
Bao quanh hai luồng trên là tầng điều phối — nơi xử lý logic nghiệp vụ: kiểm tra quyền truy cập (user này được đọc tài liệu nào?), caching câu trả lời, ghi log để đánh giá, xử lý lỗi khi vector DB hoặc LLM timeout, và fallback khi không retrieve được gì. Đây là phần khiến RAG "production-grade" khác với một notebook demo.
Tình huống thực tế
Ví dụ 1 — Chatbot hỗ trợ nội bộ của một ngân hàng số tại Việt Nam
Một ngân hàng số (giả định tên "TimoPay") muốn xây trợ lý nội bộ để 2.000 nhân viên chăm sóc khách hàng tra cứu quy trình từ 4.000 trang tài liệu nghiệp vụ. Phiên bản đầu họ làm rất ngây thơ: nhét cả file Word vào một chunk lớn, embed, xong. Kết quả: bot trả lời lan man, trộn lẫn quy định cũ và mới.
Khi ráp lại kiến trúc end-to-end đúng cách, họ làm: ở ingestion, gắn metadata effective_date và version cho mỗi tài liệu; ở chunking, cắt theo từng mục quy trình (khoảng 400–600 token), giữ tiêu đề mục trong mỗi chunk; ở retrieve, thêm filter effective_date <= today AND status = 'active' để loại bỏ quy định hết hiệu lực ngay tại tầng vector DB; thêm bước rerank để chọn 3 đoạn tốt nhất từ 15 đoạn lấy về. Độ chính xác câu trả lời (đo bằng đánh giá thủ công trên 200 câu hỏi mẫu) tăng từ 58% lên 89%.
Bài học: metadata filtering ở tầng retrieve quan trọng ngang với độ tương đồng vector. Trong môi trường có dữ liệu phiên bản hóa (ngân hàng, bảo hiểm, pháp lý), lọc sai bản hiệu lực còn nguy hiểm hơn trả lời không biết.
Ví dụ 2 — Trợ lý sản phẩm cho sàn thương mại điện tử Đông Nam Á
Một sàn TMĐT (giả định "ShopSEA", quy mô Shopee/Lazada) làm trợ lý trả lời câu hỏi về sản phẩm: "áo này giặt máy được không?", "pin sạc bao lâu?". Nguồn dữ liệu là mô tả sản phẩm + 50 triệu review của người mua, cập nhật liên tục mỗi giờ.
Thách thức của họ không phải retrieval mà là luồng indexing phải gần real-time: sản phẩm mới và review mới phải vào index trong vòng vài phút. Họ tách indexing thành pipeline streaming: mỗi review mới đi qua hàng đợi (Kafka) → ingestion worker làm sạch → embed theo batch → upsert vào vector DB. Đồng thời họ phát hiện retrieve thuần vector hay nhầm khi người dùng hỏi bằng từ khóa cụ thể như tên model "Anker 737" — vector tốt cho ngữ nghĩa nhưng kém với mã sản phẩm. Họ bổ sung hybrid search (vector + keyword, sẽ học kỹ ở Bài 24).
Bài học: kiến trúc indexing không phải lúc nào cũng là batch chạy hàng đêm. Khi dữ liệu thay đổi nhanh, bạn cần pipeline streaming và phải thiết kế cơ chế upsert/xóa chunk cũ, nếu không index sẽ phình to và trả về thông tin lỗi thời.
Ví dụ 3 — Trợ lý tra cứu văn bản pháp luật
Một startup legaltech xây công cụ tra cứu luật cho doanh nghiệp SME. Họ gặp vấn đề kinh điển: LLM trả lời nghe rất thuyết phục nhưng bịa số điều luật. Vấn đề nằm ở tầng prompt building và generation, không phải retrieval — retrieve đúng đoạn rồi nhưng prompt không ràng buộc model.
Họ sửa bằng cách: trong prompt template, thêm chỉ thị nghiêm ngặt "Chỉ trả lời dựa trên context được cung cấp. Nếu context không chứa thông tin, hãy nói 'Tôi không tìm thấy quy định liên quan' thay vì suy đoán"; bắt buộc mỗi câu trả lời phải kèm citation chỉ về chunk nguồn (ID điều, khoản); và ở tầng orchestration, thêm bước kiểm tra hậu kỳ xem số điều luật trong câu trả lời có thực sự xuất hiện trong context không. Tỷ lệ bịa đặt giảm mạnh.
Bài học: kiến trúc end-to-end phải bao gồm cả "lan can" (guardrails) ở tầng prompt và post-processing. Retrieve đúng là điều kiện cần, không phải điều kiện đủ.
Hướng dẫn từng bước
Đây là quy trình triển khai một hệ thống RAG end-to-end mà bạn có thể dùng để dẫn dắt đội kỹ thuật:
- Xác định nguồn dữ liệu và phân loại metadata. Liệt kê mọi nguồn (file, web, DB), và quan trọng hơn: liệt kê metadata cần gắn cho mỗi tài liệu — nguồn, ngày, phiên bản, quyền truy cập, ngôn ngữ. Metadata quyết định khả năng lọc về sau.
- Xây dựng ingestion pipeline. Viết bộ đọc cho từng loại nguồn, trích xuất text sạch. Đặc biệt với PDF tiếng Việt, kiểm tra kỹ vấn đề mất dấu hoặc lỗi font khi extract.
- Chọn chiến lược chunking. Bắt đầu với chunk 300–500 token, có overlap 10–15% giữa các chunk liền kề để tránh cắt mất ngữ cảnh ở ranh giới. Với tài liệu có cấu trúc rõ (mục, điều, khoản), ưu tiên cắt theo cấu trúc thay vì cắt cứng theo số token.
- Chọn model embedding và embed toàn bộ. Với nội dung tiếng Việt, chọn model đa ngôn ngữ chất lượng tốt. Ghi nhớ model này để dùng lại y hệt ở luồng query.
- Nạp vào vector DB cùng metadata và text gốc. Lưu cả text gốc của chunk (không chỉ vector) để có thể trả về và làm citation.
- Xây luồng query. Embed câu hỏi → retrieve top-K (bắt đầu K=10) → áp metadata filter theo quyền và phiên bản → rerank còn 3–5 đoạn tốt nhất.
- Thiết kế prompt template. Bao gồm: hướng dẫn vai trò, context được chèn vào, câu hỏi, ràng buộc "chỉ dùng context" và yêu cầu trích dẫn nguồn.
- Gọi LLM và xử lý response. Sinh câu trả lời kèm citations, parse và gắn link về nguồn để người dùng kiểm chứng.
- Bọc tầng orchestration. Thêm caching, logging (lưu lại query + đoạn retrieve + câu trả lời để đánh giá sau), xử lý timeout và fallback.
- Đo lường và lặp. Tạo bộ câu hỏi đánh giá, đo retrieval accuracy và answer quality (sẽ học framework chi tiết ở Bài 26). RAG là vòng lặp tối ưu liên tục, không phải làm một lần xong.
Lỗi thường gặp & mẹo
- Dùng lệch model embedding giữa indexing và query. Đây là lỗi phổ biến và khó phát hiện nhất — retrieve trả về kết quả vô nghĩa mà không báo lỗi. Luôn dùng đúng một model ở cả hai luồng.
- Bỏ qua bước rerank. Retrieve thuần vector lấy về cả đoạn "gần nhưng không đúng". Một cross-encoder reranker nhẹ nhàng cải thiện chất lượng đáng kể với chi phí thấp. Đừng bỏ qua chỉ vì nó "phức tạp thêm một bước".
- Chunk quá to hoặc quá nhỏ. To quá thì nhồi nhiều nhiễu vào context, tốn token và làm loãng tín hiệu. Nhỏ quá thì mất ngữ cảnh, mỗi chunk không đủ nghĩa. Hãy thử nghiệm và đo, đừng đoán.
- Quên xử lý cập nhật và xóa. Khi tài liệu nguồn thay đổi, chunk cũ trong index phải được cập nhật hoặc xóa. Nếu không, hệ thống sẽ trả lời bằng thông tin lỗi thời — một trong những nguyên nhân mất niềm tin nhanh nhất.
- Không lưu text gốc cùng vector. Dẫn đến không thể tạo citation, mà citation lại là yếu tố then chốt để người dùng tin tưởng (xem Bài 36, 37).
- Mẹo retrieve rộng rồi lọc hẹp: lấy top-K lớn (ví dụ 20) rồi rerank xuống còn 3–5. Cách này cân bằng tốt giữa recall (không bỏ sót) và precision (không nhiễu).
- Mẹo về context budget: đừng nhồi tối đa chunk vào prompt chỉ vì context window cho phép. Nhiều context không liên quan làm giảm chất lượng và tăng chi phí. Ít mà đúng luôn tốt hơn nhiều mà loãng.
Bài tập thực hành
- Vẽ sơ đồ kiến trúc. Chọn một sản phẩm RAG bạn muốn xây (ví dụ: chatbot tra cứu chính sách công ty bạn). Vẽ đầy đủ hai luồng indexing và query, ghi rõ ở mỗi tầng: input, output, công cụ/model dùng, và metadata cần gắn.
- Phân tích điểm vỡ. Với sơ đồ trên, viết ra cho từng tầng một câu trả lời: "Nếu tầng này hỏng/làm kém, người dùng sẽ thấy triệu chứng gì?". Đây là kỹ năng debug RAG cốt lõi của một PM.
- Thiết kế chiến lược chunking. Lấy một tài liệu thật (10–20 trang) trong lĩnh vực của bạn. Đề xuất 2 cách chunking khác nhau (cắt theo token vs cắt theo cấu trúc), nêu ưu nhược điểm mỗi cách cho loại tài liệu đó.
- Viết prompt template chống bịa. Soạn một prompt template hoàn chỉnh cho bước generation, có ràng buộc chỉ dùng context, yêu cầu citation, và hành vi khi không tìm thấy thông tin. So sánh câu trả lời trước/sau khi áp dụng template này.
Tóm tắt
- RAG end-to-end gồm hai luồng: indexing (offline: data → ingest → chunk → embed → vector DB) và query (online: embed query → retrieve → rerank → build prompt → LLM → response có citation).
- Chất lượng câu trả lời bị giới hạn bởi chất lượng retrieval — phần lớn công sức tối ưu nằm ở chunking, metadata filtering và rerank, không phải ở việc đổi LLM xịn hơn.
- Metadata (phiên bản, quyền, ngày) cho phép lọc đúng tại tầng retrieve — quan trọng ngang với độ tương đồng vector, đặc biệt trong ngân hàng, pháp lý, bảo hiểm.
- Tầng orchestration (caching, logging, guardrails, xử lý cập nhật/xóa) là thứ phân biệt một hệ thống production với một demo notebook.
- Vai trò AI PM: hiểu mỗi tầng vỡ ở đâu, ảnh hưởng trải nghiệm và chi phí ra sao, để tham gia các quyết định đánh đổi một cách có cơ sở.