尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

生成式召回:电商搜索从匹配到生成的范式跃迁与落地实践

生成式召回:电商搜索从匹配到生成的范式跃迁与落地实践 这两年做交易搜索身边不少人一提到召回优化就默认在拼向量索引召回池从一万涨到十万、再从十万涨到百万大家卷来卷去骨架其实没变。我在得物交易搜索链路里折腾生成式召回真正感受到检索范式转换不是简单加一路召回而是把匹配变成生成。这篇主要说清楚为什么在向量检索之外还要考虑生成式以及生成式召回在交易场景下的设计和落地细节适合正在做电商搜索召回、或者对大模型改造搜索链路感兴趣的朋友。1. 为什么说召回范式跃迁从倒排、向量到生成式1.1 传统召回与向量检索的边界先把几代召回方式放在一起看才能明白我为什么说向量检索已经内卷。最早是倒排索引靠词匹配干活用户搜黑白熊猫鞋分词后直接命中标题包含这些词的商品。倒排的问题是词汇鸿沟用户说篮球鞋商品标题写实战球鞋词对不上召回直接漏掉。向量检索解决的就是语义相近问题。把query和商品都映射到同一个向量空间用余弦相似度或内积算相关性比如实战球鞋和篮球鞋在向量空间里离得近就能召回。这个路线过去几年确实撑起了搜索和推荐的大部分优化空间。但向量检索有一个先天短板它的表达能力被限制在一个固定维度的向量里交互信号、属性约束、用户个性化、上下文信息最终都被压进一个embedding。向量丢信息是必然的只能靠加大向量维度、换更重的模型来稀释损失。于是大家拼命卷模型结构、卷蒸馏、卷百万负样本本质都是在固定检索范式里打磨。我自己踩过的坑是向量召回在得物的鞋类搜索里对款式颜色尺码这类复合语义的把握不稳定。query里出现黑红配色低帮AJ1向量模型容易把配色和低帮的约束信息混在一起召回结果经常缺颜色条件。这不是负样本没挖够而是双塔结构根本不适合做细粒度条件组合。真正要突破的时候靠向量这棵树已经到顶了。1.2 生成式召回的本质把召回从匹配变成生成生成式召回的核心思路是不比较query和候选商品的相似度而是把整个商品候选集当作一个词表用一个序列生成模型直接生成目标商品的ID或者生成一个能展开成商品集合的中间表示。简单说传统召回是找相关商品生成式召回是写出相关商品。我打个比方大家就理解了。传统搜索像在图书馆的书架上找书你需要根据索引卡片到对应的架子上去翻向量检索像是拿着图书内容的语义摘要去找摘要越准确越好找生成式召回则像是让一个对馆藏相当熟悉的图书管理员直接回答你要找的是第几排书架、什么颜色的封面的那本书他可以不按索引走凭整体理解把目标说出来。这个范式转换的本质变化有三个。第一交互从晚期交互变成全序列建模模型可以在生成过程中逐步参考query每个词、用户历史行为、上下文属性而不是把信息压缩到一个向量之后才交互。第二商品ID可以不是静态的词表而是结构化的语义编码模型生成的每个token都有解释性。第三生成式召回天然适合做约束条件下的候选生成比如品牌品类颜色价格带可以写进解码约束里直接输出满足全部条件的商品这是向量检索很难干净完成的事。当然生成式也有代价最直接的困难是商品ID空间巨大交易平台的在线商品动辄千万级甚至上亿直接让模型在千万级词表上做softmax训练和解码都扛不住。后面我会讲我们怎么通过语义化编码把这个问题拆掉。2. 得物交易搜索场景下的生成式召回设计2.1 交易场景的独特约束不是每个搜索场景都适合直接套生成式召回。得物交易搜索有几个非常鲜明的特点决定了方案设计必须定制化。第一转化导向。普通搜索看相关性交易搜索还得看购买概率。用户搜实战篮球鞋同样相关的两款鞋价格、库存、评价、时效都会影响成交。生成式召回如果只建模文本相关性在线排序压力会非常大。我们做法是把点击、加购、成交信号都融合进训练样本权重里让模型学习的不只是哪个商品语义相关而是哪个商品在这个query下更容易被转化。第二query多样性极高。得物平台上用户搜品牌型号、搜别称、搜配色、搜博主同款各种长短词混杂。比如craft可能指某品牌鞋款小闪电大魔王是特定配色的民间叫法。传统字典和同义词表很难穷举生成式模型反而擅长从query上下文中推理出意图。第三多模态耦合。交易的商品不只是标题文本还有大量图片属性。用户搜灰白配色翻毛皮鞋翻毛皮这个材质属性更多反映在商品图像里而不一定在标题中。我们后面把图像标签和商品属性序列化让生成模型可以在生成时使用这些侧信息这里不展开图像模型细节但设计时要留好接口。2.2 生成式模型如何输出商品候选落地生成式召回前我们想清楚了一个关键问题模型到底生成什么。这一层有多种选择选错后面就难受。一种做法是让模型直接生成商品ID比如输出item_1234567。好处是链路简单但问题很大商品ID是随机编号模型需要硬记每个ID和文本语义的对应关系训练样本少的长尾商品根本学不会而且新商品上线后ID分布变了模型没法泛化。另一种做法是生成商品属性组合比如品牌耐克品类篮球鞋系列AJ颜色黑红价格带1000-1500然后拿这个属性组合去检索商品库。这种方式解释性很强但属性组合可能对应多个商品召回精度不够。我们最终采用的做法是生成商品语义码。每个商品离线时会编码成一段结构化的离散token序列比如品类token、品牌token、系列token、颜色token、材质token再加一个短ID token。模型训练时学习根据query生成这段序列在线解码后通过序列匹配到商品。这个语义码介于纯ID和纯属性之间既保留商品级别的粒度又让模型学习的是有语义含义的token泛化能力好很多。在这个设计里商品侧离线做好语义码索引在线生成的是query对应的语义码序列然后到倒排索引里查这个序列对应的商品集合。从系统和团队分工上看生成模型只负责产出目标描述检索部分仍然复用成熟的索引基础设施迁移成本可控。2.3 与向量召回/倒排的协同瀑布 vs 并行 vs 级联生成式召回不是要取代向量和倒排我明确反对一上来就搞单路生成式召回打天下。成熟的搜索链路需要多种召回互相兜底。目前线上推荐的做法是瀑布混合。倒排召回作为基础盘保证热门精确词不漏向量召回作为语义扩展盘拉长尾和相关扩展生成式召回作为复合条件生成盘专门解决多条件组合和个性化意图较强的query。三条路线的结果先合并去重再进粗排精排。在几种协同模式里我更推荐并行召回而非瀑布式串联。原因是生成式模型既然要做全序列交互就不应该依赖倒排先筛一轮候选否则又退回了限定范围里的匹配。并行召回的代价是服务端多一路GPU推理对资源有要求。我们在初期资源受限时也试过级联式也就是生成式只负责对向量召回top结果做重排生成效果也有但召回盲区还在后来还是咬牙上了并行。这里要强调一个工程细节三路召回之间要有明确的去重和配额设计。比如倒排配额300、向量配额500、生成式配额200合并后统一按全局预估分排序。如果生成式结果和倒排高度重叠说明生成式学到的更多是热门样本分布需要调整训练样本或解码参数这个在后面问题排查里细讲。3. 落地实操从0到1实现生成式召回3.1 训练数据的构建数据是生成式召回成败的第一道门槛。我们用的不是简单的query-商品对而是query-商品-行为序列三元组。具体来说样本来源包括搜索点击日志、加购日志、成交日志还有一部分由BSLBuyer Search Log整理的query改写对。正样本的构造逻辑是同一个query下有成交行为的商品优先级最高有加购行为的次之有点击行为的再次之。我们按行为类型给样本分配权重点击权重1、加购权重5、成交权重20。同时每个query保留从高权重商品到低权重商品的排序关系而不是简单二分类。负样本的选择也很有讲究。纯随机负样本太简单模型很快收敛但有偏纯困难负样本又容易让模型训练不稳定。我们的做法是混合负采样50%从当前query曝光但无点击的商品中采样25%从全库随机采样25%从同品类热门商品中采样。这样模型既能学到区分度又不会因为过难而放弃。样本量上我们最初挖了35天的日志共计2.4亿条有效日志过滤掉点击次数少于3次的商品后剩余约4000万条样本。这个量级对于生成式模型的训练是比较健康的起步。数据清洗里一个容易踩的坑是query里包含大量口语化错别字比如得务其实是得物如果直接喂给模型它会学到错误的映射。我们额外用了一个小规模的query纠错模型先做清洗确保输入query是较规范的表述但保留用户真实长尾词分布。3.2 模型架构选型与序列目标设计架构上我们对比过两个路线一个是以T5为代表的Encoder-Decoder结构另一个是纯Decoder结构。T5风格的Encoder-Decoder更贴合这个任务因为query侧是完整上下文商品语义码是目标序列两者分工明确。Encoder对query做全量编码Decoder自回归生成商品语义码。这种结构在检索任务里表现稳定对齐也比较容易。Decoder-only结构的好处是复用已有大模型推理框架但问题在于我们并不需要模型做通用对话只需要它条件生成一段商品序列Encoder-Decoder足以胜任训练和推理成本更低。最终我们选了T5-base规模的Encoder-Decoder模型参数量约2.2亿在GPU服务上单query推理时间可以控制在15ms到25ms比一开始担心的轻很多。序列目标设计是重点。每个商品对应一段语义码序列格式如下[品类] 运动鞋 [品牌] 耐克 [系列] AJ [款式] 高帮 [配色] 黑红 [材质] 皮革 [ID] 7B3F9A其中品类、品牌、系列、款式、配色、材质都来自商品结构化属性ID token是我们为每个商品分配的64位短码经过hash映射到词表。模型生成时前面的属性token承担语义对齐最后一位ID token负责精确定位。这样做的好处是即使模型对长尾商品的ID记忆不准它也能生成正确的属性序列我们再通过属性序列召回一批候选ID token作为强约束或弱约束。训练loss就是标准的cross-entropy但我们加了一个小的技巧对属性token和ID token分别计算loss并加权属性token权重1.0ID token权重2.0。一开始ID token权重太低时模型总在属性上很准ID却总错导致最终精确命中率上不去。后来提高ID权重才把端到端命中拉起来。3.3 索引与解码策略模型训练完只是第一步上线前的索引和解码策略同样决定效果。先说话题索引。我们不能让模型直接输出一个商品ID就去数据库里查那样延迟不可控。我们的做法是提前把所有商品的语义码序列建立成前缀树索引查询时拿模型生成的token序列在前缀树上逐级匹配。命中叶子节点就能定位到商品未命中时则取最大的公共前缀路径把该路径下的所有商品作为召回结果。这个前缀树在Golang服务里用map嵌套实现线上内存占用约1.2GB查询耗时可忽略不计。解码策略上纯贪心解码容易陷入局部最优但Beam Search开太宽又会明显增加时延。我们实测下来Beam宽度设4效果和宽度8基本一致时延却能省掉一半。建议直接从宽度4起步验证不要一上来就上大Beam。解码过程中另一件重要的事是约束解码。例如用户query里明确出现低帮那解码到[款式]这个槽位时就把低帮以外的token屏蔽掉query里出现500以内就在[价格带]槽位做数值约束。这些槽位我们预先定义了可枚举的token集合约束解码就是在这个集合里做mask。这个功能是传统向量召回很难提供的也是生成式召回在交易场景相对更大价值的体现。整个线上服务架构里模型推理用Triton部署动态batch开到8单卡A10可以扛住日均千万级query的额外压力。如果qps再高优先做query侧改写缓存把重复query的生成结果缓存住而不是无限加GPU机器。4. 关键细节与避坑经验4.1 商品ID语义化表示这一节单独拿出来说因为它是生成式召回能否真正落地的胜负手。一开始内部分享时有同学建议直接用商品ID做词表理由是最简单、最直接。我们要知道随机ID token的问题不只是词表大更重要的是模型没有泛化依据。商品ID之间没有语义关联item_1001和item_1002在模型看来是完全无关的token模型只能靠死记硬背一个新品上来后它的ID从未在训练中出现模型无论如何都生成不出这个新ID。这就是典型的冷启动灾难。语义化ID做的事是让ID之间天然存在距离。我们用的是产品层级结构编码例如[一级品类] / [二级品类] / [品牌] / [系列] / [年份] / [型号序号]模型生成最后几位序号token时即使没有见过这个商品也能从前面几级属性token推导出大致的生成路径。这相当于给模型一个先验的组织架构比纯随机ID好学得多。另外一个隐蔽的坑是属性token如果包含过多细粒度信息比如把商品详情页里的长文本塞进token序列模型会学习到大量无关信号导致生成结果飘忽。我们最后固定了15个属性槽位超过的部分全部截断。宁可少一些属性也要保证序列结构稳定。4.2 生成结果的校验与兜底生成式模型再强也是概率模型输出出错是常态不是异常。线上一定要有校验层和兜底逻辑。校验层的核心是检查生成结果是否满足query的硬约束。我们维护了一个约束解析器把query里的品牌词、品类词、价格区间、尺码、颜色等约束提取出来然后逐一核对模型生成的语义码。任何一项硬约束不匹配就对这条生成结果打上不可信标记降级为候选补足而不是直接透出。否则用户搜黑色AJ却看到白色球鞋体验非常糟糕。兜底逻辑要回答一个核心问题生成式召回完全没结果时怎么办。有两种情况一种是模型生成的序列没有对应商品这时走属性前缀匹配放宽ID约束用前几个属性token召回一批商品另一种是模型连属性序列都不稳定这时直接放弃这路召回用倒排和向量结果顶上。我建议给生成式召回设置独立的超时熔断。GPU推理偶发长尾耗时如果和主链路其他召回同步等待容易拖慢整体搜索响应。我们设置生成式召回最大等待时间是25ms超过就返回空集合并打点告警。宁可少一路召回也不允许用户侧整体延迟失控。这点在交易搜索里尤其重要搜索延迟直接影响成交率。4.3 数据漂移与冷启动问题生成式模型对训练数据分布很敏感而电商的商品池和用户query是每天都在变的。我们监控了三个指标来捕捉漂移生成结果的ID命中率、属性级准确率、以及生成结果在最终排序中的透出占比。ID命中率是最敏感的指标。某次大促上新后我们发现命中率一周内从86%掉到74%排查原因是新品集中上线模型输出的ID token大多落在训练集中未出现过的商品编码段上。解决方法是给新品补充伪语义码新品上线时先按品类、品牌、属性生成一段不完整语义码并允许模型只生成属性token召回不用强行生成ID token。这样能保证新品在生成式召回里不至于完全真空。query分布漂移更隐蔽。比如某段时间站外短视频带火了一个新叫法熊猫鞋但模型训练数据里这个词出现频次极低生成结果就偏向老叫法。我们的对策是每周增量训练一次对新query做重采样把当天新增query的采样倍率调到普通query的8倍。增量训练直接解决了新旧分布切换的衔接问题比频繁调解码参数有效得多。5. 效果评估与稳定性5.1 离线指标设计生成式召回的离线评估不能只看传统RecallK因为模型有生成偏置它可能总是生成热门商品导致Recall虚高。我们综合看五个指标指标定义用途HitsK标准答案商品是否在生成结果top K里衡量基本命中能力属性准确率生成的属性token是否与商品真实属性一致衡量语义生成质量ID精确命中率生成的完整序列是否与商品语义码完全一致衡量端到端精确度平均生成长度生成的token序列长度监控是否存在截断问题熵值生成结果的多样性分布防止模型坍缩到头部商品我们内部设定的起步目标值是Hits10不低于0.55属性准确率不低于0.9ID精确命中率不低于0.8。达不到这三个数不建议上全量问题多半出在数据或序列编码设计上而不是模型参数量不够。一个容易误判的地方是RecallK在向量检索里是从K个候选里找标准答案但生成式召回的K是解码Beam产生的候选数两者不可比。所以我们更多是用融合后整体召回率提升比例来评估生成式召回的增量贡献比如基础链路召回率是0.72融合生成式后变成0.78那这6个百分点的提升才是生成式真正的价值。5.2 在线A/B与链路保护线上A/B我们做了三层防护避免生成式召回出问题影响大盘。第一层是小流量灰度。先切5%流量观察生成式召回自身指标平均生成时延、产物在曝光中的占比、曝光后的点击率。这里要小心生成式召回出来的商品如果相关性不够点击率一定偏低说明模型还没训好不要急着放量。第二层是保底策略。融合生成式召回结果前先把倒排和向量召回的强相关商品固定在头部若干个位置上生成式召回的商品只参与中后段的位置竞争。这样即使生成结果有偏差也不会直接伤害用户第一屏体验。等观察期结束、数据确认良性后再逐步放开头部位置竞争。第三层是紧急回退开关。我们把生成式召回的开关独立部署在配置中心任何一个指标触发阈值比如点击率较基线下降5%就可以秒级关闭这路召回。宁可损失增量收益也要保在线稳定。5.3 实际收益召回率提升、长尾优化上线一段时间后我记录了一组代表性数据融合生成式召回后整体搜索召回率提升6.3个百分点其中品牌配色款式三类属性同时约束的query召回率提升最明显从0.51提升到0.67。用户搜索黑红AJ高帮这类复合query时生成式召回明显优于向量召回。长尾query方面未登录词覆盖率提升了约12%很多口语化叫法第一次能召回对应的商品。还有一个容易被忽略的收益间接来自超时兜底。因为生成式模型可以对query做结构化理解在倒排和向量都没有匹配结果时它仍可能生成近似的属性组合让原本无结果的搜索返回推荐商品。我们统计到无结果率下降了1.8个百分点这在电商搜索里是实打实的体验改善。6. 常见问题排查实录6.1 解码结果ID不存在上线初期最频繁的问题是模型生成了一段漂亮的属性序列但最后的ID token对应的商品在线上不存在或已下架。原因是训练数据中存在历史商品模型记住了旧ID的分布。排查时先不急着改模型分三步看确认ID是否在校验层被过滤确认商品是否在最近一周有下架记录确认模型生成的属性序列是否与ID一致。如果是旧商品问题训练数据里过滤掉已下架商品样本即可如果属性与ID不一致说明ID token学习得不好需要提高ID token的loss权重或者增加同属性下不同ID的对比样本。6.2 生成结果集中头部模型生成结果高度集中在前100个热门商品是第二个典型问题。发生这种情况多半是训练数据里头部商品的样本量碾压式领先模型学到的分布被拉偏。解法有三层第一训练时对样本做对数降采样头部商品每类最多保留2万条样本第二解码时加入多样性惩罚也就是给已生成过的ID token加一个重复惩罚分数实现上就是在Beam Search里对重复token的得分乘0.8第三在候选合并阶段对生成式召回的配额做按需调整不固定配额而是根据本次query属性约束强度动态设置。6.3 时延瓶颈与工程优化生成式召回的时延主要瓶颈在Decoder的逐token生成上。我们上线初期平均生成长度为9个token单query要25ms。优化方案有三个方向提前终止条件设置为属性token已生成完整且ID token置信度高于0.9时即截断这一个改动把平均生成长度压到6批量动态padding减少GPU闲置Triton动态batch调大。注意不要为了追时延而把Beam宽度降到1那样生成多样性受影响召回率会掉得很快。折中方案是先用宽度4生成对所有结果求一个平均置信度如果最高序列置信度大于0.95则提前用该序列不再等其余分支。实测下来这样既保住效果又能把平均时延稳定在18ms左右。6.4 泛化到其他交易场景的注意很多人问这套方案能不能平移到其他交易搜索。我的建议是场景差异很大不能盲目复刻。如果场景中用户query高度标准化比如3C数码搜索iPhone 15 256G倒排加向量足够好用生成式的增量价值不大。但如果你负责的场景query语义复杂、属性组合多、口语化叫法频繁、长尾意图占比高生成式召回才值得投入。这里还有一个资源层面的判断。生成式召回需要GPU推理服务、增量训练链路、语义码编码系统整体落地成本比引入一个向量模型高出一个数量级。在人力不足或基础设施薄弱的情况下先把向量检索做扎实更稳妥。7. 我个人在实操中的一些补充写到最后再补几个没人写进文档的体会。第一生成式召回不是单纯算法问题它是系统工程。如果团队里只有算法没有懂推理服务部署的人建议先补基础设施否则模型训得再好也上不了线。我们团队当时是算法和工程各出一半人力花了两周把服务框架搭稳后面迭代才顺。第二线上效果波动时先查数据分布而不是急着调模型。我们踩过几次坑调了半天解码参数最后发现是当天某品牌集中上新品导致ID命中率暴跌。数据和特征里的信号远比模型结构的调整来得快。第三所有新范式都不要想着一步到位。生成式召回我们前后迭代了三个版本第一版做纯ID生成效果很差第二版做属性序列生成但召回精度不足第三版做成语义码混合生成才达到上线标准。这个过程中最大的收获不是最终模型有多好而是对交易搜索链路里什么信息该保留、什么信息可以压缩有了更清晰的认知。离线指标再漂亮也只是起点真正考验还是在真实搜索链路里和用户行为数据的反复磨合。如果你也打算尝试生成式召回建议先拿一个用户意图最复杂的品类做试点比如潮流鞋服或美妆跑通之后再横向扩展。这条路没那么轻松但一旦跑通你会明显感受到召回从一个检索问题变成了内容生成问题参数空间和理解维度都完全不一样了。
返回列表