基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-10-31 11:58

用RRF融合关键词与向量检索

dev.to · AI#检索增强#混合检索#Python
Editor brief · 编辑速览

文章用约50行Python演示BM25与向量检索的结果融合,以兼顾精确标识符和语义改写查询。核心是通过RRF合并排名,避免直接相加尺度不同的分数,并强调在自身语料上测量召回率。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

RAG 检索不到正确文档,不一定是 embedding 模型不够强。遇到工单号、产品代码、专有名词,关键词检索往往更可靠;遇到改写后的问题,向量检索更擅长。作者给出的方案是:两路同时检索,再把排名合并。

这篇值得读的地方是讲清了两种检索怎样互补,以及为什么不能直接相加分数。不过,标题里的「50 行 Python」主要演示融合流程,示例没有使用真正的 embedding,也不足以证明混合检索一定更好。

为什么工单号和自然语言问题需要两路检索

作者举了一个查询:KB-2024-7831 connection failure。用户要找的是某个具体故障记录,向量检索却可能返回几篇讨论工单系统的文章,里面根本没有这个编号。

原因在于,embedding 侧重表达语义相近程度,对字符串是否完全一致未必敏感。BM25 则根据词项重合、词频和文档长度评分,更容易抓住编号、名称和标识符。

反过来,查询「how do I reset my password」,目标文档标题却是「Account recovery steps」,关键词检索可能因为用词对不上而漏掉,向量检索则有机会识别两者的语义关联。

混合检索就是让两路分别生成候选,再合成一个结果列表。它成立的理由是两路能补漏,而不是多跑一次检索就自动提高质量。

原文称两者失败的查询类型几乎不重合,这个判断说得偏满。分块不合理、目标内容没有入库、查询信息不足,都可能让两路一起失败。互补是合理预期,互补到什么程度仍要测。

为什么合并排名比相加分数省心

作者的示例里,BM25 第一名得分是 7.289,另一侧是 0.584,部分其他结果是 0.000。直接相加,BM25 很容易占据主导。

这不是它一定更准确,而是两种分数的尺度不同。BM25 没有固定上界,还依赖语料统计;余弦相似度的范围是 [-1, 1]。先做 min-max 或 z-score 归一化再加权当然可以,但语料变化后,分数分布也会变,需要重新检查效果。

作者采用倒数排名融合(Reciprocal Rank Fusion,RRF):

RRF(d) = Σ 1 / (k + rank)

每个检索器只提交文档排名,第一名从 rank = 1 开始。默认惯例是 k = 60:两路都排第一,得分是 1/61 + 1/61 = 0.0328;一路第一、另一路第 50,得分是 1/61 + 1/110 = 0.0255。

这里的 k 用来调节名次差异的影响,不是返回条数。原文的 hybrid_search(corpus, query, top_n=3) 才通过 top_n 控制最终返回数量。RRF 由 Cormack、Clarke 和 Büttcher 在 2009 年 SIGIR 论文中提出,按原文的 2026 年时间点算,已有 17 年。

不过,示例有一个关键限制。下面这段负责生成所谓的「dense」分数,实际计算的是 TF-IDF 余弦相似度:

def dense(self, query):                     # TF-IDF 余弦相似度替身
    qv = self._tfidf(tokenize(query))
    return [self._cos(qv, self._tfidf(t)) for t in self.toks]

def _tfidf(self, toks):
    tf = Counter(toks)
    return [tf[t] * math.log(1 + self.N / self.df[t])
            if t in self.df else 0.0 for t in self.vocab]

要看的是 _tfidf(tokenize(query)) 这一行:它依靠词项重合,没有调用语义 embedding 模型。因此,8 篇文档的玩具语料中,两路都把包含编号的 doc3 排到第一,只能说明评分和融合流程能工作,不能展示真正的语义互补。

示例的 BM25 使用 Robertson 和 Zaragoza 的公式,参数为 k1 = 1.5、b = 0.75。生产中换成真实 embedding 后,只要仍输出有序文档列表,RRF 的融合逻辑可以沿用。但输入中的部分 Python 已被挤成单行,不能把排版后的文本直接当成完整可运行程序。

收益和延迟,哪些数字能当依据

原文最具体的效果数据来自其他作者的实验,并非这份示例的测试:2026 年 10 月,有人用公司财报电话会文本测试了 12 个问题,Hit@3 从 BM25 的 9/12、dense 的 10/12 提高到 hybrid 的 12/12;平均倒数排名从 0.66、0.73 提高到 0.86。

Hit@3 看正确文档是否进入前三名;平均倒数排名还关心它排得有多靠前。这组数据说明混合检索在那份语料上有效,但 12 个问题撑不起普遍结论。

另一篇文章声称召回提升 30%,一份指南报告约 91% recall@10。原文也承认,后者带有厂商相关背景,测试设置披露不完整。这些数字证明有人做出了收益,不能直接拿来估算自己项目的收益。

延迟也要保留条件。原文引用的实现报告称,两路并行相比单独 dense 检索,p50 约增加 6 ms;若给融合后的前 50 个候选增加 cross-encoder 重排,还会增加 50–200 ms。前者不是完整尾延迟数据,后者也取决于模型,不能当成固定预算。

生产流程可以拆成四步:两路并行取候选,RRF 融合,可选重排,把最终文档交给 LLM。每路取前 50–100 个是文中给出的常见范围,具体深度仍需评估。

维护成本则落在两套索引的更新、候选深度和参数选择上。原文列出 Qdrant、Weaviate、Elasticsearch、OpenSearch、Milvus,建议优先使用原生混合能力;已经使用 Postgres 的团队,也可以考虑 pgvector 配合 tsvector,把两路检索放在一个服务里。具体版本的接口和融合配置,原文没有展开。

我的判断

我赞成把混合检索作为「同时存在精确字符串和自然语言问法」时的候选方案。RRF 的优势也很实际:不用先校准两套分数,容易理解和排查。但排名融合会丢掉分差信息,也无法修复候选阶段根本没找到目标文档的问题。

与加权分数融合相比,RRF 更省调参步骤。原文引用 Weaviate 的 dense 默认权重 0.75、Pinecone 的 0.5,但没有给出具体接口、版本及适用配置,不能照搬。文中还称 LangChain 的 EnsembleRetriever 使用 RRF,k = 60 写死,并通过 weights 缩放各检索器贡献;这个说法同样需要结合实际安装版本确认。

作者说混合检索通常不会明显输给单路,这仍是小规模案例支持下的经验之谈。特别是示例中的正则 [a-z0-9]+ 只提取英文字母和数字,直接用于中文知识库会丢掉中文内容;编号也会被拆成多个词项。检索算法之前,分词方式就可能决定成败。

小而同质的语料、问法统一的 FAQ,完全可以先用单路检索。是否增加一路,应由漏检类型和评估结果决定。

能拿来做什么

  • 给现有 RAG 整理一组真实查询,分别覆盖工单号、产品代码、专有名词和改写问法,用同一份标注比较 BM25、真实 embedding 与 hybrid 的 Hit@3、recall@10 和平均倒数排名。
  • 在 Node 编排的检索服务中,记录两路候选及融合名次。回答引用错文档时,先区分是候选没召回,还是融合后排名靠后,再决定改哪一层。
  • 已有 Postgres 或支持混合检索的数据库时,先验证现有服务能力;把 k = 60、每路前 50–100 个候选作为起点,再根据质量和延迟调整。
  • 面向中文开发文档建立知识库时,先检查中文分词、API 名称和故障编号能否被正确保留,再评估混合检索,避免直接沿用示例的英文分词规则。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
让 AI 编程更可靠的项目协作习惯
下一篇
用策略映射适配图像模型并实现失败兜底

资讯速览

dev.to · AI · 2026-10-31 11:58

AI 评分 8.0 / 10

相关标签

#检索增强#混合检索#Python

继续阅读

  • OpenDsec 自托管沙箱支持运行态分叉
  • 让 AI 编程更可靠的项目协作习惯
  • 用策略映射适配图像模型并实现失败兜底
  • 用表筛选与错误重试提升文本转 SQL
  • Docker 内启用 Claude Code 沙箱的陷阱