文章
稠密检索 vs 稀疏检索:基于向量区分现代搜索技术#
在构建 RAG(Retrieval-Augmented Generation,检索增强生成)、企业知识库、站内搜索、商品搜索或问答系统时,最核心的问题之一是:如何从大量文档中找出最相关的内容。
现代检索系统里,经常会看到几个词:
- sparse retrieval
- dense retrieval
- hybrid search
- vector search
- semantic search
- rerank
这些概念容易混在一起。最基础的区分方式是:文本到底被表示成什么样的向量。
简单说:
- 稀疏检索:文本被表示成高维、绝大多数维度为 0 的词项向量,代表方法是 BM25。
- 稠密检索:文本被表示成 embedding 模型输出的连续向量,代表方法是 bi-encoder 向量检索。
- 混合检索:同时使用关键词匹配和语义向量检索,再融合或重排序结果。
生产级 RAG 通常不会只用一种方法,而是多阶段组合。
稀疏检索是什么#
稀疏检索基于词项匹配。它把文档和查询表示成一个很高维的向量,维度通常对应词表里的词。
例如查询:
如何训练神经网络
可以粗略表示成:
[如何:1, 训练:1, 神经:1, 网络:1, 其他词:0, 0, 0, ...]
词表可能有几十万甚至更多维,但一个短查询只包含几个词,所以绝大多数维度都是 0。这就是“稀疏”的含义。
更接近工程实现的方式不是存一个超长数组,而是存倒排索引:
训练 → doc1, doc8, doc20, ...
神经 → doc1, doc7, doc11, ...
网络 → doc1, doc3, doc9, ...
查询时,系统通过倒排表快速找到包含相关词项的文档,再计算分数。
BM25:稀疏检索的经典代表#
BM25 可以理解为 TF-IDF 的改进版,也是传统信息检索里非常经典、非常强的 baseline。
它主要考虑:
- 查询词是否出现在文档里。
- 查询词在文档中出现多少次。
- 这个词在整个语料中是否稀有。
- 文档长度是否过长。
直觉上:
- 一个词越稀有,区分度越高。
- 一个查询词在文档里出现越多,相关性越高,但收益会逐渐递减。
- 太长的文档天然更容易包含很多词,所以需要长度归一化。
BM25 的优势是:
- 速度快。
- 成熟稳定。
- 可解释性强。
- 对专有名词、代码、型号、ID、错误信息非常有效。
- 不需要训练 embedding 模型。
- 对冷门词和精确词非常敏感。
它的缺点是:
- 依赖词面重叠。
- 对同义词、 paraphrase、语义改写不敏感。
- 分词质量会显著影响中文、日文等语言表现。
- 很难理解“用户真正想问什么”。
例如:
查询:便宜但拍照好的手机
文档:高性价比影像旗舰推荐
如果没有足够词面重叠,纯 BM25 可能排得不高。
稠密检索是什么#
稠密检索使用 embedding 模型,把文本编码成一个连续向量:
[0.23, -0.45, 0.67, 0.12, ...]
这个向量通常有几百到几千维。与稀疏向量不同,绝大多数维度都有非零值,所以叫“稠密”。
检索时,系统会:
- 用 embedding 模型把文档提前编码成向量。
- 把这些向量存入向量索引或向量数据库。
- 查询时把用户问题也编码成向量。
- 用 cosine similarity、dot product、Euclidean distance 等方法找最相似的文档向量。
这类方法也常被叫做 semantic search,因为它不只看关键词是否重合,还试图捕捉语义相似性。
例如:
查询:深度学习入门教程
文档 A:神经网络基础教学
文档 B:深度学习的发展历史
BM25 可能更喜欢文档 B,因为它包含“深度学习”。
稠密检索可能更喜欢文档 A,因为“神经网络基础教学”和“深度学习入门教程”在语义上更接近。
稠密检索的优势和局限#
稠密检索的优势:
- 能匹配同义词和语义改写。
- 更适合自然语言问题。
- 可以支持跨语言或多语言检索。
- 在问答、推荐、知识库检索中体验更自然。
- 能处理“没有完全相同关键词但意思接近”的场景。
但它也有明显局限:
- 对专有名词、型号、错误码、函数名、法律条款编号等精确词可能不如 BM25。
- embedding 模型会引入额外计算和存储成本。
- 向量相似不等于事实相关。
- embedding 质量强依赖训练数据和领域适配。
- 对长文档需要分块,否则信息会被平均进一个向量里。
- ANN 近似检索会在速度和召回率之间权衡。
例如下面这类查询,BM25 往往非常强:
TypeError: First parameter has member readable that is not a ReadableStream
因为用户需要的是精确错误字符串,而不是“语义差不多”的错误。
不要把“向量搜索”只理解成 dense retrieval#
很多人一听到 vector search,就默认等于 embedding search。其实不严谨。
稀疏检索本质上也是向量检索,只是向量非常高维且大部分为 0。
更准确的分类是:
Sparse vector retrieval
├── TF-IDF
├── BM25
└── learned sparse retrieval, e.g. SPLADE
Dense vector retrieval
├── sentence embeddings
├── DPR-style bi-encoder
├── text embedding APIs
└── domain-specific embeddings
Hybrid retrieval
├── sparse + dense score fusion
├── sparse + dense rank fusion
└── multi-stage retrieval + rerank
所以,“基于向量”不是 dense retrieval 的专利。区别在于向量是否稀疏、维度如何定义、相似度如何计算、索引结构如何组织。
Learned Sparse Retrieval:介于两者之间的路线#
除了传统 BM25 和 dense embedding,还有一类重要方法叫 learned sparse retrieval。
代表思路包括 SPLADE 这类模型:它仍然输出稀疏词项向量,可以和倒排索引结合,但权重不是简单词频,而是由神经网络学习得到。
它试图同时获得两种优势:
- 像 BM25 一样保留词项级可解释性和倒排索引效率。
- 像神经检索一样具备一定语义扩展能力。
例如查询“汽车保险”,模型可能会激活“车险”等相关词项,即使原始查询没有这个词。
这类方法在学术和工业检索中都很重要,但工程复杂度高于 BM25,推理成本也高于纯词频模型。
混合检索为什么成为主流#
实际系统里,用户查询非常多样:
- “iPhone 15 Pro Max 256G”
- “React Router v7 modulepreload 怎么生成”
- “为什么我部署后首页白屏”
- “适合小团队的项目管理工具”
- “这份合同里离职工资怎么结算”
有的查询需要精确匹配,有的需要语义理解,有的需要两者结合。
所以生产系统经常采用 hybrid search:
BM25 topK
+
Dense embedding topK
↓
merge / dedupe
↓
score fusion or rank fusion
↓
reranker
↓
final topN
BM25 负责抓住关键词和精确信号,dense retrieval 负责补足语义召回。两者结合通常比单独使用一种方法更稳。
2024 年以后,很多检索和向量数据库系统都在强化 dense + sparse hybrid 能力;相关研究也持续关注如何把两类向量更高效地放进统一索引或统一检索流程里。
分数融合 vs 排名融合#
混合检索有两种常见融合方式。
1. 分数融合#
把 BM25 分数和 dense similarity 分数归一化后加权:
finalScore = alpha * normalizedBm25 + (1 - alpha) * normalizedDense;
优点是直观。
缺点是两个系统的分数尺度完全不同。BM25 分数和 cosine similarity 不是同一种东西,直接相加很容易出问题,所以通常要做 normalization、calibration 或调参。
2. 排名融合#
更常见、更稳妥的是 rank fusion,例如 RRF(Reciprocal Rank Fusion)。
RRF 不关心原始分数,只关心每个文档在不同检索器里的排名:
score(d) = Σ 1 / (k + rank_i(d))
如果一个文档在 BM25 和 dense 检索里都排得靠前,它会得到更高融合分数。
RRF 的优点是简单、稳健、对不同检索器的分数尺度不敏感。Elasticsearch 等搜索系统也提供了 RRF 作为混合检索结果融合方法。
Rerank:混合检索之后的关键一步#
很多高质量 RAG 系统会分成两阶段:
第一阶段:召回 retrieve
用 BM25 / dense / hybrid 找到 top 50 或 top 100
第二阶段:重排序 rerank
用更强但更慢的模型重新评估 top candidates
dense retrieval 通常使用 bi-encoder:查询和文档分别编码,速度快,适合大规模召回。
reranker 常用 cross-encoder 或 LLM judge:把 query 和 candidate chunk 一起输入模型,让模型判断相关性。它更准确,但成本更高,不适合全库扫描。
所以一个实用 pipeline 是:
query
↓
BM25 top 100 + dense top 100
↓
merge and dedupe
↓
cross-encoder rerank top 50
↓
select top 5-10 chunks for LLM context
RAG 效果很多时候不是取决于“有没有向量数据库”,而是取决于召回、分块、去重、重排序和上下文构造是否合理。
分块对检索质量的影响#
RAG 中常见单位不是整篇文档,而是 chunk。
如果 chunk 太大:
- embedding 会混合太多主题。
- 检索命中后浪费上下文窗口。
- LLM 看到很多无关文本。
如果 chunk 太小:
- 缺少上下文。
- 一个事实可能被切断。
- reranker 难以判断完整相关性。
常见做法是:
- 按标题、段落、语义边界切分。
- 保留父文档标题、路径、时间、权限等 metadata。
- 使用 overlap,但不要过大。
- 对代码、表格、Markdown、PDF 采用不同切分策略。
- 检索 chunk,必要时返回 parent section。
这也是为什么“embedding 模型很好,但 RAG 还是答不好”非常常见:问题可能不在模型,而在 chunking 和 context construction。
多语言和中文场景#
中文检索有几个额外注意点:
- BM25 依赖分词,分词器质量很重要。
- 专有名词、英文缩写、代码混写会影响词项匹配。
- dense embedding 对中英混合和跨语言查询更友好,但也要看模型是否针对多语言训练。
- hybrid search 对中文 RAG 通常很有价值,因为它能同时利用关键词和语义信号。
例如:
查询:水合失败怎么排查
文档:hydration mismatch debugging guide
如果用户中英混查,dense embedding 可能更容易召回;但如果查询是具体报错文本,BM25 又更可靠。
如何选型#
只用 BM25 的情况#
适合:
- 文档量大但预算有限。
- 查询以精确匹配为主。
- 内容包含大量代码、错误码、型号、ID。
- 需要强可解释性。
- 想先快速做一个可靠 baseline。
例如:日志搜索、代码搜索、商品 SKU、错误信息搜索。
只用 dense retrieval 的情况#
适合:
- 用户主要用自然语言提问。
- 语义改写很多。
- 需要跨语言或同义词匹配。
- 文档规模适中。
- 可以接受 embedding 成本和向量索引成本。
例如:FAQ、客服知识库、语义问答、推荐召回。
使用 hybrid search 的情况#
适合:
- 查询类型不可预测。
- 既有自然语言问题,也有专有名词和错误字符串。
- RAG 对召回质量要求高。
- 可以接受更复杂的 pipeline。
- 有能力做评估和调参。
例如:企业知识库、技术文档问答、研究助手、智能搜索产品。
评估比选型更重要#
不要凭感觉决定“BM25 还是 embedding”。应该用真实查询集评估。
常见指标包括:
| 指标 | 含义 |
|---|---|
| Recall@K | 相关文档是否出现在前 K 个结果里 |
| Precision@K | 前 K 个结果有多少是真相关 |
| MRR | 第一个相关结果出现得多靠前 |
| nDCG | 排名顺序是否合理,是否把高相关结果排前面 |
| Answer correctness | RAG 最终答案是否正确 |
| Citation accuracy | 引用是否支持答案陈述 |
| Latency | 检索和 rerank 总耗时 |
| Cost | embedding、存储、rerank、LLM 成本 |
对 RAG 来说,检索指标和最终答案指标都要看。
有时检索 Recall@20 很高,但最终答案仍然差,原因可能是:
- 相关 chunk 排太后。
- 上下文太长,LLM 忽略关键证据。
- chunk 缺少 metadata。
- 引用和证据对不齐。
- reranker 把真正关键的片段降权了。
一个实用的生产 pipeline#
如果从零开始做企业知识库或技术文档 RAG,一个稳妥起点是:
1. 文档解析
Markdown / HTML / PDF / Docs
2. 语义分块
按标题、段落、代码块、表格边界切分
3. 建索引
BM25 index + dense vector index
4. 查询改写
识别语言、实体、时间、错误码、代码符号
5. 多路召回
BM25 top 50 + dense top 50
6. 融合
RRF 或归一化加权
7. 重排序
cross-encoder / reranker / LLM judge
8. 上下文构造
top chunks + metadata + source ids
9. 生成
要求模型基于证据回答并引用来源
10. 反馈闭环
记录 bad cases,迭代 chunking、retrieval、rerank
这比“直接把所有文档塞进向量数据库,然后 topK 给 LLM”要可靠得多。
常见误区#
误区 1:向量数据库 = RAG#
向量数据库只解决一部分问题:存储和检索 embedding。
RAG 还需要文档解析、分块、权限、metadata、重排序、上下文构造、引用、评估、缓存和反馈。
误区 2:embedding 越新越好,BM25 可以丢掉#
很多生产系统里,BM25 仍然非常强,尤其是专有名词、错误码、代码搜索、型号搜索。dense retrieval 不是替代 BM25,而是补充 BM25。
误区 3:topK 越大越好#
topK 过大可能把大量无关内容塞进上下文,反而降低答案质量。更好的方式是提高召回质量、使用 rerank,并控制最终上下文规模。
误区 4:相似度高就等于能回答#
embedding 相似度表示语义接近,不等于该片段包含答案。Rerank 和 evidence verification 很重要。
小结#
稀疏检索和稠密检索不是谁取代谁的关系。
BM25 这类稀疏检索擅长精确匹配、专有名词、错误字符串和可解释排序;dense retrieval 擅长语义相似、自然语言问题和跨语言表达;learned sparse retrieval 试图在两者之间取得平衡;hybrid search 则把它们组合起来,提升复杂查询下的稳健性。
对于现代 RAG 和答案引擎,比较稳妥的结论是:
- 先用 BM25 建一个强 baseline。
- 加入 dense retrieval 补语义召回。
- 用 RRF 或归一化融合合并结果。
- 用 reranker 提升最终排序质量。
- 用真实查询和答案质量持续评估。
真正的检索质量不是来自某一个“高级组件”,而是来自一整条 pipeline 的协同。
参考资料#
- Efficient and Effective Retrieval of Dense-Sparse Hybrid Vectors using Graph-based Approximate Nearest Neighbor Search
- Sparse Meets Dense: A Hybrid Approach to Enhance Scientific Document Retrieval
- BM25S: Orders of magnitude faster lexical search via eager sparse scoring
- Anserini Gets Dense Retrieval: Integration of Lucene's HNSW Indexes
- Dense Passage Retrieval for Open-Domain Question Answering
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
