Skip to content

Latest commit

 

History

History
940 lines (773 loc) · 30.5 KB

File metadata and controls

940 lines (773 loc) · 30.5 KB

RAG评估指标 - 完整指南

🎯 概述

dingo 的 RAG 评估指标系统基于 RAGAS 论文、DeepEval 和 TruLens 的最佳实践,提供完整的 RAG 系统评估能力。

✅ 支持的指标 (5/5)

指标 评估维度 需要字段 论文来源
Faithfulness 答案忠实度 user_input, response, retrieved_contexts RAGAS
Answer Relevancy 答案相关性 user_input, response RAGAS
Context Relevancy 上下文相关性 user_input, retrieved_contexts RAGAS + DeepEval + TruLens
Context Recall 上下文召回 user_input, retrieved_contexts, reference RAGAS
Context Precision 上下文精度 user_input, retrieved_contexts, reference RAGAS

🚀 快速开始

1. 运行示例

# Dataset方式 - 批量评估baseline(推荐)
python examples/rag/dataset_rag_eval_baseline.py

# SDK方式 - 单个评估
python examples/rag/sdk_rag_eval.py

# 模拟RAG系统并评估
python examples/rag/e2e_RAG_eval_with_mockRAG_fiqa.py

2. SDK方式 - 单个评估

import os
from dingo.config.input_args import EvaluatorLLMArgs, EmbeddingConfigArgs
from dingo.io.input import Data
from dingo.model.llm.rag.llm_rag_faithfulness import LLMRAGFaithfulness

# 配置LLM
LLMRAGFaithfulness.dynamic_config = EvaluatorLLMArgs(
    key=os.getenv("OPENAI_API_KEY"),
    api_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"),
    model=os.getenv("OPENAI_MODEL", "deepseek-chat"),
)

# 准备数据
data = Data(
    data_id="example_1",
    prompt="什么是机器学习?",
    content="机器学习是人工智能的一个分支,使计算机能够从数据中学习。",
    context=[
        "机器学习是AI的子领域。",
        "ML系统从数据中学习而无需明确编程。"
    ]
)

# 评估
result = LLMRAGFaithfulness.eval(data)

# 查看结果
print(f"分数: {result.score}/10")
print(f"通过: {not result.status}")  # status=False 表示通过
print(f"理由: {result.reason[0]}")

3. Dataset方式 - 批量评估

from dingo.config import InputArgs
from dingo.exec import Executor
from pathlib import Path
import os

# 配置
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
OPENAI_URL = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
OPENAI_KEY = os.getenv("OPENAI_API_KEY", "YOUR_API_KEY")
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-3-large")

input_data = {
    "task_name": "rag_evaluation",
    "input_path": str(Path("test/data/fiqa.jsonl")),
    "output_path": "outputs/rag_results/",
    "dataset": {
        "source": "local",
        "format": "jsonl"
    },
    "executor": {
        "max_workers": 1,
        "result_save": {
            "good": True,
            "bad": True,
            "all_labels": True
        }
    },
    "evaluator": [
        {
            "fields": {
                "prompt": "user_input",
                "content": "response",
                "context": "retrieved_contexts",
                "reference": "reference"
            },
            "evals": [
                {
                    "name": "LLMRAGFaithfulness",
                    "config": {
                        "model": OPENAI_MODEL,
                        "key": OPENAI_KEY,
                        "api_url": OPENAI_URL
                    }
                },
                {
                    "name": "LLMRAGAnswerRelevancy",
                    "config": {
                        "model": OPENAI_MODEL,
                        "key": OPENAI_KEY,
                        "api_url": OPENAI_URL,
                        "embedding_config": {  # ⭐ 必需配置
                            "model": EMBEDDING_MODEL,
                            "api_url": OPENAI_URL,
                            "key": OPENAI_KEY
                        },
                        "strictness": 3,
                        "threshold": 5
                    }
                },
                {
                    "name": "LLMRAGContextRelevancy",
                    "config": {
                        "model": OPENAI_MODEL,
                        "key": OPENAI_KEY,
                        "api_url": OPENAI_URL
                    }
                },
                {
                    "name": "LLMRAGContextRecall",
                    "config": {
                        "model": OPENAI_MODEL,
                        "key": OPENAI_KEY,
                        "api_url": OPENAI_URL
                    }
                },
                {
                    "name": "LLMRAGContextPrecision",
                    "config": {
                        "model": OPENAI_MODEL,
                        "key": OPENAI_KEY,
                        "api_url": OPENAI_URL
                    }
                }
            ]
        }
    ]
}

input_args = InputArgs(**input_data)
executor = Executor.exec_map["local"](input_args)
summary = executor.execute()

# 查看结果(需要指定字段组)
field_key = "user_input,response,retrieved_contexts,reference"
print(f"总平均分: {summary.get_metrics_score_overall_average(field_key)}")
print(f"各指标平均分: {summary.get_metrics_score_summary(field_key)}")

📋 数据格式

必需字段

每个指标需要不同的字段(使用 Dingo 框架的字段名):

指标 user_input (问题) response (答案) retrieved_contexts (上下文) reference (参考答案) 说明
Faithfulness - 衡量答案是否完全基于检索到的上下文,避免幻觉
Answer Relevancy - - 衡量答案是否直接回答用户问题,不需要上下文
Context Relevancy - - 衡量检索到的上下文是否与问题相关
Context Recall - 衡量是否检索到了所有需要的信息(需要参考答案)
Context Precision - 衡量检索结果的排序质量,相关文档是否在前面(需要参考答案)

字段映射说明

  • user_input = prompt = question:用户问题
  • response = content = answer:RAG 系统生成的答案
  • retrieved_contexts = context = contexts:检索到的上下文列表
  • reference = expected_output = ground_truth:标准答案/参考答案

数据示例 (SDK方式)

SDK 方式使用 Data 对象,字段名为:prompt, content, context, reference

from dingo.io.input import Data

# Faithfulness (需要: prompt, content, context)
data = Data(
    data_id="example_1",
    prompt="什么是深度学习?",  # user_input
    content="深度学习是机器学习的子领域,使用多层神经网络。",  # response
    context=[  # retrieved_contexts
        "深度学习使用多层神经网络...",
        "深度学习在图像识别中很有用..."
    ]
)

# Answer Relevancy (需要: prompt, content)
data = Data(
    data_id="example_2",
    prompt="什么是机器学习?",
    content="机器学习是AI的分支,让计算机从数据中学习。"
    # 不需要 context
)

# Context Relevancy (需要: prompt, context)
data = Data(
    data_id="example_3",
    prompt="机器学习有哪些应用?",
    context=[
        "机器学习用于图像识别。",  # 相关
        "区块链是分布式技术。",  # 不相关
    ]
    # 不需要 content
)

# Context Recall (需要: prompt, context, reference)
data = Data(
    data_id="example_4",
    prompt="Python的特点?",
    context=[
        "Python以其简洁的语法著称。",
        # 缺少关于库的信息,召回率会低
    ],
    reference="Python简洁且有丰富的库。"  # 参考答案
)

# Context Precision (需要: prompt, context, reference)
data = Data(
    data_id="example_5",
    prompt="深度学习的应用?",
    context=[
        "深度学习用于图像识别。",  # 相关,排序第1
        "区块链是分布式技术。",  # 不相关,排序第2
        "深度学习用于NLP。"  # 相关,排序第3(应该排前面)
    ],
    reference="深度学习在图像识别和NLP中广泛应用。"
)

数据示例 (Dataset方式 - JSONL)

Dataset 方式使用 JSONL 文件,推荐字段名为:user_input, response, retrieved_contexts, reference

{"user_input": "什么是深度学习?", "response": "深度学习使用神经网络...", "retrieved_contexts": ["深度学习是ML的子领域...", "深度学习用于图像识别..."]}
{"user_input": "Python的特点?", "response": "Python简洁且有丰富的库。", "retrieved_contexts": ["Python语法简洁。", "Python有NumPy等库。"], "reference": "Python语法简洁,生态系统丰富。"}

字段映射配置

"fields": {
    "prompt": "user_input",           # 问题
    "content": "response",            # RAG生成的答案
    "context": "retrieved_contexts",  # 检索的上下文
    "reference": "reference"          # 标准答案(可选)
}

🎨 输出格式

SDK 方式输出

评估结果包含:

result = LLMRAGFaithfulness.eval(data)

# 基本信息 (EvalDetail 对象)
result.metric                    # 指标名称 (如 "LLMRAGFaithfulness")
result.score                     # 分数 (0-10,浮点数)
result.status                    # 是否未通过 (True=未通过, False=通过)
result.label                     # 标签列表 (如 ["QUALITY_GOOD.FAITHFULNESS_PASS"])
result.reason                    # 评估理由列表 (如 ["答案完全基于上下文..."])

# 示例
print(f"指标: {result.metric}")
print(f"分数: {result.score}/10")
print(f"通过: {not result.status}")  # status=False 表示通过
print(f"标签: {result.label}")
print(f"理由: {result.reason}")

输出示例

# 通过的情况
result.metric = "LLMRAGFaithfulness"
result.score = 9.2
result.status = False  # False 表示通过
result.label = ["QUALITY_GOOD.FAITHFULNESS_PASS"]
result.reason = ["答案完全基于上下文,未发现幻觉。所有陈述都有支持。"]

# 未通过的情况
result.metric = "LLMRAGFaithfulness"
result.score = 3.5
result.status = True  # True 表示未通过
result.label = ["QUALITY_BAD.FAITHFULNESS_FAIL"]
result.reason = ["答案中包含未被上下文支持的陈述:'Python是第一个面向对象语言'"]

Dataset 方式输出

执行完成后会生成 summary.json,包含:

注意:指标分数统计功能支持 localspark 两种执行器。

{
  "task_name": "rag_evaluation",
  "total": 30,
  "num_good": 28,
  "num_bad": 2,
  "score": 93.3,
  "type_ratio": {
    "user_input,response,retrieved_contexts,reference": {
      "good": 0.933333,
      "bad": 0.066667
    }
  },
  "metrics_score": {
    "user_input,response,retrieved_contexts,reference": {
      "stats": {
        "LLMRAGFaithfulness": {
          "score_average": 8.36,
          "score_count": 30,
          "score_min": 1.67,
          "score_max": 10.0,
          "score_std_dev": 2.53
        },
        "LLMRAGContextPrecision": {
          "score_average": 9.67,
          "score_count": 30,
          "score_min": 0.0,
          "score_max": 10.0,
          "score_std_dev": 1.8
        },
        "LLMRAGContextRecall": {
          "score_average": 8.42,
          "score_count": 30,
          "score_min": 2.5,
          "score_max": 10.0,
          "score_std_dev": 2.61
        },
        "LLMRAGContextRelevancy": {
          "score_average": 9.0,
          "score_count": 30,
          "score_min": 0.0,
          "score_max": 10.0,
          "score_std_dev": 2.38
        },
        "LLMRAGAnswerRelevancy": {
          "score_average": 5.77,
          "score_count": 30,
          "score_min": 0.0,
          "score_max": 7.82,
          "score_std_dev": 2.09
        }
      },
      "summary": {
        "LLMRAGFaithfulness": 8.36,
        "LLMRAGContextPrecision": 9.67,
        "LLMRAGContextRecall": 8.42,
        "LLMRAGContextRelevancy": 9.0,
        "LLMRAGAnswerRelevancy": 5.77
      },
      "overall_average": 8.24
    }
  }
}

多字段组示例

{
  "metrics_score": {
    "user_input,response": {
      "stats": {...},
      "summary": {...},
      "overall_average": 7.8
    },
    "retrieved_contexts,reference": {
      "stats": {...},
      "summary": {...},
      "overall_average": 9.1
    }
  }
}

⚙️ 执行器支持

支持的执行器

指标分数统计功能支持以下执行器:

执行器 类型 指标统计 适用场景
Local 单机 ✅ 支持 小规模数据集,开发测试
Spark 分布式 ✅ 支持 大规模数据集,生产环境

Spark 执行器示例

from pyspark import SparkConf
from pyspark.sql import SparkSession
from dingo.config import InputArgs
from dingo.exec import Executor

# 初始化 Spark
spark_conf = SparkConf().setAppName("RAG_Evaluation").setMaster("local[*]")
spark = SparkSession.builder.config(conf=spark_conf).getOrCreate()

# 配置评估参数(与 Local 相同)
input_args = InputArgs.from_dict({
    "task_name": "rag_spark_evaluation",
    "input_path": "test/data/fiqa.jsonl",
    "evaluator": [...]  # 与 Local 相同的配置
})

# 创建 RDD
data_rdd = spark.sparkContext.parallelize(data_list)

# 使用 Spark 执行器
executor = Executor.exec_map["spark"](
    input_args=input_args,
    spark_rdd=data_rdd,
    spark_session=spark
)

# 执行评估
summary = executor.execute()

# 获取指标统计(输出格式与 Local 完全一致)
field_key = "user_input,response,retrieved_contexts,reference"
print(f"总平均分: {summary.get_metrics_score_overall_average(field_key)}")
print(f"各指标汇总: {summary.get_metrics_score_summary(field_key)}")

# to_dict() 也包含完整的 metrics_score 层级结构
result = summary.to_dict()
print(result['metrics_score'][field_key]['overall_average'])
print(result['metrics_score'][field_key]['summary'])

🔧 配置阈值和参数

SDK 方式配置

from dingo.config.input_args import EvaluatorLLMArgs

# 配置阈值(默认阈值为5)
LLMRAGFaithfulness.dynamic_config = EvaluatorLLMArgs(
    key="YOUR_API_KEY",
    api_url="https://api.openai.com/v1",
    model="gpt-4o-mini",
    threshold=7  # 自定义阈值
)

# Answer Relevancy 特殊配置(需要 embedding)⭐
# 注意:必须配置 embedding_config
LLMRAGAnswerRelevancy.dynamic_config = EvaluatorLLMArgs(
    key="YOUR_API_KEY",
    api_url="https://api.openai.com/v1",
    model="gpt-4o-mini",
    embedding_config=EmbeddingConfigArgs(  # ⭐ 必需
        model="text-embedding-3-large",
        api_url="https://api.openai.com/v1",
        key="YOUR_API_KEY"
    ),
    strictness=3,  # 生成问题数量
    threshold=5    # 通过阈值
)

Dataset 方式配置

"evaluator": [
    {
        "evals": [
            {
                "name": "LLMRAGFaithfulness",
                "config": {
                    "model": "gpt-4o-mini",
                    "key": "YOUR_API_KEY",
                    "api_url": "https://api.openai.com/v1",
                    "threshold": 7
                }
            },
            {
                "name": "LLMRAGAnswerRelevancy",
                "config": {
                    "model": "gpt-4o-mini",
                    "key": "YOUR_API_KEY",
                    "api_url": "https://api.openai.com/v1",
                    "embedding_config": {  # ⭐ 必需配置
                        "model": "text-embedding-3-large",
                        "api_url": "https://api.openai.com/v1",
                        "key": "YOUR_API_KEY"
                    },
                    "strictness": 3,
                    "threshold": 5
                }
            }
        ]
    }
]

可配置参数

参数 适用指标 默认值 说明
threshold 所有指标 5.0 通过阈值(0-10),直接在 config 中配置
strictness Answer Relevancy 3 生成问题数量(1-5),直接在 config 中配置
embedding_config Answer Relevancy - 必需配置,包含 model(模型名)、api_url(服务地址)、key(API密钥)

📊 指标详细说明

1️⃣ Faithfulness (答案忠实度)

评估目标: 衡量答案是否完全基于检索到的上下文,避免幻觉

计算方式:

  1. 将答案分解为独立的陈述(claims)
  2. 对每个陈述判断是否被上下文支持
  3. 忠实度分数 = (上下文支持的陈述数 / 总陈述数) × 10

计算公式

Faithfulness = (上下文支持的声明数 / 总声明数) × 10

输入要求:

  • user_input: 用户问题(生成答案时需要)
  • response: RAG系统生成的答案
  • retrieved_contexts: 检索到的上下文列表

评分标准:

  • 9-10分: 所有陈述都有上下文支持,无幻觉
  • 7-8分: 大部分陈述有支持,少量细节不够精确
  • 5-6分: 半数陈述有支持,存在一些未支持的陈述
  • 3-4分: 大量陈述缺乏支持,幻觉较多
  • 0-2分: 答案几乎完全是幻觉或编造

推荐阈值: 7 (满分10)

使用场景:

  • 检测RAG系统是否生成了虚假信息
  • 验证答案是否基于检索到的事实
  • 生产环境中最关键的指标,防止幻觉

2️⃣ Answer Relevancy (答案相关性)

评估目标: 衡量答案是否直接回答用户问题,不需要上下文

计算方式:

  1. 基于答案生成 N 个反向问题(由 LLM 从答案推断出的问题)
  2. 计算生成问题的 embedding 与原始问题 embedding 的余弦相似度
  3. 答案相关性 = 所有相似度的平均值

计算公式

Answer Relevancy = (1/N) × Σ cosine_sim(E_gi, E_o)

其中:
- N: 生成的问题数量,默认为 3(可通过 strictness 参数调整)
- E_gi: 第 i 个生成问题的 embedding(从 response 反推生成的问题的向量表示)
- E_o: 原始问题的 embedding
- 分子: 所有余弦相似度的总和,\sum 符号表示累加
- 分母: 生成的问题数量 N,用于计算平均值

输入要求:

  • user_input: 用户问题
  • response: RAG系统生成的答案

⚠️ 重要: 此指标必须配置 embedding_config,包含:

  • model: Embedding 模型名(如 text-embedding-3-largeBAAI/bge-m3
  • api_url: Embedding 服务地址
  • key: API 密钥(可选,本地服务可用任意值)

评分标准:

  • 9-10分: 生成的问题与原始问题高度相似,答案完全切题
  • 7-8分: 生成的问题基本匹配,答案相关性好
  • 5-6分: 部分生成问题相关,答案有一定相关性
  • 3-4分: 生成问题相关性较低,答案偏题明显
  • 0-2分: 答案完全不相关或跑题严重

推荐阈值: 5 (满分10)

使用场景:

  • 检测答案是否跑题或包含不必要的信息
  • 优化生成模型的回答质量
  • 确保答案直接回答用户问题

技术细节:

  • 使用 strictness 参数控制生成问题数量(默认3个)
  • 使用 threshold 参数设置通过阈值(默认5.0)
  • 必须embedding_config 中配置 embedding 服务:
    • 云端选项:OpenAI、DeepSeek 等
    • 本地选项:vLLM、Xinference 部署的 bge-m3、multilingual-e5 等

3️⃣ Context Relevancy (上下文相关性)

评估目标: 衡量检索到的上下文是否与问题相关

计算方式: 采用双评判系统(Dual-Judge) 来评估上下文与问题的相关性,这个方法来自 NVIDIA 的研究:

评判员1 评分(Judge 1)

  • 任务: 判断上下文是否包含回答问题所需的信息
  • 0 = 上下文完全不相关
  • 1 = 上下文部分相关
  • 2 = 上下文完全相关

评判员2 评分(Judge 2)

  • 使用不同的提示词表述,从另一个角度评估
  • 同样使用 0-2 的评分标准
  • 目的: 减少单一提示词的偏差

最终分数计算

Context Relevancy = (相关上下文数 / 总上下文数) × 10

其中:
- 相关上下文:两个评判员的平均分 ≥ 阈值(默认1.0)
- 不相关上下文:平均分 < 阈值

输入要求:

  • user_input: 用户问题
  • retrieved_contexts: 检索到的上下文列表

注意: 此指标不需要答案,纯粹评估检索系统的相关性

评分标准:

  • 9-10分: 所有上下文都与问题直接相关
  • 7-8分: 大部分上下文相关,少量不太相关
  • 5-6分: 半数上下文相关,存在明显噪声
  • 3-4分: 大量不相关上下文
  • 0-2分: 上下文几乎完全不相关

推荐阈值: 5 (满分10)

使用场景:

  • 纯粹评估检索系统本身的相关性
  • 不依赖答案,只关注问题和上下文的匹配度
  • 检测检索系统是否引入了噪声上下文

与 Context Precision 的区别:

  • Context Relevancy: 只看问题和上下文的匹配度,不需要答案
  • Context Precision: 需要参考答案,评估排序质量

4️⃣ Context Recall (上下文召回)

评估目标: 衡量是否检索到了所有需要的信息(需要参考答案)

计算方式:

  1. 从参考答案(reference)中提取独立陈述
  2. 对每个陈述判断是否能从检索到的上下文中归因
  3. 召回率 = (上下文支持的参考陈述数 / 参考中总陈述数) × 10

计算公式

Context Recall = (上下文支持的参考声明数 / 参考中总声明数) × 10

分子:retrieved_contexts 能支持的参考答案中的陈述数
分母:reference 中总声明数

输入要求:

  • user_input: 用户问题
  • retrieved_contexts: 检索到的上下文列表
  • reference: 参考答案/ground truth(必需)

评分标准:

  • 9-10分: 所有关键信息都能从上下文找到
  • 7-8分: 大部分信息被覆盖,少量细节缺失
  • 5-6分: 半数信息被覆盖,存在明显遗漏
  • 3-4分: 大量关键信息缺失
  • 0-2分: 上下文几乎不支持参考答案

推荐阈值: 5 (满分10)

使用场景:

  • 检测检索系统是否遗漏了重要信息
  • 评估检索的完整性
  • 评估阶段使用,需要标注的参考答案

注意:

  • 必须有参考答案(reference),通常用于评估阶段
  • 与 Faithfulness 相反:Faithfulness 防止多说(幻觉),Context Recall 防止少说(遗漏)

5️⃣ Context Precision (上下文精度)

评估目标: 衡量检索结果的排序质量,相关文档是否在前面(需要参考答案)

计算方式:

  1. 对每个位置 k 判断该上下文是否相关(是否支持参考答案)
  2. 计算每个位置的精度(Precision@k)
  3. 使用相关性指示器(v_k)加权求和

计算公式

Context Precision = Σ(Precision@k × v_k) / top K 中相关项总数

其中:
- K: 检索返回的总文档数,例如:5个文档
- k: 当前位置(第几个),1, 2, 3, ..., K
- v_k: 相关性指示器,0(不相关)或 1(相关)
- Precision@k: 前k个文档中的精确率,0.0 到 1.0
- Precision@k = 前k个文档中相关的数量 / k

输入要求:

  • user_input: 用户问题
  • retrieved_contexts: 检索到的上下文列表(有序)
  • reference: 参考答案(必需)

评分标准:

  • 9-10分: 所有相关上下文都排在前面,排序完美
  • 7-8分: 大部分相关上下文靠前,排序较好
  • 5-6分: 相关上下文分布不均,排序一般
  • 3-4分: 相关上下文靠后,排序较差
  • 0-2分: 排序完全混乱,不相关的排在前面

推荐阈值: 5 (满分10)

使用场景:

  • 评估检索系统的排序质量
  • 优化检索和排序算法
  • 确保相关文档排在前面(Top-K 优化)
  • 评估阶段使用,需要标注的参考答案

注意:

  • 必须有参考答案(reference),通过对比参考答案判断哪些上下文相关
  • 关注排序:相关的文档越靠前,分数越高
  • 与 Context Relevancy 的区别:Context Precision 关注排序,Context Relevancy 只关注相关性

🌟 最佳实践

1. 指标组合使用建议

完整评估 (5个指标):

"evals": [
    {"name": "LLMRAGFaithfulness"},       # 检测幻觉(答案是否忠实于上下文)
    {"name": "LLMRAGAnswerRelevancy"},    # 检测答案相关性(是否回答问题)
    {"name": "LLMRAGContextRelevancy"},   # 检测噪声上下文(上下文是否相关)
    {"name": "LLMRAGContextRecall"},      # 评估检索完整性(需要reference)
    {"name": "LLMRAGContextPrecision"}    # 评估检索排序质量(需要reference)
]

生产环境 (不需要 reference):

"evals": [
    {"name": "LLMRAGFaithfulness"},       # ⭐ 最重要:防止幻觉
    {"name": "LLMRAGAnswerRelevancy"},    # 确保答案直接回答问题
    {"name": "LLMRAGContextRelevancy"}    # 检测检索噪声
]

评估阶段 (需要 reference):

"evals": [
    {"name": "LLMRAGContextRecall"},      # 评估检索完整性(是否遗漏信息)
    {"name": "LLMRAGContextPrecision"}    # 评估检索排序质量(相关的是否靠前)
]

检索系统优化:

"evals": [
    {"name": "LLMRAGContextRelevancy"},   # 评估相关性(减少噪声)
    {"name": "LLMRAGContextRecall"},      # 评估完整性(减少遗漏)
    {"name": "LLMRAGContextPrecision"}    # 评估排序质量(优化Top-K)
]

2. 阈值调整建议

根据场景调整阈值(默认为5):

  • 严格场景(金融、医疗): 阈值 7-8
  • 一般场景(问答系统): 阈值 5-6
  • 宽松场景(探索性搜索): 阈值 3-4

3. 迭代优化流程

  1. 初始评估: 使用所有5个指标评估当前系统
  2. 识别问题:
    • Faithfulness 低 → 生成模型产生幻觉,答案不基于上下文
      • 优化方向:调整生成 prompt、使用更强的模型、增强事实检查
    • Answer Relevancy 低 → 答案跑题或包含无关信息
      • 优化方向:优化生成 prompt、限制答案长度、增强问题理解
    • Context Relevancy 低 → 检索引入了大量噪声
      • 优化方向:优化检索算法、调整相似度阈值、改进 embedding 模型
    • Context Recall 低 → 检索遗漏了重要信息
      • 优化方向:增加检索数量(Top-K)、改进查询重写、扩展知识库
    • Context Precision 低 → 相关文档排序靠后
      • 优化方向:优化排序算法、调整 reranker、改进相关性计算
  3. 针对性优化: 根据问题调整相应组件
  4. 重新评估: 验证优化效果
  5. 持续监控: 在生产环境持续监控关键指标(Faithfulness, Answer Relevancy, Context Relevancy)

4. 注意事项

  • 字段分组:
    • metrics_score 按字段组(field_key)组织,访问时需指定字段组名
    • 字段组名由评估器配置中的 fields 值拼接生成,如 "user_input,response"
    • 如果不确定字段组名,可遍历 summary.metrics_score_stats.items() 获取所有字段组
  • LLM依赖: 所有指标都依赖 LLM API,需要配置正确的 API key 和 endpoint
  • Embedding 依赖:
    • Answer Relevancy 必须配置 embedding_config,包含 modelapi_urlkey
    • 可使用云端服务(OpenAI、DeepSeek)或本地部署(vLLM、Xinference)
    • 如不配置会抛出异常:ValueError: Embedding model not initialized...
  • 成本考虑: 评估会产生 API 调用成本,建议:
    • 开发阶段:小样本抽样评估(如 50-100 条)
    • 生产阶段:只使用关键指标(Faithfulness, Answer Relevancy, Context Relevancy)
    • 评估阶段:全量评估所有指标
  • 数据质量: 输入数据质量会影响评估结果,确保:
    • 问题清晰明确
    • 上下文列表格式正确(字符串数组)
    • 参考答案准确(Context Recall/Precision 需要)
  • Reference 要求:
    • Context Recall 和 Context Precision 必须有 reference
    • 其他三个指标不需要 reference
    • Reference 主要用于评估阶段,生产环境通常不需要

💡 示例场景

场景1: 检测幻觉 (Faithfulness)

from dingo.io.input import Data
from dingo.model.llm.rag.llm_rag_faithfulness import LLMRAGFaithfulness

# 答案包含上下文中没有的信息
data = Data(
    prompt="Python什么时候发布?",
    content="Python于1991年发布,是第一个面向对象语言。",  # "第一个"是幻觉
    context=["Python由Guido创建,1991年首次发布于1991年。"]
)

result = LLMRAGFaithfulness.eval(data)
print(f"分数: {result.score}/10")
print(f"理由: {result.reason[0]}")
# 预期: 分数较低,reason指出"第一个面向对象语言"未被支持

场景2: 评估检索质量 (Context Precision)

from dingo.model.llm.rag.llm_rag_context_precision import LLMRAGContextPrecision

# 检索到的上下文质量参差不齐
data = Data(
    prompt="机器学习的应用?",
    content="ML用于图像识别和NLP。",
    context=[
        "机器学习在图像识别中应用广泛。",  # 相关
        "NLP是ML的重要应用。",  # 相关
        "区块链是分布式技术。"  # 不相关
    ]
)

result = LLMRAGContextPrecision.eval(data)
# 预期: 分数约6-7分,反映3个上下文中有1个不相关

场景3: 发现遗漏信息 (Context Recall)

from dingo.model.llm.rag.llm_rag_context_recall import LLMRAGContextRecall

# 检索遗漏了重要信息
data = Data(
    prompt="深度学习的特点?",
    content="深度学习使用多层神经网络,需要大量数据。",  # expected_output
    context=["深度学习使用神经网络。"]  # 缺少"多层"和"大量数据"
)

result = LLMRAGContextRecall.eval(data)
# 预期: 分数较低,reason指出"大量数据"等信息被遗漏

场景4: 检测答案跑题 (Answer Relevancy)

from dingo.model.llm.rag.llm_rag_answer_relevancy import LLMRAGAnswerRelevancy

# 答案包含大量无关信息
data = Data(
    prompt="什么是机器学习?",
    content="机器学习是AI的分支。今天天气很好。我喜欢编程。神经网络很复杂。"
)

result = LLMRAGAnswerRelevancy.eval(data)
# 预期: 分数较低,检测出大量无关句子

场景5: 检测噪声上下文 (Context Relevancy)

from dingo.model.llm.rag.llm_rag_context_relevancy import LLMRAGContextRelevancy

# 检索包含大量噪声
data = Data(
    prompt="深度学习的应用?",
    context=[
        "深度学习用于图像识别。",  # 相关
        "区块链是分布式技术。",  # 不相关
        "天气预报需要气象数据。"  # 不相关
    ]
)

result = LLMRAGContextRelevancy.eval(data)
# 预期: 分数约3-4分,只有1/3的上下文相关