用户在知识库里输入:“iPhone 充满电为什么用不了半天?”
系统找到了“苹果手机续航异常排查”。这个结果很合理。用户没有使用“续航”这个词,检索仍然跨过了表达方式的差异,找到了相关资料。
但同一套系统也可能把“电池健康度低于某个数值时的更换建议”排在第一位,而用户的手机刚买一周,实际问题是某个应用持续在后台运行。返回的内容讨论电池,向量分数也很高,却没有对应用户的具体情况。
语义检索的价值和局限,都在这两个结果里。
Embedding 可以把不同表达中的关联转化为可计算的表示。检索系统据此寻找候选文档,但“有关联”到“能回答”,中间还隔着型号、时间、使用条件,以及文档是否提供了足够证据。
理解语义理解、Embedding 和向量相似度之间的关系,需要把这些层次分开。否则,“模型懂意思,所以距离越近答案越准”就会成为一个看似顺畅、实际经不起排查的解释。
一、相似度公式不负责理解文字
先从最容易混淆的地方开始:向量相似度是一种数学计算,可以作用于许多不同来源的向量。
假设有两个向量:
a = [1, 2, 3]
b = [2, 4, 6]
无论这些数字来自文本模型、图像模型,还是人工填写,计算程序都可以求出它们的余弦相似度。这两个向量方向相同,余弦相似度为 1。计算过程不需要知道“手机”是什么,也不需要知道“退款”和“退货”之间有什么区别。
数字具有什么含义,取决于向量的构造方式。
传统信息检索就会把文档表示成向量。例如,TF-IDF 用词项作为坐标,用词频和逆文档频率计算权重。这样的向量主要保留词项分布,也能用于有意义的检索。它并不需要先获得现代语言模型意义上的语义能力,更不是一组随机数字。《Introduction to Information Retrieval》对 TF-IDF 向量表示的说明
因此,“语义理解是向量相似度能够生效的前提”需要加上限定。
如果希望相似度反映文本的语义关系,就需要一套能够保留相关语义特征的表示。相似度函数只负责对这套表示进行计算,无法补回编码阶段已经丢失的信息。
在常见的稠密向量检索中,可以把职责分成三层:
| 层次 | 需要解决的问题 | 典型产物 |
|---|---|---|
| 任务定义 | 什么样的文档算相关? | 查询与文档的相关性标准 |
| 表示学习 | 怎样让这种相关性体现在向量中? | Embedding 模型与文本向量 |
| 打分和检索 | 怎样从向量中找出候选文档? | 相似度分数与候选列表 |
第一层经常被忽略。团队还没有说清“相关”的含义,就开始比较模型维度、向量数据库和相似度阈值。后面的调优很容易围绕一个模糊目标展开。
二、“语义接近”至少包含几种不同关系
“苹果手机”和“iPhone”在许多语境下可以对应同一类产品;“电池续航差”和“充一次电用不了多久”也可以表达相近的抱怨。但这些例子不足以概括实际检索。
在售后系统里,“怎么退款”和“如何退货”就不能直接当成同一个意图。
退款讨论资金返还,退货讨论商品退回。未发货订单可能只需要退款;换货需要寄回商品,却未必涉及退款。如果系统因为两句话向量接近,就把它们归入完全相同的流程,用户可能拿到错误的操作指引。
需要区分的关系至少有下面几种:
| 关系 | 示例 | 对检索的意义 |
|---|---|---|
| 近义或复述 | “续航很差”与“充一次电用不了多久” | 有助于跨表达匹配 |
| 主题相关 | “退款进度”与“退货运费” | 同属售后,但未必回答同一问题 |
| 问答相关 | “退款通过什么渠道退回?”与“审核通过后按原支付渠道退回” | 表述不同,却可能形成问题与答案 |
| 事实一致 | “支持离线使用”与“断网后仍可使用” | 两段内容可能支持同一判断 |
| 事实冲突 | “支持离线使用”与“不支持离线使用” | 主题接近,结论相反 |
这里还有一个容易误判的地方:矛盾文本也可能是有价值的检索结果。
如果任务是检查两份规格书是否冲突,“支持离线使用”和“不支持离线使用”就应该同时被找到。若任务是回答产品能否离线使用,系统还必须判断两份资料各自对应的版本和发布时间。
文档是否相关,取决于任务。相似度本身无法替业务定义这个目标。
问答检索追求的是可回答性
用户问“iPhone 电池能用多久”,可能在问单次充电续航,也可能在问电池几年后需要更换。这句话本身就有歧义。
下面几类文档都可能进入候选列表:
- 某型号在规定测试条件下的续航记录;
- 电池老化与循环次数的说明;
- 后台耗电排查方法;
- 电池更换服务介绍。
模型即使把这些材料都判断为相关,也没有解决用户究竟想问什么。系统可以根据会话上下文收窄问题;信息不足时,也可以让用户补充型号或明确关注单次续航还是使用寿命。
这类问题不能通过把余弦相似度换成点积来解决。查询中的信息缺失,需要在查询理解和交互中处理。
三、Embedding 如何学到“哪些文本应该接近”
“模型先理解文本,再把含义编码成向量”适合作为入门比喻,但容易让人误以为模型内部存在两个独立步骤:先生成一份完整的语义解释,再把解释压缩成数字。
常见的文本编码器直接把输入映射为表示:
文本 → 分词 → 神经网络计算 → 池化或投影 → 文本向量
模型参数来自训练。我们所说的“语义能力”,体现在它能否在不同措辞、上下文和任务中学到稳定的关系,不能仅凭它输出了一串数字就确认。
Sentence-BERT 的一个重要贡献,就是通过专门的训练方式得到适合句子比较的向量。语言模型拥有丰富的内部表示,并不意味着任意取一层输出、做一次平均,就能得到可靠的句子相似度。Sentence-BERT 论文
训练样本决定模型重视什么
以检索任务为例,训练数据可以包含一个查询、一篇相关文档和若干不相关文档。训练过程希望模型提高相关文档的得分,并降低其他候选的得分。
一种常见的对比学习目标可以写成:
其中,q 是查询,d⁺ 是相关文档,dⱼ⁻ 是负样本,s 是打分函数,τ 是温度参数。
公式表达的是一个相对排序目标:在这一组候选里,相关文档应该得到更高的分数。E5 等文本表示模型就使用了对比学习训练方法。E5 论文
负样本的选择会影响模型学到的区分能力。
对“退款什么时候到账”这个问题,用“如何更换手机壁纸”作为负样本,模型很容易完成区分。换成“退货包裹什么时候签收”,两段内容都涉及售后流程,模型就必须进一步关注用户要查的是资金到账还是物流签收。
后一类容易混淆的样本通常更有训练价值。但标注也更容易出错:一篇退货说明可能同时包含退款到账时间,不能只看标题就把它判成负样本。
“语义相近的文本在空间里靠近”因此应当被理解为训练希望实现的性质。它能实现到什么程度,取决于数据、训练目标和应用场景。
查询与文档可以采用不同的编码方式
查询通常很短,文档则可能包含背景、条件和答案。两者承担的角色不同。
双编码器检索可以分别计算:
查询编码器与文档编码器可以共享参数,也可以分别训练;即使共享参数,也可能通过不同的前缀或指令区分输入角色。DPR 就采用了面向查询和段落的双编码器框架。DPR 论文
这也解释了一个实际问题:余弦公式虽然是对称的,整个检索任务仍然可以是不对称的。把查询与文档的角色交换后,输入处理和得到的表示可能发生变化。
部署时需要遵循模型的输入约定。例如,multilingual-e5-large 的模型卡要求在检索场景中分别使用 query: 和 passage: 前缀。遗漏前缀会改变模型接收的输入形式,影响效果。Multilingual E5 模型说明
这属于模型接口的一部分,应当与模型版本、最大输入长度一起记录下来。
四、余弦相似度、点积和欧氏距离有什么区别
编码完成后,检索系统还需要选择打分函数。常见选择是余弦相似度、点积和欧氏距离。
对于两个非零向量,余弦相似度为:
这里的 u · v 表示点积,‖u‖ 表示向量 u 的欧氏范数,也就是向量长度。
余弦相似度衡量方向接近程度,理论范围是 [-1, 1]。值接近 1 表示方向接近,值接近 0 表示接近正交。负值表示方向夹角超过 90 度,不能直接解释为两段话在逻辑上互相否定。
点积为:
它同时受到方向和向量长度的影响。欧氏距离则计算两点之间的直线距离:
相似度通常越大越靠前,距离通常越小越靠前。把两种排序方向混淆,足以让一个配置正确的模型返回完全错误的结果。
若查询和文档向量都做了单位长度归一化,则:
在这个条件下,精确计算时,点积、余弦相似度和欧氏距离会产生等价排序。Faiss 文档也说明了这一关系,并提醒其 L2 返回值是平方欧氏距离。Faiss 距离与度量文档
没有归一化时,这种等价关系不成立。一个依据点积目标训练的模型,也不应未经验证就改成归一化后的余弦检索,因为向量长度可能参与了原来的打分。
实际排查时,应先确认模型推荐的打分方式,再检查入库向量与查询向量是否采用相同的处理。数据库中的“分数”还可能经过转换,不能只凭字段名称判断其数学含义。
0.85 不是“85% 的概率相关”
余弦相似度是几何量,没有天然的概率解释。
同样是 0.85,在不同模型、语料和任务中可能对应不同的相关性水平。更换模型、输入前缀或分块方式后,原来的阈值也可能失效。
E5 模型卡专门解释过其相似度分数较集中的现象,并指出排序中的相对关系比绝对数值更值得关注。这是具体模型的行为,不能推广成所有 Embedding 模型都使用同一分数区间。Multilingual E5 模型说明
对于“是否返回答案”这样的决策,需要在真实标注数据上观察相关与不相关结果的分布,再评估阈值对应的漏检和误检。把别人的 0.8 阈值复制过来,没有可靠依据。
Top-K 检索也不会自动判断知识库有没有答案。只要候选数量足够,它就可以返回 K 条结果,即使这些结果都不满足问题要求。
五、高相似度为什么仍然会带来错误答案
相似度高而答案不合用,往往对应不同类型的故障。把它们都归为“模型不够聪明”,会掩盖真正应该修改的环节。
主题相同,关键条件不同
设想一组用于测试的设备说明:
A:X100 支持离线使用。
B:X100 不支持离线使用。
C:X100 Pro 支持离线使用。
D:X100 在升级到 2.3 版固件后支持离线使用。
这些是人为构造的测试句,不代表任何真实产品。
四句话的主题和措辞接近,但型号、否定词和版本条件决定了答案。对于“运行 2.1 版固件的 X100 能否离线使用”,只找到“支持离线使用”这几个词远远不够。
Embedding 模型可能识别这些差别,也可能没有把它们反映为足够明显的分数间隔。需要在测试集中单独检查,不能从一般语义相似度成绩推断。
能可靠提取的型号、地区、生效日期等字段,可以参与结构化过滤。模型负责处理自然语言关联,明确的业务条件则需要在检索或验证阶段落实。
分块把条件和结论拆开了
一份售后文档可能这样写:
本节适用于尚未发货的订单。
用户提交申请后,平台按以下流程处理退款……
如果分块只保留第二段,查询“已发货订单如何退款”时,这个片段可能得到不错的分数。模型接收到的文本已经缺少适用条件,再强的编码器也无法从中恢复确定的信息。
因此,分块需要保留必要的标题、条件和指代关系。可以让每个片段携带所属章节,也可以先检索较小片段,再读取相邻段落或父章节。
需要保留多少上下文,应由文档结构和问题类型决定。把所有材料都切成同一长度,并不能保证每块都有完整含义。
文档表达清楚,但内容已经过期
一篇旧版接口说明可能写得完整、术语匹配准确,因此容易排在前面。相似度不会自动把“当前有效”编码成稳定的业务约束。
这类问题需要文档版本、生效时间和替代关系。查询没有指定版本时,系统应有明确的默认规则;指定旧版本时,又不能把历史文档全部过滤掉。
在知识库问答中,来源正确、版本适用和语义相关必须同时满足。它们不能由一个相似度数字代替。
向量索引漏掉了本该进入候选的文档
还有一种错误发生在编码之后。
大规模系统常使用近似最近邻搜索,以一定的召回损失换取速度和资源效率。此时,即便模型把正确文档放到了合适的位置,索引也可能没有把它返回。
可以在可控规模的数据集上,用同一批向量做一次穷举检索,再与近似索引比较。
如果穷举结果里也没有正确文档,优先检查表示、分块和查询;如果穷举可以找到、近似索引却漏掉,就应检查索引参数、量化和过滤执行方式。
这是两种不同的误差。混在一起调,可能为了补偿索引问题而更换模型,也可能为了模型排序问题不断扩大搜索范围。
六、关键词检索为什么仍然值得保留
把关键词检索描述成“只认字、不懂意思”,容易低估它在工程系统中的作用。
用户搜索错误码 PAYMENT_4097、函数名 createInvoice 或产品型号 X100-Pro 时,通常希望找到包含准确标识的资料。一个讨论相似问题、却对应另一个标识的文档,往往没有帮助。
BM25 也不只是统计重合了几个词。它结合词项的区分度、词频饱和与文档长度进行打分,因此能成为稳定的全文检索基线。《Introduction to Information Retrieval》对 BM25 的说明
不过,关键词检索同样需要配置。分词器可能拆坏错误码,中文分词可能影响短语匹配,大小写处理和字段类型也会改变结果。必须精确匹配的标识,适合使用专门字段,不宜完全依赖全文打分。
全文检索还可以加入同义词、词形处理和查询扩展。所以,“iPhone”和“苹果手机”无法通过关键词系统关联,也不是一个必然结论。能否匹配,取决于整个系统的分析和扩展机制。
稀疏表示与稠密表示同样不等于“没有语义”与“有语义”。学习型稀疏检索也能通过模型生成词项权重或扩展词项;稠密向量则可能保留大量主题信号,却忽略任务要求的细微条件。
BEIR 在跨领域检索评估中发现,BM25 是有竞争力的基线,稠密检索的收益具有任务差异。这项研究支持的工程判断是:需要用自己的数据比较方法,不能把“用了 Embedding”当成效果保证。BEIR 论文
七、混合检索与 Rerank 分别补什么
词项检索和稠密检索通常会漏掉不同的材料。
用户描述“钱一直没退回来”时,向量检索有机会找到“退款到账延迟”;用户输入明确错误码时,词项检索可以利用精确标识。混合检索把不同通道的候选合并,目的是提高覆盖率。
问题在于,两路原始分数通常不在同一个尺度上。直接计算“BM25 分数加余弦相似度”,很可能只是让数值范围较大的通道主导结果。
一种常用办法是 Reciprocal Rank Fusion,简称 RRF。它根据名次融合:
其中,Lᵢ 是第 i 路候选列表,rankᵢ(d) 是文档 d 在该列表中的名次,从 1 开始;c 是控制前排优势的常数。没有出现在某一路列表中的文档,不获得那一路贡献。这样可以避开原始分数不可直接比较的问题。Elasticsearch 的 RRF 文档
RRF 仍然受候选窗口和各通道质量影响。它能融合排名,却无法判断两个结果是否属于同一段重复内容,也不会自动发现文档已经失效。
重排让模型同时阅读问题与候选文档
初步召回需要处理大量文档,因此常把查询和文档分别编码。文档向量可以预先计算,这使检索具备较好的效率。
常见的 Cross-Encoder 重排器则把查询与一篇候选文档一起输入模型,让两段文本在计算中发生交互,再输出相关性分数。它适合对较小的候选集进一步排序。Sentence Transformers 检索与重排文档
但重排只能处理已经召回的内容。正确文档没有进入候选集,排序模型无从把它提升到前面。
重排也会遇到领域不匹配、长文截断和条件判断错误。某个重排器在公开问答数据上表现不错,不代表它能辨别内部产品编号或复杂业务规则。
它输出的分数也未必是概率。有的模型返回原始分数,有的经过 Sigmoid 映射到 0 到 1;数值落在这个区间,并不等于已经完成了概率校准。Sentence Transformers 重排模型说明
因此,加入 Rerank 后,应当比较前后排序质量及延迟。不能仅凭多了一层模型,就认定系统更准确。
八、用什么指标判断系统有没有进步
检索优化需要一批能够说明问题的标注样本。
每条样本至少应包括查询、相关文档及相关程度;业务问题还需要适用版本或其他必要条件。数据集里也要包含知识库没有答案的查询,否则系统只会接受“总能找出一个答案”的考验。
样本应覆盖不同难度:同义改写、精确标识,以及否定、数字和条件变化。前面的 X100 示例就可以扩展成一组最小差异测试,逐项检查系统是否因为只差一个词或一个版本号而返回错误结果。
评估时需要把不同阶段分开。
| 阶段 | 可以观察的指标 | 回答的问题 |
|---|---|---|
| 初步召回 | Recall@K | 标注相关文档有多少进入候选集? |
| 首条有效结果 | MRR@K | 第一条相关结果排得够不够靠前? |
| 整体排序 | nDCG@K | 更有用的文档是否排在更前面? |
| 近似索引 | 相对精确检索的近邻召回率 | 索引额外漏掉了多少向量近邻? |
| 问答结果 | 证据覆盖、回答正确性、无答案时的行为 | 最终回答是否有足够依据? |
这里的“近邻召回率”和业务相关文档的 Recall@K 不应混用。
一个近似索引可能准确找到了向量空间里的近邻,但这些近邻并不是业务上相关的文档。反过来,模型表示有效,近似搜索却可能漏掉重要候选。两种指标分别衡量不同环节。
评估重排时也要保留真实的召回结果。为了方便测试而把正确文档手动加入候选集,可以考察重排器自身的能力,却无法代表线上系统的端到端效果。
先建立能够复现的基线
一套便于比较的实验可以从三个版本开始:
- BM25;
- 稠密向量检索;
- 两者混合,再根据需要加入重排。
比较时固定文档版本、标注集和分块方式,把候选数量与计算预算记录下来。如果一个方案召回了更多候选,也消耗了更多延迟,质量提升需要连同成本一起看。
调参使用验证集,最后再用独立测试集检查结果。反复查看同一批错误并逐条修补,可能让系统记住测试集,却没有改善新查询。
平均分之外,还要查看不同查询类别。整体 nDCG 提高,可能掩盖产品型号查询的退步;自然语言问答变好,也可能伴随错误码检索变差。对业务影响大的查询,应单独设定验收标准。
九、检索结果必须回到原文验证
在检索增强生成系统中,候选文档还要交给生成模型组织答案。到了这一步,相似度的作用已经完成了大半:它帮助系统缩小阅读范围。
接下来需要检查的是证据。
继续看“运行 2.1 版固件的 X100 能否离线使用”这个问题。即使系统召回了四篇都在讨论离线功能的文档,也不能让生成模型挑一句最顺口的回答。
它需要读出文档对应的型号与版本,确认“升级后支持”是否适用于用户当前环境,并检查是否存在更新的说明。证据不足时,回答应该说明缺少哪项信息;资料互相冲突时,需要保留冲突及来源,不能把两段话拼成一个没有出处的结论。
对于需要多份证据的问题,单篇文档相关还不够。回答“升级后有哪些兼容性变化”,可能同时需要版本说明、迁移指南和已知问题列表。候选集里即使有一篇高度相关的发布公告,也可能缺少完成回答所需的其余材料。
文档去重和结果多样性因此也会影响质量。如果前十条只是同一段内容的重复副本,模型能读到的有效信息仍然有限。
十、把一次失败拆成可以验证的问题
当系统再次返回一个高分但无用的结果,可以沿着下面的顺序排查:
先打开实际入库的文本,确认答案确实存在,且没有在解析、截断或分块时丢失条件。随后核对查询与文档使用的模型版本、输入格式和归一化方式。
再用精确向量检索与线上索引比较,区分表示问题和近似搜索损失。正确文档进入候选集后,检查融合与重排是否把它压到了后面;排名没有问题,就继续检查生成模型是否忽略了原文中的限制。
这条排查路径对应的是一组可以观察的结果:
- 文档中有没有答案;
- 模型有没有把它排进合理范围;
- 索引有没有把它取回来;
- 排序有没有保留它;
- 最终回答有没有忠实使用它。
每一步都能留下证据,也对应不同的修改位置。
回到最初那句“iPhone 充满电为什么用不了半天”,一个合格系统应当先利用 Embedding 找到续航与耗电相关的材料,再识别用户尚未提供的型号、设备状态和使用条件。等这些信息足够,系统才能从通用电池知识收窄到适用的排查步骤。
验收时,应当观察它是否找到适用文档、是否保留关键条件、是否给出有出处的判断。分数负责排序,答案仍需要原文和任务要求共同检验。