Building Trustworthy Production RAG Systems Through Continuous Evaluation
TL;DR · AI 摘要
持续评估是构建可靠RAG系统的关键,通过黄金数据集、自动化工具和人工审核可有效检测系统缺陷。
核心要点
- 构建黄金数据集需包含问题、正确答案及来源文档三要素
- RAGAS可自动化评估但无法检测语义级错误
- 生产环境需结合人工审核与系统漂移监控
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- RAG系统持续评估
- 黄金数据集
- 问题/答案/来源文档
- 评估工具
- RAGAS自动化
- LLM判断器
- 监控机制
- 人工审核
- 漂移检测
金句 / Highlights
值得收藏与分享的关键句。
跳过黄金数据集建设是RAG系统开发中最常见的错误
RAGAS无法检测语义级错误,需配合自定义LLM判断器
生产环境需建立包含人工审核的闭环评估流程
通过持续评估构建可信的生产环境RAG系统 | Towards Data Science
大型语言模型
通过持续评估构建可信的生产环境RAG系统
构建一个评估工作流的实用指南,该工作流能够在问题到达用户之前捕获检索失败、幻觉和性能漂移
Priyansh Bhardwaj
2026年7月15日
10分钟阅读
分享
带有评估的RAG系统。该图像使用google gemini生成。
如果你已经构建过RAG系统,那么你肯定经历过这种情形:系统看起来运行正常,但实际上仍然存在错误。检索会获取一些片段,将其传递给生成模型,然后生成一个流畅的回答。没有任何错误抛出,但答案可能基于错误的文档,或者遗漏了需要的一半信息,或者虽然在技术上正确,但已经过时三个版本。唯一真正了解并缓解这种情况的方法,就是定期进行正确评估。
本文将逐步指导你如何构建这个评估流程,从那些看似过于基础而难以撰写的部分开始,通过使用RAGAS进行自动化评估,直到RAGAS不再足够为止,最后探讨如何将这个流程作为实际过程运行,而不仅仅是在利益相关者会议前打开的笔记本。这些步骤的编写方式使你能够直接应用于自己的RAG应用,而不仅仅是作为理论阅读。
这是《企业级RAG系列》的第4部分,如果你错过了前面的部分,我强烈建议你查看第3部分:生产环境RAG中的混合搜索与重排序
本文内容
- 构建黄金数据集
- 在自动化之前进行简单的人工检查
- 使用RAGAS进行自动化评分
- 为RAGAS无法检查的内容添加自定义LLM判断者
- 引入人工参与的闭环机制
- 系统上线后监控性能漂移
- 作为流水线运行
- 总结
构建黄金数据集
在接触任何评估库之前,你需要一组具有已知正确答案的问题。这被称为黄金数据集,而跳过这一步是团队在构建RAG系统时最常见的错误。直接在没有对比对象的情况下对随机查询运行RAGAS,几乎无法提供系统是否正确或错误的任何信息。
一个好的黄金数据集条目包含三个部分:问题、由领域专家撰写的正确答案,以及包含答案的文档。第三个字段使你能够区分检索失败(获取了错误片段)和生成失败(获取了正确片段但生成了错误答案)。这些是不同类型的错误需要不同的修复方式,而缺少这个字段的数据集会让你在调试时处于盲目状态。
golden_set = [
{
"question": "上传文件的最大尺寸是多少?",
"ground_truth": "免费计划每文件25 MB,付费计划200 MB。",
"source_doc": "upload_limits.md",
"category": "single_fact",
},
{
"question": "我可以在计费周期中途取消订阅并获得退款吗?",
"ground_truth": "不行,取消将在计费周期结束时生效,不提供部分退款。",
"source_doc": "billing_policy.md",
"category": "single_fact",
},
]二十到三十个问题是获取初始有效信号的足够数量。类别字段比条目数量更重要,而这也是团队最容易低估投入的领域。仅由简单事实查询构成的数据集会通过所有测试却提供不了任何信息,因为简单事实查询正是RAG系统极少出现的失败模式。以下是在生产环境中实际容易引发问题的类别(按常见程度排序):
- 多跳推理 – 答案需要结合两个或更多片段,这是检索系统容易遗漏关键信息的典型场景
- 无需回答 – 正确行为是拒绝回答,而非根据语义最相似的片段进行猜测
- 冲突或过时文档 – 文档库中存在同一政策的旧版和新版,但只有一个是正确的
- 对抗性表述 – 使用与源文档不同的术语提出相同的问题
第三个类别"冲突或过时文档"在黄金数据集中被跳过的情况最常见,它也是最容易导致生产事故的类别:一个流畅且引用充分的答案可能完全建立在无人及时归档的旧文档基础上。如果文档库会积累旧版本内容(大多数企业文档存储系统都会),那么评估集必须包含对此类情况的测试,否则你的流水线将和评审人员一样对此类问题视而不见。
在自动化评估前进行人工检查
在设置任何评分工具之前,先将黄金数据集通过你的流水线,查看生成答案与真实答案的对比结果。这个步骤经常被跳过,因为它看起来像是基础工作而非真正的工程实践,但它能告诉你数据集本身是否可靠,并让你在信任指标之前就了解系统中"错误"的具体表现形式。
results = []
for item in golden_set:
answer = rag_pipeline.query(item["question"])
results.append({
"question": item["question"],
"generated_answer": answer,
"ground_truth": item["ground_truth"],
"correct": None, # 需要手动填写
})这能早期发现明显故障,例如破损的提示模板、检索器返回空结果、模型完全忽略上下文等。对有缺陷的流水线进行自动化评分只会给你一个精确但毫无意义的数字。
使用RAGAS进行自动化评分
在基础验证通过后,RAGAS能提供快速且可重复的四维评分方式,无需手动检查每个答案。
from ragas import evaluate
from ragas.metrics import (
context_precision,
context_recall,
faithfulness,
answer_relevancy,
)
from datasets import Dataset
eval_dataset = Dataset.from_list([
{
"question": item["question"],
"answer": rag_pipeline.query(item["question"]),
"contexts": rag_pipeline.retrieve(item["question"]),
"ground_truth": item["ground_truth"],
}
for item in golden_set
])
result = evaluate(
eval_dataset,
metrics=[context_precision, context_recall, faithfulness, answer_relevancy],
)
print(result)- 上下文精确度 – 在检索到的片段中,实际相关片段所占比例(惩罚噪声)
- 上下文召回率 – 评估检索是否获取了生成参考答案所需的信息
- 一致性 – 答案是否基于检索内容(检测幻觉)
- 答案相关性 – 答案与问题的相关程度
- 答案相关性 – 答案是否解决了实际问题,而非类似问题
一次典型的运行结果可能如下(数字用于解释每个指标):
指标
得分
上下文精确度
0.81
上下文召回率
0.74
忠实性
0.88
答案相关性
0.85
高忠实性得分会被解读为“答案是正确的”,而这种误解恰恰让错误答案通过审核。忠实性仅检查答案是否由检索到的上下文支持,但无法判断该上下文是否是正确的检索对象。一份过时或陈旧的文档,即使被忠实总结,也会产生一个既完全有依据又完全错误的答案。这就是RAGAS的结构性上限:它在检测幻觉方面表现优异,但在识别明确错误的来源方面却非常薄弱。
为RAGAS无法检查的内容添加自定义LLM评估者
大多数RAGAS指标依赖于基于LLM的评估,使用预定义的提示词,这些提示词对您的领域一无所知。如果对您而言正确性取决于某些特定因素,如精确数字、来源的时效性、必要的免责声明、语气等,那么默认提示词将无法检测到这些内容,因为它们从未被要求这么做。
为了解决这个问题,您可以使用LLM作为评估者,并向其传递一个自定义提示词,让它根据您的具体需求来评判答案。
import json
from google import genai
from google.genai.types import GenerateContentConfig
client = genai.Client(
vertexai=True,
project="YOUR_GCP_PROJECT_ID",
location="us-central1",
)
JUDGE_PROMPT = """
将生成的答案与真实答案进行比较。在每个维度上给出1-5分。
问题:{question}
真实答案:{ground_truth}
生成答案:{answer}
来源文档日期:{doc_date}
1. numeric_accuracy - 所有数字和事实是否准确,而不仅仅是看似合理?
2. recency_awareness - 如果来源已过时,答案是否标注了不确定性,而不是将其作为当前事实陈述?
仅返回JSON:
{{
"numeric_accuracy": int,
"recency_awareness": int,
"reasoning": str
}}
"""
def custom_judge(question, ground_truth, answer, doc_date, client):
prompt = JUDGE_PROMPT.format(
question=question,
ground_truth=ground_truth,
answer=answer,
doc_date=doc_date,
)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
config=GenerateContentConfig(
temperature=0,
max_output_tokens=250,
response_mime_type="application/json",
),
)
return json.loads(response.text)不要每次都对完整数据集运行此操作,因为与RAGAS相比,每次调用的成本更高且速度更慢。应将其限定在RAGAS评估实际存在局限性的类别中,实践中这意味着conflicting_docs和no_answer_expected。在其他地方运行则是为RAGAS已经可靠评分的问题支付不必要的精度成本。
引入人工审核环节
RAGAS和自定义评估者本质上仍是LLM在评估另一个LLM的输出,它们与人类判断不总是一致。一个诚实的数字是大多数团队从未测量的——您的评估者与人类实际达成一致的频率。实践中,LLM评估者与人类判断的一致性在80%左右是常见现象,这并非意味着系统存在缺陷,而是了解真实上限比盲目假设更为重要。
def needs_human_review(ragas_score, judge_score, threshold=1.0):
return abs(ragas_score - judge_score) > threshold这使人工审核队列保持精简且聚焦,仅保留两种评分方法存在分歧的案例,而非所有回答。偶尔让两个人独立对少量边缘案例进行评分也值得尝试。如果领域专家对某类问题的判断分歧率达到三分之一,这说明问题本身存在歧义,而非评分流程的问题,任何工具都无法解决这种根本性问题。通常这意味着黄金数据集条目需要重写,而非评分者本身。
发布系统后需警惕偏移
仅针对固定黄金数据集运行的流水线存在盲区,因为实时语料库会在其下方持续变化。新文档会被添加,旧文档会被归档,真实用户查询也会逐渐偏离最初测试时的范围。这些变化在编写当日就被冻结的数据集中完全无法体现。
import random
from datetime import datetime, timedelta
def sample_production_queries(logs, n=50, days=7):
recent = [q for q in logs if q["timestamp"] > datetime.now() - timedelta(days=days)]
return random.sample(recent, min(n, len(recent)))每周从实时流量中抽取一小部分样本,通过RAGAS的上下文精确度和忠实度指标进行评估(这两个指标无需真实答案即可运行),可获得第二个信号。如果没有对应的代码变更却突然出现指标下降,通常意味着语料库发生了变化,而非流水线问题,这种失败模式与任何合并时检查都无法捕捉到的错误类型不同。
作为流水线运行
使它成为真正的流水线而非一次性任务的两个关键要素是:成本感知的调度机制,以及CI门禁。
完整流水线运行方式如下:RAGAS、自定义评分者和人工审核对每个提交都进行完整验证的成本极高,大多数团队在一个月内会悄悄停止这种做法。分层执行效果更好:
- RAGAS对完整黄金数据集运行:所有涉及检索或提示词的拉取请求
- 自定义评分者仅对标记分类运行:所有拉取请求,但仅限少量示例
- 人工审核:每周仅处理分歧队列
- 生产环境采样:每周对实时流量的轮换切片进行评估
def check_regression(current_scores, baseline_scores, threshold=0.03):
regressions = [
(metric, baseline_scores[metric], score)
for metric, score in current_scores.items()
if baseline_scores[metric] - score > threshold
]
if regressions:
raise SystemExit(f"Blocking merge — regressions found: {regressions}")
print("No regressions. Safe to merge.")将此功能接入CI系统,使其在所有涉及检索、分块或提示词的拉取请求中运行,并在任何指标跌破阈值时阻止构建。这是整个设置中最重要的部分,也是唯一能真正预防事故的环节。例如,某个分块变更悄悄破坏了一类查询,会在此处被及时发现,避免三周后变成支持工单,而非今天就触发失败检查。
结论
以上六步单独使用时都不够令人印象深刻,但真正带来差异的是将它们作为一个团队信任的流程来定期运行,而不是依赖某人偶尔想起来执行。本文的意图正是如此,从将评估作为一次性直觉检查,到将其作为RAG系统基础设施的一部分,在持续集成中静默运行并拦截那些本应上线的变更。
如果你从零开始,不要试图一次性构建所有六个步骤。一个包含20个优质问题的黄金数据集,以及你手动检查的RAGAS评分,已经优于当今大多数生产环境中的RAG系统。其余部分可以随着系统的发展和你手动阅读答案的耐心增长逐步添加。
作者
查看Priyansh Bhardwaj的全部文章
生成式AI
,
LLM应用
LLM评估
机器学习
RAG
分享本文
- 在Facebook上分享
- 在LinkedIn上分享
- 在X上分享
Towards Data Science是一份社区出版物。提交你的见解以触达全球受众,并通过TDS作者支付计划获得收益。
更新为你的实际投稿链接
为TDS写作
✦ 结束CTA ✦