在 Dify 工作流中落地 RAG 效果评估体系

你改了一版提示词,怎么证明没改坏?——在 Dify 工作流中落地 RAG 效果评估体系

本文拆解一个 Dify RAG 工作流中每个环节该看什么指标、怎么看、看到问题怎么修。适合有 Dify 使用经验但尚未建立系统化评估意识的 AI 应用开发者。


一、从一个真实场景说起

你用 Dify 搭了一个客服问答助手。第一周效果惊艳,老板很满意。

第二周,有用户反馈"问了个问题,答得驴唇不对马嘴"。你打开 Dify,改了改提示词,加了几条规则。测了刚才那个问题——好了。上线。

第三周,另一个用户投诉"以前能答对的问题,现在答错了"。

按下葫芦浮起了瓢。

问题的本质是:你没有一套量化的自动化验证体系。每次改动后,你只人工测了 2-3 个问题就上线了,完全不知道这次修改对其他 100 个场景的影响。

核心结论先抛出来:先建测试体系,再谈应用迭代。没有自动化测试兜底的提示词修改,就是赌博。

那这套测试体系怎么建?首先你需要搞清楚一个问题——你的 RAG 工作流出了错,到底该怪谁?


二、在 Dify 工作流中,到底该评估什么?

2.1 先看清你的工作流长什么样

一个典型的 Dify RAG 工作流(以客服 FAQ 为例)通常长这样:

用户提问
  ↓
[节点1] 提问改写(结合上下文消除指代、补全信息)
  ↓
[节点2] 意图识别(判断是闲聊/行政/财务/...)
  ↓
[节点3] 知识库检索召回(混合检索 + Rerank)
  ↓
[节点4] LLM 整理生成答复
  ↓
输出给用户

关键认知:RAG 的评估不是给整个工作流打一个总分,而是把每个节点拆开来,分别打分。 就像微服务的链路追踪一样,哪个环节出了问题,就定位到哪个环节去修。

如果最终回答错了:

  • 可能是节点 1 改写时丢掉了关键信息(比如把"高意向"丢了)
  • 可能是节点 2 意图识别错了,路由到了错误的知识库
  • 可能是节点 3 检索没找到正确文档,或者找回来一堆垃圾
  • 可能是节点 4 大模型看到了正确文档但自己瞎编

不拆开看,你永远不知道该修哪里。

2.2 RAGAS 四大指标:谁负责评估谁?

RAGAS(Retrieval Augmented Generation Assessment)提供了四个核心指标。它们不是一锅炖的,而是精确对应到工作流中的检索阶段和生成阶段

                    ┌─────────────────────────────────┐
                    │          评估检索阶段            │
                    │     (你的知识库搜得好不好)       │
                    │                                 │
                    │  ┌───────────────────────────┐  │
                    │  │ 上下文召回率                │  │
                    │  │ Context Recall             │  │
                    │  │ → 该找到的,找全了吗?       │  │
                    │  └───────────────────────────┘  │
                    │  ┌───────────────────────────┐  │
                    │  │ 上下文精准度                │  │
                    │  │ Context Precision          │  │
                    │  │ → 找回来的,有多少是有用的?  │  │
                    │  └───────────────────────────┘  │
                    └─────────────────────────────────┘

                    ┌─────────────────────────────────┐
                    │          评估生成阶段            │
                    │    (你的大模型答得好不好)        │
                    │                                 │
                    │  ┌───────────────────────────┐  │
                    │  │ 答案忠实度                  │  │
                    │  │ Faithfulness               │  │
                    │  │ → 模型有没有瞎编幻觉?       │  │
                    │  └───────────────────────────┘  │
                    │  ┌───────────────────────────┐  │
                    │  │ 答案相关性                  │  │
                    │  │ Answer Relevance           │  │
                    │  │ → 模型有没有答非所问?       │  │
                    │  └───────────────────────────┘  │
                    └─────────────────────────────────┘

这张图就是你在生产环境中的"仪表盘"。 四个指标,两大类,分别诊断两个不同的病灶。下面逐个拆解。


三、检索阶段的两个指标:你的知识库搜得好不好?

3.1 上下文召回率(Context Recall)——该来的全来了吗?

一句话定义:回答这个问题需要的知识片段,你的检索系统捞全了吗?

举例:用户问"查询张三本月跟进的高意向客户明细"。正确回答需要两条信息——跟进人+时间的过滤逻辑,以及意向等级的过滤逻辑。如果知识库只召回了前者,漏掉了后者,召回率就是 50%。

怎么算:

$$\text{Context Recall} = \frac{\text{被召回的相关片段数}}{\text{回答问题所需的全部相关片段数}}$$

生产环境中怎么看这个指标:

召回率区间 说明 行动
> 90% 知识库覆盖良好,检索配置合理 维持现状,关注长尾
70%-90% 有一定比例的必要信息没被找到 检查是否缺少同义词覆盖、是否需要 Query 扩写
< 70% 严重漏检 优先排查:分段策略是否合理?是否需要补充知识库文档?混合检索是否开启?

召回率低了怎么修?

  1. 开启混合检索:纯向量检索在遇到生僻人名、编号等专有名词时容易漏,关键词检索靠字面匹配可以兜底。在 Dify 中,知识库设置 → 检索设置 → 选择"混合检索"即可。
  2. 提问改写/扩写:在工作流的第一个 LLM 节点中,把用户口语化的短问题改写成包含更多关键词的完整问句。比如把"上周北京1分的数据"改写成"查询北京第一分公司上周的拜访数据"——改写后的表述更完整,检索命中的概率更高。
  3. 知识库分段策略调整:如果一个回答需要的信息被分散在两个段落中,考虑合并为一个完整片段,或者使用 Dify 的"父子分段"模式。

3.2 上下文精准度(Context Precision)——找回来的有多少是废话?

一句话定义:检索系统送给大模型的文档片段中,有多大比例是真正有用的?

举例:知识库返回了 10 个片段,但只有 2 个跟问题相关,其他 8 个都是噪音。精准度就是 20%。

怎么算:

$$\text{Context Precision} = \frac{\text{召回片段中相关的数量}}{\text{召回片段总数}}$$

生产环境中怎么看这个指标:

精准度区间 说明 行动
> 80% 送给大模型的都是干货 继续保持
50%-80% 有不少噪音混进去了 检查 Rerank 配置,考虑提高阈值或减少 Top-K
< 50% 一多半是垃圾 紧急排查:知识库文档是否混杂?元数据标签是否缺失?Rerank 是否开启?

精准度低了怎么修?

  1. 接入 Rerank 重排序模型:这是目前 RAG 系统的标配。向量检索是"粗排",速度快但不够精。Rerank 模型(如 BGE-Reranker)会把用户的问题和每个召回片段拼在一起细细品味,重新打分排序,把不相关的踢掉。在 Dify 中,知识库设置 → 检索设置 → 开启 Rerank 模型即可。
  2. 提高 Rerank 阈值:Dify 中 Rerank 有一个 Score 阈值设置。生产环境建议从 0.3 起步调试,逐步提高到 0.5-0.7,观察精准度和召回率的平衡点。阈值设太高会误杀相关文档(召回率下降),设太低等于没过滤。
  3. 元数据过滤:在知识库中给文档打标签(如部门、业务类型),检索时先用元数据硬过滤,缩小搜索范围后再做语义匹配。

3.3 召回率和精准度的跷跷板

这两个指标天然存在张力。 你把网撒大(召回多一些),召回率上去了,但精准度可能下来;你把网收紧(过滤严格),精准度上去了,但可能漏掉关键信息。

这就是为什么 Dify 的检索配置里有 Top-K(召回数量)和 Score 阈值两个参数——它们就是这架跷跷板的调节杆。

生产上的实战经验:

  • 对于 FAQ 客服场景:宁可精准度高一点,因为用户期望得到直接答案,塞一堆无关信息反而让大模型困惑。建议 Top-K 设小(3-5),Rerank 阈值设高。
  • 对于复杂分析/报告场景:宁可召回率高一点,因为回答需要综合多条信息。Top-K 可以设大一些(8-15),Rerank 阈值适当放低。

四、生成阶段的两个指标:你的大模型答得好不好?

检索做得再好,大模型拿到了正确的知识片段,还是可能搞砸。生成阶段有两种典型的"搞砸"方式。

4.1 答案忠实度(Faithfulness)——模型有没有瞎编?

一句话定义:大模型的回答内容,是不是都能在召回的知识片段中找到依据?还是它自己脑补了一些东西?

RAGAS 怎么算这个分(它的底层逻辑非常巧妙):

分两步走,用一个"裁判大模型"来自动打分——

Step 1(拆句子):把大模型生成的回答,拆成一条条独立的"原子陈述"。
Step 2(逐一验证):拿每条陈述去检索到的上下文中比对——这句话能从上下文中推导出来吗?能 = 1,不能 = 0。

$$\text{Faithfulness} = \frac{\text{能从上下文推导出的陈述数}}{\text{总陈述数}}$$

一个生产中的真实案例:

用户提问:这款蓝牙耳机续航多久?支持降噪吗?

检索到的知识库内容:
"这款蓝牙耳机单次充电可使用 6 小时,配合充电仓总续航达 24 小时。"

大模型回答:
"这款耳机总续航 24 小时,同时支持最新的主动降噪(ANC)技术。"

裁判模型拆句验证:

  • 陈述 1:"总续航 24 小时" → 上下文有提到 ✅
  • 陈述 2:"支持主动降噪 ANC 技术" → 上下文压根没提降噪 ❌

忠实度 = 1/2 = 0.5

知识库里没有降噪相关的内容,但模型自己编了一个。这就是经典的幻觉(Hallucination)

生产环境中怎么看这个指标:

忠实度区间 说明 行动
> 90% 模型很"听话",严格依据上下文 维持现状
70%-90% 偶尔脑补 检查提示词是否明确要求"仅根据上下文回答";考虑降低模型 temperature
< 70% 大面积幻觉 紧急排查:模型是否过于"发散"?提示词是否缺少约束?知识库覆盖是否不足导致模型被迫脑补?

忠实度低了怎么修?

  1. 提示词中加硬约束:在 Dify 的 LLM 节点 System Prompt 中明确写上"你必须且只能根据提供的上下文回答,如果上下文中没有相关信息,请直接回答'抱歉,我没有找到相关信息'"。
  2. temperature 设为 0:在 Dify 的 LLM 节点配置中,把温度调到 0(贪心解码),消除模型的随机发散。
  3. 减少模型决策空间:让模型只做"选择"和"填充",不做"推理"和"创造"。比如在 Text2SQL 场景中,给模型一个 SQL 模板,让它只负责填入 WHERE 条件的值,而不是从零开始写 SQL。

一个重要的认知纠偏:

忠实度低 ≠ 回答错误。模型可能脑补了一个恰好正确的答案(比如上面的降噪例子,也许这款耳机确实支持降噪),但它"超纲"了——回答的依据不在检索到的上下文中。

反过来,忠实度高 ≠ 回答正确。如果检索阶段就送来了一堆错误的文档,模型忠实地复述了错误内容,忠实度是 100%,但答案是错的。

这就是为什么必须检索指标和生成指标一起看,不能只盯一个。

4.2 答案相关性(Answer Relevance)——有没有答非所问?

一句话定义:大模型的回答,是不是在直接回答用户的问题?还是说了一堆正确但无关的废话?

RAGAS 怎么算这个分(这个思路非常反直觉):

它用了一个"逆向检验法"——

Step 1(反推问题):把大模型生成的回答丢给裁判模型,让它根据这个回答反向生成 N 个可能的问题
Step 2(对比相似度):计算这 N 个反推问题和用户原始问题的向量余弦相似度

$$\text{Answer Relevance} = \text{Avg}(\text{cos_sim}(q_{\text{original}}, q_{\text{generated_i}}))$$

为什么这招有效? 如果模型的回答确实是在回答原问题,那么从答案反推出的问题,应该跟原问题非常像。如果答非所问,反推出来的问题一定跟原问题风马牛不相及。

举个例子:

用户问:"病假怎么扣工资?"
模型回答:"请假需要提前在 OA 系统提交审批,选择假期类型..."

裁判模型反推的问题:"请假审批流程是什么?"
与原问题的相似度 → 很低(一个问钱,一个问流程)
→ 相关性得分低

模型说的内容可能完全正确(请假确实要在 OA 提交),也完全忠实于上下文(知识库里确实有这段流程说明),但它没有回答用户的问题。根源在于检索阶段送来了流程文档而不是薪资文档(精准度的问题),导致模型只能"就着手头的材料瞎说"。

生产环境中怎么看这个指标:

相关性区间 说明 行动
> 85% 问什么答什么 维持现状
60%-85% 有跑题倾向 先排查检索精准度(可能送错了材料),再检查提示词是否引导模型聚焦问题
< 60% 严重答非所问 联合排查检索和生成:是知识库里根本没有对应内容,还是模型理解力不足?

五、四个指标联合诊断:一张生产环境的诊断速查表

在生产环境中,单看某一个指标没有意义,需要交叉诊断。以下是常见的"症状-病因-治疗"对照:

症状(指标表现) 病因定位 治疗方案
召回率低 + 精准度高 检索太保守,有用的文档被过滤掉了 降低 Rerank 阈值、增大 Top-K、开启混合检索
召回率高 + 精准度低 检索太宽泛,垃圾信息太多 提高 Rerank 阈值、减小 Top-K、增加元数据过滤
召回率低 + 精准度低 知识库本身有问题 重新审视文档内容、分段策略、是否缺少关键文档
忠实度低 大模型在瞎编 加提示词约束、降 temperature、缩减模型决策范围
相关性低 + 忠实度高 模型忠实地复述了无关内容 根源在检索——送错了材料,先修检索的精准度
相关性低 + 忠实度低 检索送错材料 + 模型还自己加戏 检索和生成都要修,优先修检索
四项全高 系统运行健康 持续监控,关注边界/长尾 case

诊断的优先级顺序(重要):先看检索,再看生成。

因为如果检索送来的材料就是错的,后面的生成指标就失去了参考意义。你不能指望大模型把一堆垃圾素材变成正确答案。

在 Dify 工作流中的排查路径:

最终回答有问题
  ↓
先查 [节点3 检索] 的日志 → 看召回了什么文档 → 是不是该来的没来?不该来的来了?
  │
  ├── 是检索的问题 → 调 Rerank / Top-K / 分段策略 / 混合检索
  │
  └── 检索没问题(正确文档都在)
        ↓
      再查 [节点4 LLM 生成] → 模型是不是忠实?是不是切题?
        │
        ├── 模型幻觉 → 改提示词约束 / 降 temperature
        │
        └── 答非所问 → 检查提示词是否引导模型聚焦用户问题

六、评估怎么跑起来?生产落地的三步走

6.1 第一步:准备 Ground Truth 测试集

所有评估的前提是:你手里得有一套"标准答案"

Ground Truth 测试集长这样(以 FAQ 客服为例):

用户提问 期望召回的文档ID 期望答案要点
病假怎么扣工资 doc_salary_005 按最低工资 80% 发放
年假怎么申请 doc_leave_002 OA 提交 → 主管审批 → HR 备案
菏泽1分的拜访量 doc_visit_template_003 sql_id: visit_count_by_dept

没有历史数据怎么办(冷启动)?

RAGAS 提供了一个"合成测试集生成"功能:把你的知识库文档喂给大模型,让它扮演各种类型的用户出题——简单提取题、跨文档推理题、条件变换题——一次性生成几百道测试 QA 对。

但要注意:合成数据只能用于冷启动保底。真正有价值的测试数据来自线上真实用户的提问。上线后要持续收集真实 Bad Case,清洗后补充到测试集中。

6.2 第二步:搭建自动化评估流水线

有了测试集,评估脚本的核心逻辑如下:

# 伪代码:每日自动化评估流水线
results = []

for test_case in test_dataset:
    # 1. 调用 Dify API,获取实际输出
    prediction = dify_api.run(test_case["user_input"])
    
    # 2. 检索阶段评估
    # 路由/召回准确率:预测的文档ID 是否命中期望的文档ID
    recall_hit = test_case["expected_doc_id"] in prediction["retrieved_doc_ids"]
    
    # 精准度:召回文档中有多少是相关的
    relevant_count = count_relevant(prediction["retrieved_docs"], test_case)
    precision = relevant_count / len(prediction["retrieved_docs"])
    
    # 3. 生成阶段评估(调用裁判大模型)
    faithfulness = ragas.evaluate_faithfulness(
        answer=prediction["answer"],
        contexts=prediction["retrieved_docs"]
    )
    relevance = ragas.evaluate_relevance(
        question=test_case["user_input"],
        answer=prediction["answer"]
    )
    
    results.append({...})

# 4. 输出成绩单
print(f"召回率: {avg_recall:.1%}")
print(f"精准度: {avg_precision:.1%}")
print(f"忠实度: {avg_faithfulness:.1%}")
print(f"相关性: {avg_relevance:.1%}")

# 5. 阈值拦截:低于基线则阻断发布
assert avg_recall > 0.90, "召回率低于 90%,禁止上线!"
assert avg_precision > 0.75, "精准度低于 75%,禁止上线!"

关键配置建议(让裁判大模型打分更稳定):

配置项 建议 原因
裁判模型 temperature 设为 0 消除随机性,同样的评测每次结果一致
Few-shot 示例 在评测 Prompt 中提供 3-5 个打分样例 给裁判一个"评分标准"
裁判模型选择 用比被测模型高一个代差的模型 避免"自我偏好偏差"——同款模型评自己的输出会成绩虚高
交叉验证 出题用 A 厂模型,答题用 B 厂模型,裁判用 C 厂模型 彻底避免偏差

6.3 第三步:线上线下双循环飞轮

评估体系不是"建完就完"的一次性工程,而是一个持续旋转的飞轮:

┌──────────────────────────────────────────────────────────┐
│                                                          │
│   ┌──────────────┐      ┌──────────────┐                │
│   │  离线评估     │      │  线上监控     │                │
│   │  (防御阵地)   │      │  (进化引擎)   │                │
│   │              │      │              │                │
│   │ 每次改动后    │      │ 收集用户      │                │
│   │ 跑全量测试集  │ ←──── │ 点赞/点踩    │                │
│   │ 确保不退化    │      │ 真实 Bad Case │                │
│   │              │      │              │                │
│   └──────┬───────┘      └──────────────┘                │
│          │                                               │
│          │  清洗后的真实数据                                │
│          │  补充到测试集中                                  │
│          ↓                                               │
│   ┌──────────────┐                                      │
│   │ 测试集越来越  │                                      │
│   │ 贴合真实业务  │                                      │
│   └──────────────┘                                      │
│                                                          │
└──────────────────────────────────────────────────────────┘
  • 离线评估:每次修改提示词、调整 Rerank 参数、更新知识库文档后,跑一遍自动化测试集。分数不降才允许上线。这就是你"证明没改坏"的底气。
  • 线上监控:用户的点踩 = 一个天然的负向标签。每天从线上日志中筛出 Bad Case,人工审核后补充 Ground Truth,加入到离线测试集中。
  • 飞轮效应:冷启动时测试集可能只有合成的 200 条"不够真实"的数据。但随着线上运行,每周都有真实 Bad Case 回流。一个月后,你的测试集就从"玩具级"进化成了"生产级"。

七、回到开头那个问题

你改了一版提示词,怎么证明没改坏?

现在你的回答应该是:

  1. 我有一个包含 500 道真实业务问题的测试集,每道题都有标准答案。
  2. 我每次改动后,自动跑一遍全量测试,拿到四个指标的成绩单。
  3. 召回率 > 90%,精准度 > 75%,忠实度 > 85%,相关性 > 80%——全部达标,上线。
  4. 任何一项不达标,回滚,定位是检索的问题还是生成的问题,针对性修复。
  5. 线上持续收集 Bad Case,每周回流到测试集中,评估体系越来越强。

不再赌博,用数据说话。


附录:快速参考卡片

A. 四大指标速查

指标 评估对象 一句话 公式核心
Context Recall 检索 该来的全来了吗 召回相关数 / 应召回总数
Context Precision 检索 来的都有用吗 召回相关数 / 实际召回总数
Faithfulness 生成 有没有瞎编 可验证陈述数 / 总陈述数
Answer Relevance 生成 有没有跑题 逆向问题与原问题的平均相似度

B. 在 Dify 中对应的调优手段

指标异常 Dify 中调什么
召回率低 知识库 → 检索设置 → 开启混合检索;增加 Top-K;工作流中加提问改写节点
精准度低 知识库 → 检索设置 → 开启/调高 Rerank 阈值;减少 Top-K;给文档打元数据标签
忠实度低 LLM 节点 → 加 System Prompt 约束"只根据上下文回答";temperature 设 0
相关性低 先修检索精准度;LLM 节点 → 提示词引导聚焦用户问题

C. 一天时间快速落地的优先级

如果你只有一天时间,优先做路由/召回准确率的评估

  • 实现成本最低:预测文档ID == 期望文档ID ? 1 : 0,不需要调大模型
  • 准备门槛最低:Ground Truth 只需 (用户提问, 正确文档ID) 两列
  • 投入产出比最高:路由错了后面全白做,这是整条链路的咽喉

posted on 2026-04-23 09:46  云卷云舒灬  阅读(227)  评论(0)    收藏  举报

导航