1. 站内搜索为什么需要AI重构
做过电商、内容社区或者SaaS后台的朋友应该都有体会,站内搜索这个模块,平时没人夸它,一旦出问题就是铺天盖地的投诉。用户搜"红色连衣裙",结果出来一堆红色T恤和连衣裙不相关的搭配;搜"苹果手机壳",给你返回苹果和手机壳两个独立类目的商品;搜一个错别字"连衣群",直接零结果。这些场景我猜你多少都遇到过。
传统站内搜索的技术栈基本是倒排索引加BM25打分那一套,核心逻辑是关键词匹配。这套东西在文档检索时代是够用的,但放到今天的业务场景里,问题就暴露得很明显了。用户的表达越来越口语化、越来越长尾,而商品标题、文章标题、FAQ内容往往是运营或者商家自己填的,两边天然存在语义鸿沟。你搜"适合送女朋友的生日礼物",倒排索引会把它拆成"适合""送""女朋友""生日""礼物"几个词,然后去找包含这些词的文档,但真正符合意图的商品标题可能写的是"浪漫礼盒 女生 情人节 纪念日",一个词都没对上。
通智云智能搜索这个项目,要解决的就是这个问题。它的定位很明确:给中大型站点提供一套AI驱动的站内搜索解决方案,把传统的关键词匹配升级成语义理解加多路召回加智能排序的架构。说人话就是,让搜索框真正"听懂"用户在说什么,而不是只做字面匹配。
这篇文章适合谁看?如果你是后端开发、搜索算法工程师、技术负责人,正在考虑给自家产品做搜索升级,或者你已经在用Elasticsearch但效果一直不理想,那这篇内容应该能给你不少参考。我会从架构设计、核心模块拆解、实操部署、参数调优到问题排查,把整个方案讲透。里面涉及的一些参数和配置,是我在实际项目中反复验证过的,你可以直接拿去用。
2. 整体架构设计与技术选型思路
2.1 为什么不用纯向量检索,而是混合架构
这两年向量数据库很火,很多人第一反应是"把文档全部embedding,然后做向量检索不就完了"。我一开始也这么想过,但在实际项目里踩了坑。纯向量检索有几个绕不过去的问题:第一,对于精确匹配的场景表现很差,比如用户搜一个具体的订单号、型号"iPhone 15 Pro Max 256G",向量检索可能给你返回一堆手机,但就是没有那个精确型号;第二,向量检索的可解释性差,运营问你为什么这个商品排在前面,你很难给出一个让人信服的理由;第三,全量向量化的成本不低,尤其是文档量上千万的时候,embedding的计算和存储开销都很可观。
所以通智云智能搜索采用的是混合检索架构,我把它拆成四层来看:
| 层级 | 模块 | 核心职责 | 技术选型 |
|---|---|---|---|
| 接入层 | 查询理解 | 分词、纠错、意图识别、查询改写 | 自研NLP管线 + 大模型 |
| 召回层 | 多路召回 | 关键词召回、向量召回、个性化召回 | Elasticsearch + 向量索引 |
| 排序层 | 精排模型 | 多特征融合打分、业务规则干预 | LambdaMART / 深度排序模型 |
| 应用层 | 结果呈现 | 聚合、去重、多样性控制、埋点 | 业务服务 |
这个架构的核心思路是"召回要全,排序要准"。召回层用多路并行,保证不漏;排序层用模型加规则,保证结果符合业务预期。下面我逐层拆解。
2.2 查询理解层:让搜索框听懂人话
查询理解是整个搜索链路的第一环,也是最容易被低估的一环。很多团队把精力全放在排序模型上,结果查询理解没做好,后面再优化也是白搭。
通智云在这一层做了几件事。分词和纠错是基础,中文分词用的是自研的领域词典加通用词典的混合方案,领域词典从业务数据里自动挖掘,比如商品类目词、品牌词、型号词。纠错这块用的是编辑距离加拼音相似度的组合策略,像"连衣群"到"连衣裙"这种同音错字,拼音相似度能直接命中。
意图识别是重点。系统会把查询分成几类:导航类(用户想直接去某个页面,比如搜"我的订单")、信息类(用户想找答案,比如搜"怎么退货")、交易类(用户想买东西,比如搜"蓝牙耳机 降噪")。不同意图走不同的召回和排序策略,导航类直接给入口,交易类重点排商品。
查询改写是提升召回的关键。系统会对原始查询做扩展,比如同义词扩展("手机"扩展出"移动电话""智能机")、上下位词扩展("连衣裙"扩展出"裙子""女装")、以及基于大模型的查询重写。这里用大模型做query rewriting效果很好,比如用户搜"有没有那种能测心率的表",大模型能改写成"心率监测 智能手表",召回率直接上一个台阶。
注意:查询改写一定要做相关性校验,扩展出来的词如果和原查询语义偏离太大,会引入大量噪声。我们的做法是给每个扩展词算一个语义相似度分数,低于阈值的直接丢弃。
2.3 多路召回层:三条腿走路才稳
召回层的设计原则是"宁滥勿缺",先把可能相关的都捞出来,把筛选的压力交给排序层。通智云用了三路召回并行:
第一路是关键词召回,基于Elasticsearch的倒排索引,用BM25打分。这一路保证精确匹配的能力,对于型号、品牌、专有名词这类查询是主力。ES的配置上,我们用了ik分词器加自定义词典,同时开了edge_ngram做前缀匹配,解决用户输入到一半就想看结果的需求。
第二路是向量召回,把文档和查询都通过embedding模型转成向量,用近似最近邻(ANN)算法检索。这一路解决语义匹配问题,对于长尾、口语化的查询效果显著。向量索引我们用的是HNSW算法,召回率和速度的平衡比较好。embedding模型选的是中文语义理解能力较强的开源模型,在业务数据上做了微调。
第三路是个性化召回,基于用户历史行为做协同过滤。这一路在电商场景特别重要,同一个查询"运动鞋",男性用户和女性用户、跑步爱好者和篮球爱好者,想要的结果完全不同。个性化召回能保证结果的千人千面。
三路召回的结果会做融合,融合策略用的是加权RRF(Reciprocal Rank Fusion),每路的权重可以根据业务场景调整。比如导航类查询关键词召回权重高,探索类查询向量召回权重高。
2.4 排序层:模型加规则的组合拳
召回回来几百上千个候选,排序层要做的是把它们排出一个合理的顺序。通智云用的是两阶段排序:粗排加精排。
粗排用轻量级模型快速过滤,把候选从几百降到几十。精排用LambdaMART或者深度排序模型,输入是丰富的特征,包括查询文档相关性特征(BM25分数、向量相似度)、文档质量特征(点击率、转化率、时效性)、用户特征(历史偏好、当前上下文)、业务特征(是否广告、是否促销)。
这里有个经验:纯模型排序在业务场景里往往不够用,必须留规则干预的口子。比如运营要做活动,某些商品必须置顶;比如合规要求,某些内容必须降权。通智云在排序层之上加了一个规则引擎,支持按条件动态调整排序结果,规则可以热更新,不用重启服务。
3. 核心模块实操部署要点
3.1 环境准备与依赖清单
部署通智云智能搜索之前,先把基础环境理清楚。这套系统对资源有一定要求,我列一下我们生产环境的最小配置和推荐配置:
| 组件 | 最小配置 | 推荐配置 | 说明 |
|---|---|---|---|
| Elasticsearch | 3节点 4C8G | 5节点 8C16G | 存储索引和向量 |
| 向量索引服务 | 2C4G | 4C8G | 可复用ES或独立部署 |
| 模型推理服务 | GPU T4 16G | GPU A10 24G | embedding和排序模型 |
| 应用服务 | 2C4G x2 | 4C8G x3 | 查询理解、融合、排序 |
| Redis | 2C4G | 4C8G | 缓存和会话 |
依赖的软件版本这块,ES建议7.10以上,因为要用到dense_vector字段类型。Python环境3.8以上,主要依赖包括elasticsearch-py、sentence-transformers、fastapi、redis-py等。模型推理如果不想自己搭,可以用Triton Inference Server,吞吐和延迟都比较好。
提示:embedding模型和排序模型对显存有要求,如果文档量大,建议把embedding计算做成离线批处理,在线只做查询侧的embedding,这样能大幅降低GPU压力。
3.2 索引结构设计与字段映射
索引设计是搜索效果的地基,字段映射建错了,后面怎么调都别扭。通智云的核心索引结构包含这几个字段:
{ "mappings": { "properties": { "doc_id": {"type": "keyword"}, "title": { "type": "text", "analyzer": "ik_max_word", "fields": { "keyword": {"type": "keyword"}, "ngram": {"type": "text", "analyzer": "edge_ngram_analyzer"} } }, "content": {"type": "text", "analyzer": "ik_max_word"}, "category": {"type": "keyword"}, "tags": {"type": "keyword"}, "embedding": { "type": "dense_vector", "dims": 768, "index": true, "similarity": "cosine" }, "quality_score": {"type": "float"}, "update_time": {"type": "date"} } } }这里有几个设计要点值得说。title字段同时建了keyword、ngram和分词三个子字段,分别用于精确匹配、前缀匹配和全文检索。embedding字段的维度要和embedding模型输出一致,我们用的是768维。quality_score是文档质量分,参与排序,这个分数可以来自点击率、转化率等业务指标。
3.3 查询理解管线的实现
查询理解管线是串行执行的,每一步的输出是下一步的输入。我用伪代码把核心流程写一下:
def query_understanding(raw_query, user_context): # 1. 归一化:全半角、大小写、去特殊字符 query = normalize(raw_query) # 2. 纠错:编辑距离 + 拼音相似度 query = spell_correct(query) # 3. 分词:领域词典 + 通用词典 tokens = tokenize(query) # 4. 意图识别:分类模型 intent = classify_intent(query, tokens) # 5. 查询改写:同义词 + 大模型重写 rewritten = query_rewrite(query, intent) # 6. 实体识别:品牌、型号、类目 entities = extract_entities(query) return { "original": raw_query, "normalized": query, "tokens": tokens, "intent": intent, "rewritten": rewritten, "entities": entities }这里面意图识别和查询改写是两个难点。意图识别我们用的是BERT微调的分类模型,标注了大概两万条数据,准确率能到92%左右。查询改写用大模型做few-shot,prompt里给几个示例,让模型输出改写后的查询,效果比规则方法好很多。
3.4 多路召回与融合的工程实现
召回层是并行的,三路召回同时发起,然后做融合。工程上要注意超时控制,任何一路召回超时都不能拖垮整个查询。我们给每路召回设了独立的超时时间,比如关键词召回200ms,向量召回300ms,个性化召回150ms,超时的直接丢弃,用剩下的结果继续。
融合用加权RRF,公式是这样的:
score(d) = Σ weight_i / (k + rank_i(d))其中weight_i是第i路召回的权重,rank_i(d)是文档d在第i路召回中的排名,k是一个平滑常数,一般取60。这个公式的好处是不依赖各路的原始分数,只依赖排名,避免了不同路分数不可比的问题。
权重怎么定?我们的经验是:导航类查询关键词权重0.6、向量0.3、个性化0.1;信息类查询关键词0.4、向量0.5、个性化0.1;交易类查询关键词0.3、向量0.4、个性化0.3。这些权重可以在线调整,根据AB实验的结果优化。
4. 排序模型训练与调优实战
4.1 训练数据的构造与标注
排序模型的效果,七分靠数据,三分靠模型。训练数据的构造是重中之重。通智云用的是点击日志加人工标注的混合方案。
点击日志这块,要注意处理位置偏差。用户倾向于点击排在前面的结果,这是位置偏差,不是真的相关。我们用倾向性模型(PBM或UBM)对点击做去偏,还原真实的相关性。具体做法是给每个位置的点击算一个倾向分数,训练时用这个分数做样本加权。
人工标注这块,我们定义了一个五级相关性标准:完全相关、高度相关、部分相关、不相关、完全无关。标注团队按这个标准对查询-文档对打分。标注数据量不用太大,几千到一万条就能显著提升模型效果,关键是标注质量要高,标注规范要清晰。
4.2 特征工程:哪些特征真正有用
排序模型的特征工程,我踩过不少坑。一开始恨不得把所有能想到的特征都塞进去,结果模型过拟合,线上效果反而差。后来做了一轮特征筛选,留下真正有用的。下面是我们验证过有效的特征清单:
| 特征类别 | 具体特征 | 重要性 |
|---|---|---|
| 相关性 | BM25分数、向量相似度、词命中率 | 高 |
| 文档质量 | 点击率、转化率、停留时长 | 高 |
| 时效性 | 发布时间、更新时间 | 中 |
| 用户偏好 | 历史点击类目、品牌偏好 | 中 |
| 业务规则 | 是否广告、是否促销、库存状态 | 高 |
| 查询特征 | 查询长度、意图类型 | 低 |
特征重要性这块,相关性特征和文档质量特征贡献最大,业务规则特征虽然简单但对最终效果影响很大。查询特征单独看重要性不高,但和文档特征交叉后价值就出来了,比如查询意图和文档类目的匹配度。
4.3 模型选型与线上部署
模型选型上,我们对比过LambdaMART、DNN和Transformer三种方案。LambdaMART在特征工程到位的情况下效果就很不错,训练快、推理快、可解释性好,是我们的基线方案。DNN在特征交叉上有优势,但需要更多数据。Transformer效果最好,但推理延迟高,我们只在精排的最后阶段用。
线上部署用的是模型服务化的方案,模型训练好后导出成ONNX格式,用Triton做推理。这样做的原因是解耦,算法团队负责训练和导出,工程团队负责部署和扩缩容。模型更新走灰度发布,先切5%流量,观察指标没问题再逐步放大。
注意:排序模型的线上推理延迟要严格控制,我们的目标是P99在50ms以内。如果模型太大跑不动,可以考虑模型蒸馏,用大模型教小模型,效果损失不大但速度提升明显。
5. 常见问题排查与避坑指南
5.1 搜索结果不相关的排查思路
搜索结果不相关是最常见的问题,排查要按链路一步步来。我整理了一个排查清单:
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 零结果 | 分词错误、词典缺失 | 看分词结果 | 补充领域词典 |
| 结果不相关 | 召回噪声大、排序模型问题 | 看各路召回结果 | 调整召回权重、重训模型 |
| 结果重复 | 去重逻辑缺失 | 看文档ID | 加去重模块 |
| 结果过时 | 时效性特征权重低 | 看特征权重 | 提高时效性权重 |
| 个性化失效 | 用户画像缺失 | 看用户特征 | 补全画像数据 |
排查的时候,我习惯先看查询理解的结果对不对,分词、纠错、改写有没有问题。这一步没问题再看召回,把三路召回的结果分别打出来看,哪一路噪声大就调哪一路。最后看排序,把特征值打出来,看是不是某个特征异常导致排序错乱。
5.2 性能瓶颈的定位与优化
性能问题在搜索系统里很常见,尤其是大促期间流量暴涨的时候。常见的瓶颈点和优化手段:
ES查询慢,一般是索引设计问题或者查询太复杂。优化手段包括:合理设置分片数(单分片30-50G比较合适)、用filter代替query(filter有缓存)、避免深分页(用search_after代替from+size)。
向量召回慢,主要是ANN索引参数没调好。HNSW的ef_search参数控制召回率和速度的平衡,调大召回率高但慢,调小则相反。我们的经验是ef_search设在100-200之间比较合适。
模型推理慢,要么是模型太大,要么是batch没做好。优化手段包括:模型量化(FP16或INT8)、请求批处理、模型蒸馏。我们做过测试,FP16量化后推理速度提升约40%,效果损失不到1%。
5.3 几个我踩过的坑
第一个坑是embedding模型更新导致索引不一致。我们换了一版embedding模型,忘了重新生成全量文档的向量,结果查询侧用新模型,文档侧还是旧向量,语义空间对不上,效果直接崩了。教训是:embedding模型更新必须配套全量重建索引,而且要灰度切换。
第二个坑是查询改写过度导致意图漂移。有段时间我们放开了查询改写的阈值,结果用户搜"苹果",系统给改写成"苹果 手机 电脑 平板",召回了一堆电子产品,但用户可能只是想找水果。后来加了意图约束,改写词必须和原查询意图一致。
第三个坑是缓存击穿。热门查询的缓存过期瞬间,大量请求打到后端,把ES压垮了。解决方案是缓存过期时间加随机抖动,同时对热点查询做本地缓存加分布式锁。
6. 效果评估与持续迭代
6.1 离线评估指标怎么选
搜索效果的评估,离线指标和在线指标要结合看。离线指标常用的有NDCG、MAP、MRR,这几个指标各有侧重。NDCG考虑位置因素,适合评估排序质量;MAP关注整体相关性;MRR关注第一个相关结果的位置。
我们的做法是离线用NDCG@10作为主指标,配合人工评估。人工评估虽然成本高,但能发现模型发现不了的问题,比如结果多样性、时效性、合规性。每轮模型迭代,我们都会抽一批查询做人工评估,确保没有明显的bad case。
6.2 在线AB实验的设计
在线实验是检验效果的最终标准。AB实验的设计有几个要点:分流要随机且稳定,同一个用户每次实验分到同一组;指标要选对,核心指标是点击率和转化率,辅助指标包括零结果率、首条点击率、人均点击次数;实验周期要足够长,至少覆盖一个完整的用户行为周期,一般7天起步。
我们做过一次排序模型升级的AB实验,实验组NDCG离线提升3个点,但线上点击率只提升了0.5个点。后来分析发现,离线评估用的标注数据和线上真实分布有偏差。这件事给我的教训是:离线指标只能参考,最终还是要看线上效果。
6.3 持续迭代的机制
搜索优化不是一锤子买卖,需要持续迭代。我们建立了一个闭环机制:线上日志回流,挖掘bad case和长尾查询;bad case进入标注队列,补充训练数据;模型定期重训,一般两周一次;新模型先离线评估,再小流量AB,最后全量。
这个闭环里,bad case挖掘是最有价值的环节。我们写了一个脚本,自动从日志里捞出零结果查询、高跳出查询、点击位置靠后的查询,人工review后分类处理。有些是词典缺失,补词典就行;有些是语义理解错误,需要改模型;有些是数据问题,得推动业务方修数据。
7. 这套方案还能怎么扩展
通智云智能搜索目前的架构已经能覆盖大部分站内搜索场景,但还有一些方向可以继续深挖。一个是多模态搜索,支持以图搜图、以图搜文,这在电商和内容社区很有价值。另一个是对话式搜索,把搜索框变成对话入口,用户可以用自然语言多轮交互,逐步细化需求。还有一个是个性化推荐的融合,搜索和推荐本质上都是解决信息匹配问题,两者的用户画像和特征可以复用,做成搜推一体的架构。
我个人在实际项目中的体会是,搜索系统的优化没有终点,用户的需求在变,数据分布在变,模型和策略就得跟着变。关键是建立一套能快速迭代的机制,让优化成为一个持续的过程,而不是一次性的项目。另外,不要迷信模型,规则和模型结合才是工程上最稳的方案,纯模型方案在业务场景里往往会遇到各种意想不到的问题。