RAG 回答"一本正经地胡说"之后:我们如何用 DeepEval 给 LLM 评估挑出 3 个指标
【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval
上个月,我们上线的 RAG 知识库机器人被用户投诉了 11 次"一本正经地胡说"。为了搞清楚问题,我们第一次给系统做 LLM 评估:用 DeepEval 把 RAG 评测、对话评估和风险管控拆成具体指标,跑通了从单条用例到 CI 的完整流程。这篇是那次选型和踩坑的复盘,按"当时我们想回答什么问题"来组织,而不是按功能模块罗列。
先别急着上指标:回答"是检索差还是生成差"
用户投诉时,我们第一反应是把 FaithfulnessMetric 挂上去看分数——结果分数不高,但没人知道该改哪里。后来想明白一件事:定位问题比量化问题更急。RAG 链路只有两段,检索和生成,问题只会出在其中一段,或两段都出。
我们的定位流程变成了这样:
跑下来发现我们 80% 的 bad case 是检索侧的:chunk 切得太碎,答案信息被劈成两半。这直接决定了后续指标选型的重心。
给 RAG 系统挑指标的三步法
DeepEval 的指标很多,别一上来就把指标堆满。我们的做法是先想清楚"这个指标替我回答什么问题",再决定用不用它。核心 RAG 指标就三个,各自回答的问题不重叠:
| 它替你回答的问题 | 指标 | 必须提供的字段 | 实际跑下来的体会 |
|---|---|---|---|
| 检索回来的上下文跟用户问的是一回事吗 | ContextualRelevancyMetric | input+retrieval_context | 无关 chunk 占比高时,先别动生成侧 |
| 答案有没有"编"上下文里没有的东西 | FaithfulnessMetric | 再加actual_output | 幻觉投诉最灵敏的探针,逐条拆成断言核查 |
| 上下文是否覆盖了标准答案需要的全部信息 | ContextualRecallMetric | 再加reference(golden 答案) | 没有标注数据集根本跑不了,门槛最高 |
三步法的顺序建议:第一步先用相关性指标确认检索没掉链子;第二步用忠实度盯生成端幻觉;第三步等有 golden 数据集了再补召回率——它对数据集的依赖最强,放最后。
阈值方面,threshold不传时默认及格线是 0.5,我们线上按业务容忍度调到了 0.6~0.7 之间。
最小可运行示例
下面这段只回答一个问题:这 5 条 RAG 用例,哪些是检索的锅、哪些是生成的锅?
from deepeval import evaluate from deepeval.metrics import ( ContextualRelevancyMetric, FaithfulnessMetric, ContextualRecallMetric, ) from deepeval.test_case import LLMTestCase # 一条 RAG 用例 = 用户问题 + 检索上下文 + 模型回答 +(召回率用的)标准答案 case = LLMTestCase( input="DeepEval 怎么评估 RAG?", actual_output="它把检索和生成分开看,分别用相关性、忠实度、召回率打分。", retrieval_context=[ "官方文档建议三个指标组合使用:相关性、忠实度、召回率。", "分数落在 0 到 1 之间,并附推理说明。", ], reference="用相关性、忠实度、召回率三个指标评估 RAG。", ) # 只挂回答定位问题的三个,够了 checks = [ ContextualRelevancyMetric(threshold=0.7), FaithfulnessMetric(threshold=0.6), ContextualRecallMetric(threshold=0.6), ] result = evaluate(test_cases=[case], metrics=checks)想看更多指标的实现,可以直接翻 deepeval/metrics/ 目录,每个指标一个子包,模板和 schema 都在旁边。
对话评估:多轮里最容易漏掉的三处
单轮用LLMTestCase,多轮换ConversationalTestCase,把每轮对话建成Turn(role, content)。切换之后有三个坑,我们全踩过:
- 角色设定要放对位置。
RoleAdherenceMetric本身没有"角色"参数,人设描述写在测试用例的chatbot_role字段里。指标只负责判断每一轮回答有没有出戏。 - 区分轮级和会话级。忠实度有
TurnFaithfulnessMetric(只看当前这一轮)和会话级的FaithfulnessMetric两种用法;完整性看ConversationCompletenessMetric。单轮都没问题、整体却答非所问时,多半要加一个会话级指标兜底。 - 长对话单独盯信息一致性。用户第 2 轮给过地址、第 9 轮又问了一遍,机器人重新追问就是一次"失忆"。
KnowledgeRetentionMetric就是查这个的,我们把它作为长会话回归测试的固定项。
业务自己的标准:GEval 和 DAG 怎么选
内置指标覆盖不了的部分,我们只用了两个自定义入口,选择依据很简单:
- 标准是主观感受(友好、专业、像人话)→ 用
GEval,用一句criteria描述标准,再指定它该看用例里的哪些字段。 - 标准是能画成判断树的(必须包含 X、不能出现 Y、先 A 后 B)→ 用
DAGMetric,传一个DeepAcyclicGraph,节点是判断步骤,叶子定分。它比 GEval 稳定得多,适合做成硬规则。
客服场景的最小例子:
from deepeval.metrics import GEval from deepeval.test_case import LLMTestCase, SingleTurnParams cs_quality = GEval( name="客服回复质量", criteria="先索取订单号,再给出查询途径,语气保持礼貌不推诿", evaluation_params=[SingleTurnParams.INPUT, SingleTurnParams.ACTUAL_OUTPUT], threshold=0.6, ) # cs_quality.measure(你的 LLMTestCase 实例) 之后读 score 和 reason一个反直觉的提醒:GEval 的分数对措辞很敏感,同一句criteria换个说法分数会漂移。我们后来把 criteria 锁进版本控制,改动必须走评审,才把波动压下来。
从跑一次到持续盯着:阈值、CI 与监控
跑通单条只是开始,落地时我们定了四条规矩:
- 指标数量封顶 5 个。超过之后每个指标的分数都开始失去解释力,评审时也没人看得完。
- 阈值和
strict_mode分场景用。离线回归可以放宽阈值看趋势;对外发布前的门禁用strict_mode(等价于阈值拉到 1,全对才放行)。 - CI 里只挂最硬的 2 个。用
deepeval test run把评测编进流水线,红了就挡住合并。 - 线上流量用
@observe打点,把生产 case 回流成测试集。tracing 相关实现在 deepeval/tracing/ 里,配好导出端点后,每条 trace 都能还原成一条评测用例。
高频疑问
分数不低但人工觉得不对,怎么调?先看reason和逐条 verdict——忠实度这类指标会把答案拆成断言逐条判。多数"体感差"的问题能定位到个别断言,再决定是收紧 criteria、换裁判模型,还是调threshold。
没有 golden 答案的线上问答怎么评?跑不需要reference的指标(相关性、忠实度),再抽样人工标注沉淀成 golden 集,逐步把召回率这类指标补上。
该换更大的裁判模型吗?先不换。裁判模型升级会让历史分数不可比。我们的做法是固定一个裁判模型跑基线,想换的时候新旧各跑一轮,确认分数分布平移幅度可解释再切换。
下一步建议:挑你系统里被投诉最多的 5 条真实 case,按本文的定位流程跑一遍,再决定先优化哪一段——比通读文档更快看到效果。
【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考