Khoan dựng RAG: đếm token trước, đo Recall@k sau
Khi khách hàng gửi một thư mục PDF và đòi một chatbot, việc đầu tiên nên làm là đếm token, chưa phải chọn vector database.
- 1Đếm token kho tài liệuSo với cửa sổ ngữ cảnh và giá cache của model khách đang dùng
- 2Vừa ngữ cảnh: đưa hết vàoBật prompt caching, đo chất lượng câu trả lời trên bộ câu hỏi có đáp án
- 3Không vừa: dựng bộ đánh giáLLM sinh 5 câu hỏi cho mỗi chunk, lưu kèm chunk_id gốc
- 4Đo Recall@k với BM25Chạy k = 5, 10, 20 để có mốc baseline
- 5Sửa retrieval trướcGrid search chunking, chưa đủ thì thử hybrid search và reranking
- 6Cuối cùng mới chỉnh generationChỉ đụng tới prompt và model khi recall đã ổn
Đếm token để quyết định có dựng RAG không, rồi sửa retrieval trước khi đụng vào phần sinh câu trả lời.
Đồ hoạ: FDE Times
Tóm tắt nhanh
- Năm 2024, Anthropic đưa ra ngưỡng thực dụng: kho tri thức dưới 200.000 token (khoảng 500 trang) thì đưa thẳng vào prompt, khỏi cần RAG. Với cửa sổ 1M token hiện nay, ngưỡng này đã rộng hơn nhiều.
- Ngữ cảnh dài vẫn có giá về chất lượng, vì vị trí của thông tin trong prompt ảnh hưởng tới độ chính xác. Dù chọn cách nào cũng phải đo.
- Khi đã dựng RAG, đo Recall@k trên bộ câu hỏi–chunk trước, sửa retrieval trước rồi mới đụng tới prompt và model.
Khách hàng gửi cho bạn một thư mục gồm quy trình vận hành, chính sách bảo hành và vài bộ FAQ, rồi nhờ làm chatbot trả lời nhân viên. Phản xạ của nhiều engineer là mở ngay tài liệu về vector database, chọn embedding model và bàn chuyện chunk size.
Hai tuần sau, demo trả lời sai một câu rất cơ bản, và cả đội không biết lỗi nằm ở đâu.
Chuyện này hay gặp vì người ta bỏ qua hai câu hỏi rẻ nhất. Kho tài liệu có thực sự cần RAG không? Nếu cần, bước tìm kiếm đã tìm đúng đoạn cần tìm chưa? Với một FDE, trả lời được hai câu đó ngay ngày đầu có thể tiết kiệm nhiều tuần làm việc.
Trước khi chọn kiến trúc, hãy đếm token
Năm 2024, khi giới thiệu Contextual Retrieval, Anthropic đưa ra một ngưỡng rất thực dụng. Nếu kho tri thức nhỏ hơn 200.000 token, tức khoảng 500 trang, cứ đưa toàn bộ vào prompt, không cần RAG hay phương pháp tương tự. Đó là con số của năm 2024, và hôm nay ngưỡng này đã rộng hơn nhiều.
Cách này khả thi nhờ prompt caching. Anthropic cho biết caching giảm độ trễ hơn 2 lần và giảm chi phí tới 90%. Tài liệu hiện tại của Claude ghi rằng token đọc từ cache có giá bằng 0,1 lần giá input gốc, trừ vài ngoại lệ theo model.
Nếu hàng trăm nhân viên hỏi đi hỏi lại trên cùng một bộ tài liệu, phần đắt nhất chỉ phải trả một lần.
Theo tài liệu chính thức, các model Claude đời mới có cửa sổ ngữ cảnh 1M token, tương đương khoảng 555 nghìn từ. Vì thế, đừng học thuộc con số. Hãy học cách kiểm tra lại theo model và bảng giá mà khách hàng đang dùng.
Đưa hết vào prompt vẫn phải đo
Ngữ cảnh dài vẫn có cái giá về chất lượng, chỉ là cái giá đó không hiện trên hóa đơn. Nghiên cứu “Lost in the Middle” (2023) cho thấy hiệu năng có thể giảm đáng kể khi đổi vị trí của thông tin liên quan trong prompt. Một điều khoản bảo hành nằm ở giữa 400 trang có thể bị bỏ qua, dù model vẫn “nhìn thấy” nó.
Vì vậy, quy tắc thật sự là luôn đo, không phải “dưới 500 trang thì yên tâm”. Với phương án đưa toàn bộ tài liệu vào prompt, bạn đo chất lượng câu trả lời trên một bộ câu hỏi có đáp án. Với RAG, bạn có thêm một tầng phải đo riêng là retrieval.
Khi đã dựng RAG, lỗi thường nằm ở bước tìm kiếm
Bộ evals-skills của Hamel Husain có một hướng dẫn evaluate-rag rất rõ: trước tiên xác định vấn đề nằm ở retrieval, generation hay cả hai, rồi sửa retrieval trước. Lý do khá đơn giản. Nếu đoạn văn chứa đáp án không được đưa vào prompt, chỉnh prompt bao nhiêu cũng vô ích.
Jason Liu nói còn thẳng hơn: luôn đo retrieval bằng precision và recall, đặc biệt là recall, vì bỏ sót đoạn then chốt là chí mạng. Hướng dẫn của Husain cũng chọn Recall@k làm số đo quan trọng nhất cho retrieval vòng đầu. Recall@k trả lời một câu hỏi: trong k kết quả trả về, đoạn đúng có mặt hay không?
Cách Anthropic báo cáo kết quả cũng theo đúng tinh thần đó. Họ không khoe câu trả lời hay hơn mà đo tỷ lệ thất bại retrieval ở top-20 chunk. Kết hợp contextual embeddings với contextual BM25 làm tỷ lệ này giảm 49%, thêm reranking thì giảm 67%. Đây là số đo của riêng bước retrieval, không phải chất lượng câu trả lời cuối.
Ví dụ: đo Recall@k cho bộ tài liệu bảo hành
Thử hình dung kho tài liệu của khách quá lớn so với cửa sổ ngữ cảnh, nên bạn đã cắt thành chunk. Lúc này bạn chưa có log câu hỏi thật. Jason Liu gợi ý cách khởi động: nhờ LLM sinh 5 câu hỏi mà mỗi chunk có thể trả lời, rồi kiểm tra xem hệ thống có truy xuất lại đúng chunk đó không.
Prompt sinh dữ liệu có thể rất ngắn: “Đây là một đoạn trong tài liệu bảo hành. Hãy viết 5 câu hỏi mà một nhân viên chăm sóc khách hàng có thể đặt ra và chỉ đoạn này trả lời được.” Mỗi câu hỏi được lưu kèm chunk_id gốc. Sau đó, phần đánh giá chỉ cần vài dòng:
def recall_at_k(eval_set, search, k):
hits = 0
for item in eval_set:
results = search(item["question"], k=k)
if item["chunk_id"] in [r.id for r in results]:
hits += 1
return hits / len(eval_set)
for k in (5, 10, 20):
print(k, recall_at_k(eval_set, bm25_search, k))
Chạy với k bằng 5, 10 và 20 vì k là tham số phải đo, không phải đoán. Anthropic thấy đưa top-20 chunk vào model hiệu quả hơn top-10 hoặc top-5, nhưng phát hiện đó nói về số chunk nên đưa vào model để sinh câu trả lời, còn Recall@k chỉ đo xem chunk đúng có nằm trong k kết quả hay không.
Hai con số trả lời hai câu hỏi khác nhau, và với dữ liệu của khách, chỉ bộ đánh giá mới cho bạn biết k nào hợp lý.
Chú ý dòng bm25_search: hãy bắt đầu bằng full-text search. Năm 2024, khi thử trên các bài essay, Jason Liu thấy full-text search và embedding cho chất lượng gần như ngang nhau, nhưng full-text search nhanh hơn khoảng 10 lần. Một baseline đơn giản sẽ cho bạn mốc để so sánh mọi cải tiến về sau.
Quy trình bạn có thể làm lại cho mỗi khách hàng
Bắt đầu bằng việc đếm token của toàn bộ kho tài liệu và so với cửa sổ ngữ cảnh cùng giá cache của model. Nếu vừa, đưa toàn bộ vào prompt, bật caching và đo chất lượng câu trả lời. Nếu không vừa, dựng bộ câu hỏi–chunk, chạy baseline BM25 và ghi lại Recall@k.
Khi retrieval là điểm nghẽn, hướng dẫn của Husain khuyên tối ưu chunking bằng grid search trước khi chỉnh phần sinh câu trả lời. Bạn thử nhiều kích thước chunk và độ chồng lấn, đo lại Recall@k cho từng cấu hình.
Nếu recall vẫn chưa đủ, bước hợp lý tiếp theo là thử hybrid search và reranking, vì đó chính là hai thay đổi giúp Anthropic giảm tỷ lệ thất bại retrieval 49% rồi 67%. Chỉ khi recall đã ổn mới chuyển sang prompt và model.
Những lỗi khiến dự án RAG trượt dài
Lỗi phổ biến nhất là chỉ nhìn câu trả lời cuối. Khi demo sai, cả đội sửa prompt, đổi model, thêm chỉ dẫn, trong khi đoạn chứa đáp án chưa bao giờ được đưa vào ngữ cảnh. Lỗi thứ hai là chọn k theo cảm tính, thường là 5 vì “nghe gọn”.
Lỗi thứ ba là dựng RAG cho một bộ tài liệu chưa tới vài trăm trang, rồi phải gánh thêm pipeline chunking, index và đồng bộ dữ liệu, trong khi một prompt có cache đã đủ dùng. Lỗi ngược lại cũng nguy hiểm không kém: tin rằng cửa sổ 1M token nghĩa là không cần đo, và quên rằng vị trí thông tin vẫn ảnh hưởng đến độ chính xác.
Khi đọc JD FDE hay AI engineer, hãy để ý các cụm như “evaluation”, “retrieval quality” hay “RAG in production”. Trong CV, câu “dựng chatbot RAG” chưa nói được nhiều. Câu “dựng bộ đánh giá câu hỏi–chunk, nâng Recall@20 từ X lên Y nhờ đổi chunking” thì cho thấy bạn biết đo.
Khách hàng không quan tâm bạn dùng vector database nào. Họ cần biết khi nhân viên hỏi về điều khoản bảo hành, hệ thống có tìm ra đúng trang hay không, và một FDE giỏi trả lời câu đó bằng một con số đo được.
7 nguồn
- Introducing Contextual Retrieval (Anthropic) · 2024-09-19
- Models overview (Claude Docs)
- Prompt caching (Claude Docs)
- Lost in the Middle: How Language Models Use Long Contexts · 2023-07-06
- evaluate-rag — hamelsmu/evals-skills
- Systematically Improving RAG Applications (Jason Liu) · 2025-01-24
- Systematically Improving Your RAG (Jason Liu) · 2024-05-22