Bốn bài trước đi gần hết vòng đời của một hệ RAG trước khi nó ra ngoài production:
Kiến trúc
-> Retrieval
-> Metric
-> Benchmark
-> Regression test
-> Quality gate
-> Deploy
Nếu regression suite pass, retrieval benchmark tốt hơn và các metric như Faithfulness, Answer Relevancy hay Contextual Recall đều đạt threshold, ta có cơ sở để tự tin hơn khi deploy.
Nhưng còn một câu hỏi chưa được trả lời: sau khi deploy thì sao?
Bộ benchmark ở bài trước chỉ đại diện cho những failure mode mà team đã biết và đã đưa vào dataset. Production thì chứa cả một thế giới mà dataset chưa nhìn thấy: user mới, cách diễn đạt mới, typo, tiếng lóng, hội thoại nhiều lượt, thực thể hiếm, tài liệu mới, chính sách vừa đổi, ngôn ngữ mới, traffic tăng đột biến, provider đổi backend, index vừa rebuild.
Vì vậy hai câu này hoàn toàn có thể cùng đúng:
PASS offline benchmark
FAIL production
Offline evaluation trả lời: hệ thống có vượt qua những bài test chúng ta đã biết không?
Production evaluation trả lời một câu khác: trong traffic thật, hệ thống đang thất bại ở đâu, kể cả những failure mode chúng ta chưa biết là nó tồn tại?
Nếu bài benchmark hỏi “version mới có tốt hơn version cũ không”, thì bài này hỏi “làm sao giữ một hệ RAG tốt sau khi nó đã tiếp xúc với thế giới thật, và làm sao để chính thế giới thật đó dạy ngược lại cho bộ test của mình”.
01Pass benchmark chưa có nghĩa là production sẽ tốt
Giả sử có 1.000 golden test case và phiên bản v14 đạt:
Contextual Recall 0.91
Contextual Precision 0.88
Faithfulness 0.95
Answer Relevancy 0.93
Không có regression đáng kể so với v13. CI xanh. Team deploy.
Một tuần sau user bắt đầu gửi những câu như:
"bản cho sg thì sao?"
"ERR-PAY-942 vừa đổi chưa?"
"Policy đó có áp dụng cho intern remote ở Việt Nam không?"
"Không phải policy cũ, tôi hỏi cái vừa update hôm qua."
Những câu này có thể không giống chút nào với phân bố của golden set ban đầu. Điều đó xảy ra không phải vì ai làm sai, mà vì evaluation dataset về bản chất chỉ là một mẫu của hành vi mong muốn tại thời điểm viết ra nó. Microsoft mô tả evaluation set cho RAG đúng theo nghĩa đó và nhấn mạnh rằng tập này cần được cập nhật khi usage và requirement thay đổi.
Cách hình dung ngắn gọn: offline benchmark giảm known uncertainty — ta biết mình quan tâm tới query rewriting, hybrid retrieval, reranker, chunk size, prompt, model, nên chủ động test chúng. Production làm lộ unknown uncertainty — hành vi người dùng mới, cấu trúc nguồn mới, từ vựng mới, cụm query bất ngờ, cấu hình lệch, thay đổi phía nhà cung cấp, dữ liệu cũ, lỗi phân quyền.
Hai thứ đó bổ sung cho nhau chứ không thay nhau.
02Monitoring RAG không chỉ là CPU, RAM và latency
Khi nghe từ monitoring, backend engineer thường nghĩ tới CPU, memory, request rate, HTTP 5xx, p95 latency. Những metric đó vẫn cực kỳ quan trọng. Nhưng với một RAG application, service có thể trả HTTP 200, latency bình thường, CPU bình thường — và vẫn trả về một câu trả lời sai hoàn toàn.
Từ góc nhìn hạ tầng đó là SUCCESS. Từ góc nhìn người dùng đó là FAILURE.
Microsoft mô tả RAG monitoring quanh ba yêu cầu lớn là quality, cost và latency, và nhấn mạnh rằng vì RAG có nhiều component ảnh hưởng lẫn nhau nên cần quan sát cả từng component lẫn end-to-end.
Lớp vận hành
request count p50 / p95 / p99 latency
error rate embedding latency
timeout rate retrieval latency
availability reranker latency
retry rate LLM latency
queue depth time-to-first-token
input tokens output tokens
context tokens cost per request
OpenTelemetry hiện đã có GenAI semantic conventions cho nhiều loại telemetry như model, token usage và operation duration, đồng thời định nghĩa cả các field cho retrieval query và retrieved document.
Lớp pipeline
Metric vận hành có thể nói “request mất 3,4 giây” nhưng không nói 3,4 giây đó nằm ở đâu:
Query rewrite 220 ms
Embedding 30 ms
Dense retrieval 45 ms
BM25 18 ms
Fusion 2 ms
Reranker 210 ms
Context builder 8 ms
Generation 1820 ms
Không trace từng stage thì mọi hồi quy latency đều biến thành một câu duy nhất: “RAG chậm”. Chất lượng cũng vậy — retrieval sai, reranking sai, context sai hay generation sai đều bị gộp thành “câu trả lời tệ”.
Lớp chất lượng
Không phải tín hiệu nào cũng phải là LLM-as-a-Judge. Lớp này gộp nhiều loại: metric tất định như tỷ lệ retrieval rỗng hay thiếu citation, LLM judge như Faithfulness và Answer Relevancy, phản hồi người dùng, sự kiện sản phẩm, và kết quả nghiệp vụ.
03Trace là đơn vị quan sát quan trọng nhất của RAG
Muốn biết một answer được tạo ra như thế nào, ta phải giữ lại execution path của nó. DeepEval định nghĩa trace là toàn bộ execution của một LLM application, còn span là một scope nhỏ hơn bên trong trace — có thể là retriever, tool, một LLM call hoặc một component riêng.
TRACE rag_request_82f1
├── query_rewrite
├── retrieval
│ ├── dense_search
│ └── bm25_search
├── rank_fusion
├── reranker
├── context_builder
└── generation
Vì sao điều này quan trọng đến thế? Giả sử user báo: “Câu trả lời này đang dùng policy cũ.”
Nếu log chỉ có:
{ "query": "...", "answer": "..." }
thì gần như không biết bắt đầu từ đâu. Nhưng nếu trace giữ đủ chuỗi từ câu hỏi gốc, câu hỏi đã viết lại, filter được áp, danh sách chunk lấy về kèm điểm, thứ hạng sau fusion, thứ hạng sau rerank, context cuối cùng và prompt đã chạy, thì có thể lần ngược:
Query: "What is the current password rotation policy?"
retrieval
├── policy-2024 score=0.88
└── policy-2026 score=0.85
reranker
1. policy-2024
2. policy-2026
answer: "180 days"
Root cause ở đây nhiều khả năng nằm ở version filtering, freshness của nguồn hoặc reranking — chứ không nhất thiết nằm ở LLM. Microsoft cũng nhấn mạnh production trace logging nên ghi cả input, output và các bước trung gian như retrieved document, chính là để phân biệt lỗi retrieval với hallucination ở generation.
04Thiết kế trace schema: log gì và version gì
Tracing nên bắt đầu bằng một câu hỏi rất cụ thể:
Sáu tháng sau, khi có một incident, những dữ liệu nào tôi cần để dựng lại request này?
Định danh
request_id session_id
trace_id conversation_id
timestamp turn_id
environment
Phiên bản ứng dụng
rag_version embedding_model
prompt_version embedding_version
model_name reranker_model
model_version index_version
chunking_version retrieval_config_version
Đây là nhóm hay bị bỏ quên nhất, và cũng là nhóm có giá trị chẩn đoán cao nhất. Nếu dashboard cho thấy Faithfulness rơi từ 0.93 xuống 0.77 và mốc rơi trùng đúng lúc prompt_version = 27 bắt đầu nhận traffic, thì việc điều tra ngắn đi rất nhiều.
Ở bài trước ta đã version hoá cấu hình cho một experiment offline. Ở production, cùng ý tưởng đó nhưng gắn vào từng request, vì tại một thời điểm có thể có nhiều cấu hình cùng chạy:
{
"rag_config": "rag-v24",
"prompt": "qa-prompt-v17",
"embedding": "embed-v5",
"retriever": "hybrid-v3",
"reranker": "reranker-v2",
"index": "kb-2026-09-08"
}
Khi nghi ngờ có hồi quy, ta so sánh giữa các cohort cấu hình thay vì đoán.
Trạng thái retrieval
original_query candidate IDs
rewritten_query candidate scores
filters reranker input
dense_k reranker scores
sparse_k selected evidence
fusion_method
Không nhất thiết phải log toàn văn tài liệu nếu privacy, storage hoặc governance không cho phép. Có thể chỉ log document_id, chunk_id, version, điểm và thứ hạng, rồi lấy nội dung từ nguồn khi điều tra và người điều tra có quyền. OpenTelemetry cũng cảnh báo rằng nội dung query và tài liệu có thể chứa dữ liệu nhạy cảm.
Đánh đổi nằm ở chỗ: nếu muốn chạy Faithfulness judge bất đồng bộ thì evaluator vẫn cần context để chấm. Một kiến trúc hợp lý là để trace giữ metadata, còn một worker đánh giá có quyền tự lấy nội dung theo id — thay vì nhân bản nội dung nhạy cảm vô hạn trong telemetry backend.
Trạng thái generation
model input_tokens
temperature output_tokens
prompt_version finish_reason
latency answer
05Component-level và end-to-end nằm trong cùng một trace
DeepEval có một mapping rất hợp với RAG: trace ứng với end-to-end evaluation, span ứng với component-level evaluation. Trace-level test case đại diện cho một run hoàn chỉnh, còn mỗi span có thể mang test case riêng để chấm một retriever hoặc một LLM call.
Giá trị thực tế nằm ở chỗ đọc kết quả theo cặp. Nếu:
End-to-end = FAIL
Retriever = FAIL
Faithfulness = PASS
thì cách đọc hợp lý là: model bám vào context, nhưng context sai. Việc cần làm nằm ở retrieval.
Ngược lại nếu:
Retriever = PASS
Faithfulness = FAIL
thì evidence đã đúng nhưng generation không sử dụng nó đúng. Việc cần làm nằm ở prompt và hành vi sinh nội dung.
Chỉ nhìn một con số tổng thì hai trường hợp này trông giống hệt nhau, và đó chính là lý do component-level evaluation tồn tại.
06Online evaluation phải nằm ngoài critical path
Trong lúc phát triển, chạy evaluator ngay sau khi component kết thúc rồi in điểm ra là hoàn toàn hợp lý. Nhưng user ở production thì không nên phải chờ LLM judge.
Giả sử:
RAG generation 1.8 s
Faithfulness judge 1.2 s
Answer Relevancy 1.1 s
Nếu chạy tuần tự thì latency người dùng cảm nhận được leo lên khoảng 4.1 s. Và ngoài latency, judge còn trở thành một dependency mới của request path: judge rate limit hoặc judge lỗi sẽ kéo theo cả sản phẩm.
MLflow production tracing khuyến nghị đúng kiến trúc này: ghi trace bất đồng bộ và chạy automatic online evaluation trên các trace đang đến. DeepEval cũng phân biệt hai chế độ khá rõ — metrics trên @observe là blocking, dùng cho development và testing; production thì dùng metric_collection với evaluation bất đồng bộ.
Mental model khi triển khai với DeepEval
from deepeval.tracing import (
observe,
update_current_span,
update_current_trace,
)
@observe(type="retriever")
def retrieve(query: str):
documents = search(query)
update_current_span(
input=query,
retrieval_context=[doc.text for doc in documents],
)
return documents
@observe(
type="llm",
metric_collection="rag-generation-production",
)
def generate(query: str, documents):
context = build_context(documents)
return llm.generate(query=query, context=context)
@observe(metric_collection="rag-end-to-end-production")
def answer(query: str):
docs = retrieve(query)
output = generate(query, docs)
update_current_trace(input=query, output=output)
return output
API cụ thể có thể thay đổi theo phiên bản DeepEval nên implementation thật vẫn nên đối chiếu tài liệu của phiên bản đang dùng. Thứ đáng giữ lại là kiến trúc: retriever span cho telemetry thành phần, LLM span cho telemetry generation, root trace cho telemetry end-to-end, và production metric collection được xử lý ngoài critical path.
Cũng cần phân biệt hai thứ hay bị gộp làm một: deepeval là thư viện evaluation mã nguồn mở, còn luồng online eval qua metric collection trong tài liệu hiện tại gắn với Confident AI như backend quan sát. Nếu không dùng backend đó, raw tracing vẫn có thể đưa sang một observability stack khác, nhưng phần chấm điểm sẽ phải tự dựng.
07Online eval không có nghĩa là chấm 100% request
Giả sử hệ thống nhận 10 request mỗi giây, tức khoảng 864.000 request mỗi ngày. Nếu mỗi request chạy ba judge thì con số trở thành khoảng 2,6 triệu lần gọi judge mỗi ngày. Rất ít sản phẩm chịu được chi phí đó chỉ để quan sát.
Vì vậy production evaluation gần như luôn cần sampling. Cả MLflow lẫn DeepEval đều cho phép điều chỉnh tỷ lệ lấy mẫu ở tầng trace và tầng judge.
Nhưng sampling không nên chỉ là random 10%.
Ngẫu nhiên — ví dụ 5% toàn bộ request. Mục tiêu là ước lượng phân bố chất lượng chung. Đây là dòng duy nhất cho ước lượng không thiên lệch.
Theo tín hiệu xấu — chấm 100% những request có dấu hiệu bất thường:
thumbs_down timeout
empty_retrieval fallback
low_rerank_score no_citation
user_rephrased_immediately
Theo mức rủi ro — không phải query nào cũng có cùng giá của một lần sai. Một câu FAQ đơn giản khác hẳn một câu về quy trình bảo mật:
support FAQ 5%
policy 30%
security procedure 100%
Theo độ mới — nếu phân tích embedding hoặc classifier phát hiện chủ đề mới, thực thể mới, ngôn ngữ mới hay intent mới thì tăng tỷ lệ chấm. Đây chính là cách dùng production để đi tìm những query nằm ngoài vùng golden dataset đã phủ.
Tỷ lệ nên khác nhau theo từng loại tín hiệu
Một sample_rate = 10% áp cho mọi thứ vừa tốn vừa thiếu. Faithfulness là LLM judge nên đắt; kiểm tra retrieval rỗng là phép so sánh tất định nên gần như miễn phí; latency thì vốn đã có sẵn trong telemetry.
Latency 100% (telemetry)
Empty retrieval 100% (tất định, rẻ)
Faithfulness 10% ngẫu nhiên + dòng có mục tiêu
Human review 0.1% + toàn bộ incident
Sampling là bài toán ngân sách
Giả sử traffic một triệu request mỗi ngày, chi phí chấm một trace là 0.003 đô, ngân sách quan sát là 300 đô mỗi ngày. Tỷ lệ trung bình tối đa vì vậy là 300 / (1.000.000 x 0.003) = 0.10, tức 10%.
Nhưng thay vì rải đều 10% đó, có thể phân bổ:
5% ngẫu nhiên làm nền
100% nhóm rủi ro cao
100% request có phản hồi tiêu cực
phần còn lại cho query lạ
Cũng nên theo dõi chi phí quan sát như một khoản riêng, tách khỏi chi phí phục vụ:
application_cost_per_request
evaluation_cost_per_evaluated_request
evaluation_cost_per_total_request
Nếu RAG serving tốn $0.004 mỗi request và online eval trung bình $0.001 mỗi request, thì quan sát đang chiếm thêm khoảng 25% chi phí phục vụ. Đó là một con số nên được nói ra chứ không nên để nó tự lớn lên.
08Bẫy lớn nhất của sampling: sample có bias làm dashboard sai nghĩa
Giả sử ta chấm 5% ngẫu nhiên cộng với 100% số request bị thumbs-down, rồi gộp tất cả vào một con số:
Faithfulness = 0.71
Con số này không còn là ước lượng không thiên lệch cho toàn bộ production traffic, vì mẫu đã chủ động chứa nhiều lỗi hơn thực tế. Nghịch lý là chiến lược sampling càng tốt cho chẩn đoán thì con số trung bình càng dễ bị đọc sai.
Cách xử lý là dashboard phải biết sampling_policy của từng dòng và tách bạch chúng:
Ước lượng chất lượng chung
└── chỉ từ dòng ngẫu nhiên
Phân tích lỗi
└── từ dòng có mục tiêu
Chất lượng nhóm rủi ro cao
└── từ tầng rủi ro cao
Một mẫu dùng để ước lượng và một mẫu dùng để chẩn đoán là hai thứ khác nhau, và chúng không nên bao giờ được cộng chung vào một ô trung bình.
09Từ metric tới SLI, SLO và alert
Một con số như Faithfulness = 0.82 không tự trả lời được câu hỏi “production có đang unhealthy không”. Cần chuyển raw evaluation result thành tín hiệu ở mức dịch vụ.
Google SRE định nghĩa SLI là một phép đo định lượng cho một khía cạnh của dịch vụ, còn SLO là mục tiêu đặt cho phép đo đó.
Một SLI chất lượng cụ thể
Quy mỗi request đã chấm về PASS hoặc FAIL, rồi định nghĩa:
Faithfulness Pass Rate
= số request pass Faithfulness / số request đã được chấm
Ví dụ chấm 10.000 request, 9.750 pass, tức tỷ lệ pass 97,5%. Một SLO minh hoạ có thể là >= 97% trong cửa sổ trượt 7 ngày.
Đây không phải ngưỡng phổ quát. Nó phải được calibrate theo mức rủi ro của sản phẩm, mức độ hiệu chuẩn của judge, chính sách lấy mẫu, tỷ lệ dương tính giả và mức nghiêm trọng của từng loại lỗi. Quy trình calibrate bằng nhãn người thật đã được nói ở bài trước, và nó vẫn đúng ở đây.
Tương tự với retrieval và latency:
Eligible Retrieval Rate
= số request có >= N chunk đủ liên quan / số request retrieval đã chấm
Latency SLO
99% request dưới 4 giây, hoặc p95 dưới 3 giây
Đừng gọi người vì từng lần judge fail
Judge có nhiễu. Traffic có phương sai. Một request tệ không nhất thiết là một sự cố. Alert nên gộp theo cửa sổ thời gian, theo tỷ lệ, theo mức nghiêm trọng, theo segment và luôn kèm kích thước mẫu. Google SRE nhấn mạnh chiến lược cảnh báo phải cân bằng độ chính xác, độ phủ, thời gian phát hiện và thời gian reset; cảnh báo quá nhạy sẽ tạo ra rất nhiều sự kiện không đáng hành động.
Ngưỡng tuyệt đối và mức tụt so với nền phải cùng tồn tại
Giả sử ngưỡng tối thiểu là 0.75 và chất lượng bình thường dao động quanh 0.90 - 0.92. Sau một lần deploy, con số về 0.79.
Nhìn theo ngưỡng thì đây là PASS. Nhưng chất lượng vừa tụt khoảng 12 điểm. Vì vậy nên có hai loại cảnh báo song song:
Alert A: pass rate thấp hơn SLO
Alert B: pass rate tụt quá X so với baseline ổn định
Một metric vẫn nằm trên ngưỡng hoàn toàn có thể đang hồi quy nghiêm trọng.
10Slicing: số trung bình có thể che mất production failure
Giả sử Answer Relevancy tổng thể là 0.91. Cắt theo ngôn ngữ:
English 0.94
Vietnamese 0.72
Japanese 0.90
Cắt theo tenant:
Tenant A 0.93
Tenant B 0.94
Tenant C 0.61
Cắt theo loại query:
FAQ 0.96
Policy 0.91
Multi-hop 0.71
Conversational 0.66
Aggregate metric có thể trông rất khỏe chỉ vì phần lớn traffic là câu hỏi dễ. Vì vậy trace metadata phải hỗ trợ cắt lát theo language, tenant, product, query_type, source, risk_level, rag_version, model, prompt_version, index_version.
Một sự cố thật có thể chỉ tồn tại trong một giao điểm hẹp:
Vietnamese + multi-turn + policy + prompt-v18
Số trung bình toàn hệ thống gần như không dịch chuyển. Không có metadata đủ giàu thì sự cố đó vô hình.
Dashboard cho biết có vấn đề hay không. Slice cho biết vấn đề nằm ở đâu. Trace cho biết tại sao.
Dashboard nên trả lời bốn câu hỏi
Một dashboard tốt không phải nơi nhét càng nhiều biểu đồ càng tốt. Nó nên giúp trả lời nhanh: người dùng có đang gặp vấn đề không, vấn đề nằm ở lớp nào, bắt đầu từ khi nào, và version hay segment nào liên quan. Một cấu trúc bốn tầng phục vụ đúng bốn câu đó:
PRODUCT số request | phản hồi | tỷ lệ giải quyết
QUALITY faithfulness | relevance | retrieval
PERFORMANCE p95 latency | lỗi | token | chi phí
CHANGE query mix | model | prompt | index | source
Ở tầng chất lượng, đừng chỉ hiện Faithfulness 0.88. Nên hiện đủ bối cảnh:
Faithfulness Pass Rate
Current 88%
7d baseline 94%
Delta -6%
N 2,141
Kích thước mẫu cực kỳ quan trọng: 60% trên 5 mẫu khác hoàn toàn 60% trên 50.000 mẫu.
Ở tầng thay đổi, nên vẽ mốc deploy, đổi prompt, rebuild index, đổi embedding hay đổi provider ngay trên chuỗi thời gian chất lượng. Tương quan không chứng minh nhân quả, nhưng nó cho engineer một điểm bắt đầu để điều tra.
11Drift trong RAG không chỉ là model drift
RAG là một hệ thống có nhiều bộ phận chuyển động, nên nó có nhiều kiểu lệch hơn một mô hình đơn lẻ.
Query drift. Tháng đầu user hỏi "What is our leave policy?". Sáu tháng sau họ hỏi "Can a Vietnam-based contractor carry unused annual leave into the next calendar year?". Độ dài tăng, độ cụ thể tăng, multi-hop tăng, thực thể mới và thuật ngữ mới xuất hiện. Golden dataset cũ có thể không còn đại diện. Tín hiệu cần theo dõi: phân bố độ dài, phân bố ngôn ngữ, phân bố intent, phân bố cụm embedding, tỷ lệ thực thể mới, độ sâu hội thoại, tỷ lệ rewrite. Không cần bắt đầu bằng một statistical drift detector phức tạp — một biểu đồ query mix theo thời gian đôi khi đã đủ để thấy shift lớn.
Knowledge drift. Đây là loại riêng của RAG: nguồn sự thật đổi từ Policy 2025 sang Policy 2026 nhưng index vẫn còn bản cũ, hoặc tệ hơn là chứa cả hai và bản cũ lại xếp hạng cao hơn. Chỉ số nên có:
Freshness Lag = indexed_at - source_updated_at
kèm một SLO nếu độ tươi là yêu cầu nghiệp vụ, ví dụ 95% cập nhật nguồn hiện diện trong retrieval trong vòng 15 phút.
Retrieval drift. Không đổi dòng code nào, nhưng index tăng từ 100 nghìn chunk lên 20 triệu chunk. Cạnh tranh giữa các candidate thay đổi, và một tài liệu từng đứng hạng 2 có thể rơi xuống hạng 18. Theo dõi phân bố điểm retrieval, phân bố điểm rerank, tỷ lệ retrieval rỗng, độ đa dạng nguồn và độ trùng top-k giữa các mốc thời gian.
Model và provider drift. Không nên giả định rằng tên model không đổi thì hành vi chắc chắn không đổi. Trace nên giữ requested_model, response_model, deployment và provider để phân biệt.
Configuration drift. Một phiên bản RAG không chỉ là một Git commit — nó là tổ hợp prompt, embedding, retrieval_k, fusion, reranker, quy tắc ghép context, LLM và index. Đây chính là lý do phần 04 nhấn mạnh việc gắn rag_config vào mọi trace.
12Evaluation và guardrail không phải cùng một thứ
Hai cơ chế này hay bị gộp làm một vì chúng dùng chung công cụ, nhưng mục tiêu của chúng khác nhau và vị trí trong kiến trúc cũng khác nhau.
Evaluation đo một câu trả lời đã sinh ra, lưu lại metric và dùng nó để học, theo dõi, so sánh và gỡ lỗi. Guardrail kiểm tra một câu trả lời ứng viên và quyết định có cho nó đi ra ngoài hay không.
Một Faithfulness judge chạy bất đồng bộ là công cụ tốt để theo dõi. Nhưng nếu yêu cầu là không được lộ tài liệu mật, thì access control phải được thực thi ngay trong retrieval, trước khi context đi vào LLM — lọc ở tầng hiển thị là quá muộn, vì mô hình đã đọc nội dung đó rồi. Tương tự với rò rỉ PII, hành động nguy hiểm hoặc vi phạm chính sách: tùy mức rủi ro mà chúng cần kiểm soát đồng bộ.
Guardrail chống hallucination trông như thế nào
Trong nhóm yêu cầu chống bịa đặt, những cơ chế thường dùng là:
- Bắt buộc citation. Mỗi claim trong câu trả lời phải gắn với ít nhất một
chunk_idtrong context. Câu trả lời không có citation sẽ bị chặn hoặc bị sinh lại. - Abstain khi thiếu evidence. Nếu retrieval rỗng, hoặc điểm rerank cao nhất dưới ngưỡng, hệ thống trả về câu “không tìm thấy trong tài liệu” thay vì cố trả lời. Tỷ lệ abstain đúng chỗ là một metric đáng theo dõi riêng.
- Kiểm tra grounding đồng bộ rút gọn. Một phiên bản rẻ và nhanh của Faithfulness chỉ kiểm tra các con số, ngày tháng và tên riêng trong câu trả lời có xuất hiện trong context hay không. Nó không thay được judge đầy đủ, nhưng chặn được một nhóm lỗi rất hay gặp với chi phí thấp.
- Sinh lại có giới hạn. Khi kiểm tra thất bại, sinh lại tối đa một hoặc hai lần rồi chuyển sang câu trả lời an toàn, thay vì lặp vô hạn.
Quyết định đo hay chặn là một quyết định kiến trúc và rủi ro, không phải một lựa chọn công cụ. Chặn đồng bộ tốn latency và thêm một dependency vào request; đo bất đồng bộ thì rẻ nhưng không ngăn được lần sai đầu tiên. Chọn theo giá của một lần sai.
13Từ triệu chứng tới tầng đang hỏng
Một cảnh báo kiểu “chất lượng câu trả lời tụt” mới chỉ là triệu chứng. Để đi tiếp cần một failure taxonomy và một thứ tự kiểm tra cố định.
Lỗi retrieval. Biểu hiện: contextual recall thấp, độ liên quan thấp, tài liệu đúng vắng mặt. Chỗ cần kiểm tra: query rewrite, metadata filter, dense search, BM25, RRF, retrieval_k, trạng thái index.
Lỗi reranking. Đây là chỗ dễ bỏ sót nhất, vì tài liệu đúng thực sự có trong candidate set:
rank 11 trước rerank -> rank 32 sau rerank
Chỗ cần kiểm tra: reranker model, cách biểu diễn query, việc cắt ngắn tài liệu, độ dài candidate, thiên lệch theo version.
Lỗi context. Retriever và reranker đúng, nhưng context builder làm rơi evidence, cắt ngắn nó, xếp sai thứ tự hoặc chèn thêm bản trùng đã cũ. Trace cần so sánh được output của reranker với context cuối cùng.
Lỗi generation. Evidence đúng và đủ, nhưng câu trả lời thêm claim không được hỗ trợ, bỏ qua evidence hoặc trả lời sai câu hỏi. Lúc này Faithfulness và hành vi sinh nội dung mới là nghi phạm.
Lỗi dữ liệu. Ứng dụng hoàn toàn đúng so với index, nhưng index sai so với thế giới thật:
source updated 14:00
index still old at 17:00
Đây là lỗi freshness và phải sửa ở pipeline nạp dữ liệu, không phải ở prompt.
14Incident runbook cho một quality incident
Giả sử alert báo: Faithfulness pass rate 92% -> 71%.
Bước 1 — xác thực tín hiệu. Kích thước mẫu có đủ không, judge backend có khỏe không, sampling có vừa đổi không, judge version có vừa đổi không. Rất phí công khi debug RAG trong lúc thứ hỏng thật ra là evaluator.
Bước 2 — soi mốc thay đổi. Deploy, prompt, model, index, đợt nạp tài liệu, reranker.
Bước 3 — cắt lát. Ngôn ngữ, tenant, loại query, phiên bản RAG, nguồn tài liệu. Ví dụ:
All traffic 71%
├── English 91%
└── Vietnamese 42%
├── Policy 31%
├── FAQ 88%
└── Technical 84%
Bước 4 — đọc trace mẫu. Chọn 5 tới 20 ca lỗi tiêu biểu và phân loại chúng theo taxonomy ở phần 13. Trong ví dụ trên, trace có thể cho thấy bước rewrite đang làm sai thuật ngữ pháp lý ở các câu hỏi chính sách tiếng Việt.
Bước 5 — giảm thiểu rồi sửa gốc. Rollback prompt query-rewrite về v17 để dừng thiệt hại, sau đó mới sửa gốc.
Bước 6 — tạo tài sản regression. Đưa chính những trace đã hỏng vào evaluation dataset.
Một incident chỉ thật sự đóng khi nguyên nhân gốc được hiểu và lỗi đã tái lập được, chứ không phải khi biểu đồ xanh trở lại.
Postmortem cho quality incident
Một sự cố chất lượng xứng đáng có postmortem như một sự cố độ tin cậy:
## Impact user nào, bao nhiêu request
## Detection alert nào phát hiện, hay user báo
## Timeline deploy / index update / lỗi đầu tiên / giảm thiểu
## Root Cause dữ liệu, retrieval, context, generation hay evaluator
## Why offline tests missed it
## Corrective Actions
Trong đó câu hỏi quan trọng nhất không phải “vì sao RAG sai”, mà là:
Vì sao hệ thống đánh giá không phát hiện được điều này trước khi deploy?
Vì mỗi incident không chỉ nên cải thiện RAG. Nó phải cải thiện cả bộ đánh giá. Ví dụ: lỗi là query rewrite tiếng Việt sai ở hội thoại nhiều lượt — thì phần sửa RAG là prompt rewrite mới, còn phần sửa evaluation là bổ sung golden hội thoại tiếng Việt và thêm một slice dashboard cho nhóm đó.
15Human feedback: tín hiệu mà LLM judge không thay thế được
LLM-as-a-Judge giúp mở rộng quy mô đánh giá. Nhưng chuyên gia domain biết những thứ judge không thể tự biết. Ví dụ với một chính sách nội bộ vừa được duyệt ngoại lệ hôm qua: judge không thể biết điều đó nếu evidence nó nhận được chưa chứa thay đổi ấy, trong khi một người làm nhân sự nhìn phát là nói được “câu trả lời này đã lỗi thời”.
Vì vậy production evaluation nên có ba tầng phản hồi: tín hiệu tự động, phản hồi người dùng cuối, và đánh giá của chuyên gia. MLflow hiện cho phép gắn feedback và expectation trực tiếp vào production trace và xem đó như một nguồn dữ liệu cho cải tiến liên tục.
Thumbs-down chưa đủ
Một UI chỉ có hai nút thích và không thích thì tốt hơn không có gì, nhưng nó không giải thích nguyên nhân. Feedback có cấu trúc hữu ích hơn nhiều:
Thông tin sai Nguồn đã lỗi thời
Thiếu thông tin Bịa đặt
Sai nguồn Không liên quan
Quá dài dòng Quá chậm
Và feedback phải gắn trace_id để mở đúng execution path:
{
"trace_id": "rag_82f1",
"rating": "negative",
"category": "outdated_source",
"comment": "Policy changed last week"
}
Từ đó có thể lọc toàn bộ lỗi outdated_source và xem chúng có cùng một nguyên nhân gốc hay không.
Tín hiệu yếu vẫn chỉ là tín hiệu yếu
Ở production thường không có expected_output, nên evaluation phải dựa nhiều hơn vào metric referenceless và các tín hiệu gián tiếp như thumbs up/down, tỷ lệ hỏi lại, tỷ lệ fallback, số lần click citation, tỷ lệ chuyển cho người thật.
Nhưng cần nhớ: tín hiệu yếu không phải ground truth. User không bấm thumbs-down chưa chắc câu trả lời đúng. User hỏi lại chưa chắc câu trước sai. Click citation chưa chắc citation đó hỗ trợ claim. Vì vậy production quality nên kết hợp nhiều tín hiệu thay vì suy diễn mạnh từ một con số duy nhất.
Judge cũng cần được đánh giá
LLM judge không phải oracle. Nó có thể dương tính giả, âm tính giả, thiên lệch theo văn phong, nhạy cảm với cách đặt câu và thay đổi hành vi giữa các phiên bản model. Vì vậy nên định kỳ lấy một mẫu có nhãn người thật và dựng confusion matrix giữa judge và người, rồi theo dõi độ chính xác, độ phủ và mức đồng thuận.
Một nguyên tắc thiết kế thí nghiệm quan trọng: đừng đổi judge model và RAG system trong cùng một lần. Nếu thứ hai chạy RAG v10 + Judge A mà thứ ba chạy RAG v11 + Judge B và điểm rơi từ 0.89 xuống 0.82, thì không thể biết đó là hồi quy của RAG, là thay đổi hiệu chuẩn của judge, hay cả hai. Khi cần đổi judge, hãy chạy một cửa sổ chồng lấn — cùng một tập trace đi qua cả Judge A lẫn Judge B — để đo độ dịch của thang điểm trước.
Ưu tiên hàng đợi review của con người
Human review đắt, nên đừng review ngẫu nhiên mọi thứ với cùng mức ưu tiên:
P0 lỗi rủi ro cao về bảo mật hoặc pháp lý
P1 phản hồi tiêu cực kèm faithfulness thấp
P2 cụm query mới xuất hiện
P3 kiểm định chất lượng ngẫu nhiên
Mục tiêu là phân bổ ngân sách review vào chỗ có kỳ vọng thu được nhiều thông tin nhất.
16Production trace phải trở thành nguồn cho evaluation dataset
Đây là bước quan trọng nhất của cả bài, và cũng là bước hay bị bỏ qua nhất.
Một lỗi production xảy ra. Nếu team chỉ sửa, deploy, đóng incident, thì sáu tháng sau lỗi tương tự hoàn toàn có thể quay lại. Thay vào đó, chuỗi đúng phải là:
lỗi thật -> gom nhóm -> chọn đại diện -> gắn nhãn -> golden -> regression test
MLflow hiện cho phép xây evaluation dataset từ chính các trace đã có và mô tả tương tác production lịch sử như một nguồn rất hữu ích để tạo dataset phản ánh tình huống thật. DeepEval cũng hướng tới vòng lặp đưa production trace trở lại evaluation dataset để tiếp tục test trong development.
Không phải trace nào cũng nên thành golden
Nếu đưa tất cả vào thì dataset phình to, độ trùng lặp tăng, chi phí đánh giá tăng và chi phí bảo trì tăng. Golden dataset không phải kho log.
Một case đáng curate khi nó đại diện cho một failure mode mới, một tình huống nghiệp vụ quan trọng, một phân bố query mới, một edge case quan trọng, một hành vi dễ hồi quy hoặc một tình huống rủi ro cao. Và nên khử trùng lặp theo intent, theo loại lỗi, theo nguồn và theo cấu trúc câu hỏi. Nếu production có 1.000 biến thể của cùng một ý:
"What about contractors in VN?"
"Vietnam contractors?"
"Does this apply to contractor Vietnam?"
thì không cần giữ cả 1.000. Gom cụm, chọn vài case đại diện, rồi mới viết expectation cho chúng.
Trace thô chưa phải một golden tốt
Một trace chỉ có input, actual_output và retrieval_context. Curator phải bổ sung phần mà production không có:
{
"input": "Can Vietnam contractors carry unused leave over?",
"expected_output": "...",
"expected_sources": ["leave-policy-2026#contractors"],
"tags": ["policy", "vietnam", "contractor", "carry-over"],
"origin": "production_failure",
"failure_type": "query_rewrite"
}
Hai field origin và failure_type đáng để bắt buộc. Chúng biến dataset thành một thứ đọc được như lịch sử những gì team đã học, chứ không phải một đống case không rõ vì sao tồn tại.
17Checklist trước khi gọi một hệ RAG là production-ready
Tracing
- Mọi request có trace id.
- Có span cho các chặng retrieval và generation quan trọng.
- Lưu version của RAG, prompt, model và index.
- Có thể dựng lại được evidence đã dùng.
- Có latency theo từng component.
Chất lượng
- Có metric end-to-end.
- Có tín hiệu component-level cho retrieval và generation.
- Có đường phản hồi của con người.
- Có cắt lát theo các cohort quan trọng.
Online evaluation
- Judge không chặn request của user.
- Có chiến lược sampling, và mỗi tín hiệu có tỷ lệ riêng.
- Có ngân sách chi phí đánh giá được theo dõi tách bạch.
- Judge được version hoá và định kỳ hiệu chuẩn với nhãn người.
Monitoring
- Có dashboard đủ cả chất lượng, độ trễ và chi phí.
- Có so sánh với baseline, không chỉ so với ngưỡng.
- Có SLI và SLO rõ ràng.
- Alert có hành động kèm theo, không chỉ là thông báo.
Drift
- Theo dõi query mix.
- Theo dõi độ tươi của tri thức.
- Theo dõi version của retrieval và index.
- Theo dõi cấu hình model và prompt.
Riêng tư
- Có chính sách logging và redaction.
- Không log nội dung nhạy cảm vô tội vạ.
- Có kiểm soát truy cập cho trace.
- Có chính sách lưu trữ và xoá.
Cải tiến liên tục
- Lỗi production được review.
- Lỗi tiêu biểu được curate thành golden.
- Golden có nguồn và expectation rõ ràng.
- Regression suite được cập nhật.
- Mỗi incident cải thiện cả ứng dụng lẫn bộ đánh giá.
Nếu thiếu đúng đoạn lỗi thật -> golden -> regression thì monitoring vẫn chỉ là quan sát. Nó chưa trở thành một hệ thống biết học.
Evaluation không phải một giai đoạn, nó là một vòng lặp
RAG evaluation không kết thúc khi CI pass. Một hệ thống trước deploy có thể được đánh giá bằng một dataset hữu hạn và cho ra chữ PASS. Nhưng phân bố ở production không đứng yên: user thay đổi, tri thức thay đổi, index thay đổi, model thay đổi, prompt thay đổi. Và chính những lỗi thật đó mới cho ta biết evaluation dataset còn thiếu gì.
Vì vậy kiến trúc cuối cùng của production evaluation không nên là:
Deploy -> Dashboard
mà là:
Deploy -> Trace -> Evaluate -> Detect -> Diagnose
-> Curate -> Golden -> Regression -> Improve -> Deploy
Nếu cần cô đọng cả bài thành một câu:
Production RAG Evaluation không phải là chấm điểm response sau khi deploy; nó là cơ chế biến traffic thật thành phản hồi có cấu trúc để hệ thống ngày càng khó hồi quy hơn.
Series này bắt đầu bằng câu hỏi “RAG được xây như thế nào” và kết thúc bằng một câu hỏi trưởng thành hơn: làm thế nào để một hệ RAG tự tạo ra dữ liệu cần thiết cho phiên bản tiếp theo của chính nó? Khi production trace, automated evaluation, human feedback, failure analysis và golden dataset nối lại thành một vòng kín, RAG mới thực sự trở thành một hệ thống vận hành được, đo được và cải tiến được — thay vì một demo có retrieval.
Tài liệu tham khảo
- Microsoft Learn / Azure Databricks — Introduction to evaluation and monitoring RAG applications
- Microsoft Foundry — Retrieval-Augmented Generation (RAG) Evaluators
- MLflow — Automatic Evaluation
- MLflow — Production Tracing and Monitoring
- MLflow — Feedback Collection
- MLflow — Building Agent and LLM Evaluation Datasets
- OpenTelemetry — Generative AI Semantic Conventions
- OpenTelemetry — Inside the LLM Call: GenAI Observability with OpenTelemetry
- DeepEval — LLM Tracing
- DeepEval — Tracing RAG Applications
- DeepEval — Component-Level LLM Evaluation
- DeepEval — RAG Evaluation Quickstart
- Google SRE — Service Level Objectives
- Google SRE Workbook — Alerting on SLOs