跳转至

第4章:RAG评估基础

如何知道你的RAG系统好不好?本章将带你建立完整的评估体系,用科学的方法衡量和改进RAG系统。


📚 学习目标

学完本章后,你将能够:

  • 理解RAG评估的重要性和评估维度
  • 实现检索质量评估指标(Hit Rate、MRR)
  • 实现生成质量评估指标(Faithfulness、Relevancy)
  • 使用RAGAS评估框架
  • 建立自动化的评估流程
  • 基于评估结果优化RAG系统

预计学习时间:1.5小时 难度等级:⭐⭐☆☆☆


前置知识

在开始本章学习前,你需要:

  • 完成第3章,有一个可运行的RAG系统
  • 理解向量检索的基本原理
  • 了解基础的统计指标概念

环境要求: - 已安装RAG系统 - 需要额外的评估库:ragas


4.1 为什么需要评估?

评估的重要性

问题:感觉好 ≠ 实际好

开发者视角:
  "我的RAG系统看起来工作正常!"
  → 偶尔测试几次,觉得还行

用户视角:
  "为什么总是找不到相关内容?"
  → 实际使用时频繁遇到问题

需要科学的评估方法

评估的目的

  1. 量化性能:用数字说话,不是靠感觉
  2. 发现瓶颈:找出系统的薄弱环节
  3. 指导优化:知道该改进什么
  4. 对比方案:客观比较不同技术
  5. 持续监控:确保系统稳定运行

RAG评估的三个维度

┌─────────────────────────────────────────┐
│          RAG评估维度                     │
├─────────────────────────────────────────┤
│                                         │
│  1. 检索质量 (Retrieval Quality)       │
│     - 找到的文档是否相关?              │
│     - 相关文档是否排在前面?            │
│     指标:Hit Rate, MRR, Precision@K    │
│                                         │
│  2. 生成质量 (Generation Quality)      │
│     - 答案是否准确?                    │
│     - 是否基于检索文档?                │
│     指标:Faithfulness, Relevancy       │
│                                         │
│  3. 系统性能 (System Performance)      │
│     - 响应速度如何?                    │
│     - 能处理多少请求?                  │
│     指标:延迟, QPS, 成本               │
│                                         │
└─────────────────────────────────────────┘

4.2 检索质量评估

Hit Rate(命中率)

定义

Hit Rate:至少检索到一个相关文档的查询占比

Hit Rate = 有相关结果的查询数 / 总查询数

计算

# 文件名:04_01_hit_rate.py
"""
Hit Rate计算示例
"""

def calculate_hit_rate(queries, retrieved_docs, relevant_docs):
    """
    计算Hit Rate

    Args:
        queries: 查询列表
        retrieved_docs: 检索到的文档列表(每个查询的top-k结果)
        relevant_docs: 真实相关文档列表

    Returns:
        hit_rate: 命中率
    """
    hits = 0

    for query_id, retrieved in enumerate(retrieved_docs):
        # 获取该查询的真实相关文档
        relevant = set(relevant_docs[query_id])

        # 检查检索结果中是否有至少一个相关文档
        if any(doc_id in relevant for doc_id in retrieved):
            hits += 1

    hit_rate = hits / len(queries)
    return hit_rate

# 示例
if __name__ == "__main__":
    # 示例数据
    queries = ["Q1", "Q2", "Q3", "Q4", "Q5"]

    # 检索结果(每个查询的top-3文档ID)
    retrieved_docs = [
        [1, 5, 8],    # Q1的结果
        [2, 6, 9],    # Q2的结果
        [3, 7, 10],   # Q3的结果
        [4, 8, 12],   # Q4的结果
        [5, 9, 13]    # Q5的结果
    ]

    # 真实相关文档
    relevant_docs = [
        {1, 8},      # Q1的相关文档
        {6},         # Q2的相关文档
        {11, 12},    # Q3的相关文档
        {4, 15},     # Q4的相关文档
        {9, 13}      # Q5的相关文档
    ]

    # 计算Hit Rate
    hit_rate = calculate_hit_rate(queries, retrieved_docs, relevant_docs)

    print("Hit Rate计算示例")
    print("="*50)
    for i, (retrieved, relevant) in enumerate(zip(retrieved_docs, relevant_docs), 1):
        hit = any(doc in relevant for doc in retrieved)
        status = "✓" if hit else "✗"
        print(f"Q{i}: {status} 检索={retrieved}, 相关={relevant}")

    print(f"\nHit Rate: {hit_rate:.2%}")
    print(f"解释: {hit_rate:.0%}的查询至少检索到一个相关文档")

基准值

Hit Rate 评级 说明
< 0.5 需要大幅改进
0.5 - 0.7 基本可用
0.7 - 0.85 良好 表现不错
> 0.85 优秀 达到生产标准

MRR(Mean Reciprocal Rank)

定义

MRR:平均倒数排名,衡量第一个相关文档的平均排名

MRR = (1 / 第一个相关文档的排名) 的平均值

计算

def calculate_mrr(retrieved_docs, relevant_docs):
    """
    计算MRR

    Args:
        retrieved_docs: 检索结果
        relevant_docs: 真实相关文档

    Returns:
        mrr: 平均倒数排名
    """
    reciprocal_ranks = []

    for retrieved, relevant in zip(retrieved_docs, relevant_docs):
        # 找到第一个相关文档的位置
        for rank, doc_id in enumerate(retrieved, 1):
            if doc_id in relevant:
                reciprocal_ranks.append(1 / rank)
                break
        else:
            # 没有找到相关文档
            reciprocal_ranks.append(0)

    mrr = sum(reciprocal_ranks) / len(reciprocal_ranks)
    return mrr

# 示例
if __name__ == "__main__":
    retrieved_docs = [
        [1, 5, 8],    # Q1:相关文档是1,排第1
        [2, 6, 9],    # Q2:相关文档是6,排第2
        [3, 7, 10],   # Q3:相关文档是11,不在结果中
        [4, 8, 12],   # Q4:相关文档是4,排第1
        [5, 9, 13]    # Q5:相关文档是13,排第3
    ]

    relevant_docs = [
        {1},         # Q1
        {6},         # Q2
        {11},        # Q3
        {4},         # Q4
        {13}         # Q5
    ]

    mrr = calculate_mrr(retrieved_docs, relevant_docs)

    print("\nMRR计算示例")
    print("="*50)
    print(f"Q1: 相关文档排第1 → 1/1 = 1.000")
    print(f"Q2: 相关文档排第2 → 1/2 = 0.500")
    print(f"Q3: 相关文档未检索到 → 0.000")
    print(f"Q4: 相关文档排第1 → 1/1 = 1.000")
    print(f"Q5: 相关文档排第3 → 1/3 = 0.333")
    print(f"\nMRR: (1.0 + 0.5 + 0.0 + 1.0 + 0.333) / 5 = {mrr:.3f}")

基准值

MRR 评级 说明
< 0.3 相关文档排名靠后
0.3 - 0.5 相关文档在中游
0.5 - 0.7 良好 相关文档靠前
> 0.7 优秀 相关文档通常在前3

Precision@K

定义

Precision@K:前K个结果中相关文档的比例

def calculate_precision_at_k(retrieved_docs, relevant_docs, k=5):
    """
    计算Precision@K

    Args:
        retrieved_docs: 检索结果
        relevant_docs: 真实相关文档
        k: 前K个结果

    Returns:
        precision_at_k: 精确率
    """
    precisions = []

    for retrieved, relevant in zip(retrieved_docs, relevant_docs):
        # 取前K个结果
        top_k = retrieved[:k]

        # 计算相关文档数量
        relevant_count = sum(1 for doc in top_k if doc in relevant)

        # 精确率
        precision = relevant_count / k
        precisions.append(precision)

    avg_precision = sum(precisions) / len(precisions)
    return avg_precision

完整检索评估框架

# 文件名:04_02_retrieval_eval.py
"""
完整的检索评估框架
"""

class RetrievalEvaluator:
    """检索质量评估器"""

    def __init__(self):
        self.metrics = {}

    def evaluate(self, queries, retrieved_docs, relevant_docs):
        """
        全面评估检索质量

        Args:
            queries: 查询列表
            retrieved_docs: 检索结果
            relevant_docs: 真实相关文档

        Returns:
            评估指标字典
        """
        results = {
            "hit_rate": self.calculate_hit_rate(retrieved_docs, relevant_docs),
            "mrr": self.calculate_mrr(retrieved_docs, relevant_docs),
            "precision_at_1": self.calculate_precision_at_k(retrieved_docs, relevant_docs, k=1),
            "precision_at_3": self.calculate_precision_at_k(retrieved_docs, relevant_docs, k=3),
            "precision_at_5": self.calculate_precision_at_k(retrieved_docs, relevant_docs, k=5),
        }

        self.metrics = results
        return results

    def calculate_hit_rate(self, retrieved_docs, relevant_docs):
        """计算Hit Rate"""
        hits = sum(
            1 for retrieved, relevant in zip(retrieved_docs, relevant_docs)
            if any(doc in relevant for doc in retrieved)
        )
        return hits / len(retrieved_docs)

    def calculate_mrr(self, retrieved_docs, relevant_docs):
        """计算MRR"""
        reciprocal_ranks = []
        for retrieved, relevant in zip(retrieved_docs, relevant_docs):
            for rank, doc in enumerate(retrieved, 1):
                if doc in relevant:
                    reciprocal_ranks.append(1 / rank)
                    break
            else:
                reciprocal_ranks.append(0)
        return sum(reciprocal_ranks) / len(reciprocal_ranks)

    def calculate_precision_at_k(self, retrieved_docs, relevant_docs, k):
        """计算Precision@K"""
        precisions = []
        for retrieved, relevant in zip(retrieved_docs, relevant_docs):
            top_k = retrieved[:k]
            relevant_count = sum(1 for doc in top_k if doc in relevant)
            precisions.append(relevant_count / k)
        return sum(precisions) / len(precisions)

    def print_report(self):
        """打印评估报告"""
        print("\n" + "="*60)
        print("检索质量评估报告")
        print("="*60)

        for metric, value in self.metrics.items():
            # 格式化指标名称
            metric_name = metric.replace("_", " ").title()
            # 格式化值
            if isinstance(value, float):
                print(f"{metric_name:20s}: {value:.3f}")
            else:
                print(f"{metric_name:20s}: {value}")

        print("="*60)

        # 评级
        hit_rate = self.metrics.get("hit_rate", 0)
        mrr = self.metrics.get("mrr", 0)

        if hit_rate > 0.85 and mrr > 0.7:
            rating = "优秀 ⭐⭐⭐⭐⭐"
        elif hit_rate > 0.7 and mrr > 0.5:
            rating = "良好 ⭐⭐⭐⭐"
        elif hit_rate > 0.5 and mrr > 0.3:
            rating = "中等 ⭐⭐⭐"
        else:
            rating = "需要改进 ⭐⭐"

        print(f"综合评级: {rating}")

# 使用示例
if __name__ == "__main__":
    # 示例数据
    queries = [f"Q{i}" for i in range(1, 11)]

    # 模拟检索结果(文档ID)
    retrieved_docs = [
        [1, 5, 8, 12, 15],
        [2, 6, 9, 13, 16],
        [3, 7, 10, 14, 17],
        [4, 8, 11, 15, 18],
        [5, 9, 12, 16, 19],
        [1, 6, 11, 16, 20],
        [2, 7, 12, 17, 21],
        [3, 8, 13, 18, 22],
        [4, 9, 14, 19, 23],
        [5, 10, 15, 20, 24]
    ]

    # 真实相关文档
    relevant_docs = [
        {1, 8},
        {6, 13},
        {3},
        {15},
        {9},
        {1, 11},
        {2, 17},
        {8, 13},
        {14},
        {20}
    ]

    # 评估
    evaluator = RetrievalEvaluator()
    metrics = evaluator.evaluate(queries, retrieved_docs, relevant_docs)

    # 打印报告
    evaluator.print_report()

4.3 生成质量评估

Faithfulness(忠实度)

定义

答案是否基于检索到的文档,而不是LLM编造的。

评估方法

# 文件名:04_03_faithfulness.py
"""
Faithfulness评估示例
"""

from openai import OpenAI

def evaluate_faithfulness(answer, context_documents):
    """
    评估答案的忠实度

    Args:
        answer: RAG生成的答案
        context_documents: 检索到的上下文文档

    Returns:
        faithfulness_score: 忠实度分数 (0-1)
    """
    client = OpenAI()

    # 构建评估提示词
    context = "\n\n".join([
        f"文档{i+1}: {doc}"
        for i, doc in enumerate(context_documents)
    ])

    prompt = f"""
请评估以下答案是否基于提供的参考文档。

参考文档:
{context}

答案:
{answer}

请评估:
1. 答案中的所有声明是否都能在参考文档中找到支持?
2. 答案是否没有添加文档中不存在的信息?

评分标准:
- 1.0: 完全基于文档,无编造
- 0.7-0.9: 大部分基于文档,有少量合理推断
- 0.4-0.6: 部分基于文档,有明显添加信息
- 0.1-0.3: 大量编造信息
- 0.0: 完全不基于文档

请只返回一个0-1之间的分数,保留两位小数。
"""

    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一个专业的评估助手。"},
            {"role": "user", "content": prompt}
        ],
        temperature=0
    )

    # 提取分数
    score_text = response.choices[0].message.content.strip()
    try:
        score = float(score_text)
        return max(0, min(1, score))  # 确保在0-1之间
    except ValueError:
        # 如果返回的不是纯数字,尝试提取
        import re
        numbers = re.findall(r'0\.\d+', score_text)
        if numbers:
            return float(numbers[0])
        return 0.5  # 默认分数

# 示例
if __name__ == "__main__":
    # 示例文档
    context = [
        "Python是一种高级编程语言,由Guido van Rossum于1991年创建。",
        "Python的特点是语法简洁、易学易用,适合初学者。"
    ]

    # 测试不同质量的答案
    test_cases = [
        {
            "name": "完全忠实",
            "answer": "Python由Guido van Rossum于1991年创建,它的特点是语法简洁、易学易用。"
        },
        {
            "name": "大部分忠实",
            "answer": "Python是一种高级编程语言,由Guido创建,它非常适合数据科学和Web开发。"
        },
        {
            "name": "部分编造",
            "answer": "Python是Google开发的编程语言,发布于2000年,主要用于人工智能领域。"
        },
        {
            "name": "完全编造",
            "answer": "Java是一种脚本语言,主要用于前端开发,语法非常复杂难学。"
        }
    ]

    print("Faithfulness评估示例")
    print("="*60 + "\n")

    for test in test_cases:
        score = evaluate_faithfulness(test["answer"], context)
        print(f"{test['name']:15s}: {score:.2f}")
        print(f"  答案: {test['answer']}")
        print()

Relevancy(相关性)

定义

答案是否真正回答了用户的问题

评估方法

def evaluate_relevancy(question, answer):
    """
    评估答案的相关性

    Args:
        question: 用户问题
        answer: RAG生成的答案

    Returns:
        relevancy_score: 相关性分数 (0-1)
    """
    client = OpenAI()

    prompt = f"""
请评估以下答案是否真正回答了用户的问题。

用户问题:
{question}

答案:
{answer}

评估标准:
- 1.0: 完全回答了问题,信息充分准确
- 0.7-0.9: 很好地回答了问题,略有不足
- 0.4-0.6: 部分回答了问题,信息不完整
- 0.1-0.3: 基本没有回答问题
- 0.0: 完全不相关

请只返回一个0-1之间的分数,保留两位小数。
"""

    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": "你是一个专业的评估助手。"},
            {"role": "user", "content": prompt}
        ],
        temperature=0
    )

    score_text = response.choices[0].message.content.strip()
    try:
        score = float(score_text)
        return max(0, min(1, score))
    except ValueError:
        import re
        numbers = re.findall(r'0\.\d+', score_text)
        if numbers:
            return float(numbers[0])
        return 0.5

使用RAGAS评估框架

RAGAS是一个专门的RAG评估库,提供标准化的评估指标。

安装RAGAS

pip install ragas

使用RAGAS评估

# 文件名:04_04_ragas_eval.py
"""
使用RAGAS框架评估
"""

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

def evaluate_with_ragas(questions, answers, contexts, ground_truths=None):
    """
    使用RAGAS评估

    Args:
        questions: 问题列表
        answers: RAG生成的答案列表
        contexts: 检索到的上下文列表
        ground_truths: 真实答案列表(可选)

    Returns:
        评估结果
    """
    # 准备数据
    data = {
        "question": questions,
        "answer": answers,
        "contexts": contexts,
    }

    if ground_truths:
        data["ground_truth"] = ground_truths

    dataset = Dataset.from_dict(data)

    # 选择评估指标
    metrics = [
        faithfulness,
        answer_relevancy,
        context_precision
    ]

    # 运行评估
    results = evaluate(
        dataset=dataset,
        metrics=metrics
    )

    return results

# 示例
if __name__ == "__main__":
    # 示例数据
    questions = [
        "Python是什么时候创建的?",
        "Python有什么特点?"
    ]

    answers = [
        "Python由Guido van Rossum于1991年创建。",
        "Python的特点是语法简洁、易学易用。"
    ]

    contexts = [
        ["Python是一种高级编程语言,由Guido van Rossum于1991年创建。"],
        ["Python的特点是语法简洁、易学易用,适合初学者。"]
    ]

    # 评估
    print("使用RAGAS评估")
    print("="*60 + "\n")

    results = evaluate_with_ragas(questions, answers, contexts)

    # 打印结果
    print(results.to_pandas())

4.4 建立评估基线

黄金数据集创建

什么是黄金数据集?

人工标注的高质量问答对,作为评估的"标准答案"。

创建步骤

# 文件名:04_05_golden_dataset.py
"""
创建黄金数据集
"""

import json
from typing import List, Dict

class GoldenDatasetBuilder:
    """黄金数据集构建器"""

    def __init__(self, output_path="data/eval/golden_dataset.json"):
        self.output_path = output_path
        self.dataset = []

    def add_example(self, question: str, answer: str, context: str, metadata: dict = None):
        """
        添加一个示例

        Args:
            question: 问题
            answer: 标准答案
            context: 相关上下文
            metadata: 元数据
        """
        example = {
            "question": question,
            "answer": answer,
            "context": context,
            "metadata": metadata or {}
        }
        self.dataset.append(example)

    def save(self):
        """保存数据集"""
        import os
        os.makedirs(os.path.dirname(self.output_path), exist_ok=True)

        with open(self.output_path, 'w', encoding='utf-8') as f:
            json.dump(self.dataset, f, ensure_ascii=False, indent=2)

        print(f"✓ 保存了 {len(self.dataset)} 个示例到 {self.output_path}")

    def load(self):
        """加载数据集"""
        with open(self.output_path, 'r', encoding='utf-8') as f:
            self.dataset = json.load(f)
        return self.dataset

# 创建示例数据集
if __name__ == "__main__":
    builder = GoldenDatasetBuilder()

    # 添加示例(基于我们的测试文档)
    examples = [
        {
            "question": "Python是什么时候创建的?",
            "answer": "Python由Guido van Rossum于1991年创建。",
            "context": "Python是一种高级编程语言,由Guido van Rossum于1991年创建。",
            "metadata": {"topic": "Python历史", "difficulty": "easy"}
        },
        {
            "question": "Python有哪些特点?",
            "answer": "Python的特点是语法简洁、易学易用,适合初学者。",
            "context": "Python的特点是语法简洁、易学易用,适合初学者。",
            "metadata": {"topic": "Python特点", "difficulty": "easy"}
        },
        {
            "question": "JavaScript主要用于什么?",
            "answer": "JavaScript主要用于Web前端开发。",
            "context": "JavaScript是一种脚本语言,主要用于Web前端开发。",
            "metadata": {"topic": "JavaScript", "difficulty": "easy"}
        },
        {
            "question": "Rust如何保证内存安全?",
            "answer": "Rust通过所有权系统在编译时保证内存安全,不需要垃圾回收。",
            "context": "Rust是一种系统编程语言,注重内存安全、并发和性能。它没有垃圾回收,而是通过所有权系统在编译时保证内存安全。",
            "metadata": {"topic": "Rust", "difficulty": "medium"}
        }
    ]

    for example in examples:
        builder.add_example(**example)

    # 保存
    builder.save()

    print("\n黄金数据集创建完成!")
    print(f"包含 {len(builder.dataset)} 个问答对")

自动化评估流程

# 文件名:04_06_auto_eval.py
"""
自动化RAG评估流程
"""

from golden_dataset import GoldenDatasetBuilder
from retrieval_eval import RetrievalEvaluator
from ragas_eval import evaluate_with_ragas
from rag_system import SimpleRAG

class AutoEvaluator:
    """自动化评估器"""

    def __init__(self, rag_system, golden_dataset_path):
        """
        初始化评估器

        Args:
            rag_system: RAG系统实例
            golden_dataset_path: 黄金数据集路径
        """
        self.rag = rag_system
        self.dataset = self.load_dataset(golden_dataset_path)

    def load_dataset(self, path):
        """加载黄金数据集"""
        builder = GoldenDatasetBuilder(path)
        return builder.load()

    def run_evaluation(self):
        """运行完整评估"""
        print("="*70)
        print("自动化RAG评估")
        print("="*70 + "\n")

        # 1. 准备数据
        questions = [item["question"] for item in self.dataset]
        ground_truths = [item["answer"] for item in self.dataset]

        # 2. 运行RAG系统
        print("步骤1: 运行RAG系统生成答案\n")
        rag_answers = []
        retrieved_contexts = []

        for question in questions:
            response = self.rag.query(question)
            rag_answers.append(str(response))
            # 假设response包含检索到的上下文
            retrieved_contexts.append([response.source_nodes[0].text])

        # 3. 评估生成质量
        print("步骤2: 评估生成质量(使用RAGAS)\n")
        generation_scores = evaluate_with_ragas(
            questions,
            rag_answers,
            retrieved_contexts,
            ground_truths
        )

        # 4. 评估检索质量
        print("步骤3: 评估检索质量\n")
        # 这里需要额外的真实相关文档标注
        # 简化示例:假设第一个检索到的文档是相关的
        retrieval_evaluator = RetrievalEvaluator()
        retrieval_scores = retrieval_evaluator.evaluate(
            questions,
            [[0] for _ in questions],  # 简化
            [set() for _ in questions]  # 简化
        )

        # 5. 综合报告
        self.print_report(generation_scores, retrieval_scores)

    def print_report(self, generation_scores, retrieval_scores):
        """打印综合报告"""
        print("\n" + "="*70)
        print("评估报告")
        print("="*70 + "\n")

        print("生成质量:")
        for metric, value in generation_scores.items():
            print(f"  {metric}: {value:.3f}")

        print("\n检索质量:")
        for metric, value in retrieval_scores.items():
            print(f"  {metric}: {value:.3f}")

        print("\n" + "="*70)

# 使用示例
if __name__ == "__main__":
    # 创建RAG系统
    rag = SimpleRAG()
    documents = rag.load_documents()
    rag.build_index(documents)

    # 运行评估
    evaluator = AutoEvaluator(rag, "data/eval/golden_dataset.json")
    evaluator.run_evaluation()

总结

本章要点回顾

  1. 评估的重要性:用科学方法衡量RAG系统
  2. 检索质量评估:Hit Rate、MRR、Precision@K
  3. 生成质量评估:Faithfulness、Relevancy
  4. RAGAS框架:使用标准化工具评估
  5. 建立评估基线:创建黄金数据集和自动化流程

学习检查清单

  • 理解RAG评估的三个维度
  • 能够计算Hit Rate和MRR
  • 掌握Faithfulness评估方法
  • 会使用RAGAS框架
  • 创建了黄金数据集
  • 建立了自动化评估流程

下一步学习

扩展练习

  1. 基础练习
  2. 为你的RAG系统创建黄金数据集
  3. 计算Hit Rate和MRR
  4. 使用RAGAS评估

  5. 进阶练习

  6. 实现更多的评估指标
  7. 可视化评估结果
  8. 建立持续评估流程

  9. 挑战项目

  10. 对比不同分块策略的评估结果
  11. 优化你的RAG系统直到达到优秀标准

术语表

术语 英文 定义
Hit Rate 命中率 至少检索到一个相关文档的查询占比
MRR Mean Reciprocal Rank 平均倒数排名
Precision@K 精确率@K 前K个结果中相关文档的比例
Faithfulness 忠实度 答案基于文档的程度
Relevancy 相关性 答案与问题的相关程度
黄金数据集 Golden Dataset 人工标注的高质量问答对

返回目录 | 上一章:基础RAG实现 | 下一章:模块1总结与项目


本章结束

评估是改进的基础。没有评估,我们就像在黑暗中摸索。现在你有了科学的评估方法,可以自信地衡量和优化你的RAG系统了!