这道题问的是[[embedding]]检索,其实本质上就是一句话:把找相似文本,变成在高维语义空间里找最近的向量。所有技术都是围绕这个目标展开的,我会从向量化、索引构建和相似度计算三个环节,结合业务场景说一下我的理解。
先说向量化。现在主流的做法是用BERT或者Sentence-BERT这类预训练模型,把文本编码成一个稠密向量,维度通常是384到1536。这个向量的特点是,语义相近的文本在向量空间里距离也近,比如“king”减去“man”加上“woman”会靠近“queen”。但这里有个前提:你的模型必须和业务领域匹配。比如做客服退款场景,如果你用一个通用中文模型,它可能分不清“退货”和“换货”在业务上的区别,所以我会建议先做领域微调,或者用领域专用模型。
接下来是索引构建,这是检索性能的关键。暴力搜索O(N)在大规模数据下不可接受,所以要用[[ANN]]近似最近邻索引。我常用两种:[[HNSW]]和[[IVF]]。HNSW的核心是分层可导航的小世界图,搜索时从顶层贪心往下走,精度很高,但内存占用大,适合几十万到几百万规模。IVF则是聚类分桶,先粗粒度定位到几个桶,再精细搜索,速度更快,但精度会略降,适合上亿规模。实际落地时,我倾向于把两者结合,比如用IVF做第一级,每个桶里再建HNSW,或者直接用[[Faiss]]的[[IVF-PQ]],用[[Product Quantization]]压缩向量降低内存。
相似度计算这块,最常用的是余弦相似度,因为它消除向量长度影响,只关注方向。点积计算快,但受模长影响,适合已经归一化的向量。欧氏距离则适合需要绝对位置的场景,比如地理坐标。不过我会提醒一句:相似度计算不是孤立的,它要和后面的[[重排序]]配合。比如检索出Top-K后,我通常会用[[Cross-Encoder]]做一次精细重排,这时候相似度度量就变成模型内部的交互打分,不再依赖余弦或点积。
完整流程是这样的:用户输入query,经过embedding模型变成向量,然后在ANN索引里检索,拿到Top-K候选,最后用更精确的模型或规则重排序,返回结果。这里有个坑:索引构建好之后,如果业务数据频繁更新,比如知识库里的文档不断新增和修改,那索引的增量更新就非常关键。我见过很多项目上线后召回率突然下降,就是因为只做了全量构建,没处理增量。我的做法是维护一个base索引加一个delta索引,查询时合并,定期重建base。另外,纯向量检索在短文本或专有名词场景下可能不如关键词,比如订单号、错误码,所以我会加上[[BM25]]做[[Hybrid Search]],用规则或学习权重融合。
说到混合检索,其实这里有一个延伸点:向量检索和关键词检索的权重怎么融合?是手动调参还是用学习模型动态决定?我倾向用轻量级模型学习权重,因为不同query对向量和关键词的依赖差别很大,比如“退货政策”更依赖语义,“订单12345”更依赖精确匹配。
最后总结一下我的取舍:我更倾向于把embedding检索看成召回阶段,而不是最终答案。它的价值是快速缩小候选集,后续的重排序和过滤才是决定精度的关键。所以我会优先保证召回率,哪怕牺牲一点精度,然后用重排序拉回来。这个思路在客服退款场景里特别有效,用户说“我买的东西坏了”,先用向量召回相关政策,再用规则过滤掉不匹配的品类,最后给出准确答复。