AI FaultLab:给 Hybrid RAG 补上检索评测闭环 AI FaultLabHybrid RAG Evaluation 的补齐今天主要补的是 AI FaultLab 里 RAG 的评测闭环。之前项目已经完成了 Hybrid RetrievalMilvus 向量召回、BM25-like 关键词召回、RRF 融合、轻量 rerank以及 Runbook 索引治理。但做到这里其实还差一个关键问题没有回答现在的检索效果到底怎么样如果只是看一次 AI 报告里有没有引用到 Runbook很容易误判。某一次召回对了不代表整体稳定某一次 Hybrid 表现好也不代表它在所有故障类型上都优于单路召回。所以这次补的重点不是继续堆检索策略而是给 RAG 检索链路加一套基础评测能力。当前评测只覆盖 retrieval不调用 LLM也不改诊断主流程这一点比较关键。评测的目标是单独观察“检索器有没有把正确的 Runbook section 找回来”避免被大模型生成效果干扰。一、为什么这一步必须做RAG 链路如果没有评测很容易变成“看起来能用”。比如 MQ 消息堆积场景模型最终报告里出现了“增加消费者并发”“排查慢 SQL”“检查队列积压”这些建议看起来都合理。但真正要追问的是这些建议是不是来自正确的 Runbook section Hybrid 召回是不是比单独 Milvus 更稳 修改 query construction 后效果有没有变差 rerank 权重调整后有没有误伤某些 case如果没有评测集这些问题都只能凭感觉判断。所以这次我把 RAG Evaluation 单独抽出来做成一套小型但可扩展的评测链路。二、评测集怎么设计当前评测数据集放在faultlab-ai-service/evaluation/rag_eval_cases.json第一版一共 9 个 case覆盖项目里的三类故障MQ_BACKLOG THREAD_POOL_SATURATION IDEMPOTENCY_CONFLICT每个 case 主要包含四类信息caseId scenarioCode query 中的 ruleResult 和 metrics expected docId section这里最重要的是 expected 的定义。我没有只判断“召回到同一个文档就算命中”而是使用严格的docId section也就是说如果期望是{ docId: mq-backlog, section: 核心指标 }那么只召回mq-backlog这个文档但 section 是“常见原因”不能算完整命中。这个约束比只看 docId 更严格也更符合实际诊断场景。因为 Runbook 里的“核心指标”“常见原因”“修复建议”虽然都属于同一个文档但对 Prompt 的帮助是不一样的。诊断证据分析阶段需要“核心指标”根因分析阶段需要“常见原因”最后给解决方案时才更依赖“修复建议”。三、指标选择HitK、RecallK、MRR这次没有一开始就上很复杂的指标而是先实现了三个最基础、最容易解释的指标。HitKHitK 关注的是topK 里有没有命中任意一个期望 section只要命中一个 expected ref这个 case 就算 hit。它适合回答这个问题有没有至少召回一个有用的 Runbook sectionRecallKRecallK 更细一些计算的是topK 命中的 expected refs 数量 / expected refs 总数如果一个 case 期望召回两个 section结果只召回了一个那么 RecallK 就是 0.5。它适合回答该找回来的内容找回来了多少MRRMRR 关注第一个命中结果的位置。如果第一个结果就命中MRR 1.0如果第二个结果才命中MRR 0.5如果完全没命中MRR 0它适合观察排序质量。召回到了但排在很后面和排在第一位实际效果是不一样的。这三个指标组合起来基本可以覆盖第一版 RAG 检索评测的核心需求有没有命中、命中了多少、命中位置靠不靠前。四、支持多种 Retriever 对比当前评测接口支持bm25 milvus hybrid all也就是说可以单独评测 BM25-like也可以单独评测 Milvus还可以评测 Hybrid。retrieverall会分别跑多种 retriever然后返回各自结果。接口是POST /ai/runbooks/evaluate常见请求{retriever:bm25,topK:3}{retriever:hybrid,topK:3}{retriever:all,topK:3,report:true}这里有一个细节如果某个 retriever 失败不会影响其他 retriever 的结果。比如 Milvus 没启动milvus评测可能返回结构化错误但bm25仍然可以正常评测。这和诊断链路里的 fallback 思路是一致的外部组件失败不应该把整个流程拖垮。五、CLI 和 API 都保留这次没有只做接口也补了 CLI。本地可以直接跑.\.venv\Scripts\python.exe scripts\evaluate_retrieval.py --retriever bm25 --top-k 3也可以输出 Markdown 报告.\.venv\Scripts\python.exe scripts\evaluate_retrieval.py --retriever all --top-k 3 --report还可以写入文件.\.venv\Scripts\python.exe scripts\evaluate_retrieval.py --retriever all --top-k 3 --report --output evaluation/reports/rag_eval_report.mdCLI 的好处是方便本地调试也适合后续接 CI。API 的好处是方便以后做可视化页面或者运维入口。生成的报告文件默认不提交只保留evaluation/reports/.gitkeep。这个处理比较干净避免把每次本地运行出来的报告都混进 Git。六、Markdown Report 做了什么原来的 Evaluation 结果是 JSON适合程序读但不适合人看。今天补了 Markdown Report主要是为了复盘和展示。报告包含这些部分Overview Overall Metrics Retriever Comparison Metrics By Fault Type Case Details Miss Cases Optimization Suggestions我觉得最有价值的是后面两块Miss Cases和Optimization Suggestions。因为评测不是为了证明“我这个 RAG 很强”而是为了发现哪里没召回、为什么没召回、下一步应该怎么改。比如 BM25-like 某个 case 没命中可能说明Runbook keywords 不够 section 标题没有覆盖关键指标名 query 里的字段名和 Runbook 表达没有对齐这时优化方向就比较明确补充 Runbook keywords 调整 section 标题 在正文中补充指标名、英文别名、字段名 优化 query construction 调整 RRF k、rerank 权重和 topK这些建议目前是规则型的不调用 LLM。这样做的好处是稳定、可解释也不会把评测报告本身再变成一个不可控的大模型输出。七、今天开发完成后的链路现在 RAG Evaluation 的链路大概是rag_eval_cases.json - RetrievalEvaluator - 指定 retriever - bm25 / milvus / hybrid - retrieved chunks - docId section 命中判断 - HitK / RecallK / MRR - Markdown Report - Miss Case Analysis它和诊断主链路是分开的Evaluation 不调用 LLM Evaluation 不走 diagnosis workflow Evaluation 不改 DiagnosisResponse Evaluation 不影响 Java 后端和前端这一点很重要。评测就是评测不掺杂生成链路。这样才能更准确地看 retrieval 本身的问题。八、这次的工程取舍1. 先做小评测集不追求大而全当前只有 9 个 case数量不多但覆盖了三个核心故障类型。第一版不需要追求数据量重点是把评测结构搭起来。后面扩 case 比改评测框架容易得多。2. 使用 docId section 严格命中只看 docId 太粗容易让结果虚高。所以这里用docId section判断命中能更真实地反映检索质量。这个设计会让初始指标没那么好看但更有参考价值。3. 不调用 LLMEvaluation 只评 retrieval不评 generation。原因很简单如果把 LLM 也放进来最后结果不好时很难判断是检索问题、Prompt 问题还是模型生成问题。第一阶段先把 retrieval 单独量化清楚。4. 先用 HitK、RecallK、MRR没有一开始做 nDCG因为当前 case 数量少expected 也比较简单。HitK、RecallK、MRR 已经足够支撑第一版对比和回归。后续 case 多了再加 nDCG 更合适。5. Markdown Report 面向人读JSON 适合程序Markdown 适合复盘。这次补 Markdown Report主要是为了让结果能直接用于技术博客 面试展示 PR 说明 后续优化记录这比单纯返回一堆 JSON 指标更实用。九、目前能回答哪些问题做到这一步后这套 RAG 已经不只是“能跑”而是开始能回答一些工程问题。比如Hybrid 的整体 HitK 是否高于 bm25 Milvus 在某些 faultType 上是不是更容易 miss BM25-like 对指标名是否更敏感 哪个故障类型召回最弱 哪些 case 经常只召回到正确 docId但 section 不对这些问题一旦能被量化后续优化就不再是凭感觉。十、当前限制这套 Evaluation 还只是基础版。目前的限制主要有case 数量少目前只有 9 个 没有 nDCG 没有 CI regression gate Milvus evaluation 依赖 Milvus 和 embedding 可用 优化建议是规则型不调用 LLM BM25-like 不是标准搜索引擎级 BM25 lightweight rerank 不是真实 rerank 模型这些都不是问题只是阶段边界。当前目标是把评测闭环先跑通而不是一次性做成完整搜索评测平台。十一、后续可以怎么演进后面可以沿着几个方向继续补。第一是扩充 case。现在每类故障只有少量 case后面可以按故障现象、指标组合、边界场景继续扩。第二是按 faultType 做趋势统计。比如每次调 rerank 权重后看 MQ、线程池、幂等三类故障的 RecallK 有没有变化。第三是加 nDCG。当 expected section 有强弱相关性时nDCG 会比 RecallK 更细。第四是做 CI regression gate。比如 Hybrid 的 Hit3 不能低于某个阈值否则 PR 不允许合并。第五是接入真实 rerank 模型后做对比。现在是 lightweight rerank后续可以把真实 rerank 的效果和当前规则 rerank 做横向比较。十二、总结今天这一步看起来不是“新增一个酷功能”但对 RAG 工程化很关键。之前的链路是Runbook - Milvus / BM25-like / Hybrid - Prompt - LLM现在补上了Eval Cases - HitK / RecallK / MRR - Markdown Report - Miss Case - Optimization Suggestions也就是说RAG 不再只是一个检索增强模块而是开始有了评测和反馈闭环。这个阶段完成后AI FaultLab 的 RAG 可以更准确地描述为具备 Hybrid Retrieval、索引治理和检索效果评测的故障诊断 RAG 链路。这比单纯说“用了 Milvus 做 RAG”要扎实得多。