RAG Mastery
Chunking Strategies, Embeddings, Vector Databases, Hybrid Search, Reranking, Multi-source Retrieval.
RAG (Retrieval-Augmented Generation) vẫn là kỹ năng có nhu cầu tuyển dụng cao nhất trong AI Engineering năm 2026, vì hầu hết doanh nghiệp cần AI trả lời dựa trên dữ liệu nội bộ của họ — thứ model không được huấn luyện sẵn. RAG "demo dễ, làm đúng khó" — 80% chất lượng nằm ở retrieval, không nằm ở model sinh câu trả lời.
🎯 Mục tiêu học tập
- Thiết kế chiến lược chunking phù hợp với từng loại tài liệu (văn bản dài, bảng biểu, code, FAQ)
- Xây dựng pipeline retrieval kết hợp semantic search + keyword search (hybrid search)
- Áp dụng reranking để tăng độ chính xác của top-k kết quả trước khi đưa vào context
- Thiết kế RAG multi-source (nhiều nguồn dữ liệu khác định dạng/quyền truy cập)
- Nhận diện và xử lý các lỗi RAG phổ biến: retrieval sai, context tràn, trích dẫn sai nguồn
Chunking Strategies — không có công thức chung
- Fixed-size chunking (ví dụ 512 token, overlap 50 token): đơn giản, baseline tốt cho văn bản đồng nhất.
- Semantic/recursive chunking: cắt theo cấu trúc tự nhiên (đoạn văn, heading, câu) trước, chỉ fallback về fixed-size khi đoạn quá dài — giữ được ngữ cảnh trọn vẹn hơn.
- Document-aware chunking: bảng biểu cắt theo hàng/nhóm hàng kèm header; code cắt theo function/class; Markdown cắt theo heading level.
- Late chunking / contextual retrieval: kỹ thuật hiện đại (được Anthropic phổ biến năm 2024, nay là best practice chuẩn) — thêm một đoạn tóm tắt ngữ cảnh (do LLM sinh ra) vào đầu mỗi chunk trước khi embed, giúp chunk "tự đứng vững" khi bị tách khỏi tài liệu gốc, cải thiện retrieval rõ rệt so với chunking thô.
Dùng một kích thước chunk cố định cho toàn bộ hệ thống bất kể loại tài liệu — luôn benchmark ít nhất 2-3 chiến lược trên tập câu hỏi thật trước khi chốt.
Hybrid Search: Semantic + Keyword
Semantic search (vector) giỏi hiểu ý nghĩa nhưng yếu với từ khoá chính xác (mã sản phẩm, tên riêng, số hiệu). Keyword search (BM25/full-text) ngược lại. Hybrid search kết hợp cả hai, thường bằng Reciprocal Rank Fusion (RRF) để gộp thứ hạng từ hai nguồn — đây là baseline retrieval tốt nhất hiện nay, được hỗ trợ sẵn trong hầu hết vector DB hiện đại (Qdrant, Weaviate, pgvector + tsvector).
Reranking — bộ lọc chất lượng cuối cùng
Retrieval ban đầu (vector/hybrid) tối ưu cho tốc độ nên lấy top-k khá rộng (ví dụ 30-50 kết quả) nhưng độ chính xác thứ hạng chưa cao. Reranker (cross-encoder model như Cohere Rerank, BGE Reranker, hoặc dùng chính LLM nhỏ để chấm điểm) đọc kỹ từng cặp (câu hỏi, chunk) và sắp xếp lại — chậm hơn nhưng chính xác hơn nhiều, chỉ áp dụng trên tập nhỏ đã được retrieval lọc sơ bộ. Pipeline chuẩn: retrieve top-30 → rerank → giữ top-5 đưa vào context.
Multi-source Retrieval
Hệ thống thực tế hiếm khi chỉ có một nguồn dữ liệu — cần kết hợp Confluence, Slack, database, PDF chính sách... Vấn đề cần giải quyết: chuẩn hoá metadata (nguồn, quyền truy cập, thời gian cập nhật) để lọc theo quyền người dùng trước khi retrieval; trọng số khác nhau cho từng nguồn (ví dụ tài liệu chính sách chính thức nên ưu tiên hơn thảo luận Slack không chính thức); và routing truy vấn — dùng một model nhỏ để quyết định câu hỏi nên tìm ở nguồn nào trước khi retrieval toàn bộ, tiết kiệm chi phí và tăng độ chính xác.
Agentic RAG — xu hướng 2026
RAG "một lượt" (retrieve một lần → generate) đang được thay thế dần bởi agentic RAG: model tự quyết định có cần retrieval không, retrieval bao nhiêu lần, có cần tinh chỉnh lại câu truy vấn (query rewriting) khi kết quả đầu không đủ tốt, và có cần kết hợp nhiều nguồn tuần tự (multi-hop reasoning) hay không — biến RAG thành một dạng agent chuyên biệt (xem Module 8).
🔬 Đào sâu — Contextual Chunking: code thực hành
Đây là kỹ thuật tạo khác biệt lớn nhất giữa RAG "demo" và RAG "production-grade". Ý tưởng: trước khi embed, dùng một LLM nhỏ/rẻ sinh 1-2 câu tóm tắt ngữ cảnh cho từng chunk (chunk này thuộc tài liệu nào, phần nào, nói về gì trong bối cảnh tổng thể), rồi nối câu tóm tắt đó vào đầu chunk trước khi embed. Việc này giải quyết vấn đề cốt lõi: một chunk bị cắt rời khỏi tài liệu gốc thường mất ngữ cảnh (ví dụ chunk chỉ chứa "Mức phí này áp dụng từ ngày trên" — không biết "mức phí" nào, "ngày" nào nếu không có câu trước đó).
from anthropic import Anthropic
client = Anthropic()
CONTEXT_PROMPT = (
"Đây là toàn bộ tài liệu:\n"
"<document>\n{full_doc}\n</document>\n\n"
"Đây là một đoạn trích cần đặt vào ngữ cảnh:\n"
"<chunk>\n{chunk}\n</chunk>\n\n"
"Hãy viết 1-2 câu ngắn gọn mô tả đoạn trích này nằm ở phần nào, nói về chủ đề gì trong tài liệu, "
"để giúp việc tìm kiếm đoạn trích này chính xác hơn. Chỉ trả lời câu mô tả, không thêm gì khác."
)
def add_context(full_doc: str, chunk: str) -> str:
resp = client.messages.create(
model="claude-haiku-4-5", # dùng model rẻ/nhanh cho tác vụ phụ trợ này
max_tokens=100,
messages=[{"role": "user", "content": CONTEXT_PROMPT.format(full_doc=full_doc, chunk=chunk)}],
)
context = resp.content[0].text
return f"{context}\n\n{chunk}"
Với tài liệu dài, dùng
prompt caching (Module 10) để cache full_doc — vì cùng một tài liệu được dùng
lại cho mọi chunk của nó, chi phí sinh context giảm hơn 80% so với gửi lại toàn văn mỗi lần.
🔬 Đào sâu — So sánh Embedding Model (2026)
| Model | Số chiều | Đa ngôn ngữ (có tiếng Việt) | Ghi chú |
|---|---|---|---|
| OpenAI text-embedding-3-large | 3072 (rút gọn được) | Tốt | Lựa chọn mặc định phổ biến, cân bằng chất lượng/chi phí |
| Voyage-3 / voyage-3-large | 1024/2048 | Tốt | Thường xếp hạng cao nhất trên benchmark retrieval, có bản chuyên biệt theo domain (code, finance, law) |
| Google gemini-embedding | 3072 (rút gọn được) | Rất tốt | Tích hợp tốt trong hệ sinh thái Vertex AI |
| Cohere embed-v4 | 1536 (rút gọn được) | Rất tốt | Hỗ trợ multimodal (embed cả ảnh), nén tốt (int8/binary) |
| BAAI BGE-M3 (mã nguồn mở) | 1024 | Tốt | Tự host miễn phí, hỗ trợ dense+sparse+ColBERT cùng lúc, phù hợp khi cần kiểm soát dữ liệu |
Tiêu chí chọn: nếu dữ liệu nhạy cảm cần self-host → BGE-M3 (chạy qua sentence-transformers
hoặc vLLM, xem Module 17); nếu ưu tiên chất lượng cao nhất và sẵn sàng trả phí API → Voyage-3;
nếu muốn đơn giản, đã dùng sẵn hệ sinh thái OpenAI/Google → dùng embedding cùng nhà cung cấp để giảm số
lượng vendor phải quản lý.
Đổi embedding model bắt buộc phải re-embed và re-index toàn bộ dữ liệu — không có cách nào "chuyển đổi" vector giữa hai model khác nhau. Chọn kỹ trước khi đưa vào production ở quy mô lớn.
🔬 Đào sâu — Code đầy đủ: Hybrid Search + Rerank trên pgvector
Ví dụ đầy đủ kết hợp semantic search (pgvector) với full-text search (tsvector có sẵn trong PostgreSQL), gộp kết quả bằng Reciprocal Rank Fusion, rồi rerank top kết quả:
-- Schema: chunk vừa có vector vừa có tsvector cho keyword search
CREATE TABLE chunks (
id SERIAL PRIMARY KEY,
document_id INT NOT NULL,
content TEXT NOT NULL,
embedding VECTOR(1024),
content_tsv TSVECTOR GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED
);
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON chunks USING gin (content_tsv);
import asyncpg
async def hybrid_search(pool, query: str, query_embedding: list[float], top_k: int = 30) -> list[dict]:
sql = (
"WITH semantic AS ("
" SELECT id, content, RANK() OVER (ORDER BY embedding <=> $1) AS rank"
" FROM chunks ORDER BY embedding <=> $1 LIMIT $3"
"), keyword AS ("
" SELECT id, content, RANK() OVER (ORDER BY ts_rank(content_tsv, plainto_tsquery('simple', $2)) DESC) AS rank"
" FROM chunks WHERE content_tsv @@ plainto_tsquery('simple', $2) LIMIT $3"
") "
"SELECT COALESCE(s.id, k.id) AS id, COALESCE(s.content, k.content) AS content,"
" (1.0 / (60 + COALESCE(s.rank, 1000))) + (1.0 / (60 + COALESCE(k.rank, 1000))) AS rrf_score "
"FROM semantic s FULL OUTER JOIN keyword k ON s.id = k.id "
"ORDER BY rrf_score DESC LIMIT $3"
)
rows = await pool.fetch(sql, query_embedding, query, top_k)
return [dict(r) for r in rows]
async def rerank(query: str, candidates: list[dict], top_n: int = 5) -> list[dict]:
# Gọi Cohere Rerank / BGE Reranker — trả điểm liên quan chính xác hơn cho từng cặp (query, chunk)
scored = await cohere_client.rerank(query=query, documents=[c["content"] for c in candidates], top_n=top_n)
return [candidates[r.index] for r in scored.results]
🔬 Đào sâu — Checklist chẩn đoán khi RAG trả lời sai
Khi RAG trả lời sai/hallucinate, luôn debug theo đúng thứ tự sau — đừng nhảy thẳng vào "sửa prompt":
- Retrieval có lấy đúng chunk không? In ra top-k chunk thực tế được retrieval, tự đọc bằng mắt — nếu chunk đúng không nằm trong top-k, vấn đề nằm ở chunking/embedding, không phải ở model sinh câu trả lời.
- Chunk có đủ thông tin để trả lời không, hay bị cắt cụt giữa câu? Kiểm tra chunk size/overlap; thử contextual chunking nếu chunk đứng độc lập không đủ nghĩa.
- Top-k có quá nhiều chunk gần giống nhau (dư thừa), lấn chỗ chunk đa dạng khác không? Áp dụng MMR (Maximal Marginal Relevance) thay vì chỉ lấy top-k theo similarity thuần tuý, để cân bằng giữa độ liên quan và độ đa dạng.
- Model có đang bỏ qua context được cung cấp và trả lời từ kiến thức nội tại không? Siết chặt system prompt: "chỉ trả lời dựa trên context bên dưới, nếu không có thông tin hãy nói không biết" — và đo bằng faithfulness score (Module 11).
- Index có bị lỗi thời (stale) không? Kiểm tra pipeline cập nhật dữ liệu (Module 12) có đang chạy đúng lịch không.
🏋️ Bài tập thực hành
Chọn một bộ tài liệu thật (ví dụ tài liệu kỹ thuật Laravel, hoặc chính sách công ty giả lập ~50-100 trang). Xây pipeline: parse → contextual chunking → embed → lưu vào pgvector → hybrid search (vector + full-text) → rerank → generate câu trả lời kèm trích dẫn nguồn. Tạo bộ 20 câu hỏi test và đo tỉ lệ trả lời đúng có trích dẫn chính xác.
📚 Tài nguyên học tập
-
Anthropic — Contextual RetrievalKỹ thuật contextual chunking cải thiện retrievalBài viết
-
LangChain — RAG conceptsTổng quan khái niệm RAGDocs
-
Ragas — RAG evaluation frameworkĐánh giá chất lượng hệ thống RAG có hệ thốngDocs
-
Pinecone — Learning Center: Hybrid SearchGiải thích hybrid search & RRFBài viết
✅ Tự đánh giá hoàn thành
- So sánh được ít nhất 2 chiến lược chunking trên cùng bộ dữ liệu và có số liệu
- Triển khai được hybrid search (vector + keyword) với RRF
- Thêm được bước reranking và đo được cải thiện độ chính xác
- Xử lý được truy vấn trên tối thiểu 2 nguồn dữ liệu khác nhau
- Có bộ câu hỏi test (golden set) để đo chất lượng RAG một cách khách quan