RAG05-RAG系统评估

RAG系统评估

1 RAG系统评估工具

1.1 学习目标 ¶

  • 了解RAG系统评估的指标

  • 掌握RAGAS框架的原理和使用方式

1.2 概述 ¶

RAG系统正式上线前,需要评估 RAG 的表现到底是怎样的。如果 效果不够理想,则需要改进。

1.3 RAGAS评估框架 ¶

RAGAS(Retrieval Augmented Generation Assessment)是用于评估 RAG 效果的框架,可帮助分析检索与生成两个环节的表现。项目地址:https://github.com/explodinggradients/ragas

1 数据说明 ¶

RAGAS评估 通常需要一个评估数据集。常见做法是构建包含问题query、检索上下文context、模型答案answer以及真实答案groud_truths 字段的评估数据集。例如:

image.png

统一字段说明-全文统一:

字段名/术语统一术语记号专业英文说明
question/query问题$q$question/query输入 RAG系统的用户查询
answer模型答案$a$model answerRAG系统生成的答案
contexts检索上下文$C$retrieved contexts从知识源检索、用于生成模型答案的上下文
ground_truths真实答案$gt$ground truth问题对应的人工标注答案
claim(来自真实答案)声明$c$claim从真实答案拆分出的最小事实单元,用于 Context Recall
statement(来自模型答案)陈述$s$statement从模型答案拆分出的最小事实单元,用于 Faithfulness

注意:要区分 “声明(claim)”与“陈述(statement)”。

2 评估指标 ¶

image.png

  • 评估检索的指标:上下文精确率(Context Precision)、上下文召回率(Context Recall)。

  • 评估生成的指标:忠实度(faithfulness)、模型答案相关性(Answer Relevance)。

上下文精确率 (Context Precision) ¶

  • 作用:衡量检索上下文中“真正与问题相关的信息占比”,越高表示噪声越少。

  • 公式:

$$
\text{Context Precision} = AP平均精确率
$$
Average Precision(AP,平均精确率)

衡量检索结果中相关内容是否排在前面

相比普通 Precision,AP 不仅关注检索到多少相关内容,还关注相关内容的排序质量

  • $n$:检索结果总数(TopK)

  • $rel(i)$:第 $i$ 个检索结果是否相关

    • 相关:$rel(i)=1$
    • 不相关:$rel(i)=0$
  • $P(i)$:前 $i$ 个检索结果的 Precision

则:

$$
AP
==

\frac{\sum_{i=1}^{n}P(i)\times rel(i)}
{\sum_{i=1}^{n}rel(i)}
$$

其中:

$$
P(i)
=\frac{\text{前 }i\text{ 个结果中的相关数量}}
{i}
$$


计算示例

假设 Retriever 返回 Top5:

排名Context是否相关
Top1Context A
Top2Context B
Top3Context C
Top4Context D
Top5Context E

对应相关性序列:

[1, 1, 0, 1, 0]

计算每个相关 Context 所在位置的 Precision:

排名是否相关前 i 个相关数量Precision $P(i)$
Top11$1/1=1.00$
Top22$2/2=1.00$
Top3-不参与计算
Top43$3/4=0.75$
Top5-不参与计算

因此:

$$
AP=\frac{1.00+1.00+0.75}{3}=0.92
$$

其中:

  • 分子:所有相关 Context所在位置的 Precision 之和
  • 分母:相关 Context 的总数量(3)

最终:

Average Precision = 0.92

示例(Context Precision,统一示例)

  • 问题(query):2026 年世界杯冠军是谁?

  • 检索上下文(context):

    1. 西班牙获得 2026 年世界杯冠军。

    2. 决赛中西班牙击败荷兰。

    3. 巴西有丰富的足球文化。

  • 模型答案:2026 年世界杯冠军是西班牙,比赛在加时赛决出胜负。

  • 真实答案:2026年世界杯的冠军是西班牙。西班牙在决赛中以 1-0 击败了荷兰。

其中与问题直接相关的是前 2 句,因此:

$$
\text{上下文精确率} = \frac{2}{3} \approx 0.67
$$

上下文召回率 (Context Recall) ¶

  • 作用:衡量检索上下文 $C$ 对真实答案 $gt$ 的覆盖程度。

  • 分数范围:$[0,1]$,越高表示“真实答案中的关键信息”被检索到的比例越高。

  • 计算思路:先将 $gt$ 拆成声明集合 $\text{Claim}(gt)$,再判断每条声明是否被 $C$ 支持。

  • 公式:

$$
\text{Context Recall} = \frac{\text{被上下文支持的真实答案声明数}}{\text{真实答案总声明数}}
$$

示例(Context Recall,统一示例)

  • 问题(query):2026 年世界杯冠军是谁?

  • 检索上下文(context):

    1. 西班牙获得 2026 年世界杯冠军。

    2. 决赛中西班牙击败荷兰。

    3. 巴西有丰富的足球文化。

  • 模型答案:2026 年世界杯冠军是西班牙,比赛在加时赛决出胜负。

  • 真实答案:2026年世界杯的冠军是西班牙。西班牙在决赛中以 1-0 击败了荷兰。

将真实答案拆成 2 条声明:

声明Claim上下文是否支持结论
声明1:2026年世界杯的冠军是西班牙。明确包含该信息召回
声明2:西班牙在决赛中以 1-0 击败了荷兰。仅提到“击败荷兰”,未提到“1-0”未召回

因此:
$$
\text{Context Recall} = \frac{1}{2} = 0.5
$$

忠实度(faithfulness) ¶

  • 作用:指模型答案确实是根据给定的检索上下文得到的。这对于避免幻觉,并确保检索到的上下文可以作为生成依据非常重要。

  • 如果分数低,说明 LLM 的模型答案没有很好遵循检索到的知识,产生幻觉的可能性更高。

  • 公式:

$$
\text{Faithfulness} = \frac{\text{被上下文支持的模型答案陈述数}}{\text{模型答案总陈述数}}
$$

  • 实现方式:

  • 第一步:先让 LLM 从模型答案中提取一组陈述。使用的提示词如下:


给定一个问题和模型答案,从给定模型答案的每个句子中创建一个或多个陈述。

问题:[问题]

模型答案:[模型答案]
  • 第二步:生成这组陈述后,LLM 判断每条陈述是否可以从检索上下文中推断出来。这个验证步骤可使用如下提示词:
考虑给定的上下文和以下陈述,然后确定它们是否由上下文中的信息支持。在得出结论(是/否)之前,为每个陈述提供简要解释。在最后以给定格式为每个陈述提供最终结论。不要偏离指定的格式。

陈述:[陈述 1]
...
陈述:[陈述 n]

示例(Faithfulness,统一示例)

  • 问题(query):2026 年世界杯冠军是谁?

  • 检索上下文(context):

    1. 西班牙获得 2026 年世界杯冠军。

    2. 决赛中西班牙击败荷兰。

    3. 巴西有丰富的足球文化。

  • 模型答案:2026 年世界杯冠军是西班牙,比赛在加时赛决出胜负。

  • 真实答案:2026年世界杯的冠军是西班牙。西班牙在决赛中以 1-0 击败了荷兰。

将模型答案拆成 2 条陈述:

  1. 2026 年世界杯冠军是西班牙。

  2. 比赛在加时赛决出胜负。

其中第 1 条能被上下文支持,第 2 条无法从给定上下文中推出,因此:

$$
\text{忠实度} = \frac{1}{2} = 0.5
$$

  • 直观理解:模型答案里的陈述,能被上下文支持的越多,忠实度就越高。

答案相关性(Answer Relevance) ¶

  • 作用:衡量“模型答案是否围绕原问题作答”,而不是答非所问。

  • 公式:

$$
\text{Answer Relevance} = \frac{1}{n}{\sum \text{COSINE}(\text{模型答案反推问题}, \text{原问题})}
$$

  • 由模型答案反推问题的提示词:
为给定答案生成N个问题。
答案:[答案]

N需要自定义,比如3

示例(Answer Relevance,统一示例)

  • 原问题(query):2026 年世界杯冠军是谁?

  • 检索上下文(context):

    1. 西班牙获得 2026 年世界杯冠军。

    2. 决赛中西班牙击败荷兰。

    3. 巴西有丰富的足球文化。

  • 模型答案:2026 年世界杯冠军是西班牙,比赛在加时赛决出胜负。

  • 真实答案:2026年世界杯的冠军是西班牙。西班牙在决赛中以 1-0 击败了荷兰。

用模型答案反推得到 3 个问题,与原问题余弦相似度分别为:0.92、0.81、0.77。

则:

$$
\text{模型答案相关性} = \frac{0.92 + 0.81 + 0.77}{3} = 0.83
$$

  • 计算步骤:

    1. 从模型答案反推 $n$ 个问题 $\hat{q}_i$

    2. 计算每个 $\hat{q}_i$ 与原问题 $q$ 的余弦相似度

    3. 对相似度取平均,得到最终分数

  • 解释:分数越高,说明模型答案越聚焦原问题。

1.4 本章小结 ¶

本节介绍了 RAG 系统评估的基本方法,重点说明了 RAGAS 的四个核心指标(以下示例均基于统一示例:query=“2026 年世界杯冠军是谁?”)。

指标说明公式范围示例
上下文精确率(Context Precision)检索内容与问题的相关程度,越高噪声越少。与问题相关的上下文句子数 / 上下文总句子数0~1相关句 2 条、总句 3 条,得分 2/3≈0.67
上下文召回率(Context Recall)真实答案中的关键信息被检索覆盖的程度。被上下文支持的真实答案声明数 / 真实答案总声明数0~1支持 1 条、总陈述 2 条,得分 1/2=0.5
忠实度(Faithfulness)模型答案是否真正依据检索上下文生成。被上下文支持的模型答案陈述数 / 模型答案总陈述数0~1支持 1 条、总陈述 2 条,得分 1/2=0.5
答案相关性(Answer Relevance)模型答案是否围绕原问题作答。模型答案反推问题与原问题的相似度之和 / 反推问题数量0~1相似度 0.92、0.81、0.77,均值约 0.83

2 实现EduRAG系统的评估

2.1 学习目标 ¶

  • 理解 RAGAS 在 RAG 系统评估中的作用。

  • 掌握使用 RAGAS 评估核心指标的方法。

2.2 功能描述 ¶

generate_eval_data.py 用于生成RAG系统的评估数据集,核心功能包括:

  • 读取原始评估数据

  • 对每个 question,调用真实 RAG 系统获取 contexts, answer

  • 将 question + contexts + answer + ground_truth 写入 最终评估数据集 rag_evaluate_data_real.json

ragas_evaluate.py 用于评估 RAG 系统,核心功能包括:

  • 加载评估数据集 rag_evaluate_data_real.json

  • 转换为 RAGAS 所需的 Dataset 格式。

  • 初始化 LLM 和 embedding 模型。

  • 计算 Faithfulness、Answer Relevance、Context Precision 和 Context Recall 四项指标。

  • 输出结果并保存为 CSV。

2.3 完整代码 ¶

"""
调用 RAG 系统生成评估数据集 rag_evaluate_data_real.json

流程说明:
1. 读取原始评估数据 rag_evaluate_data.json(仅使用 question 和 ground_truth)
2. 对每个 question,调用真实 RAG 系统获取:
   - contexts:向量检索命中的文档(来自 Milvus 混合检索 + 重排)
   - answer:LLM 基于上下文生成的答案(来自 DashScope API)
3. 将 question + contexts + answer + ground_truth 写入 rag_evaluate_data_real.json
4. 该文件可供 ragas_evaluate.py 做 RAGAS 评估,反映 RAG 系统的真实表现

注意:
- 不修改原始 rag_evaluate_data.json
- contexts 和 answer 完全来自 RAG 系统的实际输出
- 如果检索为空,contexts 为 [],answer 可能为 LLM 自由生成或兜底回复
"""

import json
import os
import sys
import time

# 添加项目根目录到 sys.path,确保模块导入正常
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
sys.path.insert(0, PROJECT_ROOT)

from base.config import config
from base.logger import logger
from rag_qa.core.vector_store import VectorStore
from rag_qa.core.rag_system import RAGSystem
from rag_qa.core.prompts import RAGPrompts
from openai import OpenAI


# 1. 初始化 RAG 系统
def init_rag_system():
    """初始化向量库和 RAG 系统"""
    logger.info("=" * 50)
    logger.info("正在初始化 RAG 系统...")
    logger.info("=" * 50)

    client = OpenAI(
        api_key=config.DASHSCOPE_API_KEY,
        base_url=config.DASHSCOPE_BASE_URL
    )

    def call_dashscope_api(prompt, system_prompt=None):
        """DashScope API 调用,支持传入 system_prompt"""
        try:
            if system_prompt is None:
                system_prompt = RAGPrompts.rag_system_prompt()
            completion = client.chat.completions.create(
                model=config.LLM_MODEL,
                messages=[
                    {"role": "system", "content": system_prompt},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.1
            )
            return completion.choices[0].message.content if completion.choices else ""
        except Exception as e:
            logger.error(f"调用 DashScope API 异常: {e}")
            return f"出问题了,请联系客服: {config.CUSTOMER_SERVICE_PHONE}!"

    vector_store = VectorStore()
    rag_system = RAGSystem(
        vector_store=vector_store,
        llm=call_dashscope_api,
    )
    logger.info("RAG 系统初始化完成")
    return rag_system


# 2. 对单个问题执行 RAG 流程
def process_question(rag_system, question):
    """
    对单个问题执行完整的 RAG 流程,返回真实的 contexts 和 answer。
    评估时始终执行检索(不依赖 BERT 分类),因为评估数据集的问题
    全部来自知识库覆盖范围,目的是测试 RAG 管道的检索+生成能力。
    :param rag_system: RAGSystem 实例
    :param question: 用户问题
    :return: (contexts, answer)
    """
    # 2.1 始终执行检索(评估目的:测试完整 RAG 管道)
    # 如果按 BERT 分类跳过检索,"通用知识"类问题会得到空 contexts,
    # 导致 Faithfulness/ContextRecall/ContextPrecision 全部失真
    strategy = rag_system.strategy_selector.select_strategy(question)
    logger.info(f"问题: '{question}' → 检索策略: {strategy}")

    context_docs = rag_system.retrieve_and_merge(question, strategy=strategy)
    contexts = []
    if context_docs:
        for doc in context_docs:
            if hasattr(doc, "page_content"):
                contexts.append(doc.page_content)
            elif isinstance(doc, dict):
                contexts.append(doc.get("page_content", ""))
            else:
                contexts.append(str(doc))
        logger.info(f"检索到 {len(contexts)} 个上下文文档")
    else:
        logger.info("未检索到相关文档")

    # 2.2 基于检索到的上下文生成答案
    if contexts:
        context_text = "\n\n".join(contexts)
        prompt_input = rag_system.rag_prompt.format(
            context=context_text,
            history="",
            question=question,
            phone=config.CUSTOMER_SERVICE_PHONE
        )
        # 消耗生成器,收集完整回答
        llm_result = rag_system.llm(prompt_input)
        if isinstance(llm_result, str):
            answer = llm_result
        else:
            answer = ''.join(llm_result)
        logger.info(f"基于上下文生成答案,长度: {len(answer)} 字符")
    else:
        # 检索为空时,让 RAG 系统自然处理:
        # - 通用知识类query → general_prompt + general_system_prompt → LLM 直接回答
        # - 专业咨询类query → rag_prompt(空context) + rag_system_prompt → "信息不足"
        answer = ''.join(rag_system.generate_answer(question))
        logger.info(f"无上下文,由 RAG 系统自然处理,长度: {len(answer)} 字符")

    return contexts, answer


# 3. 生成 RAG 评估数据集
def generate_rag_eval_data():
    """
    生成 RAG 评估数据集:读取原始问题,调用 RAG 系统获取 contexts 和 answer,
    输出 rag_evaluate_data_real.json 供 RAGAS 评估使用。
    :return: 输出文件路径(str)
    """
    # 3.1 读取原始评估数据(仅使用 question 和 ground_truth)
    input_file = os.path.join(SCRIPT_DIR, "rag_evaluate_data.json")
    output_file = os.path.join(SCRIPT_DIR, "rag_evaluate_data_real.json")

    with open(input_file, "r", encoding="utf-8") as f:
        original_data = json.load(f)

    logger.info(f"读取 {len(original_data)} 个评估问题,来自: {input_file}")

    # 3.2 初始化 RAG 系统
    rag_system = init_rag_system()

    # 3.3 逐个问题调用 RAG 系统
    eval_data = []
    success_count = 0
    fail_count = 0

    for i, item in enumerate(original_data):
        question = item["question"]
        ground_truth = item["ground_truth"]

        logger.info(f"\n{'='*50}")
        logger.info(f"[{i+1}/{len(original_data)}] 处理问题: {question}")
        logger.info(f"{'='*50}")

        start_time = time.time()
        try:
            contexts, answer = process_question(rag_system, question)
            duration = time.time() - start_time
            logger.info(f"处理完成, 耗时: {duration:.2f}s")
            success_count += 1
        except Exception as e:
            duration = time.time() - start_time
            logger.error(f"处理失败, 耗时: {duration:.2f}s, 错误: {e}")
            contexts = []
            answer = ""
            fail_count += 1

        eval_data.append({
            "question": question,
            "contexts": contexts,
            "answer": answer,
            "ground_truth": ground_truth
        })

        # 每个问题处理完后保存一次(防止中断丢失数据)
        with open(output_file, "w", encoding="utf-8") as f:
            json.dump(eval_data, f, ensure_ascii=False, indent=2)

    # 3.4 输出统计 + 诊断信息
    has_context = sum(1 for item in eval_data if item["contexts"])
    no_context = sum(1 for item in eval_data if not item["contexts"])

    logger.info(f"\n{'='*50}")
    logger.info(f"评估数据生成完成!")
    logger.info(f"总计: {len(original_data)} 个问题")
    logger.info(f"成功: {success_count}, 失败: {fail_count}")
    logger.info(f"有上下文: {has_context}, 无上下文: {no_context}")
    if no_context > 0:
        logger.warning(f"以下问题未检索到上下文(可能影响评估指标):")
        for item in eval_data:
            if not item["contexts"]:
                logger.warning(f"  - {item['question']}")
    logger.info(f"数据已保存到: {output_file}")
    logger.info(f"{'='*50}")

    return output_file


def main():
    generate_rag_eval_data()


if __name__ == "__main__":
    main()
"""
用 RAGAS 对 RAG 系统做自动化评估。

流程说明(6步):
1. 读取评估数据(JSON 文件)
2. 转成 RAGAS 要求的数据格式(Dataset)
3. 初始化评估所需模型(LLM + Embedding)
4. 计算评估指标
5. 打印并保存评估结果
"""

import json
import os
import sys
import pandas as pd
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
    Faithfulness, # 忠实度
    AnswerRelevancy, # 答案相关度
    ContextPrecision, # 上下文相关度
    ContextRecall # 上下文召回
)
from langchain_openai import ChatOpenAI
from langchain_community.embeddings import DashScopeEmbeddings

# 添加项目根目录到 sys.path,确保模块导入正常
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
if PROJECT_ROOT not in sys.path:
    sys.path.insert(0, PROJECT_ROOT)

from base.config import config
from rag_qa.rag_assesment.generate_eval_data import generate_rag_eval_data


# 0) 自动生成 RAG 评估数据集(调用真实 RAG 系统)
print("开始生成 RAG 评估数据集...")
data_file = os.path.join(SCRIPT_DIR, "rag_evaluate_data_real.json")
# 如果data_file不存在,则生成
if not os.path.exists(data_file):
    data_file = generate_rag_eval_data()
    print(f"RAG 评估数据集已生成: {data_file}")
else:
    print("RAG 评估数据集已存在")

# 1) 读取评估数据(RAG 系统真实输出的 question、contexts、answer、ground_truth)
with open(data_file, "r", encoding="utf-8") as f:
    data = json.load(f)

# 3) 转成 RAGAS 需要的字段结构
# 注意:字段名要与评估指标要求一致
eval_data = {
    "question": [item["question"] for item in data],          # 问题列表
    "answer": [item["answer"] for item in data],              # 模型回答列表
    "contexts": [item["contexts"] for item in data],           # 上下文列表(list[str])
    "ground_truth": [item["ground_truth"] for item in data]   # 真实答案列表
}
dataset = Dataset.from_dict(eval_data)


# 4) 初始化 LLM(用于部分指标的判分推理)
# qwen-plus
llm = ChatOpenAI(
    model_name=config.LLM_MODEL,
    openai_api_base=config.DASHSCOPE_BASE_URL,
    openai_api_key=config.DASHSCOPE_API_KEY,
    temperature=0  # 固定输出,减少随机性
)

# 5) 初始化 Embedding(用于语义相似度类指标)
embeddings = DashScopeEmbeddings(
    model="text-embedding-v4",
    dashscope_api_key=config.DASHSCOPE_API_KEY
)


# 6) 执行评估
# 指标含义:
# - Faithfulness:回答是否忠于给定上下文
# - AnswerRelevancy:回答与问题是否相关
# - ContextPrecision:上下文中无关内容是否少
# - ContextRecall:上下文是否覆盖真实答案所需信息
result = evaluate(
    dataset=dataset,
    metrics=[
        Faithfulness(),
        AnswerRelevancy(),
        ContextPrecision(),
        ContextRecall()
    ],
    llm=llm,
    embeddings=embeddings
)


# 6) 输出并保存结果
print("RAGAS 评估结果:")
print(result)

# 保存为 CSV,便于后续查看和汇报(使用绝对路径)
result_csv = os.path.join(SCRIPT_DIR, "ragas_evaluation_results.csv")
result_df = pd.DataFrame([result])
result_df.to_csv(result_csv, index=False)
print(f"评估结果已保存到: {result_csv}")

2.4 说明 ¶

  • 数据集字段:通常包括 questionanswercontextsground_truth

  • answer 对应模型答案,ground_truth 对应真实答案。

  • contexts 必须是列表,即使只有一段上下文,也应写成 ["context text"]

  • 指标说明:Faithfulness 表示模型答案是否忠于上下文;Answer Relevance 表示模型答案与问题是否匹配;Context Precision 表示上下文是否与问题相关;Context Recall 表示上下文是否覆盖真实答案所需信息。

  • 环境配置:ChatOpenAI 用于评估推理,OpenAIEmbeddings 用于语义相似度计算,也可替换为其他兼容 LangChain 的模型。

  • 结果形式:输出为 0 到 1 的分数字典,分数越高越好,例如:

{
'faithfulness':0.95,
'answer_relevance':0.92,
'context_relevance':0.90,
'context_recall':0.93
}
  • 结果可保存为 CSV 文件(ragas_evaluation_results.csv),便于多次运行对比。

  • 这套代码结构通用,只需替换数据集和模型配置即可迁移到其他 RAG 系统。

  • 如有需要,还可以扩展更多指标或添加自定义数据处理逻辑。

2.5 章节总结 ¶

详细介绍了使用RAGAS评估RAG系统的完整流程。

3 RAG评估数据集的构造(扩展)

3.1 学习目标 ¶

  • 掌握 RAG 性能评估的指标。

  • 实现 RAG 评估数据集的构造。

3.2 引言 ¶

优化 RAG 不能只靠“试错”。仅凭少量问答的主观判断,很难确认某次改动是否真正有效。

要稳定优化 RAG,需要建立量化指标并准备高质量评估数据集。只有通过结构化评估,才能客观比较不同方案的效果。

3.3 结构化评估 RAG 的性能 ¶

RAG 系统评估通常分为两部分:

  • 检索评估(Retrieval Evaluation):检索内容是否相关。

  • 生成评估(Generation Evaluation):模型答案是否正确、完整。

端到端评估可重点关注以下四类指标:

  • Groundedness(可靠性):检索内容能否为模型答案提供可靠支撑。

  • Completeness(完整性):模型答案是否覆盖问题的关键信息。

  • Utilization(利用率):检索到的信息是否被模型有效使用。

  • Relevance(相关性):检索内容与用户问题是否匹配。

这些指标都依赖高质量测试样本和清晰的评估流程。

3.4 使用 Agents 完成 RAG 性能基准测试 ¶

在基准测试流程中,三个常见代理的分工如下:

  • 测试样本代理(Test Sample Agent):生成评估所需的 QA 样本。

  • 样本质量评价代理(Critique Agent):筛选并校验样本质量。

  • 评估代理(Evaluation Agent):依据指标对系统表现打分。

三者配合后,可以形成一套完整的 RAG 性能评估流程。

1 生成测试样本 ¶

评估 RAG 性能时,首先要生成测试样本。测试样本代理(Test Sample Agent)可以自动构造一批 QA 样本,既可用于快速验证,也可用于大规模评估。

如果面向特定知识库,通常建议先生成至少 200 个样本,因为经过质量筛选后,可保留的有效样本往往会明显减少。

以下是生成 QA 样本的提示词:


QA_generation_prompt

=

"""

你的任务是:根据给定的上下文,编写一个事实型问题及其真实答案。

你提出的事实型问题应能通过上下文中的具体、简明的事实信息来回答。

你的问题风格应与用户在搜索引擎中提出的问题类似。

这意味着你提出的问题**不能**包含“根据段落”或“根据上下文”等措辞。

请按以下格式给出你的输出:

输出

:

::

事实型问题:(你的问题)

真实答案:(你对该问题的回答)

以下是上下文内容:

上下文:{context}

\n

输出

:

::"""

2 检查样本质量 ¶

自动生成的样本可能存在质量问题,因此需要使用样本质量评价代理(Critique Agent)进行审核,例如:

  • 问题是否清晰、无歧义。

  • 问题是否适合目标知识领域。

当任一评价维度得分过低时,可直接剔除该样本。

提示:让代理先输出评分依据,再给出最终分数,通常能提升评分稳定性。以下是评估样本质量的提示词:

question_groundedness_critique_prompt = """
你将获得一个上下文和一个问题。
你的任务是给出一个总评分,评估该问题是否能够通过给定上下文明确无歧义地回答。
请在 1 到 5 分之间评分:
1 表示完全无法根据上下文回答,5 表示可以清晰无歧义回答。
请输出:
Feedback: <详细反馈>
[RESULT] <1-5整数>
"""

print("question_groundedness_critique_prompt loaded")

3 设置评估代理 ¶

最后,我们需要在测试数据集上评估 RAG 系统的表现,核心包括三部分:

  • 选择评估指标:优先关注 faithfulness(可靠性),它能较全面地反映端到端效果。

  • 选择评估模型:可使用 GPT-4,也可尝试 kaist-ai/prometheus-13b-v1.0BAAI/JudgeLM-33B-v1.0

  • 设计评估提示词:明确评分标准(如 1 到 5 分),并要求模型先给出评分依据,再输出最终分数。

提示:评分标准越清晰,评估结果越稳定、一致。以下是 RAG 评估模型的提示词:

EVALUATION_PROMPT = """

### 任务描述

提供了一条指令(可能包含输入)、待评估模型答案、真实答案与评分细则。



1. 根据评分细则严格评估模型答案质量并给出详细反馈。

2. 在反馈后给出 1 到 5 的整数分数。

3. 输出格式:

Feedback: <详细反馈>

[RESULT] <1-5整数>

"""



print("EVALUATION_PROMPT loaded")

3.5 本章小结 ¶

准备高质量的评估数据集是优化 RAG 性能的基础。通过引入生成代理和评价代理,我们可以建立一个系统化的评估流程,确保每个调整都有量化依据。这种基于数据驱动的方法不仅能帮助开发者快速迭代 RAG 系统,还能避免无效尝试导致的时间浪费。

本文为 程序员青阳 原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文链接及本声明。

原文链接:https://heliufang.github.io/posts/d06f11a5/index.html