企业级RAG 的胜负手不在「召回」,在「排得准」:开源Harness平台BizBuddy 检索增强实录

企业知识库 RAG 做完第一版,几乎都会遇到同一个尴尬:明明都召回了,模型偏偏用了第二、第三条,第一条反而不是答案。

一、第一版 RAG 的通病

BizBuddy 的第一版 RAG 很「标准」:文档解析切片 → 向量化进 Milvus(COSINE)→ 提问时单路稠密检索取 Top-K → 拼进上下文。切片策略是「字符窗口 + 句边界对齐」(默认 500 字 / 50 字重叠),只为不把句子从中间劈开。

能用,但三个问题很典型:

  1. top1 不准------相关切片基本都在 Top-5 里,却排不在第一位;
  2. 上下文冗余------同一段的相邻切片重复进上下文;
  3. 上下文不可控------按固定字数硬截断。

为什么「top1 不准」?因为稠密向量衡量的是语义相近 ,而语义相近不等于答案就在这里。几段都在谈同一主题时,向量分往往咬得很紧,真正那句反而排在后面。

换个角度说:召回决定「有没有」,排序决定「用不用得上」。一次检索里,切好的切片各自是一个向量、存进 Milvus;提问也向量化,做余弦近邻取回一批候选------在重排介入之前,「排序」这件事基本就是「看谁离得近」。

于是有了那句总结:瓶颈是「排序」,不是「召回」。

二、先建评测,再动手

改 RAG 最怕「感觉好像好了一点」。所以我们先做评测闭环:一个零依赖脚本(随仓库开源),自动建评测库、按语料目录入库,跑 hit@1 / hit@3 / hit@5、recall@5、MRR,并按用例类别拆分统计。

三个指标各有分工:

  • hit@k:正确答案是否出现在前 k 条里;
  • recall@5:该召回的相关切片覆盖了多少;
  • MRR:第一条正确答案的平均排名倒数------最能反映「排得准不准」。

评测集是自建的 56 条用例、5 类 :事实 / 术语 / 同义词 / 口语化 / 跨文档------前两类偏「关键词能命中」,后三类专门考语义与指代。基线(纯向量、threshold=0 纯排名口径)hit@1 64.3%,跨文档与口语化是主要短板。有了这把尺子,后面每一步改动都能前后对比。

脚本是零依赖的 Node ESM :自动建评测库(可 --rebuild 重建、--clean 清理)、按语料目录批量入库,输出整体 + 分类别的数字------跑一次就能对照,不靠手工记分。

三、第一招:上下文装配(去重 + 相邻合并)

对「已排序命中」做确定性后处理:去重 (规范化后互为子串,或 n-gram Jaccard ≥ 0.9)+ 同文档相邻切片合并,再加字符 / Token 上限。

效果:片段数 −22% ,关键词覆盖不降、排序不劣化,hit@1 从 64.3% 升到 67.9% 。注意它只改上下文、不改排序------真正的排序收益留给下一招。

四、胜负手:Rerank 重排

引入文本重排模型(DashScope gte-rerank-v2),链路变成:

稠密召回 max(topK, rerankTopN) → 重排 → 融合 → 截断 topK

融合策略我们做了有界对比:

策略 hit@1
不重排(基线) 67.9%
纯替换 replace 64.3%
排名融合 rank_rrf 66.1%
分数融合 score_fusion(α=0.5) 75.0%

最终选 score_fusion + rerankTopN=30。相对基线:

  • hit@1 67.9% → 75.0% 、MRR 0.772 → 0.829
  • hit@5 89.3% → 98.2% 、recall@5 96.4% → 98.2%
  • 代价仅延迟 +约 170ms

工程上还留了兜底:未配密钥 / 非 2xx / 超时 / 响应结构异常,一律降级为「保持原序」,检索永不因重排而中断。

为什么是「分数融合」?纯替换(replace)会丢掉向量分里已有的良好信号,排名融合(rank_rrf)又把分数信息压成了名次;把两路分别归一化后加权(α=0.5),既不浪费向量分,又引入重排模型的判断------实测也确实最稳。

五、走过的弯路:查询改写 + RRF 实测无收益

我们也试过「更重」的方案------查询改写 + 多路召回 + RRF 融合。结果实测 MRR 不升反略降、延迟涨到约 29 倍 。于是整体回退。

这条弯路值得写出来:不是所有论文里的招都适合你的语料。评测的价值,正是让你敢于「退掉一个看起来很先进的功能」。

六、检索也要守权限

检索从来不是「全库搜」:知识库有公开 / 本部门 / 仅本人三档生效范围;对话检索链路还多一层**「可见且启用」**------停用库不再被检索。这条过滤发生在检索入口,与智能体装配共用同一套可见性判定,因此不会出现「越权召回」。

这也解释了为什么「知识库检索」要作为一个显式工具绑定给智能体,而不是当内置黑盒:它既要按人过滤,也要能被权限与审计看见。

七、把开关交给运维,把尺子交给社区

能力集中在 bizbuddy.ai.rag.*:

配置 默认 说明
rerank-enabled 开 重排总开关
rerank-mode score_fusion 融合模式
rerank-top-n 30 进重排的候选数
assemble-* 开 去重 / 相邻合并 / 字符与 Token 上限

评测脚本与 56 条用例随代码开源,任何一次检索改动都能 A/B 出数字。

调优顺序也有讲究:先把上下文装配做对 (便宜、无外部依赖)→ 再上重排 (收益最大)→ 最后才考虑查询改写(最贵、最不确定)。我们就是按这个顺序走下来,才敢于在中途果断退掉改写。

八、为什么它是「Harness 平台」的 RAG

BizBuddy 的检索不是一个独立的「问答接口」,而是接入智能体的一个工具 (search_knowledge_base),因此天然继承平台工程能力:

  • 权限------按提问用户的生效范围过滤,停用库不参与;
  • 安全 ------命中片段进上下文前带 <untrusted> 边界标记,入库前过内容审核;
  • 审计------每次工具调用留痕,可回溯引用了哪些片段。

这些能拼在一起,是因为内核是 AgentScope Java Harness :一个 JVM 内,工具、权限、安全、审计走同一条装配链路,没有跨语言的 sidecar。

换句话说,RAG 在 BizBuddy 里不是「另起一个服务」,而是在平台里长大的一个能力------它天然带上权限、安全与审计,也天然能被「入口智能体 → 专家」的编排链路复用。

九、纯 Java、全量开源

整条检索链路------自建 OpenAI 兼容向量客户端、Milvus 接入、重排与融合、上下文装配、评测脚本------全部是 Java / 标准协议,无 Python 依赖。

RAG 做到最后,拼的不是「接了个向量库」,而是有没有度量、敢不敢取舍、能不能运营。这三件事,BizBuddy 都交在了代码里。

BizBuddy 全量开源(MIT License) :gitee.com/zl3624/biz-...

相关推荐
zhidian_AI1 小时前
约束编码智能体:4 个杠杆,只有 1 个能拒绝
人工智能
自养Agent1 小时前
Agent Harness 从用到会造:把工具接上,只是开始负责
人工智能·llm
追光者491 小时前
JSONL 日志的三个隐形坑:BOM、半行、和按字节轮转
ai编程
木头科技1 小时前
【AI 工程化第十五篇】Spring AI 流式输出高并发性能优化实战:SSE、背压、限流、缓存与灰度发布
人工智能·spring·性能优化
追光者491 小时前
重试是解药还是毒药?聊聊幂等性
ai编程
AICoder码农王1 小时前
如何写 Skill 第4课,脚本不进门
人工智能
打呵欠的猫1 小时前
用 AI 做性能分析:一行命令找出拖慢页面的 5 个组件,优化后首屏快了 40%
前端·性能优化·ai编程
星云低代码开发平台1 小时前
AI 连接器运行健康度:指标、异常恢复和联调清单
大数据·运维·网络·数据库·人工智能·mcp
stereohomology1 小时前
用免费算力额度实现markdown TeX混合编码主题及转换
人工智能·语言模型·llm·薅羊毛