0Pricing
AI Engineering Academy · 课时

生成指标:忠实度与答案相关性

使用 RAGAS 衡量生成的答案是否忠实于检索到的上下文,以及是否真正回答了用户的问题而没有产生幻觉。

生成指标:忠实度与答案相关性 是 CoddyKit 上的免费 AI Engineering Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Engineering Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Engineering Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Measuring the Generation Stage

Even when your retriever finds the perfect chunks, the generation stage can still fail. The LLM might ignore the retrieved context and answer from its parametric memory, misinterpret what the context says, or answer a slightly different question than what was asked. Generation metrics quantify these failures independently from retrieval so you can pinpoint and fix each problem. The two primary generation metrics are faithfulness and answer relevance.

Faithfulness: Definition

Faithfulness measures whether every claim in the generated answer can be directly traced back to the retrieved context. A faithful answer introduces no information that is not present in the context. Faithfulness is measured at the claim level: the answer is decomposed into individual atomic statements, and each is checked against the context for support. The faithfulness score is the fraction of claims that are supported.

# Faithfulness = supported_claims / total_claims

example_answer = (
    'Employees receive 15 vacation days per year. '
    'Remote work is allowed on Wednesdays and Fridays. '
    'The CEO is John Smith.'
)
example_context = (
    '15 vacation days are granted annually. '
    'Remote work is permitted on Wednesdays and Fridays.'
)

# Claim 1: 15 vacation days — SUPPORTED
# Claim 2: Remote work Wed+Fri — SUPPORTED
# Claim 3: CEO is John Smith — NOT IN CONTEXT (hallucinated)
# Faithfulness = 2/3 = 0.67

Implementing Faithfulness with LLM-as-Judge

The most practical way to measure faithfulness at scale is to use a powerful LLM as a judge. Prompt the judge LLM to decompose the answer into individual claims, then check each claim against the context. The judge returns a list of claims labeled SUPPORTED or UNSUPPORTED, and you compute the fraction that are supported. This approach scales to thousands of evaluations per hour at a cost of a few cents per evaluation.

import json

def evaluate_faithfulness(answer, context, llm_client):
    prompt = (
        'Task: Evaluate the faithfulness of an answer against a context.\n\n'
        f'Context:\n{context}\n\n'
        f'Answer:\n{answer}\n\n'
        'Steps:\n'
        '1. Break the answer into individual atomic claims.\n'
        '2. For each claim, check if it is supported by the context.\n'
        '3. Return JSON: {"claims": [{"text": "...", "supported": true/false}], "score": 0.0-1.0}'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o',
        response_format={'type': 'json_object'},
        messages=[{'role': 'user', 'content': prompt}]
    )
    return json.loads(response.choices[0].message.content)

Answer Relevance: Definition

Answer relevance measures whether the generated answer actually addresses the user's question. A highly faithful answer might still miss the point — for example, if the user asks 'How do I reset my password?' and the answer explains the company's general security policy in detail without mentioning the password reset procedure. Answer relevance is independent of faithfulness: you can be faithful (only saying things in the context) but irrelevant (not addressing what was asked).

Measuring Answer Relevance

RAGAS measures answer relevance using a clever reverse-generation technique: the judge LLM generates several hypothetical questions that would be answered by the generated response, then measures how similar these generated questions are to the original question using embedding cosine similarity. High similarity between the generated hypothetical questions and the original question indicates high answer relevance.

def evaluate_answer_relevance(question, answer, llm_client, embed_fn):
    # Generate hypothetical questions for this answer
    prompt = (
        f'Given this answer: "{answer}"\n\n'
        'Generate 3 questions that this answer would be a good response to.\n'
        'Return as JSON: {"questions": ["...", "...", "..."]}'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o-mini',
        response_format={'type': 'json_object'},
        messages=[{'role': 'user', 'content': prompt}]
    )
    hyp_questions = json.loads(response.choices[0].message.content)['questions']

    # Measure similarity to original question
    orig_embedding = embed_fn(question)
    hyp_embeddings = [embed_fn(q) for q in hyp_questions]
    similarities = [cosine_similarity(orig_embedding, e) for e in hyp_embeddings]
    return sum(similarities) / len(similarities)

Context Recall: Did We Retrieve Enough?

Context recall measures whether the retrieved context contains sufficient information to answer the question correctly. It checks the ground truth answer sentence by sentence: can each sentence be attributed to one of the retrieved chunks? High context recall means the retriever found everything needed. Low context recall means key information was missing from the retrieved chunks, so the LLM cannot possibly answer correctly even with perfect generation.

def evaluate_context_recall(ground_truth_answer, retrieved_contexts, llm_client):
    prompt = (
        f'Ground truth answer:\n{ground_truth_answer}\n\n'
        f'Retrieved context:\n{",".join(retrieved_contexts)}\n\n'
        'For each sentence in the ground truth answer, determine if it '
        'can be attributed to the retrieved context.\n'
        'Return JSON: {"sentences": [{"text": "...", "in_context": true/false}], "recall": 0.0-1.0}'
    )
    response = llm_client.chat.completions.create(
        model='gpt-4o',
        response_format={'type': 'json_object'},
        messages=[{'role': 'user', 'content': prompt}]
    )
    return json.loads(response.choices[0].message.content)

Context Precision: Are Retrieved Chunks Relevant?

Context precision measures whether the retrieved chunks are actually useful for answering the question. High context precision means the retrieved chunks are tightly relevant. Low context precision means many retrieved chunks are off-topic noise that the LLM must read and discard, increasing the risk of confusion. Context precision is measured by checking which retrieved chunks were actually used or referenced in the generated answer.

def evaluate_context_precision(question, answer, retrieved_contexts, llm_client):
    precision_scores = []
    for i, context in enumerate(retrieved_contexts, 1):
        prompt = (
            f'Question: {question}\n\n'
            f'Context chunk {i}: {context}\n\n'
            f'Answer: {answer}\n\n'
            'Was this context chunk useful in generating the answer? '
            'Return JSON: {"useful": true/false, "reason": "..."}'
        )
        response = llm_client.chat.completions.create(
            model='gpt-4o-mini',
            response_format={'type': 'json_object'},
            messages=[{'role': 'user', 'content': prompt}]
        )
        result = json.loads(response.choices[0].message.content)
        precision_scores.append(1.0 if result['useful'] else 0.0)
    return sum(precision_scores) / len(precision_scores)

Using RAGAS for All Metrics at Once

The RAGAS library implements all four core RAG metrics — context precision, context recall, faithfulness, and answer relevance — in a single framework. It handles the LLM judge calls internally. Pass a dataset with questions, generated answers, retrieved contexts, and ground truth answers, and receive a comprehensive score report. RAGAS also supports async evaluation so you can evaluate hundreds of examples in parallel.

from ragas import evaluate
from ragas.metrics import (
    faithfulness, answer_relevancy,
    context_precision, context_recall
)
from datasets import Dataset

# Build evaluation dataset
eval_samples = [
    {
        'question': item['question'],
        'answer': item['generated_answer'],
        'contexts': item['retrieved_texts'],
        'ground_truth': item['expected_answer']
    }
    for item in test_results
]

eval_dataset = Dataset.from_list(eval_samples)
results = evaluate(eval_dataset,
    metrics=[faithfulness, answer_relevancy, context_precision, context_recall]
)
results.to_pandas().to_csv('eval_results.csv', index=False)

Diagnosing with Metric Combinations

The combination of metrics reveals specific system problems. Low faithfulness + high context precision → LLM is ignoring the context and hallucinating (fix the prompt). Low context recall + high faithfulness → retriever is missing key chunks but LLM faithfully reports what it found (fix chunking or embedding). Low answer relevance + high faithfulness → retrieved chunks are tangentially related and the LLM faithfully discusses them but misses the question (improve retrieval filtering or query rewriting).

# Diagnostic matrix
diagnostics = [
    {
        'condition': 'Low faithfulness + High context precision',
        'cause': 'LLM ignoring context, answering from parametric memory',
        'fix': 'Strengthen system prompt: "Answer ONLY from the provided context"'
    },
    {
        'condition': 'Low context recall + High faithfulness',
        'cause': 'Retriever missing relevant chunks',
        'fix': 'Improve chunking strategy, embedding model, or increase top-k'
    },
    {
        'condition': 'Low answer relevance + High context recall',
        'cause': 'Retrieved context is off-topic; LLM is answering wrong question',
        'fix': 'Add query rewriting or improve metadata filters'
    }
]

Human Evaluation for Calibration

LLM-as-judge metrics are correlated with human judgment but not perfectly aligned. Calibrate your automated metrics by having 3 human raters score a random sample of 50 outputs on faithfulness and answer relevance using a 1-5 scale. Compute agreement between the LLM judge and the average human rating. If the LLM systematically over- or under-scores relative to humans, apply a correction factor. Calibrated automated metrics give you confidence that score improvements reflect real quality improvements.

from scipy.stats import spearmanr

def calibrate_judge_vs_humans(samples):
    '''samples: [{"llm_score": 0.9, "human_score": 4.2}, ...]'''
    llm_scores = [s['llm_score'] for s in samples]
    human_scores = [s['human_score'] / 5.0 for s in samples]  # normalize to 0-1

    correlation, pvalue = spearmanr(llm_scores, human_scores)
    print(f'LLM-Human Spearman correlation: {correlation:.3f} (p={pvalue:.4f})')

    mean_llm = sum(llm_scores) / len(llm_scores)
    mean_human = sum(human_scores) / len(human_scores)
    bias = mean_llm - mean_human
    print(f'LLM bias vs humans: {bias:+.3f}')
    return correlation, bias

Setting Metric Targets for Production

Before deploying a RAG system to production, define minimum metric thresholds that the system must meet. Common production targets are: faithfulness > 0.90 (fewer than 10% of answer claims are hallucinated), answer relevance > 0.80 (80%+ of answers actually address the question), context precision > 0.60 (most retrieved chunks are relevant), and context recall > 0.75 (most key facts are available in retrieved context). Systems that fail these thresholds should not be deployed without further improvement.

PRODUCTION_THRESHOLDS = {
    'faithfulness': 0.90,
    'answer_relevancy': 0.80,
    'context_precision': 0.60,
    'context_recall': 0.75
}

def check_production_readiness(metrics):
    ready = True
    print('Production readiness check:')
    for metric, threshold in PRODUCTION_THRESHOLDS.items():
        score = metrics.get(metric, 0)
        status = 'PASS' if score >= threshold else 'FAIL'
        print(f'  {metric}: {score:.2f} (>= {threshold}) -> {status}')
        if status == 'FAIL':
            ready = False
    print(f'Overall: {"READY" if ready else "NOT READY"}')
    return ready

Quick Check

Test your understanding of AI Engineering concepts from this lesson.

Lesson Recap

In this lesson you learned: faithfulness as the claim-level metric checking whether every answer statement is supported by the retrieved context, answer relevance as the metric measuring whether the answer addresses the actual question, context recall and precision for measuring retrieval quality from the generation perspective, and the RAGAS library for automated multi-metric evaluation. Next up we assemble all these metrics into an automated evaluation harness you can run on every change.

常见问题解答

「生成指标:忠实度与答案相关性」课时是免费的吗?

是的 — 「生成指标:忠实度与答案相关性」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Engineering Academy 课程的其余内容,请升级到 CoddyKit PRO。 AI Engineering Academy 课程共包含 4 节课。

「生成指标:忠实度与答案相关性」这节课中我会学到什么?

使用 RAGAS 衡量生成的答案是否忠实于检索到的上下文,以及是否真正回答了用户的问题而没有产生幻觉。 你通过在浏览器中直接运行的动手代码来练习 AI Engineering Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Engineering Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Engineering Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「生成指标:忠实度与答案相关性」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Engineering Academy 课中编写并运行代码吗?

能。每节 AI Engineering Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 为什么 RAG 中的评估很重要
  2. 检索指标:命中率、MRR 与 NDCG
  3. 生成指标:忠实度与答案相关性
  4. 构建自动化评估工具
← 返回 AI Engineering Academy