Có một cách giải thích RAG rất phổ biến:
Chia tài liệu thành các chunk
-> tạo embedding
-> lưu vào vector database
-> tìm chunk gần với câu hỏi
-> đưa cho LLM
Cách giải thích này không sai. Nhưng nếu dùng nó làm mental model chính, chúng ta rất dễ xây một hệ thống chạy đẹp trong demo rồi vỡ khi gặp dữ liệu thật.
Một hệ Retrieval-Augmented Generation trong thực tế không phải là Vector Database + LLM. Nó là một chuỗi xử lý gồm rất nhiều quyết định: parsing, chunking, metadata, indexing, query transformation, lexical retrieval, dense retrieval, fusion, reranking, context construction, prompting, generation, citation, security, observability và evaluation. Mỗi quyết định ở đó đều có thể là nguyên nhân khiến câu trả lời cuối cùng sai.
Bài viết này đi xuyên qua toàn bộ pipeline đó. Mục tiêu không phải đào sâu từng thuật toán — chunking, embedding, hybrid search, reranking hay query transformation đều xứng đáng có một bài riêng — mà là dựng một mental model hoàn chỉnh: mỗi khâu nhận gì, xử lý gì, trả ra gì, vì sao nó tồn tại, và nó liên hệ với các khâu còn lại như thế nào.
01Vì sao chúng ta cần RAG
Một Large Language Model sau khi pretrain đã hấp thụ một lượng lớn pattern và kiến thức từ dữ liệu huấn luyện. Phần kiến thức đó có thể xem là parametric memory: thông tin được mã hoá gián tiếp trong chính các tham số của model.
Cách lưu trữ này tạo ra bốn giới hạn khá cụ thể.
Thứ nhất, model không tự nhiên biết tài liệu riêng của tổ chức nếu chúng chưa từng nằm trong training data. Thứ hai, cập nhật một tài liệu trong database không hề cập nhật kiến thức bên trong model. Thứ ba, ngay cả khi model từng nhìn thấy một sự kiện lúc training, việc yêu cầu nó truy xuất chính xác một chi tiết cụ thể vẫn không giống một lần database lookup. Thứ tư, nếu chỉ dựa vào parametric knowledge, ta gần như không thể chỉ ra nguồn nào đã hỗ trợ cho một câu trả lời.
Paper RAG của Lewis và cộng sự năm 2020 đặt vấn đề đúng theo hướng này: kết hợp parametric memory của mô hình sinh với một non-parametric memory bên ngoài, có thể truy xuất khi cần.
Điểm quan trọng nhất, và cũng là điểm hay bị hiểu nhầm nhất:
RAG không cập nhật weights của model. RAG thay đổi thông tin có sẵn tại thời điểm inference.
Model vẫn là model đó. Nhưng trước khi yêu cầu nó trả lời, hệ thống đi tìm những thông tin có khả năng liên quan từ nguồn bên ngoài rồi đưa chúng vào context. Vì vậy:
RAG = Retrieval + Context Augmentation + Generation
Bốn nhóm vấn đề RAG thường giải quyết
Tri thức nằm ngoài training data. Một chatbot nội bộ cần trả lời “quy trình deploy production của team hiện tại là gì”. Thông tin đó nằm trong Notion, Confluence, Google Drive, git repository, runbook hay ticket. Không có lý do gì để kỳ vọng một foundation model đã biết chúng.
Tri thức thay đổi theo thời gian. Nếu chính sách công ty đổi hôm nay, ta cập nhật knowledge source và re-index, thay vì fine-tune lại model chỉ để sửa một đoạn thông tin.
Grounding. Thay vì bảo model trả lời bằng kiến thức của nó, ta đưa evidence cụ thể kèm chỉ dẫn chỉ được dùng evidence đó. RAG không đảm bảo tuyệt đối rằng model sẽ không hallucinate, nhưng nó tạo ra một kênh grounding để câu trả lời có chỗ bám.
Provenance. Nếu retrieval layer giữ được document_id, title, url, page, section và chunk_id, hệ thống có thể đưa source metadata sang generation layer và trả về câu trả lời kèm nguồn. Citation không tự nhiên xuất hiện chỉ vì ta dùng vector database — nó phải được bảo toàn xuyên suốt từ ingestion đến response cuối.
Khi nào RAG không phải là đáp án
RAG phù hợp khi vấn đề là model cần truy cập đúng tri thức tại runtime. Nhưng nếu mục tiêu là thay đổi phong cách trả lời, cấu trúc output, hành vi ổn định, khả năng thực hiện một task hay domain adaptation ở mức model, thì fine-tuning hoặc instruction tuning thường hợp hơn.
02RAG là một hệ thống, không phải một model
Một trong những sai lầm phổ biến nhất là đồng nhất RAG với vector search. Sơ đồ quen thuộc:
Document -> Embedding -> Vector DB
Query -> Embedding -> Top-k -> LLM
Đây là Naive RAG, rất hữu ích để học, nhưng chưa phải cách tốt để suy nghĩ về một hệ thống thật. Một RAG application đầy đủ nên được tách thành ít nhất hai flow lớn, như Hình 1 ở đầu bài.
Data pipeline trả lời câu hỏi: làm thế nào biến tri thức thô thành một biểu diễn có thể search tốt? File này parse ra sao, có giữ được heading, bảng và caption không, chunk theo token hay theo cấu trúc, metadata nào phải giữ, lưu dense vector hay cả sparse, tài liệu đổi thì re-index thế nào, permission metadata có được bảo toàn không.
Query pipeline trả lời câu hỏi: khi user hỏi, hệ thống phải làm gì để tìm được evidence tốt nhất và dùng evidence đó hiệu quả? Raw query có đủ rõ không, có cần rewrite hay decomposition, search bằng keyword hay vector hay cả hai, lấy bao nhiêu candidate, fuse thế nào, có cần rerank, bao nhiêu evidence thực sự nên đưa vào LLM, sắp xếp theo thứ tự nào, khi evidence không đủ thì có nên trả lời.
Điều này dẫn tới một nguyên tắc rất thực dụng khi debug:
Nếu câu trả lời cuối cùng sai, chưa chắc LLM là nơi sai.
Chất lượng cuối cùng của RAG gần với một phép nhân hơn là phép cộng: mỗi khâu đều có thể kéo kết quả về gần không, và không khâu nào bù được cho khâu trước nó.
03Data pipeline: từ dữ liệu thô đến knowledge index
Một RAG system chỉ tốt bằng biểu diễn tri thức mà nó search trên đó. Ta bắt đầu từ PDF, DOCX, PPTX, HTML, Markdown, wiki, email, database, API, ảnh, transcript — và cần đi tới những đơn vị tri thức search được.
Điểm đáng chú ý nhất trong hình này là hàng dưới. Mỗi khâu ingestion không chỉ thêm cấu trúc, nó còn có thể phá cấu trúc. Và cái đã mất ở khâu này thì không khâu nào sau đó khôi phục lại được.
04Parsing và chuẩn hoá: vấn đề thường bị đánh giá thấp
Giả sử tài liệu là một PDF có heading, đoạn văn, bảng, hình, footnote và layout nhiều cột. Nếu parser biến tất cả thành một khối text phẳng thì rất nhiều cấu trúc đã mất trước khi RAG kịp bắt đầu.
Lấy một bảng giá làm ví dụ. Một parser kém trả về:
Plan Price Limit Basic $10 10 GB Pro $30 100 GB
Một biểu diễn tốt hơn giữ lại được quan hệ hàng-cột:
## Pricing
| Plan | Price | Limit |
| Basic | $10 | 10 GB |
| Pro | $30 | 100 GB |
Khác biệt này ảnh hưởng trực tiếp tới chunking, embedding, retrieval và cả khả năng LLM đọc được context. Các document parser hiện đại như Docling hướng tới việc giữ hierarchy và metadata của tài liệu, đồng thời xuất chunk trực tiếp cho RAG pipeline.
Parsing không chỉ là extract text. Parsing là khôi phục semantic structure của tài liệu.
Sau parsing là chuẩn hoá. Header lặp trên mỗi trang, footer, số trang, navigation text, cookie notice, boilerplate, nội dung trùng, whitespace vỡ, artifact OCR — nếu không kiểm soát, tất cả những đoạn không có giá trị ngữ nghĩa đó sẽ được embed, được index, được retrieve, và cuối cùng ăn mất token trong context.
Nhưng có một lỗi ngược lại cũng nguy hiểm không kém: clean quá mạnh. Bỏ hết ký tự đặc biệt có thể làm vỡ bảng. Gộp hết xuống dòng có thể xoá ranh giới mục. Chuẩn hoá quá tay thường mất chính thứ giúp retrieval hoạt động.
05Chunking: đơn vị retrieval thực sự là gì
Search trên cả document thường quá thô. Một handbook 200 trang mà người dùng chỉ hỏi “thời gian thử việc của nhân viên kỹ thuật là bao lâu” thì ta không muốn nhét cả cuốn vào model. Ta muốn một đoạn đủ nhỏ để chính xác, nhưng đủ lớn để giữ ngữ cảnh.
Có nhiều chiến lược: fixed-size, recursive, sentence-based, semantic, structure-aware, parent-child, hierarchical, sliding window. Điều quan trọng ở bài kiến trúc chưa phải chọn thuật toán nào, mà là hiểu trade-off.
Một chunk quá nhỏ như "The company grew by 18%." làm mất công ty nào, quý nào, chỉ số nào, so với mốc nào. Một chunk 3.000 token thì ngược lại: nó có thể chứa câu trả lời, nhưng embedding bị pha trộn nhiều chủ đề, retrieval kém chính xác, context tốn token, và LLM phải đọc rất nhiều nhiễu.
Anthropic từng chỉ ra một failure mode rất điển hình: chunk sau khi tách khỏi document có thể mất thông tin về chính document, về entity hoặc về thời gian. Contextual Retrieval giải quyết theo hướng bổ sung một đoạn context ngắn vào mỗi chunk trước khi tạo embedding và biểu diễn BM25. Một chunk như "Revenue increased 3% over the previous quarter." trở thành một đơn vị giàu ngữ cảnh hơn khi được gắn thêm "ACME Corp, Q2 2023 financial report.".
Điều rút ra không phải là mọi hệ thống đều phải dùng Contextual Retrieval, mà là một phép thử rất đơn giản:
Đọc riêng một chunk mà không nhìn tài liệu gốc. Nếu bạn không hiểu nó nói về ai, cái gì, thời điểm nào, thì retrieval cũng không hiểu.
06Metadata và index: một chunk sinh ra ba biểu diễn
Mỗi chunk thường cần cả content lẫn metadata:
{
"chunk_id": "postgres-runbook#auth#0007",
"document_id": "postgres-runbook",
"content": "To rotate the database password...",
"document_title": "PostgreSQL Production Runbook",
"section_path": ["Authentication", "Password Rotation"],
"page": 14,
"source_url": "https://...",
"version": "2026-08-14",
"updated_at": "2026-08-14T11:25:00Z",
"tenant_id": "platform-team",
"access_groups": ["platform", "sre"]
}
Schema này quyết định rất nhiều khả năng ở cuối pipeline:
citation <- source_url / page
filter <- tenant / team / type
freshness <- version / updated_at
deduplication <- document_id / chunk_id
ACL <- access_groups
context <- title / section_path
Cách phân công công việc giữa vector và metadata khá rõ ràng: quan hệ ngữ nghĩa thuộc về vector và lexical ranking, còn ràng buộc chính xác thuộc về metadata filtering. Với câu hỏi “tìm policy engineering được cập nhật sau tháng 6/2026”, semantic search lo phần nội dung nào liên quan, còn filter lo phần department = engineering và updated_at >= 2026-06-01.
Ngoài metadata có sẵn, ingestion pipeline còn có thể tạo thêm field bằng enrichment: title, summary, keywords, entities, category, section path, hoặc những câu hỏi mà chunk này có thể trả lời. Enrichment giúp retrieval nhưng có cái giá của nó — thêm inference lúc index, có thể sinh dữ liệu sai, tăng complexity, và bắt buộc re-index mỗi khi logic enrichment thay đổi. Vì vậy nó nên phục vụ một giả thuyết retrieval cụ thể, chứ không phải thêm field vì “có thể hữu ích”.
Indexing là một vòng đời
Tri thức trong production luôn thay đổi: tài liệu được tạo, sửa, xoá, đổi quyền, đổi phiên bản, đổi chỗ. Pipeline phải trả lời được: có incremental indexing không, khi document sửa thì chunk cũ bị xoá thế nào, dedup ra sao, re-embedding khi đổi model thế nào, có giữ version không, permission đổi thì bao lâu index mới cập nhật, có cơ chế phát hiện index cũ không.
Nếu source of truth đã đổi mà search index chưa đổi, câu trả lời của RAG sẽ khác sự thật hiện tại. Đây là một dạng lỗi hoàn toàn độc lập với chất lượng LLM.
07Query processing: câu người dùng gõ chưa phải câu nên đem đi search
Người dùng nói chuyện với ứng dụng, không nói chuyện với search engine. Trong một hội thoại:
User: So sánh PostgreSQL và MySQL cho workload analytics.
Assistant: ...
User: Còn chi phí thì sao?
Nếu embed thẳng câu thứ hai, retrieval mất gần như toàn bộ chủ thể. Thứ ta muốn đem đi search là “so sánh chi phí vận hành PostgreSQL và MySQL cho workload analytics”. Đó là query rewriting.
Query expansion xuất phát từ chỗ một ý có nhiều cách diễn đạt. "SSO login error" có thể liên quan tới tài liệu chứa single sign-on, identity provider, SAML authentication hay federated login. Sinh nhiều biến thể rồi retrieve nhiều lần và fusion lại có thể tăng recall, nhưng đổi lại là thêm search call và thêm nhiễu.
Query decomposition xử lý câu hỏi nhiều vế. “So sánh SLA của hệ thống tại East US và West Europe, và cho biết region nào phù hợp hơn với workload của team” thực chất là ba câu hỏi. Microsoft phân biệt khá rõ giữa decomposition theo một flow cố định do orchestrator định nghĩa, và agentic RAG nơi agent tự quyết định cách tách dựa trên reasoning lúc chạy.
HyDE đi theo hướng khác hẳn. Thay vì embed câu hỏi, nó để LLM viết trước một tài liệu giả định trả lời câu hỏi đó, rồi embed tài liệu giả định để tìm hàng xóm phù hợp trong corpus. Cách này hữu ích khi khoảng cách biểu diễn giữa câu hỏi và passage quá lớn, nhưng không miễn phí: nội dung giả định có thể sai chi tiết, và nó thêm một model call vào latency.
08Dense, sparse và hybrid retrieval
Dense retrieval ánh xạ cả query lẫn chunk vào cùng một không gian rồi tìm láng giềng gần nhất. Nó đặc biệt tốt khi query và document dùng từ ngữ khác nhau nhưng nghĩa gần nhau — "How do I terminate my account?" và "Steps for closing a customer subscription" gần như không trùng chữ nào.
Lexical retrieval như BM25 mạnh ở hướng ngược lại: khi token chính xác mới là thứ quan trọng. Mã sản phẩm, mã lỗi, tên riêng, endpoint API, tên class, số hiệu điều khoản, version, acronym hiếm. Với một định danh gần như tuỳ ý kiểu ERR_CONNECTION_4821, embedding không nhất thiết là biểu diễn tốt nhất, còn inverted index thì được thiết kế đúng để tận dụng độ hiếm của term.
Vì dense và sparse hỏng theo hai kiểu khác nhau, rất nhiều kiến trúc RAG chạy cả hai rồi hợp nhất kết quả.
Chi tiết đáng nhớ ở đây là vì sao phải fuse theo rank chứ không theo score. Cosine similarity và điểm BM25 không cùng thang đo, nên cộng thẳng chúng không có ý nghĩa thống kê. RRF bỏ điểm thô đi và chỉ dùng thứ hạng:
RRF(d) = tổng theo từng list của 1 / (k + rank_i(d))
Azure AI Search hiện thực hybrid search bằng cách chạy full-text và vector query song song rồi hợp nhất bằng RRF, và tài liệu của họ mô tả k thường dùng quanh 60. Anthropic cũng mô tả pipeline dùng BM25 cộng embeddings cộng rank fusion trước khi đưa top candidate sang bước sau.
Song song với đó, metadata filtering thu hẹp không gian tìm kiếm theo những ràng buộc mà similarity không nên đụng tới: tenant_id, language, region, product, version, khoảng ngày, loại tài liệu, access group. Filter không chỉ tăng relevance — nó liên quan trực tiếp tới security boundary, và ta sẽ quay lại điểm này ở phần cuối.
09Rerank và top-k: hai bài toán khác nhau
Retriever và reranker tối ưu hai thứ khác nhau. Retriever tối ưu recall và tốc độ: nó phải quét hàng triệu chunk và trả về vài chục candidate thật nhanh. Reranker tối ưu precision: nó đọc query và passage cùng nhau thay vì so hai vector độc lập, nên đắt hơn nhiều nhưng chính xác hơn nhiều.
Anthropic báo cáo trong thí nghiệm Contextual Retrieval của họ rằng reranking tiếp tục giảm tỉ lệ retrieval thất bại so với contextual BM25 cộng contextual embeddings mà không rerank, đồng thời nhấn mạnh trade-off về latency và chi phí khi rerank nhiều candidate hơn.
Có một trực giác rất phổ biến và rất nguy hiểm ở chặng này:
retrieve nhiều hơn = LLM có nhiều thông tin hơn = answer tốt hơn
Thực tế, nhiều context hơn cũng đồng nghĩa với nhiều nội dung lạc đề hơn, nhiều mâu thuẫn hơn, nhiều token hơn, và latency cùng chi phí cao hơn. Paper Lost in the Middle cho thấy khả năng sử dụng long context của LLM không đồng đều theo vị trí: hiệu năng có thể giảm khi thông tin liên quan nằm ở giữa một context dài.
Điều đó dẫn tới một cách phát biểu lại mục tiêu của retrieval:
Mục tiêu không phải là đưa thật nhiều thứ vào context, mà là đưa đúng evidence, với đủ ngữ cảnh, theo một cấu trúc mà model dùng được hiệu quả.
Và đó chính là lúc context engineering bắt đầu.
10Context engineering: tầng phải tự viết
Sau reranking ta có một danh sách evidence. Cách làm ngây thơ là nối chúng bằng hai dòng trống rồi dán vào prompt. Một pipeline production thường cần hẳn một context builder riêng.
Lọc và ngưỡng. Không phải candidate nào cũng phải vào prompt. Dưới ngưỡng thì bỏ. Và nếu không còn evidence nào đủ mạnh, hệ thống nên được phép nói rằng chưa tìm thấy đủ thông tin, thay vì ép LLM hoàn thành mọi query.
Khử trùng lặp. Hybrid và multi-query retrieval hay trả về nhiều chunk gần giống nhau, hoặc cùng nội dung xuất hiện ở nhiều nguồn. Đưa hết vào context thì vừa lãng phí token, vừa khiến một fact được “bỏ phiếu” nhiều lần chỉ vì nó bị trùng.
Mở rộng ngữ cảnh. Đôi khi chunk retrieve được rất chính xác nhưng thiếu ngữ cảnh: "Thời hạn là 30 ngày." là một retrieval đúng, nhưng generation layer chưa biết thời hạn của cái gì. Một chiến lược phổ biến là retrieve chunk con rồi mở rộng sang chunk cha hoặc chunk lân cận. Nói cách khác, ta tách retrieval unit khỏi generation context unit. Đây là một insight quan trọng: chunk tối ưu để search chưa chắc là chunk tối ưu để LLM đọc.
Thứ tự. Vì model dùng thông tin không đồng đều theo vị trí trong context dài, thứ tự evidence không phải chi tiết vô nghĩa. Context builder có thể ưu tiên điểm cao, đa dạng nguồn, trình tự thời gian, nhóm logic hay thứ bậc nguồn. Không có quy tắc đúng cho mọi ứng dụng, nhưng thứ tự phải được xem như một tham số có thể đánh giá, không phải hành vi ngẫu nhiên.
Nén. Một chunk 800 token có thể chỉ có hai câu liên quan. Context compression cố biến tài liệu đã retrieve thành đoạn liên quan hoặc bản tóm tắt để giảm nhiễu. Rủi ro là bản nén do model sinh ra có thể mất chi tiết hoặc bóp méo fact, nên vẫn phải giữ ánh xạ về evidence gốc để citation trỏ đúng chỗ.
Ngân sách token. Context window là tài nguyên hữu hạn và phải chia cho nhiều thứ:
available_context_budget
= model_context_window
- system_tokens
- conversation_tokens
- query_tokens
- reserved_output_tokens
- other_tool_tokens
Từ ngân sách đó, context builder mới quyết định giữ evidence nào, mỗi nguồn bao nhiêu token, và bao nhiêu nguồn.
11Grounded generation và citation
Sau khi context được dựng, prompt thường có dạng:
SYSTEM
Bạn là trợ lý hỏi đáp trên tài liệu nội bộ.
Quy tắc:
1. Chỉ dùng thông tin trong EVIDENCE cho mọi factual claim.
2. Không suy đoán nếu evidence không đủ.
3. Khi evidence mâu thuẫn, nêu rõ sự mâu thuẫn.
4. Trích dẫn source_id của evidence đã dùng.
EVIDENCE
[source: policy-2026, section: 4.2]
...
[source: handbook-2026, page: 27]
...
QUESTION
...
Chất lượng RAG vì vậy phụ thuộc đồng thời vào ba thứ:
retrieval quality x context quality x generation behavior
Retriever tìm đúng nhưng prompt cho phép model bỏ qua evidence thì hệ thống vẫn hallucinate như thường.
Cũng cần nói rõ: grounding không có nghĩa là model không được biết gì khác. Tuỳ use case, ta có thể chọn strict grounding chỉ dùng evidence đã retrieve, grounding-first ưu tiên evidence và chỉ dùng kiến thức chung để giải thích, hay open synthesis coi evidence là một nguồn trong nhiều nguồn. Với legal, finance, compliance hay quy trình kỹ thuật, strict grounding thường quan trọng hơn; với một trợ lý học tập thì kiến thức chung có thể được phép nhiều hơn. Đây là product requirement, không phải thuộc tính tự động của RAG.
Citation đáng tin cậy đòi hỏi source identity được giữ từ đầu tới cuối:
Original Document
-> Chunk + document_id + page + section + url
-> Retriever
-> Context Builder
-> LLM / citation mapper
-> Answer + Source
Nếu ingestion chỉ lưu "text": "..." và bỏ hết source metadata thì rất khó dựng lại provenance chính xác ở cuối pipeline. Đây là một trong những quyết định rẻ nhất lúc đầu và đắt nhất khi phải sửa lại sau.
12Từ Naive RAG đến các kiến trúc hiện đại
Không có một kiến trúc duy nhất tên là “modern RAG”. RAG đã phát triển từ một pipeline tuyến tính đơn giản thành nhiều pattern khác nhau, và chúng chồng lấn lên nhau chứ không phải một taxonomy tuyệt đối.
Naive RAG đơn giản, dễ debug, latency và chi phí thấp, rất tốt để dựng baseline. Hạn chế là raw query có thể retrieve kém, keyword và định danh chính xác dễ bị bỏ qua, top-k theo vector similarity chưa chắc là ranking tốt nhất, context dễ nhiễu, và multi-hop query gần như không xử lý được.
Advanced RAG bổ sung các stage trước và sau retrieval: query rewrite, multi-query, decomposition, HyDE, routing ở phía trước; fusion, reranking, filtering, compression, dedup, parent expansion, ordering ở phía sau. Ở đây “advanced” không đồng nghĩa với “luôn tốt hơn”: mỗi component thêm vào là thêm latency, chi phí, moving part, failure mode và bề mặt cần đánh giá.
Hãy bắt đầu bằng standard RAG đủ đơn giản để đo được. Chỉ thêm complexity khi evaluation chỉ ra một failure cụ thể.
Modular RAG xuất hiện khi retrieval không còn là một hàm duy nhất. Câu hỏi “doanh thu tháng này của khách hàng X và điều khoản thanh toán trong hợp đồng là gì” có một nửa nằm trong SQL và một nửa nằm trong index hợp đồng. Lúc đó cần một router điều phối giữa vector search, SQL, web search, knowledge graph và internal API.
Agentic RAG chuyển một phần quyết định từ code cố định sang reasoning lúc chạy.
Microsoft phân biệt standard RAG — orchestrator chạy một chuỗi cố định — với agentic RAG, nơi agent quyết định search nguồn nào, khi nào search, và có cần thêm bước retrieval nữa không. Điểm quan trọng:
Agentic RAG không phải là “RAG nhưng viết bằng agent framework”. Khác biệt nằm ở dynamic decision-making trong retrieval workflow.
Và cũng vì vậy, nếu phần lớn query chỉ cần một câu hỏi, một index, một lần retrieval, thì agent loop chỉ thêm latency, token cost, tính bất định và độ khó khi debug. Tài liệu kiến trúc của Microsoft cũng nhấn mạnh standard RAG phù hợp hơn nếu một lần search giải quyết được query.
GraphRAG phục vụ một loại câu hỏi khác hẳn. Vector RAG rất mạnh với “đoạn nào gần nghĩa nhất với câu hỏi này”, nhưng yếu với “những nhóm chủ đề lớn nhất trong toàn bộ bộ tài liệu là gì” hay “entity A liên hệ với entity B qua những sự kiện và tổ chức nào”. Với những câu đó, không tồn tại một chunk duy nhất chứa toàn bộ câu trả lời. GraphRAG dựng thêm một biểu diễn graph gồm entity, quan hệ, community và community report, rồi cung cấp nhiều chiến lược truy vấn:
Local Search kết hợp graph data và raw text quanh một entity cụ thể
Global Search dùng community report để reasoning trên cả dataset
DRIFT Search kết hợp community context rộng với khám phá local tiếp theo
Chi phí dựng graph đáng kể, nên GraphRAG không nên được coi là mặc định thay thế cho hybrid retrieval thông thường.
13Một hệ tham chiếu hoàn chỉnh
Ghép tất cả lại cho một use case cụ thể: trợ lý hỏi đáp trên bộ tài liệu kỹ thuật nội bộ gồm PDF, Markdown và runbook. Hình dạng tổng thể chính là Hình 1 ở đầu bài — offline dựng index, online phục vụ câu hỏi.
Offline pipeline, dưới dạng pseudo-code:
documents = load_sources()
parsed = [parse(document) for document in documents]
normalized = [normalize(document) for document in parsed]
chunks = chunk(normalized)
enriched = attach_metadata(
chunks,
fields=[
"document_id", "title", "section", "page",
"version", "source_url", "access_groups",
],
)
vectors = embed([c.text for c in enriched])
dense_index.upsert(chunks=enriched, vectors=vectors)
text_index.upsert(chunks=enriched)
Đây chỉ là hình dạng. Pipeline production còn phải xử lý retry, idempotency, xoá, cập nhật, versioning, dedup, batching, rate limit, dead-letter queue và thay đổi permission.
Online pipeline:
def answer(user, query, conversation):
retrieval_query = rewrite_query(query=query, conversation=conversation)
filters = build_filters(user=user, query=retrieval_query)
dense_hits = dense_search(retrieval_query, filters=filters, top_k=30)
lexical_hits = bm25_search(retrieval_query, filters=filters, top_k=30)
candidates = rrf(dense_hits, lexical_hits)
evidence = rerank(query=retrieval_query, candidates=candidates, top_k=8)
context = build_context(evidence, max_tokens=6000)
if not context.is_sufficient:
return abstain()
return generate_grounded_answer(
query=query,
context=context,
include_citations=True,
)
Nhìn vào hàm này, có thể thấy RAG không còn là vector_db.similarity_search(query) mà là một orchestrated information pipeline.
Tech stack map
Không có một stack duy nhất tốt nhất. Một bản đồ tham khảo:
| Layer | Nhiệm vụ | Ví dụ lựa chọn |
|---|---|---|
| Source connectors | Đọc tri thức | custom connector, filesystem, DB/API connector |
| Parsing | Trích cấu trúc và nội dung | Docling, Unstructured, PyMuPDF, parser riêng |
| Chunking | Tạo retrieval unit | splitter của framework, structure-aware chunker |
| Embedding | Text sang dense vector | hosted API, Sentence Transformers, model domain |
| Lexical search | Truy xuất chính xác | Elasticsearch/OpenSearch, engine hỗ trợ BM25 |
| Vector search | Truy xuất ngữ nghĩa | pgvector, Qdrant, Milvus, Weaviate, Pinecone |
| Metadata | Filter, bảo mật, ngữ cảnh | field của search engine, payload của vector store |
| Fusion | Hợp nhất ranked list | RRF, weighted rank fusion |
| Reranking | Candidate sang evidence | cross-encoder, hosted reranker, LLM reranking |
| Orchestration | Ghép pipeline | Python, LangChain, LlamaIndex, Haystack |
| Generation | Sinh câu trả lời | LLM hosted hoặc self-hosted |
| Observability | Trace pipeline | tracing tương thích OpenTelemetry, telemetry riêng |
| Evaluation | Chất lượng và regression | DeepEval, benchmark riêng |
Nhưng quan trọng hơn tên tool là interface giữa các layer:
Parser -> Structured Document
Chunker -> Chunk + Metadata
Retriever -> Candidate + Score + Source
Reranker -> Evidence + Relevance
Context Builder -> Grounded Context
Generator -> Answer + Citation
Nếu các interface này rõ ràng, việc thay một vector database hay một embedding model không đòi hỏi viết lại cả hệ thống.
14Từ demo RAG đến production RAG
Một demo có thể thành công chỉ với upload PDF, hỏi vài câu, thấy câu trả lời khá đúng. Production phải trả lời nhiều câu hỏi khó hơn nhiều.
Đánh giá không chỉ ở câu trả lời cuối
Vì RAG là hệ multi-component, evaluation cũng nên tách theo tầng:
Query processing độ rõ của truy vấn sau biến đổi
Retrieval recall, precision, relevance
Context context relevance, evidence coverage
Generation faithfulness, answer relevancy, task correctness
Microsoft và Databricks đều nhấn mạnh việc đánh giá ở mức component song song với end-to-end, bởi thay đổi ở parsing, chunking hay retrieval đều có thể lan xuống câu trả lời cuối. Toàn bộ kiến trúc evaluation và các metric cụ thể là nội dung của bài về đánh giá RAG với DeepEval trong series này. Ở bài kiến trúc, chỉ cần giữ một ý:
Evaluation không phải bước cuối của RAG. Nó là feedback loop bao quanh toàn pipeline.
Observability: phải trace được các bước trung gian
Khi một người dùng báo “câu trả lời này sai”, ta cần dựng lại được toàn bộ đường đi.
Một trace hữu ích cần trả lời được: query gốc là gì, rewrite thành gì, filter nào được áp, dense trả gì, BM25 trả gì, fusion xếp thế nào, reranker chấm bao nhiêu, context cuối gồm chunk nào, prompt version nào, model nào, latency từng chặng và chi phí token bao nhiêu.
Bảo mật, độ mới, chi phí và độ tin cậy
Security. Một lỗi cực kỳ nghiêm trọng là user không được đọc tài liệu nhưng retriever vẫn lấy chunk về, LLM nhìn thấy chunk đó, và câu trả lời rò rỉ thông tin. Permission không nên chỉ áp dụng ở tầng UI sau retrieval — security boundary phải nằm trước hoặc bên trong retrieval. Microsoft khuyến nghị document-level access control bằng permission metadata được index và enforce ngay tại query time. Với SaaS đa khách hàng, tuỳ nền tảng có thể dùng index riêng, namespace, collection, partition hay metadata filter nghiêm ngặt; Pinecone chẳng hạn mô tả namespace-based isolation như một pattern multitenancy, còn metadata filtering thì có trade-off về hiệu năng và không phải lúc nào cũng là ranh giới cô lập tốt nhất.
Freshness. Knowledge system cần một SLA rõ ràng cho câu hỏi “nguồn cập nhật xong thì bao lâu RAG nhìn thấy”. Một trang FAQ có thể chấp nhận index hằng ngày; một incident runbook thì cần gần realtime.
Latency và cost. Một request có thể tiêu 200 ms cho rewrite, 50 ms cho dense, 30 ms cho BM25, 180 ms cho rerank và 1500 ms cho generation. Thêm một agent loop với planning, ba subquery, vài tool call và một vòng retrieval nữa thì con số tổng có thể nhân lên đáng kể. Chi phí cũng không chỉ nằm ở lần generation cuối: parsing, OCR, enrichment và embedding lúc index đều tốn tiền. Một tối ưu thường gặp là chuyển chi phí từ online sang offline — ví dụ precompute contextual enrichment lúc indexing thay vì sinh nó tại query time.
Caching. Có nhiều tầng cache khác nhau: parsed document, embedding, retrieval, reranker, prompt/context và câu trả lời cuối. Mỗi tầng có bài toán invalidation riêng, và cache câu trả lời cuối là nguy hiểm nhất nếu tài liệu nguồn đã cập nhật. Cache key ở production thường phải phụ thuộc vào query, phạm vi quyền của user, index version, prompt version và model version.
Reliability. Embedding API chết, vector store timeout, reranker timeout, LLM rate limit, agent loop vượt ngân sách, nguồn không truy cập được — hệ thống cần biết trước sẽ retry, fallback, bỏ reranker, chỉ dùng lexical, trả lời một phần hay từ chối. Production RAG không chỉ tối ưu chất lượng ở trường hợp tốt nhất, nó cần một cách hỏng đoán trước được.
RAG là một information system quanh LLM
Nếu chỉ giữ lại một điều sau bài này:
RAG != Vector Database + LLM
RAG = Knowledge Preparation
+ Information Retrieval
+ Context Engineering
+ Grounded Generation
+ Evaluation / Operations
Giá trị thật của mental model này lộ ra khi hệ thống hỏng. Thay vì đổi model rồi hy vọng, ta có một danh sách câu hỏi đi đúng thứ tự của pipeline:
Parser có làm mất thông tin không?
-> Chunk có thiếu ngữ cảnh không?
-> Embedding có retrieve được entity đó không?
-> BM25 có cần thiết ở đây không?
-> Filter có loại nhầm evidence không?
-> Fusion có hợp lý không?
-> Reranker có chọn đúng không?
-> Context có quá nhiễu không?
-> Prompt có ép grounding đủ mạnh không?
-> LLM có thực sự dùng evidence không?
Những gì nên mang theo:
- RAG không sửa weights, nó sửa thông tin có sẵn tại thời điểm inference;
- chất lượng cuối gần với phép nhân của các khâu hơn là phép cộng, nên một khâu hỏng sớm thì không khâu nào sau bù được;
- parsing là khôi phục cấu trúc chứ không chỉ trích text, và cái đã mất ở đó không lấy lại được;
- chunk phải đứng vững khi tách khỏi tài liệu gốc, nếu không thì retrieval cũng không hiểu nó;
- metadata vừa là tín hiệu relevance vừa là security primitive, và là thứ dựng nên citation;
- dense và sparse hỏng theo hai kiểu khác nhau, nên hybrid tồn tại vì lý do kiến trúc chứ không phải vì mốt;
- retriever tối ưu recall, reranker tối ưu precision, và reranker không tạo ra evidence mà retriever đã bỏ sót;
- nhiều context hơn không đồng nghĩa với câu trả lời tốt hơn;
- đơn vị tối ưu để search khác đơn vị tối ưu để LLM đọc;
- “advanced” không đồng nghĩa với “tốt hơn”, mỗi lớp thêm vào là thêm một bề mặt cần đánh giá.
Bài tiếp theo trong series sẽ đi sâu vào phần quan trọng nhất của nửa đầu pipeline: chunking, embedding, vector search, BM25, hybrid retrieval, fusion và reranking thực sự hoạt động như thế nào, và nên tối ưu chúng ra sao. Nếu bạn muốn nhảy thẳng sang nửa sau — làm sao biết hệ thống của mình tốt hay tệ ở đâu — thì bài về đánh giá RAG với DeepEval là chỗ bắt đầu.
Tài liệu tham khảo
- Patrick Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, NeurIPS 2020
- Microsoft Azure Architecture Center — Design and develop a RAG solution
- Microsoft Azure Architecture Center — RAG information retrieval phase
- Microsoft Azure Architecture Center — Develop an agentic RAG solution
- Anthropic — Introducing Contextual Retrieval
- Docling — Chunking
- Qdrant — A complete guide to filtering in vector search
- Luyu Gao et al. — Precise Zero-Shot Dense Retrieval without Relevance Labels (HyDE)
- Microsoft Learn — Hybrid search in Azure AI Search
- Microsoft Learn — Relevance scoring using Reciprocal Rank Fusion
- Nelson F. Liu et al. — Lost in the Middle: How Language Models Use Long Contexts
- Microsoft — GraphRAG query engine overview
- Azure Databricks — Evaluation and monitoring for RAG applications
- Microsoft Learn — Security best practices for Azure AI Search
- Pinecone — Implement multitenancy