RAG — retrieve rồi mới generate
Không phải model tra database. Các đoạn liên quan được truy hồi rồi nhét vào context như phao thi trước khi sinh — hiểu từng bước để biết từng bước hỏng ở đâu.
TL;DR: RAG (Retrieval-Augmented Generation) không phải "cho model tra database bằng khoá trùng khớp". Đoạn tài liệu liên quan được truy hồi (retrieve) bằng cosine similarity, rồi nhét vào context như một tờ phao thi, trước khi model sinh câu trả lời. Bài này trace đủ 5 bước của một lượt truy vấn — embed câu hỏi, retrieve top-k, nhét context, generate — và tách rõ khỏi bước index-time chạy trước đó. Biết chính xác dữ liệu chảy qua đâu ở từng bước là điều kiện để sau này chẩn đoán được một hệ RAG hỏng ở đâu.
Nhóm nhân viên tra cứu policy nội bộ giờ đã có một index embed xong: mỗi chính sách được cắt đoạn, mỗi đoạn có một vector nghĩa nằm trong không gian đã học ở bài 01. Gõ câu hỏi vào, hệ thống trả về đúng vài đoạn tài liệu gần nghĩa nhất — nhưng người dùng không muốn đọc nguyên văn điều khoản, họ muốn một câu trả lời thẳng bằng văn xuôi. Ai đó đề xuất: "cứ nhét mấy đoạn tìm được vào cho model, bảo nó trả lời dựa trên đó". Có người phản đối: "vậy khác gì để model tự tra database rồi trả lời luôn?" — câu hỏi đó lẫn lộn hai việc rất khác nhau, và là đúng chỗ bài này cần đập.
Bạn đã học phép đo "gần nghĩa": cosine similarity giữa vector câu hỏi và vector từng đoạn, một con số càng cao thì càng gần. Đây chính là phép đo dùng ở bước retrieve của bài này — và nó là một phép xếp hạng tương đối, không có ngưỡng "đủ liên quan" mặc định.
1. Analogy — thi mở phao, không phải thi thuộc lòng
Một học sinh không thể nhớ nguyên văn cả cuốn sách giáo khoa. Nhưng trước khi viết câu trả lời, em được lật đúng vài trang liên quan nhất tới câu hỏi — không phải cả cuốn, chỉ vài trang do em (hoặc ai đó) chọn lọc — rồi viết câu trả lời dựa trên kiến thức nền cộng với đúng những trang vừa xem.
| Thi mở phao có chọn lọc | RAG |
|---|---|
| Không nhớ hết cả cuốn sách | Model không "chứa" toàn bộ tài liệu công ty trong tham số |
| Trước khi viết, lật đúng vài trang liên quan | Trước khi generate, retrieve đúng k đoạn liên quan nhất |
| Chỉ xem đúng những trang đã chọn, không thấy phần còn lại của sách | Chỉ thấy đúng k đoạn được nhét vào context, không thấy phần còn lại của index |
| Viết câu trả lời = kiến thức nền + trang vừa xem | Generate = tham số đã học (nền) + context vừa nhét (mới) |
Analogy hỏng ở một chỗ quan trọng: học sinh biết tự nhận ra "trang này lạc đề, bỏ qua" nếu lỡ lật nhầm. Model không có bước mặc định nào như vậy — nó cứ nhận context được đưa vào là dùng, coi như luôn đáng tin, dù đoạn đó có thật sự liên quan hay không.
RAG = thi mở phao có chọn lọc: không thuộc lòng cả sách, chỉ được xem đúng vài trang chọn trước — và bài thi diễn ra SAU khi trang đã được chọn xong, không phải trước.
2. Không phải "tra database bằng khoá" — retrieve là xếp hạng gần đúng
Phản ứng "vậy khác gì tra database" ở đầu bài lẫn hai cơ chế khác hẳn nhau. Tra database bằng khoá (WHERE id = ...) là so khớp chính xác: đúng khoá thì ra đúng một dòng, sai khoá thì ra rỗng. Retrieve trong RAG không làm vậy. Nó tính cosine similarity giữa vector câu hỏi và từng vector trong index, xếp hạng toàn bộ theo điểm số, rồi lấy k đoạn cao nhất. (Ở quy mô lớn, việc này làm bằng approximate nearest-neighbor — HNSW, IVF… — chứ không so từng vector một; nhưng nguyên lý xếp hạng theo cosine vẫn vậy.)
Hệ quả khác biệt lớn nhất: retrieve luôn trả về đúng k đoạn, vì luôn có k điểm cao nhất trong một danh sách xếp hạng — kể cả khi tài liệu chẳng có đoạn nào thật sự trả lời được câu hỏi. Không có khái niệm "không tìm thấy" như tra khoá thất bại; chỉ có "k đoạn ít-xa-nhất-so-với-phần-còn-lại", đúng hay sai với câu hỏi là chuyện khác.
3. Trace pipeline — index-time trước, query-time sau
Toàn bộ pipeline tách làm hai giai đoạn không chạy cùng lúc.
Index-time (chạy một lần, hoặc lại mỗi khi tài liệu đổi — không phụ thuộc câu hỏi nào): tài liệu được cắt thành đoạn (chunking), mỗi đoạn được embed thành vector, và cặp (đoạn gốc, vector) được lưu vào index. Việc này xong trước khi người dùng gõ câu hỏi đầu tiên.
Query-time (chạy lại từ đầu cho mỗi câu hỏi mới) gồm đúng 5 bước:
1. Query -- cau hoi tho cua nguoi dung den he thong
2. Embed query -- embed CAU HOI bang DUNG model da dung luc index
3. Retrieve -- tinh cosine similarity giua vector cau hoi va MOI vector trong index
-- lay k doan diem cao nhat
4. Context -- ghep k doan goc (khong phai vector) + cau hoi goc thanh MOT prompt dai hon
5. Generate -- chay vong lap autoregressive tren prompt da mo rong, sinh cau tra loi

Hai điểm dễ bỏ sót khi trace: bước 2 phải dùng đúng model đã dùng lúc index — hai model tự dựng hai không gian nghĩa khác nhau, vector câu hỏi và vector index sống ở hai nơi không so sánh chéo được (bài 01). Và bước 5 không phải cơ chế mới: đó chính xác là vòng lặp dự đoán token kế tiếp — chỉ khác input dài hơn, vì giờ chứa thêm k đoạn "phao thi" trước câu hỏi.
Bạn đã trace: mỗi bước, model nhận toàn bộ chuỗi token đã có, tính phân phối xác suất cho token kế tiếp, chọn một token, nối vào, lặp lại. Bước generate ở đây chạy đúng vòng lặp đó — input chỉ dài hơn vì có thêm k đoạn được nhét vào trước câu hỏi.
4. Tự dự đoán — bước nào hỏng thì sai kiểu gì?
Đã trace xong 5 bước, thử tự dự đoán trước khi đọc tiếp: nếu một bước hỏng (các bước khác vẫn chạy đúng), hệ thống có tự báo lỗi không, hay vẫn chạy trơn tru và chỉ trả lời sai?
Viết ra một câu dự đoán triệu chứng cho mỗi tình huống, trước khi đọc phần giải thích ngay sau:
- Bước 2 (embed query) lỡ dùng sai model so với model đã dùng lúc index toàn bộ tài liệu. Triệu chứng quan sát được là gì?
- Bước 3 (retrieve top-k) chạy đúng cơ chế, nhưng không đoạn nào trong index thật sự trả lời được câu hỏi. Triệu chứng quan sát được là gì?
- Bước 4 nhét đúng đoạn chứa câu trả lời vào context, nhưng bước 5 vẫn generate sai chi tiết. Đây có phải lỗi của retrieve không?
Cả ba tình huống có một điểm chung đáng ngại: không tình huống nào tạo ra lỗi runtime. Hệ thống vẫn chạy hết 5 bước, vẫn trả về một câu trả lời — chỉ là câu trả lời sai, không có tín hiệu nào tự báo.
- Sai model ở bước 2: vector câu hỏi giờ sống trong không gian nghĩa khác vector của toàn bộ index. Nếu hai model tình cờ cùng số chiều output (khá phổ biến khi đổi giữa model cùng họ), bước 3 vẫn tính cosine bình thường và vẫn xếp hạng ra đúng k con số — nhưng con số đó không phản ánh nghĩa thật, nên top-k trả về gần như ngẫu nhiên, mà không có dòng lỗi nào. (Nếu khác số chiều thì phép nhân vector báo lỗi ngay — đỡ nguy hiểm hơn vì lộ liền.)
- Retrieve "đúng" ở bước 3 dù index rỗng nghĩa: cosine similarity là phép xếp hạng tương đối (mục 2), không có ngưỡng loại bỏ mặc định. Nếu index không có đoạn nào thật sự liên quan, hệ thống vẫn trung thực trả về k đoạn điểm cao nhất trong những gì đang có — dù tất cả đều lạc đề. Bước 4 vẫn nhét đúng k đoạn đó, bước 5 vẫn generate bình thường trên context toàn nhiễu.
- Đây là ranh giới cần tách bạch: nếu context ở bước 4 đã chứa đúng thông tin mà bước 5 vẫn sinh sai, lỗi nằm ở generation, không phải retrieval — hai nửa pipeline hỏng vì hai lý do khác hẳn nhau. Tách được câu hỏi "hỏng ở đâu" là điều kiện để sửa đúng chỗ, thay vì đổi retrieval cho một lỗi thật ra nằm ở generation.
5. Pitfall tổng hợp
❌ Nhầm 1 — coi RAG là cho model "tra database bằng khoá trùng khớp":
✅ Retrieve không so khớp chuỗi hay khoá chính xác. Nó xếp hạng toàn bộ index theo cosine similarity giữa vector câu hỏi và vector từng đoạn, rồi lấy k đoạn điểm cao nhất — luôn trả về đúng k đoạn, kể cả khi chẳng đoạn nào thật sự liên quan.
❌ Nhầm 2 — coi RAG là cho model "đọc luôn" toàn bộ tài liệu trong index:
✅ Model không nhìn thấy index. Nó chỉ nhìn thấy đúng phần chữ được nhét vào context ở bước 4 — nếu retrieve chọn sai đoạn, phần còn lại của index, dù chứa câu trả lời đúng, model không hề "biết" nó tồn tại.
6. 📚 Deep Dive
- Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (NeurIPS 2020, arXiv:2005.11401) — nguồn gốc tên gọi và kiến trúc RAG. Động lực gốc của paper: kết hợp bộ nhớ tham số (parametric — kiến thức nén sẵn trong trọng số model) với bộ nhớ phi tham số (non-parametric — một index truy hồi được, cập nhật độc lập với model), để câu trả lời có nguồn gốc tường minh và cập nhật được mà không cần train lại toàn bộ model. "Giảm hallucination" không phải động lực ban đầu ghi trong bài báo năm 2020 — đó là lợi ích được các nghiên cứu sau này ghi nhận thêm, đừng gán ngược động lực.
Ghi chú: đối chiếu nguồn ngày 2026-07-23; bài này không tóm tắt kết quả thực nghiệm của paper, chỉ dùng nó làm nguồn gốc thuật ngữ và ý tưởng kiến trúc.
7. Liên hệ các bài khác
- Bài 02 — Cosine similarity — bước retrieve ở mục 3 chính là phép đo đó áp lên toàn bộ index.
- Bài 04 — Chunking — index-time bắt đầu từ đây; "đoạn" nhét vào context ở bước 4 chính là chunk được cắt ở bài đó.
- Dự đoán token kế tiếp — bước generate ở mục 3 là đúng vòng lặp autoregressive đó, chỉ khác input dài hơn.
- Bài 06 — RAG failure modes — mỗi kiểu hỏng vừa tự dự đoán ở mục 4 sẽ được đặt tên chính thức theo taxonomy.
8. Tóm tắt
- Pipeline tách hai giai đoạn: index-time (chunk → embed → lưu, chạy trước) và query-time (5 bước, chạy lại từ đầu cho mỗi câu hỏi).
- 5 bước query-time: nhận câu hỏi → embed bằng đúng model đã index → retrieve top-k bằng cosine → nhét k đoạn + câu hỏi vào context → generate bằng vòng lặp autoregressive.
- Model chỉ "thấy" đúng phần được nhét vào context — không có quyền truy cập ngầm vào phần còn lại của index.
- Nguồn gốc RAG (Lewis et al., 2020): kết hợp bộ nhớ tham số + phi tham số để có nguồn gốc và cập nhật được — không phải ban đầu để chống hallucination.
9. Tự kiểm tra
Q1Một đồng nghiệp nói: "RAG là cho model tra cứu đúng tài liệu bằng ID, giống một câu query database". Chỗ nào sai trong câu này, và cơ chế thật sự là gì?▸
Retrieve không so khớp khoá/ID chính xác — nó tính cosine similarity giữa vector câu hỏi và vector từng đoạn trong index, rồi lấy top-k đoạn điểm cao nhất. Không có bước "tìm đúng một dòng theo điều kiện", chỉ có xếp hạng theo độ gần nghĩa.
Hệ quả: retrieve luôn trả về đúng k kết quả, kể cả khi không đoạn nào trong index thật sự đúng với câu hỏi — khác hẳn một truy vấn database có thể trả về rỗng.
Q2Phân biệt index-time và query-time trong pipeline RAG — cái gì chạy khi nào, và vì sao gộp chung hai giai đoạn này là một nhầm lẫn phổ biến?▸
Index-time chạy trước, không phụ thuộc câu hỏi nào cả: chunk tài liệu, embed từng đoạn, lưu vector vào index. Query-time chạy lại toàn bộ 5 bước (embed câu hỏi, retrieve, nhét context, generate) cho mỗi câu hỏi mới.
Gộp chung dễ dẫn tới nhầm lẫn về chi phí và về việc đổi model: đổi embedding model chỉ ảnh hưởng câu hỏi mới nếu nghĩ query-time là toàn bộ pipeline, trong khi thực ra index cũ (tạo bằng model khác) phải làm lại từ đầu ở index-time.
Q3Bước 2 (embed query) lỡ dùng model khác với model đã dùng lúc index. Retrieve ở bước 3 có báo lỗi không? Vì sao đây lại là ca nguy hiểm?▸
Không báo lỗi nào cả — cosine similarity vẫn tính ra một con số cho mọi cặp vector, kể cả khi hai vector sống ở hai không gian nghĩa khác nhau. Hệ thống vẫn trả về đúng k kết quả, trông có vẻ bình thường.
Nguy hiểm ở chỗ các con số đó không phản ánh gì về độ liên quan thật, nên top-k gần như ngẫu nhiên — mà không có tín hiệu lỗi nào để phát hiện sớm; phải tự biết kiểm tra "model embed lúc query có khớp model embed lúc index không".
Q4Hệ thống nhét đúng đoạn tài liệu chứa câu trả lời vào context, nhưng model vẫn generate sai chi tiết. Lỗi này nằm ở retrieval hay generation? Giải thích.▸
Generation. Retrieve đã làm đúng việc của nó — chọn đúng đoạn — nên context ở bước 4 đã chứa dữ liệu đúng.
Lỗi xảy ra ở bước 5, khi model sinh token dựa trên context đó nhưng vẫn chọn sai — hai loại hỏng có nguyên nhân khác hẳn nhau, cần hai cách chẩn đoán và sửa khác nhau.
Q5Vì sao nói "model không biết những gì nằm ngoài context vừa được nhét vào", dù đoạn đó có nằm trong index đi chăng nữa?▸
Model không có quyền truy cập trực tiếp vào index — nó chỉ nhận một chuỗi token duy nhất ở bước 4: câu hỏi cộng k đoạn mà bước retrieve đã chọn.
Nếu đoạn chứa câu trả lời đúng tồn tại trong index nhưng không lọt vào top-k ở bước 3, nó chưa bao giờ tới tay model — về phía model, đoạn đó coi như không tồn tại.
Bài tiếp theo: RAG failure modes — bốn kiểu hỏng có tên gọi
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên