$ cat ./blog/gen-ai/danh-gia-rag-voi-deepeval.md
seriesRAG từ cơ bản đến nâng caobài 3

Đánh giá RAG với DeepEval: Fundamentals

Bài thứ ba trong series RAG từ cơ bản đến nâng cao: vì sao câu hỏi RAG của tôi có tốt không là quá rộng để trả lời, DeepEval tách chất lượng RAG thành những dimension nào, Golden khác LLMTestCase ra sao, năm metric đo đúng những gì, LLM-as-a-Judge sinh ra score bằng cơ chế nào, và threshold nên được calibrate thế nào.

~/diagrams/danh-gia-rag-voi-deepeval/rag-metric-map.htmltương tác
mở riêng ↗
HìnhHàng trên là đường đi của một câu hỏi qua hệ thống RAG: retriever tìm chunk, context được ghép vào prompt, generator viết câu trả lời. Hàng dưới là chỗ từng nhóm metric bám vào - ba metric đo chặng retrieval và hai metric đo chặng generation. Đây là lý do không tồn tại một con số duy nhất cho cả RAG: mỗi thước đo gắn vào một chặng khác nhau và trả lời một câu hỏi khác nhau.
đường đi của một câu hỏimetric cần expected_outputmetric referenceless

Một hệ thống RAG có thể trả lời đúng một vài câu hỏi trong demo nhưng vẫn thất bại nghiêm trọng khi đi vào production. Retriever có thể lấy thiếu dữ liệu, lấy đúng nhưng xếp sai thứ tự, hoặc kéo theo quá nhiều nhiễu. Generator có thể bỏ qua evidence, trả lời lạc đề, hoặc hallucinate dù context đã chứa thông tin đúng.

Vì thế câu hỏi quen thuộc nhất:

"RAG của tôi có tốt không?"

thực ra quá rộng để có thể trả lời bằng một con số duy nhất.

Muốn đánh giá RAG nghiêm túc, cần tách hệ thống thành những thành phần đo đạc được, xác định mỗi metric đang đo điều gì, hiểu cách metric tạo ra score, và chỉ sau đó mới dùng score để ra quyết định. DeepEval là một framework khá phù hợp với cách tiếp cận này.


01Vì sao đánh giá RAG khó hơn đánh giá một LLM thông thường

Với một LLM thuần tuý, pipeline thường được hình dung khá đơn giản:

User query
    ->  LLM
    ->  Answer

RAG thêm một tầng retrieval vào giữa:

User query
    ->  Retriever
    ->  Retrieved documents / chunks
    ->  Generator LLM
    ->  Final answer

Chính tầng thêm vào đó tạo ra nhiều failure mode khác nhau. Một câu trả lời sai có thể đến từ:

  1. retriever không tìm thấy evidence cần thiết;
  2. retriever tìm thấy evidence nhưng relevant chunk bị xếp quá thấp;
  3. retriever lấy được evidence đúng nhưng đồng thời kéo về rất nhiều noise;
  4. generator không sử dụng evidence đã retrieve;
  5. generator thêm claim không được evidence hỗ trợ;
  6. generator trả lời đúng context nhưng không trả lời đúng câu hỏi người dùng;
  7. câu trả lời đúng nhưng không đáp ứng tiêu chí business riêng của hệ thống.
~/diagrams/danh-gia-rag-voi-deepeval/rag-failure-modes.htmltương tác
mở riêng ↗
HìnhHàng trên là đường đi bình thường của một câu hỏi. Hàng dưới là bốn chỗ hỏng tương ứng với bốn chặng - không tìm thấy evidence, xếp sai thứ tự hoặc kéo quá nhiều nhiễu, bỏ qua evidence đã lấy được, và thêm claim không có căn cứ trong context. Nhìn mỗi câu trả lời cuối thì cả bốn trường hợp đều trông giống nhau: sai.
đường đi của một câu hỏichặng retrievalchỗ có thể hỏng

Nếu chỉ nhìn final answer:

Question -> Answer -> Correct / Incorrect

ta biết hệ thống có lỗi, nhưng không biết lỗi nằm ở đâu.

Một evaluation framework tốt cần giúp chuyển bài toán từ một câu hỏi rộng thành nhiều câu hỏi hẹp:

Retriever có lấy đủ thông tin không?
Retriever có xếp relevant chunks lên trên không?
Retriever có kéo quá nhiều noise không?
Generator có bám evidence không?
Generator có trả lời đúng trọng tâm không?
Output có đáp ứng yêu cầu domain không?

Đây là tư duy quan trọng nhất khi benchmark RAG.


02DeepEval nhìn evaluation như một dạng software testing

DeepEval là một framework Python dành cho LLM evaluation. Nó tổ chức việc đánh giá theo tư duy khá gần với testing phần mềm:

Test data
   ->  Run application
   ->  Collect runtime output
   ->  Apply metrics
   ->  Score
   ->  Threshold
   ->  PASS / FAIL

Khác với các metric truyền thống chỉ so khớp string hoặc n-gram, phần lớn metric mặc định của DeepEval sử dụng LLM-as-a-Judge để thực hiện semantic judgement.

Tuy nhiên cần hiểu chính xác điều đó nghĩa là gì. DeepEval không chỉ gửi toàn bộ câu trả lời cho một LLM rồi hỏi “hãy chấm từ 0 đến 10”. Nhiều metric phân rã bài toán thành các judgement nhỏ hơn:

Claim này có được context support không?
Statement này có relevant với query không?
Chunk này có relevant với expected answer không?

Sau đó framework dùng một công thức xác định để tổng hợp các verdict thành score. Đây là khác biệt quan trọng giữa hai kiến trúc:

LLM trực tiếp nghĩ ra score

và:

LLM thực hiện semantic judgement
        ->  code tổng hợp judgement thành score

03Golden, LLMTestCase và Metric

Ba khái niệm này rất hay bị dùng lẫn nhau, nhưng chúng đứng ở ba chỗ khác nhau trong pipeline.

~/diagrams/danh-gia-rag-voi-deepeval/deepeval-flow.htmltương tác
mở riêng ↗
HìnhHàng trên là đường đi của một lần đánh giá: Golden cung cấp input và câu trả lời chuẩn, hệ thống được chạy để sinh ra output thật, hai phần đó ghép thành một LLMTestCase, metric đo test case rồi so score với threshold. Hàng dưới là những điều dễ bỏ qua - Golden chưa chứa output nào, phần động đến từ đúng lần chạy đó, mỗi metric đòi hỏi field khác nhau, và judge chỉ làm phán đoán hẹp chứ không tự nghĩ ra điểm.
đường đi của một lần đophần động lúc chạyđiều dễ bỏ qua

Golden

Golden là dữ liệu mô tả thứ bạn muốn test:

Golden(
    input="Self-attention khác attention thông thường như thế nào?",
    expected_output="..."
)

Golden thường chỉ chứa dữ liệu tĩnh:

input
expected_output
context
metadata

Nó chưa nhất thiết chứa output do phiên bản RAG hiện tại sinh ra. Có thể hiểu Golden chính là test specification.

LLMTestCase

LLMTestCase là evaluation unit sau khi application đã chạy. Nó có thể chứa:

input
actual_output
expected_output
context
retrieval_context
tools_called
expected_tools
token_cost
completion_time

Với RAG, hai field đặc biệt quan trọng là actual_output và retrieval_context, vì chúng phản ánh những gì hệ thống thực sự làm trong lần chạy đó.

Golden
      |  run system
      v
LLMTestCase

Metric

Metric là thước đo áp lên test case. Với RAG, năm cái hay dùng nhất là:

FaithfulnessMetric
AnswerRelevancyMetric
ContextualRecallMetric
ContextualPrecisionMetric
ContextualRelevancyMetric

Mỗi metric cần những field khác nhau trong test case. Thiếu field thì metric không chạy được, và đây là nguyên nhân rất phổ biến khi mới bắt đầu.


04Không có một “DeepEval score” duy nhất

Một hiểu nhầm phổ biến là DeepEval nhận một RAG interaction rồi trả về:

RAG Score = 0.84

Không phải vậy. Một test case được đánh giá bằng nhiều metric, mỗi metric một con số riêng:

Test Case #17
├── Contextual Recall      = 0.91
├── Contextual Precision   = 0.76
├── Contextual Relevancy   = 0.72
├── Faithfulness           = 0.96
└── Answer Relevancy       = 0.89

Các metric này đo những dimension khác nhau. DeepEval chuẩn hoá score về khoảng từ 0 đến 1, theo quy ước 1 là tốt và 0 là xấu. Metric pass khi:

score >= threshold

Ngưỡng mặc định của đa số metric là 0.5. Nhưng đây chỉ là framework default, không phải một ngưỡng chất lượng production có ý nghĩa phổ quát. Phần cuối bài sẽ quay lại chuyện này.


05Tách RAG thành Retriever và Generator

DeepEval đề xuất nhìn RAG theo hai component chính, và mỗi component có bộ metric riêng. Sơ đồ ở đầu bài (Hình 1) là toàn bộ bức tranh đó.

Retriever có ba metric quan trọng:

Contextual Recall
Contextual Precision
Contextual Relevancy

Generator có hai metric cốt lõi:

Faithfulness
Answer Relevancy

Có thể nhớ theo bảng sau:

Metric Component Câu hỏi nó trả lời
Contextual Recall Retriever Có lấy đủ evidence cần thiết không?
Contextual Precision Retriever / ranking Relevant chunks có nằm đủ cao không?
Contextual Relevancy Retriever Retrieved context có quá nhiều noise không?
Faithfulness Generator Các claim có được retrieved context hỗ trợ không?
Answer Relevancy Generator Answer có thực sự trả lời query không?

Bộ năm metric này không phải năm cách khác nhau để đo cùng một thứ. Chúng tạo thành một quality vector của RAG.


06Contextual Recall: retriever có lấy đủ evidence không

Contextual Recall đo coverage. Câu hỏi của metric là: những thông tin cần thiết để tạo ra expected answer có được retrieval context cung cấp đầy đủ hay không?

Metric này là reference-based, vì nó cần expected_output. Các field chính:

input
actual_output
expected_output
retrieval_context

Trong đó phần logic quan trọng nhất nằm ở quan hệ giữa expected_output và retrieval_context.

~/diagrams/danh-gia-rag-voi-deepeval/contextual-recall.htmltương tác
mở riêng ↗
HìnhHàng trên là bốn bước của metric: câu trả lời lý tưởng được tách thành các statement cần thiết, judge đối chiếu từng statement với retrieval context, gán verdict attributable hay không, rồi cộng lại thành tỉ lệ. Hàng dưới là cái bẫy đi kèm - lấy top-20 gần như luôn đạt recall cao hơn top-5, nhưng cái giá là token, latency và tỉ lệ tín hiệu trên nhiễu.
bốn bước của metricverdict của judgerecall cao chưa đủ

Trực giác

Giả sử expected answer cần bốn facts, và retriever lấy được evidence hỗ trợ ba trong số đó:

F1 có
F2 có
F3 thiếu
F4 có

Về mặt khái niệm:

Contextual Recall
  = số statement trong expected output được context support
  / tổng số statement cần thiết
  = 3 / 4
  = 0.75

DeepEval dùng LLM judge để xác định attribution giữa các statement cần thiết và retrieval context.

Recall cao chưa chắc retriever tốt

Giả sử Top-20 retrieve đủ mọi evidence cần thiết:

Relevant chunks   = 3
Irrelevant chunks = 17

Retriever vẫn đạt recall rất cao. Nhưng việc kéo 17 chunk nhiễu sẽ tăng token usage, làm prompt dài hơn, giảm signal-to-noise ratio, tăng khả năng LLM tập trung nhầm evidence, tăng latency và tăng chi phí generation.

Vì thế recall cao không đồng nghĩa với retrieval tốt toàn diện. Ta cần thêm Precision và Relevancy.


07Contextual Precision: relevant evidence có được xếp đủ cao không

Contextual Precision tập trung vào ranking order: trong danh sách retrieved chunks, các chunk relevant có được xếp phía trên các chunk irrelevant không?

Đây là metric đặc biệt hữu ích khi đánh giá reranker, ranking strategy, hybrid retrieval và thứ tự top-k. Metric cần reference, trong đó expected_output giúp judge xác định chunk nào thực sự relevant với câu trả lời lý tưởng.

Hai retriever có thể lấy cùng evidence nhưng chất lượng khác hẳn

Retriever A            Retriever B
Rank 1 -> Relevant     Rank 1 -> Irrelevant
Rank 2 -> Relevant     Rank 2 -> Irrelevant
Rank 3 -> Irrelevant   Rank 3 -> Relevant
Rank 4 -> Irrelevant   Rank 4 -> Relevant
Rank 5 -> Relevant     Rank 5 -> Relevant

Cả hai đều có ba relevant chunk trên năm chunk. Nếu chỉ đếm số relevant, chúng ngang nhau. Nhưng A rõ ràng tốt hơn vì evidence hữu ích xuất hiện sớm.

~/diagrams/danh-gia-rag-voi-deepeval/contextual-precision.htmltương tác
mở riêng ↗
HìnhHai hàng là hai retriever chạy trên cùng một truy vấn và cùng lấy được ba chunk relevant trên năm chunk. Chặng giữa là precision tính tại mỗi rank có chunk relevant, chặng sau là trung bình của các giá trị đó. Cùng một lượng evidence, nhưng thứ tự đưa ra khiến điểm chênh nhau gần gấp đôi.
retriever xếp evidence lên trênprecision tại từng rankretriever đẩy evidence xuống dưới

DeepEval sử dụng logic gần với Average Precision:

CP = (1 / R) * tổng theo k của ( (R_k / k) * r_k )

Trong đó k là vị trí rank, r_k bằng 1 nếu chunk tại rank k relevant và bằng 0 nếu không, R_k là số relevant chunks từ rank 1 đến k, còn R là tổng relevant chunks được judge xác định.

Với Retriever A:

rank 1 relevant -> precision@1 = 1/1 = 1.00
rank 2 relevant -> precision@2 = 2/2 = 1.00
rank 5 relevant -> precision@5 = 3/5 = 0.60

CP_A = (1.00 + 1.00 + 0.60) / 3 = 0.867

Với Retriever B:

rank 3 relevant -> 1/3
rank 4 relevant -> 2/4
rank 5 relevant -> 3/5

CP_B = (1/3 + 2/4 + 3/5) / 3 = 0.478

Cùng retrieve được ba relevant chunk, nhưng ranking quality khác xa nhau.


08Contextual Relevancy và hệ chẩn đoán ba metric

Contextual Relevancy trả lời câu hỏi: thông tin được retrieve có thực sự liên quan đến query không?

Metric này là referenceless, không cần expected_output. Điều đó rất hữu ích trong production, vì phần lớn traffic thực tế không có answer chuẩn.

Có thể hình dung context được phân tích thành các judgement:

Thông tin 1 -> relevant
Thông tin 2 -> relevant
Thông tin 3 -> irrelevant
Thông tin 4 -> irrelevant
Thông tin 5 -> relevant

Score về trực giác là tỉ lệ thông tin relevant trên tổng thông tin được xét, ở đây là 3 / 5 = 0.6.

Điểm quan trọng là hai metric này hỏi hai chuyện hoàn toàn khác nhau:

Contextual Recall     = "có lấy đủ không?"
Contextual Relevancy  = "những gì lấy về có sạch không?"

Ba metric tạo thành một hệ chẩn đoán

Đọc chúng cùng lúc thì mỗi tổ hợp chỉ về một chỗ khác nhau:

Recall Precision Relevancy Diễn giải
Cao Cao Cao Retriever hoạt động tốt
Cao Thấp Cao Tìm đủ nhưng ranking chưa tốt
Cao Cao Thấp Tìm đúng nhưng kéo quá nhiều noise
Thấp Cao Cao Những gì tìm được tốt nhưng bị thiếu evidence
Thấp Thấp Thấp Retrieval pipeline có vấn đề tổng thể

Đây không phải rule tuyệt đối, nhưng là khung debug rất hữu ích. Recall thấp dẫn ta xem lại embedding model, query rewriting, index coverage, chunking, top-k và metadata filter. Trong khi recall cao đi kèm precision thấp lại gợi ý rằng retrieval đã có candidate tốt, nhưng ranking hoặc reranking chưa tốt.


09Faithfulness: generator có thực sự bám evidence không

Faithfulness là một trong những metric quan trọng nhất của RAG evaluation. Nó hỏi: các claim trong actual_output có được retrieval_context hỗ trợ hay không?

Metric này chỉ cần actual_output và retrieval_context, không cần expected_output, nên dùng được cho production traffic.

~/diagrams/danh-gia-rag-voi-deepeval/faithfulness-claims.htmltương tác
mở riêng ↗
HìnhHàng trên là bốn bước: câu trả lời được tách thành các claim, judge đối chiếu từng claim với retrieval context, gán supported hay unsupported, rồi cộng lại thành tỉ lệ. Hàng dưới là hai điều dễ hiểu nhầm - metric này không đo đúng sai so với thế giới thực, và nó không cần câu trả lời chuẩn nên chạy được ngay trên traffic production.
bốn bước của metricverdict của judgechỗ dễ hiểu nhầm

Faithfulness không phải factual correctness với thế giới

Giả sử context chỉ chứa:

GPT-4 was released in March 2023.

Còn answer là:

GPT-4 was released in March 2023.
It was developed by OpenAI.

Claim thứ hai đúng trong thế giới thực. Nhưng nếu retrieval context không cung cấp evidence cho claim đó, metric faithfulness vẫn có thể xem nó là unsupported.

Điều DeepEval đo là quan hệ giữa answer và retrieved evidence, chứ không phải quan hệ giữa answer và toàn bộ tri thức thật của thế giới. Khái niệm này gọi là groundedness.

Cách tính ở mức khái niệm

Giả sử answer có ba claims, trong đó hai claim được support:

Faithfulness = supported claims / total claims = 2 / 3 = 0.667

Điểm đáng chú ý là LLM judge chỉ làm phần việc ngữ nghĩa - “claim này có được evidence hỗ trợ không” - còn việc tổng hợp thành score là do framework.


10Answer Relevancy và bốn kiểu lỗi của generator

Answer Relevancy hỏi: actual_output có relevant với input hay không? Metric chỉ cần input và actual_output, và cũng là referenceless.

Ví dụ với query:

"Self-attention hoạt động như thế nào?"

và answer:

S1. Self-attention tạo Query, Key và Value.
S2. Attention score thể hiện mức liên quan giữa token.
S3. Transformer được công bố trong paper năm 2017.

Nếu judge đánh S1 và S2 là relevant còn S3 là irrelevant, thì về trực giác Answer Relevancy bằng 2 / 3.

Điểm quan trọng: Answer Relevancy cao chỉ nói rằng answer tập trung vào câu hỏi, chứ không nói rằng answer đúng fact. Một câu trả lời có thể rất relevant nhưng hoàn toàn sai:

Question: "Thủ đô của Pháp là gì?"
Answer:   "Thủ đô của Pháp là London."

Nó trả lời đúng loại thông tin được hỏi, nhưng factual claim sai. Trong RAG, nếu context ghi Paris thì answer này cũng sẽ có Faithfulness thấp. Vì vậy hai metric nên được nhìn cùng nhau.

Answer Relevancy Faithfulness Ý nghĩa
Cao Cao Answer đúng trọng tâm và grounded
Cao Thấp Trả lời đúng chủ đề nhưng hallucinate / unsupported
Thấp Cao Bám context nhưng không trả lời đúng trọng tâm
Thấp Thấp Generator có vấn đề toàn diện

Một pattern rất đáng chú ý:

Retriever:
Recall      0.95
Precision   0.92
Relevancy   0.91

Generator:
Faithfulness 0.51

Điều này nói rằng evidence đã có, nhưng generator vẫn không dùng evidence tốt. Nếu chỉ nhìn final accuracy, rất dễ quay lại tuning retriever trong khi vấn đề thật nằm ở prompt, context formatting, instruction hierarchy, generation model hoặc citation strategy.


11RAG Triad: bộ metric cho lúc không có ground truth

Trong production, chúng ta thường có query, retrieval_context và actual_output, nhưng không có expected_output. Khi đó hai metric reference-based là Contextual Recall và Contextual Precision không thể chạy theo cấu hình đầy đủ.

DeepEval gọi bộ ba referenceless còn lại là RAG Triad:

Contextual Relevancy
Faithfulness
Answer Relevancy
~/diagrams/danh-gia-rag-voi-deepeval/rag-triad.htmltương tác
mở riêng ↗
HìnhHàng trên là ba câu hỏi đi liền một mạch: context có liên quan tới query không, answer có bám vào context đó không, và answer có trả lời đúng query không. Cả ba chỉ cần những gì đã có sẵn trong trace lúc chạy. Hàng dưới là hai metric bị loại khỏi cấu hình production vì chúng cần một câu trả lời chuẩn mà traffic thật hiếm khi có.
ba metric referencelesschỉ cần trace lúc chạymetric cần reference

Ba metric này trả lời ba câu hỏi nối tiếp nhau:

Retrieve đúng thứ liên quan chưa?
        ->  Answer có bám thứ retrieve không?
        ->  Answer có trả lời query không?

Đây là một cấu hình hợp lý cho online / production evaluation, nơi ground truth khan hiếm.


12DeepEval dùng LLM-as-a-Judge như thế nào: QAG, G-Eval và DAG

Nếu chỉ nói “DeepEval sử dụng LLM-as-a-Judge” thì vẫn quá chung chung. DeepEval có nhiều cách biến semantic judgement thành metric, và ba cơ chế quan trọng nhất là QAG, G-Eval và DAG.

~/diagrams/danh-gia-rag-voi-deepeval/judge-mechanisms.htmltương tác
mở riêng ↗
HìnhBa hàng là ba cơ chế, đọc theo cùng năm chặng: tiêu chí, cách hỏi judge, thứ judge trả về, cách tổng hợp và score cuối. QAG hỏi những câu nguyên tử rồi để code đếm tỉ lệ. G-Eval dựng judge prompt từ evaluation steps rồi chuẩn hoá điểm rubric về khoảng 0 tới 1. DAG đi theo cây quyết định và ánh xạ verdict ở nút lá thành điểm.
QAGphần code tổng hợpG-Eval và DAG

QAG: judgement hẹp cộng aggregation xác định

Với nhiều metric mặc định, logic có thể hiểu như sau:

Complex criterion
      ->  Break into atomic semantic questions
      ├── Question 1 -> YES
      ├── Question 2 -> NO
      └── Question 3 -> YES
      ->  Mathematical aggregation
      ->  score = 2 / 3

Điểm hay ở đây là judge không phải tự nghĩ “tôi thấy answer này đáng 0.73”. Thay vào đó nó xử lý tác vụ hẹp: claim có được support không, statement có relevant không, thông tin có attributable không. Sau đó score được code tổng hợp. Đây là lý do score có interpretability tốt hơn một holistic number.

Tuy nhiên QAG không hoàn toàn deterministic. Nếu LLM đổi verdict từ YES sang NO thì score vẫn đổi. Nói chính xác hơn: không gian quyết định của judge được giới hạn nên variance có thể giảm, nhưng semantic judgement vẫn đến từ một probabilistic model.

G-Eval: metric cho tiêu chí custom và chủ quan

Không phải mọi thứ đều diễn đạt được bằng recall hoặc faithfulness. Một ứng dụng có thể cần đo correctness, professionalism, coherence, completeness, tone, helpfulness hoặc một tiêu chí đặc thù của domain. DeepEval cung cấp GEval cho những trường hợp đó:

from deepeval.metrics import GEval
from deepeval.test_case import SingleTurnParams

correctness = GEval(
    name="Correctness",
    criteria=(
        "Determine whether the actual output is factually correct "
        "based on the expected output."
    ),
    evaluation_params=[
        SingleTurnParams.ACTUAL_OUTPUT,
        SingleTurnParams.EXPECTED_OUTPUT,
    ],
)

Nếu không cung cấp evaluation_steps, DeepEval có thể tạo các bước đánh giá từ criteria. Nếu cung cấp sẵn:

evaluation_steps=[
    "Check factual contradictions.",
    "Check important omissions.",
    "Penalize unsupported claims.",
]

evaluation có khả năng ổn định hơn, vì bỏ qua bước sinh evaluation plan mỗi lần.

Rubric và weighted score trong G-Eval

DeepEval hỗ trợ rubric theo range 0 đến 10:

from deepeval.metrics.g_eval import Rubric

rubric = [
    Rubric(score_range=(0, 2), expected_outcome="Factually incorrect."),
    Rubric(score_range=(3, 6), expected_outcome="Mostly correct."),
    Rubric(score_range=(7, 9), expected_outcome="Correct with minor omissions."),
    Rubric(score_range=(10, 10), expected_outcome="Fully correct."),
]

Raw score trên thang 0 đến 10 được chuẩn hoá về 0 đến 1:

normalized = (raw - min) / (max - min)

raw = 8.2, min = 0, max = 10   ->   normalized = 0.82

G-Eval gốc còn dùng xác suất output token để tránh biến scoring thành một lựa chọn integer quá cứng. Giả sử judge có phân phối:

P(1) = 0.01
P(2) = 0.04
P(3) = 0.20
P(4) = 0.50
P(5) = 0.25

Nếu lấy argmax thì score bằng 4, và ta mất thông tin rằng model vẫn đặt 25% xác suất vào 5 và 20% vào 3. Weighted score lấy tổng của i * P(i):

s = 1(0.01) + 2(0.04) + 3(0.20) + 4(0.50) + 5(0.25) = 3.94

DeepEval có logic weighted summation khi evaluation model cung cấp log probabilities. Với custom model không hỗ trợ raw response hoặc logprobs, nó có thể fallback về raw score. Vì vậy G-Eval không chỉ đơn giản là “LLM trả về một integer”.

DAG: khi quality rubric là một decision tree

G-Eval hợp với holistic judgement. Nhưng một số yêu cầu có cấu trúc rõ ràng:

Nếu vi phạm rule bắt buộc     -> fail ngay.
Nếu không                     -> kiểm tra disclaimer.
Nếu có disclaimer             -> mới đánh giá helpfulness.

Đó là trường hợp phù hợp với DAG:

Output
  -> Policy violation?
     ├── Yes -> Score 0
     └── No  -> Required disclaimer?
                ├── No  -> Score 4/10
                └── Yes -> Evaluate helpfulness

Với terminal verdict trên thang 0 đến 10:

DAGScore = VerdictScore / 10

verdict score = 4   ->   DAGScore = 0.4

DAG có score mapping được kiểm soát rõ hơn G-Eval. Tuy nhiên “DAG deterministic” không có nghĩa là “không còn LLM uncertainty”. Nếu nhánh “Policy violation?” vẫn do LLM judge quyết định, semantic judgement vẫn là probabilistic. Điểm deterministic hơn nằm ở decision structure và score mapping.


13Score, threshold và cái bẫy của trung bình

Mỗi metric trả về score trong khoảng 0 đến 1, và pass khi score >= threshold:

FaithfulnessMetric(threshold=0.8)

khi đó:

0.91 -> PASS
0.82 -> PASS
0.80 -> PASS
0.79 -> FAIL

Một test case dùng nhiều metric có thể có:

Faithfulness       0.92 -> PASS
Answer Relevancy   0.88 -> PASS
Contextual Recall  0.71 -> FAIL

Nếu cả ba đều đóng vai trò gate thì test case fail. Đây là cách DeepEval đưa LLM evaluation vào tư duy regression testing:

assert faithfulness >= 0.90
assert answer_relevancy >= 0.80

strict_mode, threshold=None và flaky

Ba option này có ý nghĩa thực tế lớn.

Với strict_mode=True, metric trở thành rất nghiêm ngặt: nhiều metric chuyển sang chế độ perfect thì 1, không perfect thì 0, và threshold được đưa về 1. Nó phù hợp với rule kiểu “không được phép có unsupported claim” hơn là một quality metric mềm.

Với threshold=None, metric vẫn tính score nhưng không dùng score để quyết định pass hay fail. Phù hợp khi đang quan sát một metric mới, chưa calibrate threshold, và không muốn metric block CI.

Với flaky=True, metric có thể vẫn được report nhưng failure của nó không nhất thiết phải block toàn bộ test case hoặc CI flow. Nhờ vậy có thể thiết kế:

Hard gates            Monitoring metrics
├── Faithfulness      ├── Tone
├── Safety            ├── Style
└── Compliance        └── Conciseness

Không phải metric nào cũng nên có quyền chặn deployment.

Vì sao không nên lấy trung bình năm metric

Giả sử:

Contextual Recall      = 1.00
Contextual Precision   = 1.00
Contextual Relevancy   = 1.00
Answer Relevancy       = 1.00
Faithfulness           = 0.00

Nếu average thì RAGScore = 0.8, và ta có thể bị đánh lừa rằng “RAG đạt 80%”, trong khi generator đang hoàn toàn không grounded. Đây là compensatory metric problem: metric rất tốt cộng với metric critical rất xấu vẫn cho một trung bình đẹp.

Vì thế nên giữ nguyên quality vector:

[ Recall, Precision, Relevancy, Faithfulness, AnswerRelevancy ]

và chọn một số metric critical làm hard gate.

Mean score cũng chưa đủ

Giả sử hai hệ thống đều có mean Faithfulness bằng 0.90:

System A: 0.88  0.90  0.91  0.89  0.92  0.90
System B: 1.00  1.00  1.00  1.00  0.40  1.00

Average tương đương, nhưng B có catastrophic tail. Khi benchmark nên xem ít nhất mean, median, pass rate, low-percentile score, số lượng severe failure và phân loại failure. Đặc biệt với hallucination, tail risk thường quan trọng hơn 0.01 điểm trung bình.


14Calibrate threshold và bốn tầng để nhìn DeepEval

0.5 là default thuận tiện. Production threshold nên phản ánh kỳ vọng của con người, rủi ro nghiệp vụ, hành vi của judge và yêu cầu của domain.

~/diagrams/danh-gia-rag-voi-deepeval/threshold-calibration.htmltương tác
mở riêng ↗
HìnhCùng một sample đi qua hai nguồn phán xét: người gán nhãn và metric chấm điểm. Đối chiếu hai nguồn cho ra bảng bốn ô, từ đó tách được false pass và false fail. Threshold không được chọn từ một con số mặc định, mà từ việc cân nhắc chi phí của hai loại lỗi này trong đúng domain đang làm.
đường calibrateđiểm của metrichai loại lỗi

Một quy trình tốt hơn là lấy một sample đủ đại diện, cho human reviewer label, chạy DeepEval trên cùng sample, so sánh judge với người, rồi mới chọn threshold. Ví dụ kết quả có thể là:

Human Good Human Bad
DeepEval Pass 310 25
DeepEval Fail 35 130

Lúc này bạn có thể phân tích false pass và false fail, rồi chọn threshold theo chi phí của từng loại lỗi. Với hệ thống hỏi đáp nội bộ, false fail có thể chỉ gây bất tiện. Với domain rủi ro cao, false pass của hallucination có thể nghiêm trọng hơn nhiều.

LLM-as-a-Judge cũng là một measuring instrument

Một điểm cần giữ trong mọi benchmark: judge model không phải ground truth. Nó có thể chịu ảnh hưởng bởi prompt, rubric, ngôn ngữ, độ dài output, vị trí, phiên bản model, evaluation template và hành vi sampling.

Vì thế khi ghi kết quả benchmark, nên version cả evaluator:

DeepEval version
judge model
metric configuration
threshold
rubric
evaluation_steps
dataset version

Nếu không, câu “Faithfulness tăng từ 0.81 lên 0.85” có thể không có ý nghĩa nếu evaluation setup đã đổi.

Bốn tầng, và cách debug ngược từ dưới lên

~/diagrams/danh-gia-rag-voi-deepeval/deepeval-layers.htmltương tác
mở riêng ↗
HìnhHàng trên là đường đi từ evidence lên tới quyết định: dữ liệu thô, phán đoán ngữ nghĩa, cách tính điểm, so với ngưỡng, rồi hành động. Hàng dưới là câu hỏi cần đặt ở đúng tầng đó khi score trông sai. Debug nên đi từ tầng thấp nhất lên, vì sửa threshold trong khi evidence đang sai là sửa nhầm chỗ.
từ evidence tới quyết địnhtầng verdictcâu hỏi khi debug

DeepEval có thể hiểu theo các tầng chồng lên nhau:

4. Decision            deploy / reject / alert / regression
3. Verdict             score >= threshold
2. Scoring             ratio / AP / G-Eval / DAG
1. Semantic Judgement  relevant? supported? attributable?
0. Evidence            query / output / context / expected

Khi score có vấn đề, debug từ dưới lên:

Evidence có đúng không?
       ->  Judge có hiểu đúng không?
       ->  Metric aggregation có phù hợp không?
       ->  Threshold có được calibrate không?
       ->  Decision rule có đúng business requirement không?

Đây là cách hiểu DeepEval sâu hơn nhiều so với “một tool dùng GPT để chấm RAG”.


DeepEval hữu ích vì nó decompose quality

DeepEval hữu ích không phải vì nó tạo ra một số điểm duy nhất cho RAG, mà vì nó giúp tách chất lượng thành những phần đo được.

Một RAG tốt cần trả lời được ít nhất năm câu hỏi:

1. Retriever có lấy đủ evidence?          -> Contextual Recall
2. Relevant evidence có nằm đủ cao?       -> Contextual Precision
3. Retrieved context có nhiều noise?      -> Contextual Relevancy
4. Generator có bám retrieved evidence?   -> Faithfulness
5. Generator có trả lời đúng câu hỏi?     -> Answer Relevancy

Những gì nên mang theo:

  • không có một con số duy nhất cho RAG, chỉ có một quality vector năm chiều;
  • hai metric reference-based cần expected_output, ba metric còn lại chạy được trên production traffic;
  • Faithfulness đo groundedness với context, không đo đúng sai với thế giới thực;
  • Answer Relevancy cao chỉ nói answer bám câu hỏi, không nói answer đúng;
  • judge chỉ làm phán đoán ngữ nghĩa hẹp, phần biến verdict thành số là do code;
  • 0.5 là default của framework, không phải ngưỡng chất lượng của hệ thống bạn;
  • trung bình các metric che mất đúng thứ nguy hiểm nhất, và mean che mất phần đuôi;
  • judge là một thiết bị đo, nên phải được version cùng kết quả benchmark.

Sau khi hiểu rõ từng metric, bước tiếp theo mới là câu hỏi thực tế hơn: làm thế nào xây một dataset, chạy hai phiên bản RAG, thu retrieval context, chạy DeepEval và đọc kết quả một cách có hệ thống? Đó là nội dung của bài tiếp theo.


Tài liệu tham khảo

Trương Đức Dũng

AI Engineer - Hà Nội

Tập trung vào LLM, RAG và các hệ thống AI cần chạy ổn định trong môi trường vận hành thật.