混合搜索的坑我踩全了
去年我司搜索转化率直接跌了37%,老板脸都绿了。排查下来发现原因特别蠢:用户搜“轻量冲锋衣”,结果跳出来一堆帐篷;搜“苹果”,出来的是红富士而不是iPhone。老一套关键词匹配,彻底凉了。
真相就一句话:你不搞懂 Embeddings 向量搜索,就永远猜不透用户到底想要啥。
搜索这玩意儿到底进化到哪了
传统搜索引擎像个死板的图书管理员。你跟他说“编程入门书”,他只会在书架上找标题里带这五个字的。向量搜索呢?像个懂你的老司机,你问“怎么上手写代码”,他能直接把《Python从入门到放弃》塞你手里。
Embeddings 说白了就是把任何东西——文字、图片、声音——都压缩成一串数字。 语义相近的东西,在向量空间里天然就挨得近。
我第一次搞这个是2019年在大厂做推荐系统。当时的想法特别 naive:把词转成向量能有多难?上线第一天,给点过儿童教育文章的用户推了“性感荷官在线发牌”。真·当场社死。那个组后来团建我都没脸去。
单靠向量搜索,坑到你怀疑人生
别一上来就 All-in 向量搜索。我给你数数我交过的学费:
坑1:精确匹配直接翻车
有次用户搜“iPhone 15 Pro Max 256G 黑色”,向量搜索哗哗返回一堆“手机选购攻略”“旗舰机对比评测”,唯独没有那个具体SKU。因为向量搜索擅长理解语义,不擅长死磕型号和规格参数。用户是想掏钱下单,不是来听你讲手机发展史的。
坑2:专业术语灾难现场
2022年我在一个医疗项目里,有医生搜“ST段抬高型心肌梗死”,向量搜索返回了“心脏病注意事项”“心绞痛怎么缓解”——都是泛化结果。急诊科主任直接打电话骂我们CTO,说这破系统耽误抢救,差点出事。那通电话之后我三天没睡好。
坑3:长尾查询丢信息
电商场景里搜“适合送女朋友的生日礼物 预算200以内 实用型”,纯向量搜索就逮住“礼物”“女朋友”两个词,预算和“实用型”这些限定全扔了。然后推荐了800块的祖马龙香水。用户直接截图发微博吐槽,评论区一片哈哈哈。运营同学差点提离职。
等等,这里我要更正一下——坑3这个案例不完全是因为向量搜索。后来我们复盘发现,query 理解那层也已经把长尾修饰词给截断了。所以问题出在整个 pipeline 上,不能光让向量搜索背锅。
所以聪明人怎么干?混合搜索。
混合搜索怎么搞才不翻车
混合搜索就是把关键词匹配(BM25那套)和向量搜索(ANN语义匹配)的结果揉到一起。但很多人就是简单把两堆结果拼起来——那是培训班学员的水平。
线上实际跑着的架构:
第一层:双路召回
- 关键词召回:Elasticsearch 的 BM25,专门逮精确匹配、型号、专有名词、SKU
- 向量召回:用 bge-large-zh-v1.5(2024年1月发的那个版本)把所有商品描述和用户 query 转成向量,扔进 Milvus 做 ANN 检索
第二层:融合排序
这是真正拉开差距的地方。我见过太多团队用固定权重,关键词0.3、向量0.7,然后就开始喝茶等结果。这跟瞎蒙有什么区别?
真正的做法是根据用户意图动态调权重。思路大概是:
# 伪代码,理解思路就行,别直接抄
def dynamic_fusion(query, bm25_results, vector_results):
# 判断查询类型
if is_exact_match_query(query): # 包含型号、编号、具体规格
weight_kw = 0.8
weight_vec = 0.2
elif is_semantic_query(query): # 描述性、模糊的问法
weight_kw = 0.2
weight_vec = 0.8
else: # 混合型查询
weight_kw = 0.5
weight_vec = 0.5
return merge_and_rerank(bm25_results, vector_results, weight_kw, weight_vec)我们还训了一个查询意图分类模型,用的 DistilBERT 蒸馏版,拿用户过去三个月的点击日志 fine-tune。上线之后点击率涨了23%——但我对这个数字持保留态度,我觉得大概有3-5个点是其他优化带来的。能确定的是退货率降了15%,因为用户真的找到了想要的东西。
重排序才是分水岭
嗯...这个比较复杂。
如果说混合搜索是发动机,重排序就是变速箱。没变速箱你马力再大也跑不起来。
我踩过的三种方案:
方案一:Cross-encoder 精排
用 Cohere 的 rerank-v3 对融合后的 Top50 做二次打分。效果好到离谱,但延迟直接加了200ms。老板说“要保证用户体验”,我说行那你给我加机器,老板说“没有预算”。行吧。
方案二:特征工程 + LambdaMART
提取了30多个特征:文本相似度、关键词命中情况、历史CTR、价格匹配度、品类相关性、品牌匹配度……然后用 LambdaMART 排序。效果中规中矩,但维护这些特征差点把两个实习生送走。其中一个离职前跟我说“师兄我觉得我不适合搞技术”,我愧疚到现在。
方案三:多阶段漏斗(现在线上跑的)
- 双路召回各取 Top100
- 融合排序取 Top50
- Cross-encoder 精排取 Top20
- 业务规则层(去重、黑名单、多样性控制)输出 Top10
这个架构上线后搜索相关性涨了42%(A/B Test 统计显著,p值0.003),P99延迟压在300ms以内。不过说实话,300ms 这个数在618峰值那天飙到过480ms,运维半夜两点给我打电话,我俩对着监控屏幕沉默了五分钟。
一个让我重新想这个事的案例
去年双11前,我们发现用户搜“冲锋衣”,向量搜索给三合一冲锋衣和单层冲锋衣打的分差不多。但数据分析显示:搜“冲锋衣”的用户,87%最后买了三合一款。
问题出在 Embeddings 模型上。通用模型根本理解不了垂直品类里那些细微差别。我们做了两件事:
1. 拿历史交互数据 fine-tune Embeddings:点击对、加购对、成交对分别当正样本,随机采样当负样本,用对比学习跑。bge-large 用 LoRA 微调,显存才占18G,单卡A100就跑起来了
2. 重排序时加入场景特征:冬天加权保暖性参数、用户历史行为(登山党加权专业款)
微调完,Top5命中率从68%涨到83%。但我得说实话:fine-tune Embeddings 是个体力活,数据清洗阶段差点又送走一个实习生。我们花了整整3周清理刷单数据和误点击,那三周的周报我都不忍心看。
你大概率会犯的五个错误
错误1:选错 Embeddings 模型
中文场景别用 OpenAI 的 text-embedding-3-large,贵得要死还水土不服。bge-large-zh-v1.5 或者 text2vec-large-chinese,HuggingFace 的 MTEB 中文榜单上霸榜一年多了,还免费。我们线上跑的 bge-large-zh-v1.5,单条 embedding 耗时大概8ms。
错误2:不管向量数据库索引类型
Faiss 的 IVF 和 HNSW 在不同量级下差异巨大。100万向量以内用 HNSW,构建时间短、查询快;过亿了老老实实上 IVF+PQ,不然内存直接打满。别问我怎么知道的,凌晨三点回滚代码的痛。
错误3:不跑 A/B Test 直接全量上线
我们组有个同事在排序里加了个“好评率”特征,离线评估涨了5%,上线后转化率掉了8%。因为好评率高的商品往往贵,用户买不起就跑了。脱离业务场景的优化都是耍流氓——这句话我贴在工位上。
错误4:把向量搜索结果当最终结果
一定要加一层业务规则:去重、黑名单、库存过滤、价格区间、安全合规。不然你会在搜索结果里看到已下架商品甚至违禁内容,然后法务会请你喝茶。我们之前就出过一次,下架商品被搜出来了,用户截图发到群里质问“你们是不是要跑路了”。
错误5:不监控向量漂移
定期跑同义词、近义词的相似度检查。我们发现“核酸检测”和“新冠检测”的向量相似度在2022年12月突然从0.95掉到0.7,因为上游模型更新了训练数据。幸亏监控告警发现得早,不然线上搜索质量要崩。
最后说几句
混合搜索不是银弹。但确实是目前性价比最高的方案。纯关键词体验拉胯,纯向量精确度翻车,混合搜索加重排序能在中间找到个可以接受的点。
我最近在试一个新方向:用 LLM 做 query 理解和结果解释。比如用户搜“通勤穿搭”,LLM 能推断出这人大概率是上班族、需要正式偏休闲风格、预算可能有限——然后把这些结构化信息传给搜索系统。这比现在那套 query 意图分类灵活太多了。不过目前推理延迟还不太可控,2024年12月试了 GPT-4o 做 query 改写,单次耗时400ms+,线上根本没法用。可能得等2025年模型再卷一波。
你们团队在搜索上踩过啥坑?用了哪些 Embeddings 模型?评论区聊聊,我每条都会看。如果这篇对你有用,转发给你那个还在用 MySQL LIKE 做搜索的同事,救救他。
#搜索系统 #Embeddings #向量数据库 #RAG #机器学习实战 #系统架构
读者评论 5