云计算百科
云计算领域专业知识百科平台

Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?

Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?

Dify 实验系列 · 中级 10/20 | 实验编号:DIFY-102-11

上篇:Dify 中级实验(09):HTTP 节点进阶——如何搞定认证、分页与错误重试?

1. 实验目的

掌握知识库高级调优的方法论:分段策略(固定长度/自定义分隔符/智能分段)、检索模式(向量/全文/混合)、Rerank 重排,以及最重要的——建立检索质量评估体系。没有评估体系的调优就是瞎调:改一个参数,好不好,得用数字说话。

适合场景:产品文档知识库、客服 FAQ、RAG 问答系统的上线前调优与持续监控。

2. 场景设计

500 页产品技术文档做成知识库后「导入即用」召回率低。本实验构建一个检索质量评估工作流:

  • 代码节点内置 10 组测试用例(query + expected_keywords 期望关键词 + expected_doc 期望命中文档);
  • 迭代逐条:拆解测试项 → 知识库检索(top_k 3)→ 评估(关键词命中率 + Top1 文档匹配);
  • 汇总综合评分,输出「哪些查询召不回、平均分多少」。
  • 输入:无(测试集硬编码在代码节点);输出: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:
    459c49816b7643e7b44fc430f33ef035 # 你的知识库 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: knowledgeretrieval
    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 流水线——如何搭建多路检索与精排?

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!