AI Core cho lập trình viên
42/54
Bài 42 / 54~13 phútEmbedding, tìm kiếm & RAGMiễn phí… lượt xem

RAG — retrieve rồi mới generate

Không phải model tra database: đoạn liên quan được truy hồi rồi nhét vào context 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". Các đoạn tài liệu liên quan được retrieve (truy hồi) bằng cosine similarity, rồi nhét vào context như tài liệu thí sinh được mở trong phòng 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 (nhận câu hỏi, embed câu hỏi, retrieve top-k, nhét context, generate) và tách rõ chúng 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 ở chỗ nào.

Nhóm 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 nằm trong không gian nghĩa ở bài 01. Gõ câu hỏi vào, hệ thống trả về 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. 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 phản đối đó trộn hai cơ chế rất khác nhau, và bài này gỡ đúng chỗ trộn ấy.

Nhớ lại — Cosine similarity

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, con số càng cao thì càng gần. Bước retrieve của bài này dùng đúng phép đo đó, và nó là phép xếp hạng tương đối, không có ngưỡng "đủ liên quan" mặc định.

1. Analogy: thi được mở tài liệu, 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 bài, em được lật đúng vài trang liên quan nhất tới đề, không phải cả cuốn, chỉ vài trang do em (hoặc ai đó) chọn, rồi viết câu trả lời dựa trên kiến thức nền cộng với những trang vừa xem.

Thi được mở tài liệu có chọn lọcRAG
Không nhớ hết cả cuốn sáchModel 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 quanTrước khi generate, retrieve đúng k đoạn liên quan nhất
Chỉ xem những trang đã chọn, không thấy phần còn lại của sáchChỉ thấy k đoạn được nhét vào context, không thấy phần còn lại của index
Bài làm = kiến thức nền + trang vừa xemGenerate = 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 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. Context đưa vào là nó dùng, coi như đáng tin, bất kể đoạn đó có thật sự liên quan hay không.

💡 Cách nhớ

RAG = thi được mở tài liệu có chọn lọc: không thuộc lòng cả sách, chỉ được xem vài trang chọn sẵn, và trang được chọn XONG rồi mới bắt đầu làm bài.

Thử ngẫmhọc sinh tự bỏ qua được trang lật nhầm, lạc đề. Nếu một hệ RAG retrieve nhầm một đoạn không liên quan vào context, model có tự làm được điều tương tự không?

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 trộ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, 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 như 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.)

Khác biệt lớn nhất: retrieve luôn trả về đúng k đoạn, vì danh sách xếp hạng nào cũng có k điểm cao nhất, kể cả khi tài liệu chẳng có đoạn nào trả lời được câu hỏi. Không có khái niệm "không tìm thấy" như khi tra khoá thất bại. Chỉ có k đoạn đỡ xa nhất trong đám còn lại, đúng hay sai với câu hỏi là chuyện khác.

Thử ngẫmmột index chỉ chứa tài liệu về bóng đá. Ai đó hỏi công thức nấu ăn. Retrieve vẫn trả về k đoạn bóng đá điểm cao nhất. Hệ thống có báo lỗi "không tìm thấy" không?

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 chạy lại mỗi khi tài liệu đổi, và 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:

Plain Text
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

Khung index-time cắt tài liệu thành chunk và embed vào một kho index; khung query-time chạy lại năm bước đánh số cho mỗi câu hỏi: nhận câu hỏi, embed bằng đúng model lúc index, retrieve top-k từ index, nhét k đoạn vào context, generate

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 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 chéo được (bài 01). Còn bước 5 không có cơ chế gì mới: đó đúng là vòng lặp dự đoán token kế tiếp, chỉ khác input dài hơn vì chứa thêm k đoạn tài liệu 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ử 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?

Tự điền trước khi xem đáp án

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:

  1. 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ì?
  2. 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ì?
  3. 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 chung một điểm đá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à sai, và không có gì tự báo.

  1. Sai model ở bước 2: vector câu hỏi giờ sống trong không gian nghĩa khác với vector của cả index. Nếu hai model tình cờ cùng số chiều output (khá phổ biến khi đổi giữa hai model cùng họ), bước 3 vẫn tính cosine bình thường và vẫn xếp ra đúng k con số. Chỉ là những con số đó không phản ánh nghĩa thật, nên top-k gần như ngẫu nhiên, mà không có dòng lỗi nào. (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.)
  2. Retrieve "đúng" ở bước 3 dù index không có đoạn nào liên quan: cosine là phép xếp hạng tương đối (mục 2), không có ngưỡng loại bỏ mặc định. Index không có đoạn nào thật sự liên quan thì hệ thống vẫn răm rắp 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 một context toàn nhiễu.
  3. Đây là ranh giới cần tách bạch: context ở bước 4 đã chứa đúng thông tin mà bước 5 vẫn sinh sai thì 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" mới sửa đúng chỗ, thay vì đi đổ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, và luôn trả về đủ k đoạn kể cả khi chẳng đoạn nào 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ỉ thấy 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 thì model cũng không hề biết là có.

6. 📚 Deep Dive

📚 Nguồn gốc: đọc khi muốn xuống tầng sâu hơn
  • 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 là kết hợp bộ nhớ tham số (parametric, kiến thức nén sẵn trong trọng số) với bộ nhớ phi tham số (non-parametric, một index truy hồi được và 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 phải train lại model. Giảm hallucination là lợi ích các nghiên cứu sau này ghi nhận thêm, không phải động lực ban đầu của bài báo năm 2020.

Ghi chú: đối chiếu nguồn ngày 2026-07-23; bài dùng paper làm nguồn gốc thuật ngữ và ý tưởng kiến trúc, không tóm tắt kết quả thực nghiệm của nó.

7. Liên hệ các bài khác

8. Tóm tắt

  • Index-time chạy trước và chạy lại mỗi khi tài liệu hoặc embedding model đổi; query-time chạy lại cả 5 bước cho mỗi câu hỏi.
  • Bước 2 dùng khác model với lúc index mà cùng số chiều là ca nguy hiểm nhất: không lỗi nào, top-k gần như ngẫu nhiên.
  • Index chỉ có tài liệu bóng đá thì câu hỏi nấu ăn vẫn nhận về k đoạn bóng đá, vì retrieve không có khái niệm "không tìm thấy".
  • Nguồn gốc RAG (Lewis et al., 2020): kết hợp bộ nhớ tham số với 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

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Mộ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ì?
  2. Q2
    Phâ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 hay gặp?
  3. Q3
    Bướ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?
  4. Q4
    Hệ 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.
  5. Q5
    Vì 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?

Bài tiếp theo: Bốn kiểu hỏng của RAG: lỗi ở retrieval hay generation?

Bài này có giúp bạn hiểu bản chất không?

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.

Thảo luận & góp ý

Hỏi đáp về bài này

Bài tiếp theo

Bốn kiểu hỏng của RAG: lỗi ở retrieval hay generation?