语义搜索架构:双塔与表示型检索系统设计

FreeGuideOnline 最新 2026-06-24

语义搜索架构:双塔与表示型检索系统设计

1. 为什么需要语义搜索

传统关键词检索(如 BM25)基于字面匹配,无法处理同义词、上下文语境和长尾查询语义偏移的问题。
语义搜索通过理解查询与文档的深层含义,将两者映射到统一语义空间,利用向量距离衡量相关性,实现“懂你意图”的检索。

2. 表示型检索的核心思想

表示型检索将查询和文档分别编码为固定长度的稠密向量,检索过程转化为 最近邻搜索

  • 离线阶段:将所有文档编码成向量并构建索引。
  • 在线阶段:输入查询 → 编码查询向量 → 在索引中快速找到最相似的文档向量。

优势:独立编码、索引预计算、召回性能高、支持多模态扩展。
挑战:语义对齐、向量高效搜索、模型更新与冷启动。

3. 双塔模型架构

双塔模型是最经典的表示型检索范式,包含两个独立的神经网络:

  • 查询塔(Query Tower):将查询文本编码成向量 q
  • 文档塔(Document Tower):将文档(标题、正文)编码成向量 d

两个塔共享同一个向量空间,采用对比损失训练,使相关查询–文档对在空间中距离接近,不相关对距离拉远。

典型结构

Query Input → BERT/DistilBERT → Pooling → q (d-dim)
Doc Input → BERT/DistilBERT → Pooling → d (d-dim)

池化通常用 [CLS] 输出或平均池化,最终按余弦相似度 cos(q, d) 排序。

4. 训练目标与负采样策略

双塔检索系统的训练常采用 批量内负采样(in-batch negatives),高效利用 GPU 并行能力:

  • 每个 batch 内正样本为配对的 (query, doc+),batch 内其他文档均视为 doc-
  • 损失函数使用 交叉熵损失InfoNCE 损失
    Loss = -log( exp(s(q_i, d_i)/τ) / Σ_j exp(s(q_i, d_j)/τ) )
    
    其中 s 为余弦相似度或点积,τ 是温度系数。

实际训练技巧

  • 使用难负样本(Hard Negatives):被当前模型检索到但不相关的文档,或从 BM25 粗召回的错误结果中采样。
  • 知识蒸馏:从交互式模型(cross-encoder)中获得更精准的软标签。
  • 数据增强:查询改写、回译、随机裁剪等。

5. 工程系统设计

5.1 离线流程

  1. 文档塔推理:使用训练好的文档塔对所有文档编码,生成向量。
  2. 向量索引构建:利用近似最近邻(ANN)库(如 Faiss、ScaNN、Annoy)构建索引,支持十亿级向量搜索。
  3. 元数据存储:保留文档原始内容、ID 等,供在线阶段返回结果。

5.2 在线流程

  1. 查询编码:接收用户查询,调用查询塔生成向量 q(延迟需控制在 10 ms 内)。
  2. ANN 检索:基于 q 在索引中检索 Top-K 候选文档(通常 K=100~1000)。
  3. 后处理:可选重排序(用轻量级交叉编码器)、多样性控制、过滤业务规则。
  4. 返回结果:拼接文档信息并返回。

6. 近似最近邻索引选型

优势 适用场景
Faiss (CPU/GPU) 极致性能,支持量化,多种索引结构 大规模离线索引、低延迟在线服务
ScaNN (Google) 超高召回率,针对内积优化 十亿级、内存受限
Annoy 内存映射,无需加载全量索引 小规模快速部署
Milvus 分布式向量数据库,管理便利 全栈向量数据管理

常见索引策略:IVF+PQ 或 HNSW,根据延迟与召回率权衡选择参数。

7. 双塔模型的实际部署要点

模型选择
轻量编码器如 MiniLM、distiluse-base 适合在线低延迟;追求极致效果可选用 BERT-large 或 T5 编码器并做蒸馏。

多向量表示
单向量可能损失细节,可尝试 ColBERT 式多向量(每 token 一向量)再配合 MaxSim 重排序,但会增大索引和检索开销。

冷启动

  • 新文档加入:仅需通过文档塔编码并插入向量索引,对现有索引进行增量更新。
  • 新域名/语言:使用领域自适应预训练或微调文档塔。

在线更新
定期(如每日)用新增文档重新构建索引,或利用支持增删的向量引擎(FAISS 的 IDMap 模式)实时添加。

8. 评估与效果调优

离线指标

  • Recall@K(K=10, 50, 100)、MRR、nDCG
  • 尤其关注 Recall@K,因为表示型检索常用于粗排阶段。

A/B 测试
在线观测点击率、首屏满足度、无结果率等业务指标。

效果提升路径

  • 增大 batch size 和负采样数量(可跨 GPU 汇聚 batch)。
  • 引入难负样本挖掘管道。
  • 组合多粒度表示(文档 + 段落 + 句子)。
  • 蒸馏自更大规模的交互模型或 LLM 重写查询。

9. 从双塔到更高级的表示型架构

架构 特点 代表
纯双塔 独立编码,快速检索 DPR, Sentence-BERT
多向量 保留细粒度交互,延迟稍高 ColBERT
模型“粗排”一体 使用单塔模型生成稠密向量并以查询端稀疏性加速 Splade (学习稀疏表示)
混合检索 结合 BM25 与稠密向量,确保字面与语义兼顾 Elastic 的 hybrid search

大部分生产环境采用 双塔粗排 + 交叉编码器精排 的混合流水线,平衡效果与性能。

10. 简易代码示例(伪代码)

# 离线索引
from sentence_transformers import SentenceTransformer
import faiss

doc_tower = SentenceTransformer('document-encoder-model')
docs = ["文档1内容...", "文档2内容...", ...]
doc_embeddings = doc_tower.encode(docs, show_progress_bar=True)

dim = doc_embeddings.shape[1]
index = faiss.IndexIVFPQ(faiss.IndexFlatIP(dim), dim, 1024, 128, 8)
index.train(doc_embeddings)
index.add(doc_embeddings)

# 在线检索
query_tower = SentenceTransformer('query-encoder-model')
query_vec = query_tower.encode(["用户查询"])
D, I = index.search(query_vec, k=20)
results = [docs[i] for i in I[0]]

11. 总结

  • 双塔架构将查询和文档解耦为独立向量,天然契合大规模检索场景。
  • 训练的关键在于负样本构造与对比损失设计,in-batch negatives 让训练高效可扩展。
  • 工程落地需重点设计离线索引管道、低延迟 ANN 检索与数据更新机制。
  • 持续通过难负样本、蒸馏、混合检索等手段迭代优化效果,最终在召回率和用户体验上达成商业目标。

部署自己的语义搜索系统,从双塔模型切入是最稳健的选择。