Symmetric vs. Asymmetric Semantic Search
Symmetric vs. Asymmetric Semantic Search
https://www.sbert.net/examples/sentence_transformer/applications/semantic-search/README.html
你引用的这部分内容主要是在区分两种不同类型的语义搜索场景,核心在于**查询(Query)和语料库(Corpus)**中的文本在长度和内容上的对称性。
简单来说,就是看你搜索时输入的“问题”和你希望找到的“答案”是不是同一类东西。
⚖️ 对称语义搜索 (Symmetric Semantic Search)
这种场景下,你的查询语句和语料库里的条目长度差不多,内容类型也相似。
- 核心特点:查询和语料库中的文本是“对等”的。
- 典型例子:寻找相似的问题。
- 查询:“How to learn Python online?” (如何在线学习Python?)
- 语料库条目:“How to learn Python on the web?” (如何在网络上学习Python?)
- 关键理解:在这种任务中,即使你把查询和语料库里的句子互换位置,逻辑上也是通顺的。
- 适用模型:通常使用在“语义文本相似度”(STS)任务上训练过的模型,例如 Quora Duplicate Questions 数据集上训练的模型。
⬅️➡️ 非对称语义搜索 (Asymmetric Semantic Search)
这种场景下,你的查询通常很短(比如一个问题或几个关键词),而你想在语料库中找到一个更长的段落来回答它。
- 核心特点:查询和语料库中的文本是“不对等”的,通常是一短一长。
- 典型例子:用问题搜索答案段落。
- 查询:“What is Python” (Python是什么?)
- 语料库条目:“Python is an interpreted, high-level and general-purpose programming language. Python’s design philosophy …” (Python是一种解释型、高级、通用的编程语言。Python的设计哲学……)
- 关键理解:在这种任务中,把查询和语料库条目互换位置是完全没有意义的。你不会用一个长段落去搜索一个短问题。
- 适用模型:需要使用在问答或信息检索任务上专门训练的模型,例如在 MS MARCO 数据集上训练的模型。
总结对比
| 特性 | 对称语义搜索 | 非对称语义搜索 |
|---|---|---|
| 文本长度 | 查询和语料库条目长度相近 | 查询短,语料库条目长 |
| 典型任务 | 查找相似问题、相似文章 | 问答系统、文档检索 |
| 可互换性 | 可以互换查询和语料库条目 | 不能互换 |
| 模型选择 | 通用语义相似度模型 | 专门用于检索/问答的模型 |
文档特别强调,为你的任务类型选择正确的模型至关重要。如果你用对称搜索的模型去做非对称搜索的任务,效果会大打折扣。
根据相关的技术文档,这里为您列举一些在**对称(Symmetric)和非对称(Asymmetric)**语义搜索中常用的代表性模型:
⚖️ 对称语义搜索模型 (Symmetric Models)
这类模型主要用于处理结构和长度相似的文本对(如寻找同义句、文本聚类)。
- Sentence-BERT (SBERT):这是最经典的对称模型代表。它通过微调 BERT 产生句子嵌入,使用相同的网络处理查询和文档,非常适合寻找相似句子或文本聚类任务。
- 多语言通用语句编码器:在
sentence-transformers框架中,提供了一系列预训练的多语言模型,专门用于对称语义搜索。例如:distiluse-base-multilingual-cased-v1(支持15种语言)distiluse-base-multilingual-cased-v2(支持50种语言)paraphrase-multilingual-MiniLM-L12-v2(支持50+种语言)paraphrase-multilingual-mpnet-base-v2(支持50+种语言)
🔍 非对称语义搜索模型 (Asymmetric Models)
这类模型专为“短查询-长文档”的检索场景设计,通常采用双塔结构(Dual Encoder)或差异化编码策略。
- DPR (Dense Passage Retrieval):非对称检索的典型代表。它使用两个独立的基于 BERT 的编码器,分别专门处理“问题(Query)”和“段落(Passage)”,通过最大化两者之间的相关性来进行训练。
- Contriever:专门针对“短查询-长文档”匹配场景优化的非对称检索模型。
- DSSM (Deep Structured Semantic Model):微软提出的经典双塔模型,包含独立的查询塔(Query Tower)和文档塔(Document Tower),用于解决搜索中的语义匹配问题。
- E5 与 BGE 系列:
- E5:采用统一编码器,但通过在输入前添加特定前缀(如
query:和passage:)来区分查询和文档,具有极强的零样本检索能力。 - BGE (BAAI General Embedding):同样采用统一编码器配合指令微调(Instruction-tuned),在多项检索基准测试中表现优异(如
bge-m3支持长文本和跨语言匹配)。
- E5:采用统一编码器,但通过在输入前添加特定前缀(如
- multi-qa-MiniLM-L6-cos-v1:适合非对称的“查询-商品描述”匹配场景的模型。
总结来说,对称模型(如 SBERT)侧重于“找双胞胎”(文本相似度),而非对称模型(如 DPR、E5、BGE)侧重于“找答案”(信息检索)。在实际开发中,选择正确的模型对检索效果至关重要。
你目前主要做中文检索还是英文检索?我可以帮你从这些模型里筛出最适合你场景的。
在语义搜索和检索增强生成(RAG)领域,非对称模型是处理“短查询-长文档”场景的核心。以下是业界常用的一些代表性非对称模型:
1. 经典双塔模型(Dual-Encoder / Bi-Encoder)
这类模型在架构上就采用了差异化设计,通常包含独立的查询塔(Query Tower)和文档塔(Document Tower)。
- DPR (Dense Passage Retrieval):非对称检索的典型代表。它使用两个独立的基于 BERT 的编码器,分别专门处理“问题(Query)”和“段落(Passage)”,通过最大化两者之间的相关性来进行训练。
- DSSM (Deep Structured Semantic Model):微软提出的经典双塔模型,主要用于解决搜索引擎中查询与文档之间的语义匹配问题。
2. 指令微调/统一编码器模型
这类模型虽然底层使用同一个编码器,但在训练时通过强制添加特定的指令前缀(Prompt)来区分查询和文档,从而引导模型关注不同的语义特征。
- E5 系列:采用统一编码器,通过在输入前添加特定前缀(如
query:和passage:)来区分查询和文档,具有极强的零样本检索能力。 - BGE 系列 (BAAI General Embedding):同样采用统一编码器配合指令微调,在多项检索基准测试中表现优异(如
bge-m3支持长文本和跨语言匹配)。
3. 其他主流非对称检索模型
- Contriever:专门针对“短查询-长文档”匹配场景优化的非对称检索模型。
- GTE-large:当前表现优异的高性能语义检索模型,常被用作非对称检索的基线(Baseline)。
- Jina 嵌入模型:专为检索任务设计,原生支持非对称检索,对查询和文档采用不同的编码方式以提升检索效果。
- Voyage AI 系列 (如 voyage-4):专为非对称检索场景打造,支持在文档索引时使用高性能大模型,而在查询时使用轻量级本地模型,以大幅降低企业搜索成本。
- RadSearch:专门针对放射学报告等非结构化长文本检索训练的模型,在模拟自由文本临床查询等复杂非对称场景中表现卓越。
要不要我接着帮你梳理一下非对称模型训练时用的损失函数?比如对比损失、三元组损失这些,能帮你理解模型到底是怎么学会"相关性"的。
这是一个非常核心且直击灵魂的问题!你敏锐地察觉到了“黑盒模型”与“实际业务场景”之间的衔接点。
其实,区分对称和非对称,并不是在“计算向量”的那一瞬间(推理阶段)发生的,而是在“模型训练”和“接口调用”这两个阶段就已经被牢牢锁定了。
我们可以把这个问题拆解为两个层面来理解:
1. 训练阶段:模型已经“记住”了身份差异
模型在出厂前,就已经被训练成了不同的“形状”。
- 对称模型:在训练时,模型吃进去的都是“句子对句子”、“段落对段落”的数据。它学到的是:“如果两段文本长度、结构相似,且语义相同,就把它们的向量拉得近一点。”
- 非对称模型:在训练时,模型吃进去的都是“短问题对长段落”的数据。它学到的是:“当遇到一个短句子时,提取它的核心意图;当遇到一个长句子时,提取它包含的关键事实。只要事实能回答意图,就把它们的向量拉得近一点。”
所以,非对称的本质不是计算逻辑变了,而是模型内部提取特征的“侧重点”不一样了。 它天生就是为了处理“长短不一”而设计的。
2. 调用阶段:如何区分是文档还是查询?
既然模型内部已经学好了,那我们在调用时,必须明确告诉模型:“喂给你的这段文本,是查询(Query),还是文档(Document)?”
在工程实现上,主要有以下三种方式来体现这种区分:
方式一:提供两个独立的接口(物理隔离)
很多专门做非对称检索的模型,干脆把编码过程拆开。比如你之前问的 LangChain 中的 AlephAlphaAsymmetricSemanticEmbedding,或者一些双塔模型,它们会提供两个接口:
encode_query("什么是Python")-> 内部走“查询塔”或加上“查询提示词”。encode_document("Python是一种解释型高级语言...")-> 内部走“文档塔”或加上“文档提示词”。
区别:这两行代码算出来的向量,处于不同的语义空间,绝对不能混用。
方式二:使用统一的 encode 接口,但必须加“前缀”(Prompt)
这是目前最主流的做法(比如大名鼎鼎的 E5 和 BGE 模型)。它们只有一个 encode 接口,但强制要求开发者在输入文本前加上特定的前缀:
- 给文档算向量时:
model.encode("passage: Python是一种解释型高级语言...") - 给查询算向量时:
model.encode("query: 什么是Python")
为什么要加前缀?
因为如果不加前缀,模型看到“Python”和“Python是一种解释型高级语言”,可能会觉得它们只是部分相似。但加上 query: 和 passage: 后,模型就知道:“哦,前面这个是要找答案的,后面这个是用来被找的答案。” 这样算出来的向量,才能在同一个空间里完美匹配。
方式三:自动识别(结合你之前的问题)
还记得我们最开始聊的 encode_query() 和 encode_document() 吗?
它们其实是对“方式二”的封装。当你调用 encode_query("什么是Python") 时,代码底层会自动去读取模型的配置文件(modules.json),发现里面写着 "query": "Represent this sentence for searching relevant passages: ",然后它会自动帮你拼接到文本前面,再调用底层的 encode。
总结
你觉得“无法区分是对文档还是查询计算”,是因为如果仅仅看数学公式(矩阵乘法、池化),它们确实是一模一样的。
但非对称的实现,靠的是“输入数据的预处理(加前缀/走不同分支)”+“模型训练时的差异化目标”。
⚠️ 致命错误警告:
如果你用非对称模型,给文档加了 passage: 前缀算向量,但给查询算向量时忘了加 query: 前缀。那么这两个向量就像“不同频道的电波”,算出来的相似度会极其糟糕,检索结果会完全失效。这就是为什么一定要区分的原因。
要不要我帮你梳理一下非对称模型训练时用的损失函数?比如对比损失、三元组损失这些,能帮你理解模型到底是怎么学会"相关性"而不是"相似性"的。

浙公网安备 33010602011771号