欢迎光临
我们一直在努力

RAG 知识库-知识库检索编排实战:单库流水线与多库结果融合

一、问题的起点

企业知识库问答有一个绕不开的现实:用户的一次提问,往往要同时检索多个知识库——制度库、产品手册库、故障案例库。这带来两个看似简单、实则棘手的问题:

  • 每个知识库有独立的检索配置:A 库用向量检索、开了 Rerank、阈值 0.7;B 库用混合检索、阈值 0.5。各库的分数体系、召回策略完全不同,怎么并行执行、互不干扰?
  • 多路结果怎么合成一路:向量相似度是 [0,1] 的余弦分,关键词命中是固定分,不同库的分数量纲不一,直接拼在一起排序毫无意义。怎么融合才公平?
  • 更隐蔽的一个坑是:如果在粗召回阶段就按阈值过滤,一个“向量分只有 0.55、但经过重排序模型判定相关度 0.9”的高质量文档块,会在它被证明价值之前就被扔掉。

    本文介绍我们在生产环境中落地的一套检索编排架构,核心思想只有一句话:

    单库流水线是唯一的核心方法,每个知识库都执行它;多库检索只是“各库并行跑流水线 + 一次跨库融合”。


    二、总体架构

    检索发生在三层权限过滤之后(知识库可见性 → 文档元数据过滤 → 检索),确保只在“用户有权看的文档”范围内工作。整体编排如下:

    用户查询 + 可见知识库列表
    │
    ┌─────────────────┴─────────────────┐
    │ 各库并行执行「单库流水线」 │
    │ 粗召回 → Rerank → 阈值 → 库内TopK │
    └─────────────────┬─────────────────┘
    │
    ┌──────────────┴──────────────┐
    │ 知识库数量 == 1? │
    └──────┬───────────────┬───────┘
    是 │ │ 否
    ▼ ▼
    单库短路直接返回 多库 RRF 等权融合
    │
    全局 Rerank(可选)
    │
    全局 Score 阈值过滤 【前提:配置Rerank 】
    │
    全局 TopK

    关键设计决策有三个,后文逐一展开:

    • 单库流水线是核心:召回、重排、过滤、截断四步闭环,多库只是它的并行组合;
    • 分数融合用 RRF(多库):跨库只按“名次”而非原始分数融合,天然规避量纲问题;
    • 单库短路:只有一个有权限的知识库时,跳过全部全局步骤。

    三、单库流水线:核心方法

    每个知识库都走同一条四步流水线,它是整套系统的原子单元。

    3.1 流水线四步

    [1] 粗召回(模式层)
    向量 / 关键词 / 混合(混合内部再按融合规则二选一)
    返回 topK×2 候选池,按分数降序
    ↓
    [2] Rerank 重排序(可选)
    知识库开启 Rerank 时,用重排序模型按“查询-文档”语义相关度重新打分
    模型未配置/调用失败 → 保底保留粗召回顺序
    ↓
    [3] Score 阈值过滤
    按【最终分数】过滤(经过 Rerank 则过滤的是重排分数)
    ↓
    [4] Top-K 截断
    取前 k 条,单库结果产出完毕

    3.2 第一步:粗召回三种模式

    • 向量检索:查询经 Embedding 向量化,用 pgvector 余弦距离 <=> 做 ANN 近邻搜索,score = 1 – cosine_distance,懂语义、善同义;
    • 关键词检索:PG ILIKE 词面匹配(BM25 的阶段一替代,接口已预留替换点),不依赖任何模型,对型号、错误码、专有名词精确可靠;
    • 混合检索:两路各召回 topK×2,再按知识库配置的融合规则二选一、互斥执行:
      • 加权分数融合(默认):两路分数各自 min-max 归一化到 [0,1],再按权重加权——score = 0.7×normVec + 0.3×normKw,同一块双路命中则两份加权分相加,天然靠前;
      • Rerank 重排序融合:两路先 RRF 等权合并成候选池(顺序仅作保底),精排交给流水线第二步统一做,全链路只重排一次。

    3.3 第二步:Rerank 的位置是精心安排的

    粗召回追求“快而全”,Rerank 模型(Cross-Encoder 类)追求“准而贵”——把“查询+每个候选块”成对输入重新打分。它被显式放在粗召回之后、阈值之前,原因是:

    阈值必须基于最终分数执行。

    一个向量路只给了 0.55 分的块,可能恰恰是 Rerank 眼中相关度 0.9 的答案。如果粗召回时就阈值预过滤,它连进入 Rerank 的资格都没有。这就是候选池设计(见 3.5)存在的意义。

    容错策略也值得一提:Rerank 是“锦上添花”而不是“必经之路”。模型未配置、返回分数数量不匹配、下标越界、网络异常——任何一种情况都返回空,流水线保底使用粗召回顺序,绝不因为重排失败而丢掉结果。【注意点:需要留意一种边界情况:如果 Rerank 模型频繁失败但每次都静默降级,系统会长期运行在“无 Rerank”状态而不被察觉。建议增加一个监控指标,记录 Rerank 失败率,超过阈值时主动告警】

    3.4 第三、四步:阈值与 Top-K

    阈值过滤和条数截断是两步独立动作:先按分数滤掉噪声(阈值为 0 表示不过滤),再截取前 k 条。分开做的好处是语义清晰——阈值回答“够不够格”,Top-K 回答“要多少条”。

    3.5 候选池设计:为什么模式层返回 topK×2 且阈值传 0

    这是整套实现最关键的细节:

    阶段条数是否做阈值过滤
    模式层粗召回 topK × 2 否(阈值传 0)
    Rerank 全候选池 —
    阈值过滤 保留达标项 是,基于最终分数
    Top-K 截断 topK —

    放大召回、后置收紧:给 Rerank 和融合留足“原料”,把淘汰权交给掌握最终分数的编排层。


    四、多库编排:并行流水线 + 跨库融合

    当用户有权访问多个知识库时,在单库流水线之上叠加跨库处理。

    4.1 五步流程

    [1] 各库并行执行单库流水线(线程池并发,单路失败不影响其他库)
    ↓
    [2] 多库 RRF 等权融合(候选池 = 全局TopK × 4)
    ↓
    [3] 全局 Rerank(全局配置开启时;失败保底 RRF 顺序)
    ↓
    [4] 全局 Score 阈值过滤 【前提:rerank开启】
    ↓
    [5] 父子扩展等后处理 → 全局 Top-K 截断

    4.2 第一步:并行执行 + 故障隔离

    各库通过固定线程池(4 线程)并行跑同一条单库流水线。每个知识库用自己的参数独立完成召回、库内 Rerank、库内阈值、库内 Top-K。任意一库检索抛异常只记日志、返回空列表,不拖累其他库——这是多库场景必须的故障隔离。

    4.3 第二步:为什么跨库融合用 RRF 而不是加权分数

    这是多库融合的算法核心。不同库的原始分数不可直接比较:

    • 向量分是余弦相似度,关键词命中是固定分;
    • 即使都是向量分,不同库内容分布不同,0.8 分在 A 库和 B 库的“含金量”也不同。

    RRF(Reciprocal Rank Fusion,倒数名次融合)只看名次、不看分数,因此天然免疫量纲问题:

    RRF_score(块) = Σ 1 / (k + rank_i)
    各库

    • rank_i:该块在第 i 个知识库结果中的名次(从 1 开始);
    • k = 60:学术界与工业界通用的经验常数,作用是“压缩头部名次优势”——第 1 名和第 2 名的差距不会大到碾压其他库的贡献;
    • 同一块在多个库中被召回 → 各路 RRF 分累加,跨库共识的块自然浮到顶部。

    举例:某块在 A 库排第 1、在 B 库排第 3,其融合分 = 1/(60+1) + 1/(60+3) ≈ 0.0322;而只在一个库排第 1 的块只有 1/61 ≈ 0.0164。“多个知识库都认可”比“单个知识库特别看好”权重更高,这正是跨库融合想要的语义。

    融合后块的分数被覆盖为 RRF 分,按融合分降序,候选池取 全局TopK × 4,同样为后续全局 Rerank 预留空间。

    注意两种融合的分工:库内混合检索用加权分数融合(同库、同 Embedding、分数量纲一致,可以直接操作分数);跨库用 RRF(异质分数不可比,只能比名次)。同一个 RRF 组件以“两路带权 / 多路等权”两个方法复用。

    4.4 第三~五步:全局加工

    • 全局 Rerank:跨库 RRF 给出的只是“按名次共识”的粗排,再由全局配置的重排序模型对整个融合池做一次跨库精排,回答“在所有库的候选中,谁才是真正最相关的”;
    • 全局阈值/全局 Top-K:基于全局最终分数统一过滤、截断,参数取自“多库结果融合”全局配置;
    • 父子扩展收尾:命中单位是子块(检索单元),送入大模型的是父块(上下文单元)。按子块 parentId 批量回查父块内容、同父多子去重取最高分,既保证上下文完整,又保留引用溯源能力。

    五、单库短路:不要给单库结果做“多库按摩”

    一个容易被忽略但很重要的规则:

    当用户只有一个知识库权限时,直接返回该库流水线结果,跳过 RRF、全局 Rerank、全局阈值、全局 Top-K 全部全局步骤。

    原因有三:

  • 语义正确:单库结果的分数已经是该库体系下的最终分数(可能是 Rerank 分),再按全局阈值(RRF 分体系或另一套配置)过滤属于张冠李戴;
  • 避免重复重排:库内已经按知识库配置重排过一次,没必要用全局模型再排一次,白花 token 和延迟;
  • 参数归属清晰:单库只认知识库自身设置,全局配置天然只在“多库”这个它该出现的地方生效。
  • 实现上就是流水线产出后的一个分支判断,一行短路,省掉整条全局链路。


    六、参数归属:单库只执行单库的参数

    编排的复杂性很大程度来自“这个参数到底听谁的”。我们定下的规则简单而严格:

    参数单库流水线多库全局步骤
    检索方式(向量/关键词/混合) 知识库设置 —
    库内 Rerank 开关 / 模型 知识库设置 —
    库内 Score 阈值 / Top-K 知识库设置 —
    混合融合规则 / 双路权重 知识库设置 —
    全局 Rerank 开关 / 模型 — 多库结果融合配置
    全局 Score 阈值 / 全局 Top-K — 多库结果融合配置
    • 单库配置配置只管单库:单库只执行单库的参数;
    • 全局配置只管多库:它控制的是融合之后的跨库加工;

    七、容错与分层小结

    整套编排的容错是分级的:

    • 模式层:只负责召回与融合,不感知 Rerank/阈值/Top-K,输出候选池;
    • Rerank 层:任何失败都退化为“保留上游顺序”,不阻断流程;
    • 多库并行层:单库异常隔离,返回空路,融合照常进行;
    • 后处理层:父子扩展对无 parentId 的通用分块原样透传,父块缺失时保留子块,数据异常也不丢结果。

    分层之后,每个组件都可以独立演进:关键词路未来从 ILIKE 升级为真正的 BM25(tsvector / ES),只需替换模式实现;融合算法调整只动融合组件;上层编排一行不用改。


    八、写在最后

    回顾这套设计,真正让系统变简单的不是某个算法,而是两个结构性决定:

  • 把单库流水线确立为唯一核心方法——多库不再有自己的一套召回逻辑,只是“并行 N 次 + 融合 1 次”,重复代码与分叉判断全部消失;
  • 把“分数”在正确的阶段用在正确的地方——库内同质分数用加权融合,跨库异质结果比名次(RRF),阈值永远等在 Rerank 之后,候选池先放大再收紧。
  • RAG 检索没有银弹,但一套“单库闭环、多库组合、名次融合、短路保底”的编排骨架,足以支撑从单库试点到成百上千个知识库的平滑扩展。


    赞(0)
    未经允许不得转载:171主机测评 » RAG 知识库-知识库检索编排实战:单库流水线与多库结果融合
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址