RAG nâng cao 1 — Vì sao naive RAG thất bại & bản đồ RAG hiện đại

13 thg 7, 2026 4 lượt xem
#ai
#llm
#rag
#retrieval
#search

Mở đầu: RAG chạy được demo, chết ở production

Bạn dựng một trợ lý hỏi-đáp trên bộ quy định nội bộ ngân hàng. Trong buổi demo, nó trả lời trơn tru. Đưa vào dùng thật, người dùng đặt những câu hỏi thật — và tỷ lệ trả lời sai, thiếu, hoặc "bịa có dẫn chứng" tăng vọt. Đây là câu chuyện quen thuộc của naive RAG: kiến trúc tối giản đủ để demo nhưng không đủ để tin cậy.

Series này đi sâu vào RAG nâng cao — các kỹ thuật biến một pipeline "chạy được" thành hệ thống production đáng tin. Bài mở đầu không dạy lại RAG từ đầu (xem RAG: kiến trúc & thực chiếnRAG retrieval với vector), mà trả lời hai câu hỏi bản lề: naive RAG thất bại ở đâu, và có những tầng nâng cấp nào để vá từng loại thất bại đó.

Nhắc nhanh: RAG cơ bản là gì

RAG (Retrieval-Augmented Generation) ghép truy hồi (retrieval) với sinh (generation). Vòng cơ bản gồm 4 bước:

  1. Embed — nhúng tài liệu thành vector số nhiều chiều bằng embedding model (xem Embeddings & vector). Tài liệu được cắt thành chunk trước khi nhúng.
  2. Vector search top-k — nhúng câu hỏi thành vector, tìm k chunk gần nhất theo độ tương đồng cosine/dot-product trong vector store.
  3. Nhồi context — dán k chunk vào prompt làm bối cảnh.
  4. Sinh — LLM đọc bối cảnh + câu hỏi, sinh câu trả lời kèm (kỳ vọng) trích dẫn.

Tư tưởng cốt lõi: thay vì nhồi cả kho tài liệu vào LLM, ta chỉ đưa phần liên quan nhất. Vấn đề là chữ "liên quan nhất" đó — naive RAG định nghĩa nó bằng đúng một tín hiệu (độ gần vector của top-k), và đó là gốc rễ của phần lớn thất bại.

Tám kiểu thất bại của naive RAG

Dưới đây là các dạng lỗi gặp thường xuyên nhất khi đưa RAG vào dùng thật. Mỗi loại gắn với một khâu trong pipeline.

1. Chunk cắt vụn làm mất ngữ cảnh

Cắt cố định 500 token có thể xẻ đôi một điều khoản: định nghĩa nằm chunk này, ngoại lệ nằm chunk sau. Retrieve trúng một nửa, LLM trả lời thiếu vế. Bảng bị cắt rời khỏi tiêu đề cột; danh sách điều kiện bị chặt giữa chừng. Chunk quá nhỏ mất ngữ cảnh, quá lớn thì loãng tín hiệu và tốn token.

2. Vector search bỏ sót khớp từ khoá, số và mã

Embedding giỏi nắm ngữ nghĩa nhưng kém với khớp chính xác. Hỏi về sản phẩm mã "TK-2024-07", điều khoản "Điều 12.3", hay hạn mức "500 triệu", vector search dễ trả về chunk "gần nghĩa" mà lệch đúng con số/mã cần. Với ngân hàng — nơi mã sản phẩm, số điều, ngưỡng số là bản chất — đây là điểm chết người.

3. Top-k lẫn nhiễu

k cố định là con dao hai lưỡi. k nhỏ thì sót; k lớn thì kéo theo chunk lạc đề. LLM đọc phải nhiễu, hoặc bị đánh lạc hướng, hoặc "trung bình hoá" các mẩu mâu thuẫn thành câu trả lời sai.

4. Câu hỏi đa bước / tổng hợp toàn corpus

"So sánh điều kiện vay của sản phẩm A và B" cần gộp thông tin từ nhiều tài liệu. "Có bao nhiêu quy định nhắc tới hạn mức ngoại tệ?" là câu tổng hợp toàn kho — không một top-k chunk nào chứa sẵn đáp án. Naive RAG (một vòng retrieve) về bản chất không giải được lớp câu hỏi này.

5. Câu hỏi mơ hồ, thiếu ngữ cảnh

"Cái đó áp dụng cho khách VIP không?" — "cái đó" là gì? Câu hỏi ngắn, đại từ, viết tắt nội bộ, lỗi chính tả khiến vector câu hỏi lệch khỏi vùng tài liệu đúng. Retrieval rác thì generation cũng rác (garbage in, garbage out).

6. "Lost in the middle"

Khi nhồi nhiều chunk, LLM chú ý mạnh phần đầu và cuối context, lơ là phần giữa. Chunk đúng đáp án nằm ở vị trí thứ 6/10 dễ bị bỏ qua. Nhồi nhiều hơn không đồng nghĩa trả lời tốt hơn — thứ tự và chất lượng mới quan trọng.

7. Trích dẫn sai / ảo giác

LLM có thể sinh câu trả lời nghe hợp lý nhưng gán sai nguồn, hoặc "sáng tác" điều khoản không có trong context. Không có cơ chế kiểm tra "câu trả lời có thật sự bắt nguồn từ tài liệu retrieve không" thì ảo giác lọt lưới.

8. Dữ liệu cập nhật

Quy định sửa tuần trước nhưng index chưa re-embed, hoặc bản cũ và mới cùng tồn tại trong store. RAG trả lời theo bản lỗi thời — về mặt kỹ thuật thì "đúng theo tài liệu retrieve", về nghiệp vụ thì sai.

Một cách nhìn gọn: naive RAG cược tất cả vào một tín hiệu (vector top-k) và một vòng lặp. Mỗi kiểu thất bại là một chỗ mà giả định đó vỡ.

Bản đồ RAG nâng cao

Mỗi tầng nâng cấp dưới đây nhắm vào các kiểu thất bại cụ thể. Toàn series đi lần lượt qua các tầng này.

Tầng 1 — Indexing tốt hơn

Sửa từ gốc: cách cắt và lưu tài liệu. Chunking chiến lược cắt theo cấu trúc (điều/khoản, tiêu đề, đoạn) thay vì độ dài cố định, thêm overlap và metadata. Multi-vector nhúng một chunk bằng nhiều biểu diễn (tóm tắt, câu hỏi giả định). Parent-document đánh index trên chunk nhỏ để retrieve chính xác nhưng trả về đoạn cha lớn để đủ ngữ cảnh. Vá lỗi #1 (chunk vụn), giảm #6. Chi tiết ở Chunking & indexing.

Tầng 2 — Retrieval tốt hơn

Hybrid search kết hợp BM25 (khớp từ khoá, lexical) với vector (ngữ nghĩa), rồi hợp nhất điểm (ví dụ Reciprocal Rank Fusion). Vá lỗi #2 (sót từ khoá/số/mã). Xem Hybrid search. Reranking dùng cross-encoder chấm lại độ liên quan của từng ứng viên với câu hỏi, đưa chunk đúng lên đầu và cắt nhiễu — vá #3 và #6. Xem Reranking.

Tầng 3 — Hiểu câu hỏi

Xử lý câu hỏi trước khi retrieve. Query rewriting làm rõ đại từ, sửa chính tả, thêm ngữ cảnh hội thoại. HyDE (Hypothetical Document Embeddings) sinh một câu trả lời giả định rồi lấy vector của nó đi tìm — thu hẹp khoảng cách giữa "giọng câu hỏi" và "giọng tài liệu". Multi-query tách một câu thành nhiều truy vấn con. Routing chọn nguồn/index phù hợp. Vá #4, #5. Xem Query transformation.

Tầng 4 — Kiến thức có cấu trúc (GraphRAG)

Khi câu hỏi cần quan hệtổng hợp toàn corpus, vector search phẳng bất lực. GraphRAG trích thực thể và quan hệ thành đồ thị tri thức (knowledge graph), cho phép trả lời "sản phẩm nào liên quan phòng ban nào", "chuỗi điều khoản dẫn chiếu nhau" — vá thẳng #4. Xem GraphRAG.

Tầng 5 — Tự lặp (Agentic RAG)

Thay vì retrieve một lần, LLM đóng vai tác nhân: tự đánh giá kết quả, retrieve lại, phân rã câu hỏi đa bước, gọi công cụ, lặp đến khi đủ chứng cứ. Vá #4, #7 và các câu khó. Xem Agentic RAG, RAG với agents, và nền tảng Harness engineering.

Tầng 6 — Đo & vận hành (Eval)

Không đo thì không cải thiện. Đánh giá riêng retrieval (recall, precision, hit-rate, MRR) và generation (faithfulness/độ trung thành với nguồn, answer relevance, tỷ lệ ảo giác). Vá #7, #8 và cho vòng lặp cải tiến. Xem Eval & production và nền tảng Đánh giá LLM.

Bảng ánh xạ nhanh:

Kiểu thất bạiTầng nâng cấp chính
#1 Chunk vụnIndexing (chunking, parent-document)
#2 Sót từ khoá/số/mãHybrid search
#3 Top-k nhiễuReranking
#4 Đa bước / tổng hợp corpusGraphRAG, Agentic
#5 Câu hỏi mơ hồQuery transformation
#6 Lost in the middleReranking, parent-document
#7 Trích dẫn sai / ảo giácAgentic, Eval (faithfulness)
#8 Dữ liệu cập nhậtVận hành index, Eval giám sát

RAG vs fine-tune vs context dài

Ba cách để LLM "biết" dữ liệu riêng — chọn theo bản chất bài toán, thường là kết hợp:

Tiêu chíRAGFine-tuneContext dài
Giải quyếtKiến thức thay đổi, cần dẫn nguồnĐịnh dạng/phong cách/kỹ năngNgữ cảnh gọn, dùng một lần
Cập nhậtChỉ cần re-indexPhải huấn luyện lạiĐổi prompt
Trích dẫn nguồnCó (thế mạnh)KhôngCó (trong context)
Chi phí thay đổiThấpCaoToken cao mỗi lần gọi
Điểm yếuPhụ thuộc retrievalKhông dẫn nguồn, dễ lỗi thờiĐắt, "lost in the middle"

Nguyên tắc: kiến thức thay đổi và cần dẫn nguồn → RAG; hành vi/định dạng cố định → fine-tune; tài liệu nhỏ, một lần → nhồi thẳng context. Context dài không xoá bỏ RAG: nhồi 500 trang mỗi lần gọi vừa đắt vừa vướng lost-in-the-middle, và vẫn cần chọn đúng tài liệu để nhồi.

Kiến trúc RAG production tổng quan

Hệ thống thật tách hai đường: ingest (offline) dựng index, và serve (online) phục vụ truy vấn.

Pseudocode: pipeline RAG nâng cao

Minh hoạ retrieve → rerank → generate (mã rút gọn để làm rõ ý, không phải API chạy được). Model dùng là claude-opus-4-8.

# MINH HOẠ — pseudocode, không phải API thật
def advanced_rag(question, history):
    # 1) Hiểu câu hỏi: làm rõ + tách truy vấn con
    q = rewrite_with_context(question, history)      # sửa đại từ, chính tả
    subqueries = multi_query(q)                       # 1 -> N truy vấn

    # 2) Hybrid retrieve cho từng truy vấn con
    candidates = []
    for sq in subqueries:
        vec_hits = vector_store.search(embed(sq), k=20)
        bm25_hits = bm25_index.search(sq, k=20)
        candidates += reciprocal_rank_fusion(vec_hits, bm25_hits)
    candidates = dedup(candidates)

    # 3) Rerank bằng cross-encoder, giữ ít nhưng chất
    ranked = reranker.score(q, candidates)
    top = ranked[:6]                                  # tránh lost-in-the-middle

    # 4) Parent-document: đổi chunk nhỏ -> đoạn cha đủ ngữ cảnh
    context = [fetch_parent(c) for c in top]

    # 5) Sinh có ràng buộc trích dẫn
    answer = llm.generate(
        model="claude-opus-4-8",
        system="Chỉ trả lời dựa trên NGỮ CẢNH. Trích dẫn [id]. "
               "Nếu thiếu dữ kiện, nói rõ là không đủ thông tin.",
        context=context, question=q,
    )

    # 6) Agentic: nếu không đủ chứng cứ, lặp lại
    if not grounded(answer, context):
        return advanced_rag(refine(q, answer), history)  # có giới hạn số vòng
    return answer

Bốn ý cần nhớ trong đoạn trên: (1) xử lý câu hỏi trước khi tìm; (2) hybrid + rerank để vừa đúng ngữ nghĩa vừa đúng từ khoá; (3) giữ context ít mà chất; (4) buộc dẫn nguồn và kiểm tra grounding trước khi tin.

Use case thực tế

Bối cảnh — NCB, trợ lý tra cứu quy định & sản phẩm nội bộ. Kho tri thức gồm ~4.000 trang: quy định tín dụng, biểu phí, mô tả sản phẩm tiền gửi/vay, quy trình vận hành. Người dùng là nhân viên chi nhánh và tổng đài, hỏi bằng ngôn ngữ tự nhiên xen mã sản phẩm và số điều khoản.

Bản naive RAG (v0): cắt cố định 512 token, chỉ vector search top-5, nhồi thẳng vào LLM. Nghiệm thu với 200 câu hỏi thật, đội nghiệp vụ chấm tay. Các lỗi lặp lại đúng như phần trên:

  • Hỏi "phí tất toán trước hạn sản phẩm TK-2024-07" → trả về sản phẩm gần nghĩa nhưng sai mã (lỗi #2).
  • Hỏi "điều kiện vay và ngoại lệ với khách dưới 25 tuổi" → điều kiện đúng chunk, ngoại lệ rơi mất ở chunk kế (lỗi #1).
  • Hỏi "so sánh 2 gói tiết kiệm" → chỉ lấy được thông tin một gói (lỗi #4).
  • Vài câu bịa mức phí không có trong tài liệu (lỗi #7).

Độ chính xác nghiệm thu ~58% (ước lượng nội bộ trên 200 câu).

Nâng cấp (v1), theo bản đồ series:

BướcNhắm lỗiThay đổi
Chunk theo điều/khoản + parent-document#1Cắt theo cấu trúc văn bản, retrieve chunk nhỏ, trả đoạn cha
Hybrid BM25 + vector#2Khớp đúng mã sản phẩm, số điều, mức phí
Reranking cross-encoder#3, #6Từ ~40 ứng viên còn 6 chunk chất
Query rewrite + multi-query#4, #5Làm rõ câu mơ hồ, tách câu so sánh
Ràng buộc trích dẫn + kiểm grounding#7Bắt buộc dẫn [id]; câu không grounded bị chặn
Re-index theo lịch + eval giám sát#8Quy định sửa là re-embed; theo dõi hit-rate

Kết quả nghiệm thu lại trên đúng 200 câu: độ chính xác ~85% (ước lượng), lỗi bịa mức phí giảm mạnh nhờ chặn câu không grounded. Lưu ý: mọi con số 58% → 85% là ước lượng minh hoạ cho một cấu hình cụ thể, không phải cam kết; phải đo lại trên tập câu hỏi và corpus thực của bạn (xem Eval & production).

Bài học vận hành: đóng góp lớn nhất đến từ hybrid search (mã/số) và reranking (cắt nhiễu) — hai tầng rẻ, tác động nhanh; nên làm trước GraphRAG và agentic vốn phức tạp hơn.

Ghi nhớ

  • Naive RAG = embed → vector top-k → nhồi context → sinh. Đủ để demo, không đủ để tin cậy vì cược tất cả vào một tín hiệu và một vòng lặp.
  • Nhớ 8 kiểu thất bại: chunk vụn, sót từ khoá/số/mã, top-k nhiễu, câu đa bước/tổng hợp corpus, câu mơ hồ, lost-in-the-middle, trích dẫn sai/ảo giác, dữ liệu cũ.
  • Mỗi tầng vá một lớp lỗi: indexing (#1), hybrid search (#2), reranking (#3,#6), query transformation (#4,#5), GraphRAG (#4), agentic (#4,#7), eval & vận hành (#7,#8).
  • Thứ tự ưu tiên khi cải tiến: hybrid + reranking cho tác động nhanh; query transform khi câu hỏi khó; GraphRAG/agentic khi cần quan hệ và đa bước; eval xuyên suốt.
  • RAG vs fine-tune vs context dài: kiến thức thay đổi + cần dẫn nguồn → RAG; hành vi/định dạng → fine-tune; tài liệu nhỏ một lần → context. Thường kết hợp.
  • Production tách offline (index) và online (serve); luôn có vòng log → eval → cải tiến index.
  • Mọi con số phải đo lại trên corpus và tập câu hỏi của chính bạn — đừng tin ước lượng minh hoạ.

Nguồn tham khảo

Bài viết liên quan

Đặt nền cho chuỗi AI: phân biệt ba vòng tròn lồng nhau AI ⊃ ML ⊃ DL và khác biệt bản chất giữa lập trình truyền thống với học từ dữ liệu. Giới thiệu ba kiểu học máy (supervised, unsupervised, reinforcement), phân loại descriptive/predictive/prescriptive, quy trình ML end-to-end, chia train/validation/test, overfitting/underfitting và các thuật ngữ nền tảng, gắn với ứng dụng ngân hàng NCB.

13 thg 7, 2026 18

Harness — lớp scaffolding quanh model (vòng lặp, tool, context, memory, verify, sub-agent) — mới là thứ quyết định agent chạy được hay chỉ là demo. Bài này mổ xẻ giải phẫu một harness, 7 kỹ năng cốt lõi khi xây agent, single vs multi-agent (kèm số liệu hiệu quả/chi phí), các repo nên dùng, và một quickstart Python dựng-là-chạy cho bối cảnh ngân hàng.

13 thg 7, 2026 15

Hiểu LLM từ gốc: bản chất dự đoán token, ba giai đoạn huấn luyện (pretraining, fine-tuning, RLHF), token, context window và các tham số sinh (temperature, top-p). Nắm hiện tượng hallucination và kỹ thuật prompt engineering (vai trò, few-shot, chain-of-thought, ràng buộc đầu ra), kèm ví dụ gọi API model Claude mới nhất với adaptive thinking.

13 thg 7, 2026 14

Vì sao dữ liệu quyết định chất lượng mô hình hơn cả thuật toán. Bài này đi qua toàn bộ pipeline chuẩn bị dữ liệu: phân loại dữ liệu, làm sạch (thiếu/ngoại lai/trùng lặp), mã hoá hạng mục, scaling, feature engineering, giảm chiều, và cách phòng data leakage — soi qua bài toán chấm điểm tín dụng.

13 thg 7, 2026 14

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!