# RAG评估指标 - 完整指南 ## 🎯 概述 dingo 的 RAG 评估指标系统基于 [RAGAS 论文](https://arxiv.org/abs/2309.15217)、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. 运行示例 ```bash # 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方式 - 单个评估 ```python 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方式 - 批量评估 ```python 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` ```python 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` ```jsonl {"user_input": "什么是深度学习?", "response": "深度学习使用神经网络...", "retrieved_contexts": ["深度学习是ML的子领域...", "深度学习用于图像识别..."]} {"user_input": "Python的特点?", "response": "Python简洁且有丰富的库。", "retrieved_contexts": ["Python语法简洁。", "Python有NumPy等库。"], "reference": "Python语法简洁,生态系统丰富。"} ``` **字段映射配置**: ```python "fields": { "prompt": "user_input", # 问题 "content": "response", # RAG生成的答案 "context": "retrieved_contexts", # 检索的上下文 "reference": "reference" # 标准答案(可选) } ``` ## 🎨 输出格式 ### SDK 方式输出 评估结果包含: ```python 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}") ``` **输出示例**: ```python # 通过的情况 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`,包含: > **注意**:指标分数统计功能支持 `local` 和 `spark` 两种执行器。 ```json { "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 } } } ``` ### 多字段组示例 ```json { "metrics_score": { "user_input,response": { "stats": {...}, "summary": {...}, "overall_average": 7.8 }, "retrieved_contexts,reference": { "stats": {...}, "summary": {...}, "overall_average": 9.1 } } } ``` ## ⚙️ 执行器支持 ### 支持的执行器 指标分数统计功能支持以下执行器: | 执行器 | 类型 | 指标统计 | 适用场景 | |--------|------|---------|---------| | **Local** | 单机 | ✅ 支持 | 小规模数据集,开发测试 | | **Spark** | 分布式 | ✅ 支持 | 大规模数据集,生产环境 | ### Spark 执行器示例 ```python 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 方式配置 ```python 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 方式配置 ```python "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-large`、`BAAI/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个指标): ```python "evals": [ {"name": "LLMRAGFaithfulness"}, # 检测幻觉(答案是否忠实于上下文) {"name": "LLMRAGAnswerRelevancy"}, # 检测答案相关性(是否回答问题) {"name": "LLMRAGContextRelevancy"}, # 检测噪声上下文(上下文是否相关) {"name": "LLMRAGContextRecall"}, # 评估检索完整性(需要reference) {"name": "LLMRAGContextPrecision"} # 评估检索排序质量(需要reference) ] ``` **生产环境** (不需要 reference): ```python "evals": [ {"name": "LLMRAGFaithfulness"}, # ⭐ 最重要:防止幻觉 {"name": "LLMRAGAnswerRelevancy"}, # 确保答案直接回答问题 {"name": "LLMRAGContextRelevancy"} # 检测检索噪声 ] ``` **评估阶段** (需要 reference): ```python "evals": [ {"name": "LLMRAGContextRecall"}, # 评估检索完整性(是否遗漏信息) {"name": "LLMRAGContextPrecision"} # 评估检索排序质量(相关的是否靠前) ] ``` **检索系统优化**: ```python "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`**,包含 `model`、`api_url`、`key` - 可使用云端服务(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) ```python 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) ```python 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) ```python 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) ```python from dingo.model.llm.rag.llm_rag_answer_relevancy import LLMRAGAnswerRelevancy # 答案包含大量无关信息 data = Data( prompt="什么是机器学习?", content="机器学习是AI的分支。今天天气很好。我喜欢编程。神经网络很复杂。" ) result = LLMRAGAnswerRelevancy.eval(data) # 预期: 分数较低,检测出大量无关句子 ``` ### 场景5: 检测噪声上下文 (Context Relevancy) ```python from dingo.model.llm.rag.llm_rag_context_relevancy import LLMRAGContextRelevancy # 检索包含大量噪声 data = Data( prompt="深度学习的应用?", context=[ "深度学习用于图像识别。", # 相关 "区块链是分布式技术。", # 不相关 "天气预报需要气象数据。" # 不相关 ] ) result = LLMRAGContextRelevancy.eval(data) # 预期: 分数约3-4分,只有1/3的上下文相关 ```