如何做语义检索
关键词搜索理解字面意思,语义检索理解真实意图。当用户问「如何让用户留存更高」时,关键词搜索只能匹配包含「留存」字样的文档;语义检索能理解「用户粘性」「活跃度」「回访率」背后的共同含义,把真正相关的文档带回来。
这种从「字面匹配」到「意图理解」的跨越,是 RAG(Retrieval-Augmented Generation)系统从可用到好用的关键分水岭。本章讲清楚语义检索的完整实现链路:从向量生成到相似度计算,从检索优化到混合检索策略,最后是排序与融合的工程决策。
语义检索的基本原理
语义检索的核心思路是:把查询和文档都映射到同一个向量空间,用数学上的「接近程度」代替字符串的「字面匹配」。整个过程分三步。
第一步:文档向量化(Embedding)。 用预训练的 Embedding 模型把每段文本转换为高维向量。以 OpenAI 的 text-embedding-3-small 为例,一段文本会被编码成 1536 维的浮点数数组。向量中每个维度编码了文本在不同语义轴上的信息。语义相近的文本,向量在空间中的方向就相近。
第二步:查询向量化。 用户的查询文本用同一个 Embedding 模型编码,得到查询向量。这一步必须使用与文档向量化相同的模型,否则两个向量处于不同的语义空间,比较就失去意义。
第三步:相似度计算与返回结果。 在向量数据库中计算查询向量与所有文档向量之间的距离,按相似度从高到低排序,取 Top-K 返回。向量数据库内部使用 ANN(Approximate Nearest Neighbor)索引加速搜索,常见算法包括 HNSW(Hierarchical Navigable Small World)和 IVF(Inverted File Index),能在百万级向量中毫秒级返回结果。
相似度计算方法
向量之间的「接近程度」用数学公式量化。不同度量方式对结果的排序、对向量长度的敏感度都不同。RAG 场景下最常用的三种方法如下。
余弦相似度(Cosine Similarity)
余弦相似度衡量两个向量夹角的余弦值,忽略向量的模长。公式为:
$$\cos(\theta) = \frac{A \cdot B}{|A| |B|}$$
取值范围 -1 到 1。值越接近 1 表示方向越一致,语义越相关。余弦相似度是语义检索中最常用的度量方式,原因是大多数 Embedding 模型输出的向量已经做过归一化(L2 Normalize),此时余弦相似度退化为点积,计算更快。它只关心方向不关心长度,对文本长度差异有天然的鲁棒性。
欧氏距离(L2 Distance)
欧氏距离衡量两点在空间中的直线距离:
$$d(A, B) = \sqrt{\sum_{i=1}^{n}(A_i - B_i)^2}$$
距离越小表示越相似。与余弦相似度不同,欧氏距离同时考虑方向和模长。当向量没有做归一化、且长度本身携带信息时(例如某些多模态 Embedding),欧氏距离比余弦更有优势。
点积(Dot Product / Inner Product)
点积公式为:
$$A \cdot B = \sum_{i=1}^{n} A_i B_i$$
如果向量已归一化,点积等价于余弦相似度。点积的优势是计算开销最小,不需要额外的除法或开方。在大规模检索场景中,Pinecone、Qdrant 等向量数据库默认推荐归一化后用点积做相似度计算。
如何选择? 实践中,先用余弦相似度或归一化后的点积作为默认选项。如果发现检索结果对文本长度过于敏感,切换到欧氏距离。具体选择与 Embedding 模型相关——OpenAI 和 Cohere 的模型官方推荐余弦相似度,BGE 系列模型推荐点积。
检索优化策略
拿到 Top-K 结果只是起点。直接把这 K 条文档送给 LLM,往往混入噪声或遗漏关键信息。以下是三层优化。
元数据过滤(Metadata Filtering)
在向量检索之前,先用文档的结构化元数据做预过滤。常见元数据包括:文档来源、所属类别、创建时间、语言、权限标签等。向量数据库(Pinecone、Weaviate、Qdrant)均支持在 ANN 检索的同时施加元数据过滤条件。
例如:用户问的是产品定价问题,可以先过滤 category: pricing,再在这个子集里做语义检索。这样既缩小搜索空间,又避免跨领域的语义「近邻」干扰。
重排序(Reranking)
向量检索返回的 Top-K 是「粗排」结果。重排序模型(如 Cohere Rerank、bge-reranker、Jina Reranker)对查询和每一篇候选文档做交叉注意力计算,得到更精细的相关性分数。重排序的计算量远大于向量检索,但只对少量候选(通常 20-100 条)操作,延迟可控。
重排序的价值在实践中非常显著:它能把语义检索 Top-20 中排在第 15 位但实际最相关的文档提升到 Top-3。对于需要高精度检索的场景(如法律、医疗文档问答),重排序几乎是必选项。
查询改写(Query Rewriting)
用 LLM 或规则对原始查询做改写,提升检索效果。常见策略包括:
- 查询扩展(HyDE):先让 LLM 基于查询生成一个「假设性回答」,再用这个回答做语义检索。因为回答与文档的语义空间更接近,检索效果更好。
- 多查询扩展:把原始查询改写成 3-5 个不同角度的变体,分别检索后合并去重。
- 查询拆解:对于包含多个子问题的复杂查询,拆解成独立子查询分别检索。
混合检索:语义 + 关键词
纯语义检索有一个短板:对于精确的专有名词、产品编号、代码片段、特定术语,向量空间的模糊匹配反而不如精确的关键词匹配。混合检索(Hybrid Search)同时执行语义检索和关键词检索,融合两路结果,兼顾「理解意图」和「精确匹配」。
为什么需要混合检索
考虑一个场景:用户问「LangChain 的 ChatOpenAI 怎么设置 temperature 参数」。关键词检索能精确命中包含 ChatOpenAI 和 temperature 的文档;语义检索能找到讨论「大模型参数调优」的相关文档但可能不包含具体类名。两者结合才能覆盖全。
Pinecone 的实验数据表明,混合检索在多个基准测试集上比纯语义检索的 Recall@10 高出 5-15 个百分点。
BM25 关键词检索
BM25 是 TF-IDF 的进化版,考虑了词频、逆文档频率和文档长度归一化。它在稀疏向量空间工作,对精确词匹配非常敏感。大多数关系型数据库和搜索引擎(Elasticsearch、PostgreSQL with pg_trgm)都内置 BM25 支持。
融合策略:RRF 与加权融合
两路检索返回的结果分数来自不同空间(向量相似度 vs. BM25 分数),无法直接比较。常用的融合方法有两种。
倒数排名融合(Reciprocal Rank Fusion, RRF) 只看排名不看分数。对每个文档,取两路排名倒数之和作为融合分数:
$$RRF(d) = \sum_{r \in R} \frac{1}{k + r(d)}$$
其中 $k$ 是常数(通常取 60),$r(d)$ 是文档 $d$ 在该路检索中的排名。RRF 的优点是对异常分数不敏感,实现简单,无需调参。
加权线性融合 给两路分数赋予权重 $\alpha$ 和 $1-\alpha$:
$$score(d) = \alpha \cdot s_{semantic}(d) + (1-\alpha) \cdot s_{keyword}(d)$$
需要先对两路分数做归一化(Min-Max 或 Z-Score),再通过调节 $\alpha$ 控制两路的权重。适合对业务场景有深入理解、可以做 A/B 测试调参的团队。
混合检索方案对比
| 维度 | 纯语义检索 | 纯关键词检索(BM25) | 混合检索 |
|---|---|---|---|
| 语义理解 | 强 | 无 | 强 |
| 精确匹配 | 弱 | 强 | 强 |
| 专有名词/编号 | 容易遗漏 | 精确命中 | 精确命中 |
| 实现复杂度 | 中 | 低 | 高 |
| 对 Embedding 模型依赖 | 高 | 无 | 高 |
| 适用场景 | 概念性问答 | 精确查找 | 通用问答、生产级 RAG |
检索结果排序策略
拿到融合后的候选文档,排序策略决定了最终送给 LLM 的上下文质量。
相关性分数排序 是最基础的方式:按融合分数从高到低取 Top-K。简单有效,但存在一个问题——Top-K 中可能有大量内容重复的文档(同一来源、相似表述)。
最大边际相关性(MMR, Maximal Marginal Relevance) 在相关性和多样性之间做平衡。MMR 每选一篇文档时,不仅考虑与查询的相关性,还惩罚与已选文档的相似度。公式为:
$$MMR = \arg\max_{d_i} [\lambda \cdot Sim(d_i, Q) - (1-\lambda) \cdot \max_{d_j \in S} Sim(d_i, d_j)]$$
其中 $\lambda$ 控制相关性与多样性的权衡,$S$ 是已选文档集。MMR 能有效避免「Top-5 全是同一篇文章的不同段落」的问题。
分块质量加权 在排序时考虑文档块本身的质量信号:来源可信度、时效性、被引用次数、人工标注分数等。例如一篇 2026 年的官方文档和一篇 2023 年的博客文章,语义检索分数接近时,优先选择更新的来源。
上下文窗口预算排序 在 LLM 上下文窗口有限的情况下,不是简单取 Top-K,而是根据每篇文档的信息密度(单位 token 中包含的关键事实数)做排序。信息密度高的短文档优先于信息稀疏的长文档。
| 排序策略 | 核心目标 | 适用场景 | 调参复杂度 |
|---|---|---|---|
| 相关性分数排序 | 最大化单条相关性 | 简单场景、快速原型 | 低 |
| MMR | 相关性 + 多样性 | 通用问答、摘要生成 | 中(需调 λ) |
| 分块质量加权 | 可信度优先 | 企业知识库、客服 | 中 |
| 上下文窗口预算 | 信息密度最大化 | 长文档、窗口受限 | 高 |
案例一:SaaS 产品帮助中心的语义检索
一个面向海外用户的 SaaS 产品,帮助中心有 2000+ 篇英文文档,涵盖产品使用、API 文档、FAQ。用户提交工单前,系统先做语义检索返回相关文档。
实现方案:使用 text-embedding-3-small 对文档分块(每块 512 token,50 token 重叠)做向量化,存储在 Pinecone。查询时先用元数据过滤文档类别(category: api-docs 或 category: how-to),再做 ANN 检索取 Top-20,用 Cohere Rerank 重排后取 Top-5 展示。
遇到的问题与解决:
- 产品编号(如
ORG-12345)在语义检索中经常被忽略。解决:对包含编号的块额外建 BM25 索引,用 RRF 融合两路结果。 - 同一 API 方法在多个版本的文档中出现,检索结果重复。解决:在排序时加入版本去重逻辑,每个 API 方法只保留最新版本的文档。
- 用户查询太短(如「webhook 失败」),语义检索效果差。解决:用 HyDE 策略,让 LLM 先生成假设性回答再检索,Recall@5 从 62% 提升到 81%。
案例二:跨境电商知识库的多语言语义检索
一个跨境电商平台,客服知识库同时包含中文、英文、日文文档。用户用日文提问,需要从三种语言的文档中检索相关内容。
实现方案:使用多语言 Embedding 模型 multilingual-e5-large 对所有文档做向量化。该模型把不同语言的文本映射到同一个向量空间,日文的查询向量能与中文文档的向量直接比较。存储在 Qdrant,元数据标注语言字段。
关键决策:
- 检索时不做语言过滤,让跨语言语义匹配自然发生。但排序时加入「同语言优先」的加权:如果查询是日文,日文文档的分数乘以 1.2 的权重。
- 对于包含品牌名、SKU 编号的查询,补充 Elasticsearch 的 BM25 检索,用加权融合($\alpha=0.7$ 语义 + $0.3$ 关键词)。
- 分块策略按段落而非固定 token 数,避免语义不完整的截断。
效果:相比之前纯 BM25 的关键词匹配,客服首次响应准确率提升 34%,用户满意度从 3.2 提升到 4.1(5 分制)。
语义检索的完整实现清单
在落地语义检索之前,逐项确认以下内容。
Embedding 模型选择
- 是否选择了与业务语言匹配的模型(中文场景考虑 BGE、GTE 等国产模型)
- 是否确认模型支持的最大 token 长度,分块策略是否与之匹配
- 是否对比了至少 2 个模型在业务数据上的检索效果
向量数据库与索引
- 是否选择了支持 ANN 索引的向量数据库(Pinecone、Qdrant、Milvus、Weaviate、pgvector)
- 是否选择了合适的距离度量(余弦相似度 vs. 欧氏距离 vs. 点积)
- 是否评估了数据规模与索引类型的匹配(HNSW 适合百万级以下,IVF 适合更大规模)
分块策略
- 分块大小是否在 256-1024 token 之间做了对比实验
- 是否设置了块之间的重叠(通常 10%-20%)
- 是否按语义边界(段落、章节)分块而非机械切割
检索优化
- 是否需要元数据过滤缩小检索范围
- 是否引入了重排序模型提升精度
- 是否评估了混合检索对精确匹配需求的覆盖
- 排序策略是否考虑了多样性和去重
评估与迭代
- 是否建立了人工标注的评估集(至少 50-100 条查询-文档对)
- 是否跟踪了 Recall@K、MRR、NDCG 等检索指标
- 是否有定期评估机制,在 Embedding 模型更新或数据变化时重新跑评估
小结
语义检索的本质是把「文本匹配」升级为「意图匹配」。它不替代关键词检索,而是在关键词检索力不从心的场景——同义词、跨语言、概念性问答——补上关键一环。生产级系统几乎都采用混合检索,用语义理解兜底,用关键词精确匹配兜底。
落地时最容易踩的三个坑:Embedding 模型选错(中文场景用英文模型)、分块太大或太小、缺少重排序环节。把这三个坑填上,语义检索的效果就已经超过大多数初始实现。
后续章节会讲 RAG 系统中的上下文组装和 Prompt 工程——检索回来的文档如何被有效利用,是下一个需要解决的问题。
参考资料
- What Is Cosine Similarity? — IBM
- Vector Similarity Explained — Pinecone
- Implementing Hybrid Semantic-Lexical Search in RAG — Machine Learning Mastery
- Hybrid Search: Combining Semantic and Keyword Approaches — Google Cloud
- 什么是语义搜索?— Google Cloud
- 从零实现一个生产级 RAG 语义搜索系统 — 腾讯云
- Similarity Metrics for Vector Search — Zilliz
- 基于语义检索的知识问答(RAG 范式)— 博客园