登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

RAG 只用向量检索找不到精确编号时怎么加混合检索

来源:17golang原创

时间:2026-09-08 00:23:06 320浏览 收藏

RAG 只用向量检索时,问“设备编号 ZX-2047 对应哪份维护记录”很容易拿不到正确文档:编号本身没有丰富语义,embedding 更关注整句含义,精确字符串反而可能排在较后。处理办法是把检索拆成两路:关键词检索保护编号、型号和条款号,向量检索覆盖“怎么更换滤芯”这类自然语言表达,再把两路候选融合成一个 Top-K。

精确编号不是把向量模型换大就能稳定解决的问题。保留 BM25/全文检索作为 sparse 通道,再与 dense 向量候选用 RRF 或可解释权重合并,通常比单路向量召回更稳。
要点速览
  • 编号、型号、版本号优先交给关键词通道;自然描述交给向量通道。
  • 刚开始用 RRF,避免直接比较 BM25 分数和向量相似度的不同量纲。
  • 若精确命中仍靠后,再提高 sparse 权重,并用四组查询做回归。

为什么精确编号会被单一路径漏掉

向量检索回答的是“语义上像不像”,而不是“是否包含这串字符”。订单号、设备序列号、SKU、法规条款号和内部缩写往往是低语义、高区分度的词。查询只改一个数字,业务含义可能完全改变,但两个句子的向量距离未必拉开足够差距。

先把查询中的词分成两类:编号词原样送入全文索引,自然描述送入 embedding。NVIDIA RAG Blueprint 将搜索类型区分为 dense 与 hybrid;Elastic 的混合搜索说明也把全文和向量查询合成一个排序列表。这里的关键不是二选一,而是让两条通道互相补位。

RAG 混合检索中查询入口分到编号词和自然语言描述,再连接关键词检索 BM25、向量检索 Embedding 与候选文档的静态框图
图1:查看精确词边界与语义边界中的两条召回通道,理解为什么 RAG 不应只依赖向量距离。
纯向量检索对精准编号、工号、订单号这类离散字符串的匹配召回率很低,加混合检索时可以先在向量库外绑定关键词倒排索引,同时给编号类字段开启精确匹配权重加权,最后通过多路归并把两类检索结果按业务规则融合排序,就能解决精准编号找不到的问题。

两条召回通道如何分工

通道擅长命中常见短板适合保留的字段
sparse / BM25订单号、型号、原文短语、条款号同义表达和改写不容易命中编号、标题、别名、关键词字段
dense / 向量自然语言描述、同义词、概念关联可能忽略一个关键数字正文切片及其 embedding

以 NVIDIA RAG Blueprint 为例,部署层可把 APP_VECTORSTORE_SEARCHTYPE 设为 hybrid。如果使用 weighted ranker,还可以分别设置 APP_VECTORSTORE_SPARSE_WEIGHTAPP_VECTORSTORE_DENSE_WEIGHT。这只是召回配置,不能替代字段分析:编号最好仍有可检索的原文或 keyword 字段。

# 开启混合召回,让关键词和向量候选同时参与
export APP_VECTORSTORE_SEARCHTYPE="hybrid"
# 编号类查询更看重原词命中,可先从均衡权重开始
export APP_VECTORSTORE_RANKER_TYPE="weighted"
export APP_VECTORSTORE_SPARSE_WEIGHT="0.6"
export APP_VECTORSTORE_DENSE_WEIGHT="0.4"

配置改变后要让 RAG 服务和 ingestion 服务使用一致的搜索类型,并按所用后端的要求重建或重新写入索引。不要把 0.6 当成通用答案;它只是保护精确词的起点,最终应由真实查询集决定。

RRF 和加权融合该怎么选

两路检索的分数通常不能直接相加:BM25 分数受词频、字段长度等因素影响,向量相似度又是另一种尺度。RRF 只看排名位置,把两路都排得靠前的文档推到前面,适合作为第一版基线。NVIDIA 文档说明混合搜索默认使用 RRF,也提供 weighted 方式调节 dense 与 sparse 的相对重要性。

需要保护“编号必须出现”时,再采用加权融合或硬规则。示例中的融合函数只表达决策边界,不绑定某个数据库 SDK:

def merge_candidates(sparse_hits, dense_hits, top_k=6):
    # 用文档 ID 合并两路候选,避免同一切片重复出现
    merged = {}
    for rank, hit in enumerate(sparse_hits, start=1):
        item = merged.setdefault(hit["doc_id"], {"doc_id": hit["doc_id"], "score": 0.0})
        # 倒数排名让不同检索器的分数无需直接比较
        item["score"] += 0.6 / (60 + rank)
    for rank, hit in enumerate(dense_hits, start=1):
        item = merged.setdefault(hit["doc_id"], {"doc_id": hit["doc_id"], "score": 0.0})
        item["score"] += 0.4 / (60 + rank)
    # 稳定排序后截断,实际项目还应保留来源和命中通道用于解释
    return sorted(merged.values(), key=lambda item: item["score"], reverse=True)[:top_k]

如果系统已经提供 RRF,优先使用原生实现;自写融合时至少保留 doc_id、来源和命中通道,方便回答“为什么这条排在前面”。对于要求编号完全一致的场景,可以在融合后给包含编号的文档加一个小幅业务加分,但不要让它绕过权限过滤或文档状态过滤。

RAG 混合检索中关键词候选和向量候选按文档 ID 进入 RRF 排名或 sparse dense 权重,再形成去重集合和最终 Top-K 的静态框图
图2:查看两路候选在融合层的关系,判断何时采用 RRF,何时把 sparse 权重调高来保护编号命中。

上线前用四组查询检查召回是否真的变好

不要只拿一个编号测试。至少准备四组小样本:完整编号、编号加自然描述、只说业务含义的改写句、故意接近但不相同的编号。分别记录正确文档是否进入 Top-K、首位排名和重复块数量。若第一组变好而第三组明显变差,说明 sparse 权重过高;若第一组仍漏召回,应检查编号是否被分词、是否进入索引字段,而不是继续调 embedding。

  • 先用 RRF 建立基线,再决定是否需要 weighted。
  • 两路候选取更大的候选池,融合后再做 Top-K 截断。
  • 按文档 ID 或稳定 chunk ID 去重,保留来源字段供引用。
  • 记录 sparse、dense、融合后三个结果,排障时不要只看最终列表。

相关问题

为什么不能直接把 BM25 分数和向量分数相加?

两者量纲和分布不同,直接相加会让某一路因为数值范围更大而主导结果。先用 RRF,或在离线样本上校准权重更可靠。

混合检索是不是一定比向量检索准确?

不一定。它增加了召回覆盖,但也可能带来延迟和噪声;应以精确词、自然描述和误命中样本的 Top-K 结果共同判断。

改成 hybrid 后为什么旧集合仍然查不到?

要检查后端限制和索引状态。NVIDIA 文档提示,部分已有 dense 集合在切换 hybrid 后需要新建集合并重新写入文档;具体行为以所用向量数据库的官方说明为准。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>