Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?
Dify 实验系列 · 中级 10/20 | 实验编号:DIFY-102-11
上篇:Dify 中级实验(09):HTTP 节点进阶——如何搞定认证、分页与错误重试?
1. 实验目的
掌握知识库高级调优的方法论:分段策略(固定长度/自定义分隔符/智能分段)、检索模式(向量/全文/混合)、Rerank 重排,以及最重要的——建立检索质量评估体系。没有评估体系的调优就是瞎调:改一个参数,好不好,得用数字说话。
适合场景:产品文档知识库、客服 FAQ、RAG 问答系统的上线前调优与持续监控。
2. 场景设计
500 页产品技术文档做成知识库后「导入即用」召回率低。本实验构建一个检索质量评估工作流:
输入:无(测试集硬编码在代码节点);输出:total_cases / avg_score / avg_keyword_rate / top1_matched + 汇总文本。
3. 节点拓扑
开始(无变量)
↓
生成测试集(Code:10 组 query/expected_keywords/expected_doc)
↓
逐条检索评估(迭代)
├─ 拆解测试项(Code:item → query / expected_keywords / expected_doc)
│ ↓
│ 技术文档库检索(KB,top_k 3,迭代内)
│ ↓
│ 评估检索质量(Code:keyword_rate + top1_match + score)
↓
汇总综合评分(Code)→ 结束
4. 关键配置
4.1 测试集(Code)
测试用例要覆盖典型查询形态:操作类(重置密码)、错误码类(E1001)、概念类(什么是 RAG):
def main() –> dict:
test_cases = [
{"query": "如何重置密码", "expected_keywords": ["密码重置", "忘记密码", "重置步骤"], "expected_doc": "用户管理_密码重置"},
{"query": "API 调用频率限制", "expected_keywords": ["限流", "Rate Limit", "API配额"], "expected_doc": "API文档_限流策略"},
{"query": "错误码 E1001 是什么", "expected_keywords": ["E1001", "错误码", "排查"], "expected_doc": "排障手册_错误码"},
# … 共 10 组
]
return {"test_cases": test_cases}
4.2 迭代内知识库检索
迭代内 KB 节点需要五件套(isInIteration/iteration_id/parentId/sourcePosition/targetPosition):
– data:
dataset_ids:
– 459c4981–6b76–43e7–b44f–c430f33ef035 # 你的知识库 ID
isInIteration: true
iteration_id: iter_test
output_retrieval_result: true # 必须 true,否则 result 为空
parentId: iter_test
query_attachment_selector: []
query_variable_selector: [cd_split, query]
retrieval_mode: single
score_threshold: 0.0
title: 技术文档库检索
top_k: 3
type: knowledge–retrieval
id: kb_retrieve
4.3 评估节点(Code)
KB 结果传给代码节点,参数类型必须声明为 list(检索结果是 list[dict]),评分 = 0.5 × 关键词命中率 + 0.5 × Top1 文档匹配:
def main(query: str, expected_keywords: str, expected_doc: str, retrieved: list) –> dict:
import json
retrieved = retrieved if isinstance(retrieved, list) else []
texts = [str(r.get("content", "")) for r in retrieved if isinstance(r, dict)]
all_text = " ".join(texts).lower()
try:
kws = json.loads(expected_keywords or "[]")
except Exception:
kws = []
kws = [str(k).lower() for k in kws if k]
hits = sum(1 for k in kws if k in all_text)
keyword_rate = round(hits / len(kws), 2) if kws else 0.0
top1_title = str(retrieved[0].get("title", "")) if retrieved and isinstance(retrieved[0], dict) else ""
top1_match = bool(top1_title) and str(expected_doc or "").lower() in top1_title.lower()
score = round(keyword_rate * 0.5 + (1.0 if top1_match else 0.0) * 0.5, 2)
return {"eval_text": json.dumps({...}, ensure_ascii=False)} # 序列化成 string 供迭代收集
4.4 迭代输出与汇总
迭代 output_selector 只能选可见类型(array[object] 收集不到),所以评估节点输出 eval_text 字符串、output_type: array[string];汇总节点再逐个 json.loads 聚合:
def main(results: list) –> dict:
import json
total = 0; score_sum = 0.0; kw_sum = 0.0; top1_ok = 0
for r in results:
try:
d = json.loads(r) if isinstance(r, str) else {}
except Exception:
d = {}
total += 1
score_sum += float(d.get("score", 0) or 0)
kw_sum += float(d.get("keyword_hit_rate", 0) or 0)
if d.get("top1_match"):
top1_ok += 1
return {
"total_cases": total,
"avg_score": round(score_sum / total, 2) if total else 0.0,
"avg_keyword_rate": round(kw_sum / total, 2) if total else 0.0,
"top1_matched": top1_ok,
"summary_text": "检索质量评估:共 {} 组用例,综合评分 {},关键词命中率均值 {},Top1 文档匹配 {} 组".format(
total, round(score_sum / total, 2) if total else 0.0,
round(kw_sum / total, 2) if total else 0.0, top1_ok),
}
5. 运行验证
| total_cases | 10 | 10 |
| avg_keyword_rate | 0~1 之间,反映关键词召回水平 | 视知识库质量而定 |
| top1_matched | 期望文档命中 Top1 的组数 | 视知识库质量而定 |
| summary_text | 「共 10 组用例,综合评分 X,关键词命中率均值 Y,Top1 文档匹配 Z 组」 | 与预期一致 |
调优闭环:跑出基线 → 调整知识库分段策略/TopK/是否开 Rerank → 重跑同一测试集 → 对比 avg_score。分数上升说明改对了——这就是「评估比配置重要」的落地方式。
6. 采坑点
| KB 结果传给 code 签名写 str | 运行报 'list' object has no attribute … | 参数类型声明 list,用 r.get("content", "") 提取 |
| 忘了 output_retrieval_result | [kb, result] 返回空,评估全 0 | 设为 true,结果才是结构化 list[dict] |
| 把 Rerank 当工作流节点 | 找不到 rerank 节点类型 | Rerank 是知识库检索设置(dataset 层面 reranking_enable + reranking_model),不在工作流里配置 |
| 迭代 output_selector 选 array[object] | 迭代输出为空数组 | 评估节点输出 json.dumps 字符串,output_type: array[string] |
| 测试集超过 30 组 | 迭代报 then length of var "item" must be less than 30 elements | 测试集留余量(本实验 10 组) |
| 种子文档不含测试关键词 | 关键词命中率恒 0,误判「检索坏了」 | 测试集与知识库种子文档对齐,先验证数据再调参 |
💡 调优顺序建议:① 先保证文档质量(预处理清洗、分段语义完整)——垃圾进垃圾出;② 再选检索模式(混合 > 单一,有 rerank 模型就开);③ 最后调 TopK/Score 阈值,每次只改一个变量并用同一测试集回归。
7. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-11:知识库深度调优.md
- 源码(可直接导入):dify102_11_知识库调优评估.yml
文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。
下一篇:Dify 中级实验(11):高级 RAG 流水线——如何搭建多路检索与精排?
网硕互联帮助中心



评论前必须登录!
注册