博客
技术深度解析

使用倒数排名融合(Reciprocal Rank Fusion)构建混合 RAG 流水线

向量相似度与 PostgreSQL 全文搜索并行运行,并通过 Reciprocal Rank Fusion 融合为带引用和相关性评分的答案。

Simmetric Team7 分钟阅读12/06/2026

为什么单一的检索策略永远不够

检索增强生成(RAG)的好坏取决于检索器交给模型的内容。向知识库提问,答案的质量只取决于它前面的分块 - 而 enterprise 级问题有两种形态,没有任何单一搜索策略能同时处理好。

语义问题 - "计费如何处理按比例分摊?"、"我们关于供应商锁定的决定是什么?" - 关乎含义。向量搜索在这里大放异彩:它将查询和文档分块嵌入到同一空间并检索最近邻,因此用完全不同的词写成的分块也能浮出水面。但纯向量搜索对另一种问题形态并不可靠:精确标识符。产品代码、错误字符串、法规编号、人名 - 嵌入会模糊它们,而某个晦涩错误代码的最近邻往往是一个不相关的其他代码。

关键词问题则是镜像。PostgreSQL 全文搜索擅长精确 token 和稀有词,却完全错过同义改写:搜索"人员扩充",它找不到写着"承包商资源"的文档。

真实的企业文档会吸引这两种问题,往往还在同一次会话中。因此 Simmetric Chat 拒绝二选一。每次检索并行运行两条腿 - 向量相似度和 PostgreSQL 全文搜索 - 并在任何内容到达模型之前用 Reciprocal Rank Fusion(RRF)融合结果。本文介绍这条流水线:两条腿、融合数学、为它们供料的摄取路径,以及让答案可审计的引用层。

两条腿,一次查询

当聊天需要知识时,ReAct 代理会调用其 rag_search 技能,混合搜索同时启动两个独立的检索:

  • 向量腿离开服务器,调用 collector - 拥有向量存储的服务。collector 使用与摄取时相同的嵌入模型嵌入查询,并从工作区的集合返回最近的分块。向量存储本身是可插拔的 - 默认 LanceDB(基于文件、本地、适合 air-gap),或 Qdrant、pgvector、Chroma(适合偏好服务端索引的部署)。
  • 全文腿从不离开服务器。它直接查询 PostgreSQL,将查询与分块表上的拼接全文向量列匹配,由 GIN 索引支持并按词法相关性排序。分词覆盖七种语言,因此意大利语和德语文档可以按自己的词法规则搜索,而不是用英语近似。

集合按工作区隔离,这正是知识得以隔离的原因:工作区 A 中的聊天只从工作区 A 的分块检索,除此之外别无其他。每次查询运行两条腿多花一次往返,换来任何单腿都没有的覆盖率。

故障模式也刻意冗余。一个守卫将今天配置的嵌入模型与工作区文档嵌入时所用的模型进行比较。如果不匹配 - 例如模型更换之后 - 向量腿被完全跳过,检索降级为仅全文,而不是从不具可比性的嵌入空间提供相似度分数。聊天继续工作,操作员在管理面板中获得明确的重新索引路径,而不是静默的质量回退。

倒数排名融合,具体而言

两条腿返回的排名列表在不具可比性的尺度上衡量:一边是余弦相似度,另一边是词法相关性。对原始分数取平均意味着要相互校准这些尺度 - 脆弱,而且对每个嵌入模型和每个语料库都不同。Simmetric Chat 融合排名而非分数,使用 Reciprocal Rank Fusion:

text
fused(chunk) = sum over legs of 1 / (k + rank),  with k = 60

每个分块在它出现的每条腿中累积一次贡献,因此在两条腿上都排名第一的分块得分约为仅在一条腿上排名第一的分块的两倍。常数 k 抑制了最高排名的过度影响 - k = 60 时,单条腿上第一名与第五名的差异只是很小的增量,而跨腿共识才是真正把分块推向合并列表上方的力量。

两个工程细节让融合达到生产级而非教科书级:

  • 每个分块的来源集合记录它是由向量腿、全文腿还是两者找到的。被两条腿都检索到的分块是流水线能产生的最强佐证,下游格式化保留该信号而不是将其抹平。
  • 确定性决胜规则 - 融合分数降序,然后文档标识符,然后分块位置 - 保证相同查询在每台副本上返回相同顺序。当有人问"为什么引用了这段?"时,答案必须可复现;非确定性融合会让这个问题无法回答。

从文档到可搜索的分块

融合只是流水线的一半;另一半发生在摄取时,上传的文档变成两条腿都能搜索的分块。collector 解析 PDF、Word、Excel、PowerPoint、Markdown、CSV 文件和 YouTube 转录文本,用递归字符分割器切分文本(每块 1,000 字符,200 字符重叠,避免跨越边界的句子丢失),嵌入每个分块,并将向量写入工作区的集合。

关键在于,分块文本也会落入 PostgreSQL,服务器在那里维护 FTS 腿查询的全文搜索向量。collector 从不接触关系数据库 - 一条硬性的服务边界,让解析并嵌入流水线保持可替换,并让搜索索引由查询它的服务器所有。

0.22 版本让检索在第二个维度上变得精确:元数据过滤。代理现在可以将 rag_search 调用限定到文档类型(PDF、Markdown、TXT、CSV、DOCX、XLSX)和摄取日期窗口,修复了经典的"2023 年文档回答 2025 年问题"故障。过滤器贯穿两条腿 - 在向量存储中作为带时间戳摄取元数据的真正预过滤器,在全文侧作为参数化 SQL 谓词。服务端元数据兜底随后对照权威文档表重新检查每个融合结果,因此过滤正确性不依赖于每个向量提供商标记完美的谓词实现。在元数据戳记之前摄取的旧向量在过滤器激活时只是掉落,并通过管理员触发的重新嵌入恢复可过滤性。

展示依据的答案

检索质量只是故事的一半;另一半是对答案依据的诚实。引用与 token 流经同一流式通道:引用徽章内联显示在响应中,每个都携带源文档、分块和相关性评分,并链接到源,读者一键即可验证主张。

时效性纪律也在这里。融合结果去重后,接地过滤器将每文档引用限制在按相关性评分最高的前两条,并丢弃文本与最终答案没有有意义词法重叠的分块引用。该门控刻意保守 - wiki 页面、存档结果和非常短的答案始终保留 - 但它消除了这样的故障模式:回复说"没有更多信息",却显示来自单个边缘相关文档的"来源(5)"。"无支持证据"免责声明也针对同一过滤集合判定,因此免责声明和来源列表始终描述同一现实。

选择与调优技术栈

流水线刻意由配置驱动,默认值是最注重隐私的:

  • 向量存储: 默认 LanceDB - 基于文件、本地存储、无需外部服务、完全兼容 air-gap。当部署规模超出时,Qdrant、pgvector 和 Chroma 仅一步环境更改之遥;提供程序在启动时选定。
  • 嵌入: 默认本地 transformers(384 维,完全离线),或当部署接受出站调用时使用 OpenAI 嵌入。切换嵌入模型需要重新索引,由管理面板驱动;不匹配守卫在过渡期保障系统安全。
  • 重新排序: 可选。当答案质量比延迟更重要时,reranker 可以超量获取并重新排序融合结果。
  • 融合常数: k = 60 作为默认值交付;如果您的排名分布需要不同的阻尼,它是混合搜索服务中的单个常数。

完整的数据流演示 - 服务器与 collector 的边界、每个向量提供程序背后的存储布局以及流式引用事件 - 记录在架构指南中。

在文档中阅读完整指南 →

相关文章