6.向量相似度是怎么计算的?从余弦距离到语义检索 📅 发布时间:2026/8/19 11:03:49 👁 浏览次数: 向量相似度是怎么计算的从余弦距离到语义检索码海寻道 · 大模型、智能体与 RAG 工程组件系列第 6 篇上一篇我们把文字转换成了向量。接下来还有一个关键问题两个向量究竟怎样比较才能判断它们的语义是否接近向量数据库的核心工作可以概括成一句话给定一个查询向量从大量候选向量中找出“最相似”的 Top K 个结果。这里的“相似”不是凭直觉判断而是由距离或相似度函数计算出来的。函数不同分数含义不同排序方向也可能相反。在真实系统里距离指标并不是只写在检索代码中的一个参数。它需要同时出现在 Embedding 服务配置、Milvus/pgvector Schema、索引操作类、评测脚本和监控日志中。只改其中一处就可能出现“查询能返回结果但排序和阈值都不可信”的问题。一、先理解向量空间中的“近”假设我们把一批文档转换成向量每个向量都可以看成高维空间中的一个点文档 A → 向量 A → 空间中的点 A 文档 B → 向量 B → 空间中的点 B 用户问题 → 查询向量 Q → 空间中的点 Q语义检索要做的事情就是计算 Q 与所有候选点之间的关系然后按结果排序。但“距离近”并没有唯一答案可以看两个点之间的直线距离可以看两个向量的夹角可以看两个向量对应坐标的乘积总和也可以使用关键词或稀疏向量的匹配分数。因此选择距离指标本质上是在定义你的系统认为“相似”是什么。二、余弦相似度最常见的文本向量比较方式余弦相似度关注两个向量的夹角而不是它们距离原点有多远。公式是cos(A, B) (A · B) / (||A|| × ||B||)其中A · B是向量内积||A||是向量 A 的长度||B||是向量 B 的长度。余弦相似度通常在[-1, 1]范围内越接近 1方向越接近接近 0方向接近正交越接近 -1方向越相反。在很多文本 Embedding 场景中方向比向量长度更重要因此余弦相似度经常被采用。但不能只因为“文本检索常用余弦”就盲目设置还应该看 Embedding 模型的说明和实际评测结果。三、内积 IP为什么归一化后它等价于余弦内积的公式很简单A · B a1b1 a2b2 ... anbn内积同时受到两个因素影响两个向量的方向是否一致两个向量的长度是否较大。如果先把向量归一化使每个向量的长度都等于 1那么A · B cos(A, B)这也是为什么一些系统会使用 IP 搜索归一化后的向量。但要注意归一化不是一句可有可无的预处理。如果向量没有归一化却把 IP 当作余弦相似度使用结果可能被向量长度影响排序就会与预期不同。Milvus 官方文档明确说明归一化后的向量使用内积时结果等价于余弦相似度未归一化时IP 和余弦的结果可能不同。四、欧氏距离 L2直线距离越短越相似欧氏距离也叫 L2 距离二维情况下就是我们熟悉的两点直线距离L2(A, B) sqrt((a1-b1)^2 ... (an-bn)^2)在 L2 检索中距离越小结果越相似。而在余弦和 IP 检索中通常是分数越大结果越相似。这是工程中非常容易犯错的地方如果业务代码统一把“分数越大越好”却没有区分 L2 和 COSINE可能把最不相关的结果排到前面。对于长度已经归一化的向量L2 与余弦之间存在单调关系排序可能一致但对于未归一化向量二者的排序可能明显不同。不能仅凭“都是距离”来替换。五、Milvus 中三种指标的直观对比Milvus 对浮点向量常见的指标包括L2、IP和COSINE。它们的排序方向需要明确指标衡量方式更相似的结果COSINE向量夹角分数更大IP向量内积分数更大L2欧氏距离距离更小Milvus 的搜索结果字段通常被称为 distance但它在不同指标下可能表示距离或相似度分数。不要只看字段名必须结合metric_type判断数值含义。组件之间必须保持同一套约定Embedding 服务是否归一化 ↓ 向量字段维度和数据类型 ↓ 索引metric / operator class ↓ 查询距离方向、阈值和排序 ↓ Reranker候选片段的二次排序例如pgvector 中使用余弦距离时索引操作类应使用vector_cosine_opsMilvus 中则需要让 Collection 的索引和搜索参数使用相匹配的 metric。不能只在应用层把“距离越小”改成“分数越大”而不检查底层操作符和索引。六、Top K 到底是什么Top K 表示从候选结果中返回排名最靠前的 K 条。查询向量 ↓ 计算候选相似度 ↓ 排序 ↓ 返回 Top K例如top_k5意味着系统返回前 5 条不代表这 5 条都一定足够相关。K 太小会怎样可能漏掉真正有用的片段尤其是文档切分不理想或问题表达比较模糊时。K 太大会怎样会带来更多无关内容进入上下文Prompt 变长成本上升大模型注意力被噪声分散后续生成延迟增加。因此常见做法不是简单地把 K 设置得很大而是“先多召回再重排序再截取少量结果”。这就是下一篇 Reranker 文章会讨论的两阶段检索。七、相似度阈值为什么 Top K 还不够如果只使用 Top K即使查询和所有文档都不相关系统仍然会返回 K 条“相对最接近”的结果。例如知识库里根本没有答案但系统仍可能返回 5 个分数最高的无关片段最后让模型据此编造答案。因此可以增加阈值只保留 score threshold 的结果但阈值不是越高越安全阈值过高会漏掉表达方式不同但实际相关的文档阈值过低会让大量噪声进入 Prompt不同模型、不同数据集和不同指标的分数分布不同。尤其要注意余弦分数、IP 分数和 L2 距离不能直接使用同一个阈值。阈值必须在真实评测集上标定。八、近似最近邻 ANN为什么不直接比较全部向量如果只有几百个向量逐个计算距离并不困难。但当向量数量达到百万、千万甚至更大规模时每次查询都与所有向量比较成本会很高。向量数据库通常使用 ANN也就是 Approximate Nearest Neighbor近似最近邻搜索全部向量 ↓ 索引定位可能相关的候选区域 ↓ 只对候选进行精细比较 ↓ 返回近似 Top KANN 的目标不是在任何情况下保证数学意义上的绝对最优而是在召回率、延迟和资源消耗之间取得平衡。Milvus 的基础向量搜索文档说明ANN 会先定位候选子集再比较查询向量与候选向量从而减少全量比较带来的开销。常见索引包括FLAT接近暴力搜索结果精确适合数据量较小或评测基准IVF先把向量分到若干簇只搜索部分簇HNSW通过图结构寻找近邻常用于低延迟检索DiskANN 等面向更大规模和磁盘场景。索引参数越激进速度可能越快但召回率可能下降。向量数据库的“快”通常不是没有代价的快。九、过滤条件会改变检索结果企业知识库不能只按向量相似度检索还要增加元数据过滤向量相似度检索 tenant_id 当前租户 department_id in 用户可访问部门 document_status published version 当前有效版本过滤可以发生在向量检索之前、检索过程中或检索之后具体取决于数据库能力和实现方式。关键是不能先召回无权文档再把它们交给大模型后才试图补救。如果过滤条件过于严格候选集合可能变小召回率下降如果过滤条件缺失则会产生严重的数据泄露风险。十、为什么检索分数不能直接当作“答案可信度”向量分数只表示查询向量与候选向量在某种指标下的接近程度不等于文档一定包含答案文档内容一定正确文档对当前用户可见大模型一定能正确利用它最终回答一定没有幻觉。一个高分片段可能只是与问题主题相近却没有回答关键条件。一个相对低分的片段可能包含真正重要的限定语。所以实际 RAG 系统还需要元数据过滤多路召回Reranker 重排序答案引用和事实校验低置信度时拒答或转人工。十一、一个简单的相似度计算示例下面用 Python 展示余弦相似度的核心计算逻辑importmathdefcosine_similarity(a:list[float],b:list[float])-float:iflen(a)!len(b):raiseValueError(向量维度不一致)dotsum(x*yforx,yinzip(a,b))norm_amath.sqrt(sum(x*xforxina))norm_bmath.sqrt(sum(y*yforyinb))ifnorm_a0ornorm_b0:raiseValueError(零向量不能计算余弦相似度)returndot/(norm_a*norm_b)生产环境不会用 Python 循环逐条扫描百万向量而是交给向量数据库和索引完成。但理解这段逻辑有助于排查维度错误、零向量和排序方向问题。用执行计划确认数据库是否真的使用了向量索引在 PostgreSQL pgvector 中可以用EXPLAIN (ANALYZE, BUFFERS)检查查询计划和实际耗时EXPLAIN(ANALYZE,BUFFERS)SELECTid,content,embedding[0.1,0.2,0.3]::vectorASdistanceFROMknowledge_chunksWHEREtenant_idtenant-aORDERBYembedding[0.1,0.2,0.3]::vectorLIMIT5;如果增加过滤条件后召回数量明显下降不要先假定距离公式错了。先分别检查过滤字段的选择性、索引是否被使用、候选是否足够以及是否需要在数据库过滤后进行应用层重排。十二、上线前的向量检索检查清单文档向量和查询向量使用兼容模型所有向量维度一致距离指标与模型说明匹配如果使用 IP明确是否做了归一化业务代码正确处理 L2 的“小分更好”Top K 经过真实评测不是随意设置阈值根据真实分数分布标定检索加入租户、权限和版本过滤ANN 索引有召回率与延迟对比数据不把向量分数直接当作答案可信度。结语距离指标决定了系统如何理解“相似”向量检索不是简单地“把文本放进数据库然后搜索”。它至少包含四个决定用什么模型生成向量用什么指标比较向量返回多少候选结果如何在速度、召回率和上下文长度之间取平衡。余弦、内积和 L2 没有绝对的“最好”只有与模型、数据和业务目标是否匹配。下一篇我们继续讨论《如何选择 Embedding 模型从维度、中文能力到成本》参考资料Milvus DocumentationSimilarity MetricsMilvus DocumentationBasic Vector Searchpgvector 官方项目HNSW 与距离操作符Milvus DocumentationIndex Explained本文为“码海寻道”原创技术文章。具体指标、索引和参数应结合 Embedding 模型官方说明及真实数据集进行评测。