ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【Spring AI 实战 · 阶段三·篇3】检索质量工程:五阶段混合检索管线

【Spring AI 实战 · 阶段三·篇3】检索质量工程:五阶段混合检索管线 系列说明一个 Java 后端视角的 Spring AI 渐进式实战教程载体为开源项目「劳小司 · 智能法律助手」。序章技术栈全景与 AI 学习指南阶段一 · 流式对话内核篇1 SSE 流式·停止·思考可见化 / 篇2 会话记忆压缩与滚动体验阶段二 · 工具调用篇1 Function Calling 与法律计算器 / 篇2 联网搜索与工具预算阶段三 · RAG 知识库篇1 起步与底账化 / 篇2 Agentic RAG 与引用可信度 /篇3 检索质量工程与知识库体验本文阶段四 · 多模型路由篇1 五路级联路由阶段五 · 安全与质量门篇1 安全层与强制检索 / 篇2 质量门与评估门禁 / 篇3 指代消解与阻塞隔离阶段六 · 产品化与用户体系篇1 认证·配额·门禁 / 篇2 前端·移动端·身份 / 篇3 劳动法专精与多模态阶段七 · 存储演进与部署篇1 存储迁移 / 篇2 部署契约本篇涉及rag/KnowledgeRetrievalService.java、rag/RerankService.java、rag/LawArticleBrowseService.java。一、单纯向量检索的天花板篇1、篇2 打通了检索得到、同步得起、引用可信但一个核心问题还没解决检索准不准单靠向量 Top-K 有两个天花板Bi-Encoder 精度有限向量检索是 query 和 doc各自独立编码成向量再算余弦无法建模词级交互比如合同解除和解除合同语义近但未解除合同和解除合同向量可能很近语义却相反离散符号命中差用户问第四十七条向量检索对这种精确编号反而不如关键词匹配。一个直觉的错误做法是把 topK 调大点多召回一些总没错。大错特错——噪声条目会稀释模型注意力、撑爆上下文、还会诱发模型从一堆半相关条文里硬凑依据的幻觉。召回率和精度不能靠一个 topK 硬扛。工业界的标准解是两阶段宽进粗召回 窄出精排。本项目落地为五阶段管线。二、五阶段检索管线问题Planner 改写后 ① 稠密路粗召回 pgvector KNNrecallTopK12similarity-threshold0.55 截断噪声 ② 稀疏路召回 pg_trgm GINILIKEbm25TopK10补第四十七条类离散编号精确匹配 ③ RRF 融合 score Σ 1/(60rank)两路互补条文级去重 ④ rerank 精排 百炼 gte-rerank-v2 Cross-Encoder 取 topK5失败降级融合序 ⑤ Small-to-Big chunk 子块命中 → 按 articleId 还原整条全文注入对应retrieveCitations()的主干稠密召回 → 稀疏召回 → RRF 融合 → rerank → 整条还原。下面逐个拆。① 稠密路向量 KNN 粗召回SearchRequest.builder().query(query).topK(recallTopK)// 12宽进.similarityThreshold(similarityThreshold)// 0.55低于此视为未命中.build();recallTopK12是宽进——先多召回一些保召回率similarity-threshold0.55是降噪闸门低于阈值的直接砍掉同时激活检索落空分支落空时提示模型换词或转通用知识。可选category过滤劳动/民事…缩小检索域。② 稀疏路pg_trgm 补精确匹配向量不擅长的精确编号/术语交给稀疏检索。本项目用 PostgreSQL 的pg_trgm GIN 索引三元组 ILIKE近似 BM25命中第四十七条这种离散符号。它是向量路的互补不是替代。③ RRF 融合两路合成一个序Reciprocal Rank Fusion公式极简score(d) Σ 1/(k rank)k60工业经验值。scores.merge(key,1.0/(RRF_Ki1),Double::sum);// rank 从 1 起妙处在于只用名次不用原始分数天然规避了向量余弦分和BM25 分不同量纲无法直接相加的问题。同一条文的多个 chunk 按lawName|articleNo条文级去重保留融合分最高的。④ rerank 精排Cross-Encoder 的关键一跃前一步的融合还是 Bi-Encoder 级别的排序。这里上Cross-Encoder把 query 和每个候选 doc拼在一起送进gte-rerank-v2模型输出精确的相关性分数重排取 topK5。MapString,ObjectbodyMap.of(model,gte-rerank-v2,input,Map.of(query,query,documents,docs),parameters,Map.of(top_n,topN,return_documents,false));精度高但慢、贵所以只用在窄出这一层对 12 条候选精排不是对全库。和联网搜索一样Spring AI 没有 rerank 自动装配手写 RestClient 直调。精排的relevance_score回写进citation.score——前端引用卡上的TOP 0.xx就是 Cross-Encoder 的真实分数注意它和 ① 的余弦相似度阈值不是同一个量表。⑤ Small-to-Big命中小块注入整条篇1 分块时把长条文拆成了子块检索粒度小、保精度。命中子块后按articleId回 PG 底账还原整条全文再注入 Prompt注入粒度大、保上下文完整if(!c.chunked()||c.articleId()null)returnc;LawArticleEntityalawArticleMapper.findById(c.articleId());returnnewLawCitation(a.getId(),...,a.toEmbeddingText(),false);// 整条还原检索用小块、注入用整条——这就是 Small-to-Big 的精髓。三、全链路降级信条五阶段里每一阶段失败都不阻断只降级阶段失败降级分类过滤检索失败去掉过滤重搜BM25 稀疏路失败索引未建退纯稠密路rerank 精排失败退 RRF 融合序截断Small-to-Big 还原失败退 chunk 子块文本整条向量库不可用返回空列表对话退化为纯 LLM检索是锦上添花的能力绝不能因为精排服务抖动就把用户的对话带崩。四、知识库前端体验检索质量之外法条库浏览页LawArticleBrowseService也做了体验精修faceted 高级检索按法名/领域/条号分面过滤、分页栏固定底部、法条正文的字体与标签样式优化。这部分偏前端核心是把后端检索能力如实、清晰地呈现给用户与引用可信度一脉相承。五、踩坑备忘① topK 不是越大越好。调大 topK 看似提高召回实则引入噪声、稀释注意力、诱发硬凑幻觉。要召回率和精度兼得靠的是宽进recallTopK 窄出rerank topK两阶段不是单点调参。② pg_trgm 索引要先建。稀疏路依赖pg_trgmGIN 索引扩展没装或索引没建时keywordSearch会抛异常——代码里 catch 住降级为纯稠密路不阻断。上线前记得确认扩展和索引就位。③ rerank 分数 ≠ 向量相似度。两个量表别混引用卡TOP 0.xx是 Cross-Encoder 相关性分similarity-threshold0.55是余弦相似度阈值。给用户的文案别写错。④ RRF 融合用名次不用分数。千万别试图把余弦分和 BM25 分加权平均——量纲不同加出来是错的。RRF 只取名次是这个场景的标准解。六、小结阶段作用稠密粗召回向量 KNN宽进保召回稀疏召回pg_trgm 补精确编号RRF 融合名次合成跨量纲rerank 精排Cross-Encoder 窄出提精度Small-to-Big小块命中、整条注入七、下篇预告到这里RAG 知识库这条线起步→底账化→Agentic→引用可信→检索质量完整闭环了。但一直用同一个模型跑所有问题成本和质量的平衡没解决——闲聊用贵模型浪费、复杂推理用便宜模型降质。阶段四我们做五路模型级联路由。源码与体验Gitee国内快https://gitee.com/spaserby/laoxiaosi.git GitHub https://github.com/spaserby/laoxiaosi.git 在线演示https://laoxiaosi.noctisblue.com本系列全套代码皆开源觉得这篇有帮助欢迎顺手点颗 ⭐
返回列表