ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

生成式召回在交易搜索中的落地实践与踩坑指南

生成式召回在交易搜索中的落地实践与踩坑指南 1. 从“卷向量”到“拼生成”交易搜索的召回逻辑为什么必须换挡得物交易搜索这个场景做过电商搜索的人应该都有体会它跟通用网页搜索完全是两码事。通用搜索里你搜“苹果”出来的是苹果官网、百科、新闻语义相关性排第一。但交易搜索里用户搜“苹果”他大概率是想买手机而不是想了解水果的营养成分。更麻烦的是交易搜索的query往往极短、极口语化还夹杂大量品牌缩写、型号黑话、圈层梗比如“aj1 low 北卡蓝”、“dunk 熊猫”、“椰子350 冰蓝”这些词在标准词表里根本找不到但用户就是要搜。过去几年行业里主流的做法是“向量检索”打天下。把query和商品标题、属性、图片都编码成稠密向量然后在大规模向量索引里做近似最近邻搜索。这套方案在通用语义匹配上确实能打但它有几个硬伤在交易搜索场景里会被无限放大。第一个硬伤是语义漂移。向量模型训练的时候追求的是“语义相似”但交易搜索要的是“交易意图匹配”。举个例子用户搜“轻薄本 编程”向量检索可能会把“轻薄本 办公”的商品排前面因为“编程”和“办公”在语义空间里很近。但实际上程序员要的轻薄本往往对CPU性能、内存容量、键盘手感有特定要求这些细粒度的交易属性在稠密向量里被平均掉了。第二个硬伤是长尾query覆盖不足。得物上每天都有大量新品牌、新联名、新配色出现向量模型的词表更新速度根本跟不上。一个新出的联名款它的名称在训练数据里可能一次都没出现过向量编码出来的结果就是随机噪声。你指望用这种向量去召回无异于大海捞针。第三个硬伤是多模态融合生硬。交易搜索里图片信息极其重要。一双鞋的配色、材质、鞋型光靠文字描述根本不够。但传统的多模态向量检索往往是把图片向量和文本向量简单拼接或者加权求和这种“早期融合”或者“晚期融合”的方式丢失了模态之间的细粒度交互信息。比如用户上传一张街拍图想搜同款图片里鞋子的纹理和文字query“复古跑鞋”之间的关联在简单融合里很难被捕捉到。所以当“生成式”这个概念开始进入搜索领域时我第一反应是这东西能不能解决交易搜索的召回瓶颈它跟向量检索到底是什么关系是替代还是互补带着这些问题我花了不少时间研究得物交易搜索团队公开的技术思路也结合自己在搜索召回上踩过的坑梳理出了一套“生成式召回”的落地逻辑。这篇文章不聊虚的就聊怎么把生成式思路塞进交易搜索的召回链路里让它真正跑起来。2. 生成式召回到底“生成”了什么核心思路与方案选型拆解2.1 生成式召回不是“用大模型写商品标题”很多人一听“生成式召回”第一反应是是不是让大语言模型去生成一堆候选商品这理解偏了。生成式召回的核心不是生成商品本身而是生成“查询-商品”之间的结构化匹配信号。传统向量检索做的是把query映射到一个点把商品映射到一个点然后算距离。生成式召回做的是给定query和商品让模型直接判断“这个商品能不能满足这个query”或者更进一步让模型生成一个“为什么这个商品能满足这个query”的理由。这个理由可以是关键词、属性组合、场景标签甚至是一段简短的匹配解释。得物交易搜索团队的做法我推测是走了“生成式索引”“生成式匹配”的双路。生成式索引是指用大语言模型对商品库进行离线“理解”为每个商品生成一组结构化的“可召回特征”比如“适合场景通勤、运动”、“风格复古、街头”、“关键属性透气、耐磨”。这些特征不是人工标注的而是模型从商品标题、详情页、用户评价、图片描述里“生成”出来的。生成式匹配则是在线阶段用轻量级的生成模型或者经过蒸馏的小模型快速判断query和商品特征的匹配度。为什么这么选因为交易搜索的query和商品之间存在大量“隐含推理”。用户搜“送男朋友 生日礼物 500以内”向量检索可能召回一堆500以内的商品但“送男朋友”这个意图需要模型推理出“男性偏好”、“礼盒包装”、“有仪式感”这些隐含属性。生成式模型擅长做这种“从query到属性”的映射它能把一个模糊的query拆解成一组可检索的结构化条件。2.2 为什么不是纯生成式而是“生成向量”混合纯生成式召回有个致命问题推理延迟。你不可能在用户输入query的瞬间让一个大语言模型去遍历百万级商品库逐个生成匹配分数。所以得物的方案一定是混合架构生成式模型负责“理解”和“索引”向量检索负责“粗筛”和“快召”。具体来说离线阶段用大语言模型对商品库做“生成式增强”把每个商品的多模态信息文本、图片、视频压缩成一组“生成式特征向量”。这些特征向量不是传统的稠密向量而是带有结构信息的“语义指纹”。在线阶段先用传统向量检索做第一层粗筛召回Top-K候选然后用生成式匹配模型对这K个候选做精排。这样既保证了速度又引入了生成式的推理能力。这个混合架构的关键在于生成式特征的设计。如果生成式特征只是把商品标题换个说法那跟传统向量没区别。得物的做法我猜测是让模型生成“多粒度的匹配单元”。比如一个商品可以生成“品类级匹配单元”运动鞋、“属性级匹配单元”低帮、透气、白色、“场景级匹配单元”日常穿搭、轻度运动、“风格级匹配单元”简约、日系。在线匹配时query也会被生成模型拆解成对应的粒度然后做层级匹配。这种“生成式多粒度匹配”比单一向量相似度要精细得多。2.3 多模态在生成式召回里的角色不是拼接是“翻译”多模态是得物交易搜索的命脉。一双鞋的图片包含了颜色、材质、鞋型、联名标识等大量信息。传统多模态检索是把图片编码成一个向量文本编码成另一个向量然后算余弦相似度。这种做法的问题在于图片向量和文本向量是在不同空间里训练的它们之间的“对齐”是粗粒度的。生成式召回给多模态融合提供了一个新思路用生成模型做“跨模态翻译”。具体来说让一个多模态大模型把商品图片“翻译”成一段结构化的文本描述比如“白色低帮运动鞋鞋面为皮革材质侧面有红色 swoosh 标志鞋底为橡胶大底适合日常休闲穿搭”。这段描述不是给用户看的而是给召回系统用的。它把视觉信息“翻译”成了文本空间里的结构化特征然后就可以用文本召回的那套逻辑来处理。反过来用户上传的图片query也可以被“翻译”成文本描述然后跟商品的结构化描述做匹配。这种“翻译式”多模态融合比简单的向量拼接要精准得多因为它保留了模态内部的细粒度信息又在文本空间里实现了对齐。3. 落地实操生成式召回链路的关键环节与参数设计3.1 离线生成式索引构建从商品库到“语义指纹”离线阶段是整个生成式召回的基础。没有高质量的生成式索引在线匹配就是空中楼阁。得物交易搜索的商品库规模我估计在千万级到亿级之间。要对这个量级的商品做生成式理解必须解决两个问题吞吐量和一致性。吞吐量方面不可能用最大的模型逐个商品跑。我的经验是用“大模型生成小模型蒸馏”的两级方案。先用一个中等规模的多模态大模型比如7B参数级别对商品做批量推理生成结构化的“语义指纹”。这个指纹的格式我建议设计成JSON结构包含以下字段{ category: 运动鞋, attributes: [低帮, 透气, 白色, 皮革], scenes: [日常通勤, 轻度运动, 校园], styles: [简约, 日系, 街头], target_audience: [男性, 18-25岁], price_band: 500-800, brand: Nike, series: Dunk }这个结构不是拍脑袋定的它对应了交易搜索里最常见的query意图维度。用户搜“学生党 白色运动鞋 500以内”系统就能快速匹配到category、attributes、target_audience、price_band这几个字段。生成这个指纹的prompt设计很关键。我的做法是给模型一个“角色设定”“你是一个电商商品理解专家请从以下商品信息中提取结构化标签用于搜索召回。标签要覆盖品类、属性、场景、风格、人群、价格带、品牌、系列。属性要具体到材质、功能、设计元素。场景要覆盖通勤、运动、约会、校园、旅行等。风格要覆盖简约、复古、街头、日系、欧美等。”一致性方面同一个商品在不同时间生成的指纹必须稳定。解决办法是固定随机种子并且对生成结果做后处理校验。比如如果模型生成的price_band跟商品实际价格不符就用规则修正。如果attributes里出现了重复项就去重。这些后处理规则我整理了一个清单放在后面的排查表里。3.2 在线生成式匹配query拆解与层级召回在线阶段用户输入query后系统要做两件事query生成式拆解和层级匹配。query拆解是用一个轻量级的生成模型或者经过蒸馏的小模型把query映射成跟商品指纹同构的结构。比如用户搜“送男朋友 生日礼物 500以内 实用”拆解结果可能是{ intent: 送礼, target_audience: [男性, 男朋友], price_band: 0-500, scenes: [生日, 纪念日], attributes: [实用, 礼盒装] }这个拆解结果就是在线匹配的“查询条件”。然后系统用这些条件去倒排索引或者向量索引里做粗筛。粗筛的策略是“宽进严出”先用category和price_band做硬过滤把候选集缩小到万级然后用attributes和scenes做软匹配召回千级最后用生成式匹配模型做精排选出Top-100。层级匹配的关键在于权重设计。不同字段的匹配权重不一样。我的经验是category和price_band是硬条件权重最高attributes和scenes是核心条件权重次之styles和target_audience是辅助条件权重最低。具体权重值需要根据业务数据做AB测试。我试过的一组初始值是category 0.3price_band 0.2attributes 0.25scenes 0.15styles 0.05target_audience 0.05。这组值在得物这种潮流电商场景下召回率和准确率的平衡还不错。3.3 多模态翻译模块的工程实现多模态翻译模块是整个链路里工程复杂度最高的部分。它要处理三种输入商品图片、用户上传图片、query文本。输出是统一的结构化文本描述。商品图片的翻译是离线批量做的。用多模态大模型比如CLIP系列的升级版或者专门微调过的视觉语言模型对每张商品主图生成描述。描述要包含主体物品、颜色、材质、形状、图案、文字标识、背景风格。生成后跟商品标题做融合得到最终的语义指纹。用户上传图片的翻译是在线实时做的。这里有个性能瓶颈多模态大模型的推理延迟通常在几百毫秒到几秒之间对于搜索场景来说太慢了。解决办法是“异步缓存”用户上传图片后先返回一个“以图搜图”的粗排结果用传统图片向量检索同时后台异步调用多模态模型生成文本描述等描述生成后再刷新精排结果。这个体验上的折中在实际产品里是可以接受的因为用户对“以图搜图”的首次响应时间容忍度通常在1秒左右后续刷新可以稍慢。query文本的翻译其实不是“翻译”而是“结构化拆解”。这个用轻量级模型就能做延迟可以控制在50毫秒以内。拆解后的结构化query跟商品语义指纹做字段级匹配。3.4 召回效果评估别只看召回率生成式召回上线后怎么评估效果很多人第一反应是看召回率。但交易搜索里召回率是个“虚荣指标”。你召回了一堆相关商品但用户真正想买的那个没排前面召回率再高也没用。我的经验是看三个指标首屏点击率、加购转化率、长尾query覆盖率。首屏点击率反映的是Top结果的相关性加购转化率反映的是交易意图匹配度长尾query覆盖率反映的是对新品牌、新款的覆盖能力。生成式召回在这三个指标上通常比纯向量检索有10%-20%的提升尤其是在长尾query上提升幅度可能超过30%。还有一个容易被忽略的指标零结果率。交易搜索里零结果是最伤用户体验的。用户搜一个具体型号结果啥也没出来他可能直接就走了。生成式召回因为能理解query的隐含意图即使没有完全匹配的商品也能召回“近似替代品”从而降低零结果率。得物交易搜索团队如果把这个指标降下来了那生成式召回的价值就体现出来了。4. 踩坑实录生成式召回落地时最容易翻车的五个地方4.1 生成式指纹的“幻觉”问题大语言模型生成结构化标签时最大的风险是“幻觉”。比如一个商品明明是“帆布鞋”模型可能生成“皮革”属性。这种错误在离线阶段很难被发现因为商品库太大不可能人工逐个校验。但一旦上线就会导致召回结果驴唇不对马嘴。我的解决办法是“多模型投票规则校验”。用两个不同的大模型分别生成指纹然后对比结果。如果某个字段两个模型不一致就标记为“低置信度”交给规则引擎处理。规则引擎里我预设了一批“硬约束”比如“帆布鞋”的材质只能是“帆布”、“橡胶”、“织物”不能是“皮革”。如果模型生成的属性违反了硬约束就直接丢弃或者修正。还有一个技巧是“反向验证”让模型生成指纹后再让它根据指纹“复述”商品信息然后跟原始商品标题做相似度对比。如果相似度低于阈值说明指纹可能跑偏了需要重新生成。4.2 在线匹配的延迟抖动生成式匹配模型即使经过蒸馏推理延迟也可能在几十毫秒到几百毫秒之间波动。在搜索场景里延迟抖动比平均延迟更可怕。用户可不管你的P99延迟是多少他只要感觉到“卡了一下”体验就崩了。我的做法是“分级降级”。在线匹配分三级一级是纯向量粗排延迟10ms二级是轻量级生成式匹配延迟50ms三级是完整生成式精排延迟200ms。正常情况下走三级如果系统负载高自动降级到二级或一级。降级策略用动态阈值控制当P99延迟超过100ms时触发降级当P99延迟回落到50ms以下时恢复三级。另外生成式匹配模型一定要做“批处理”。把多个query的候选商品合并成一个batch一次性推理能显著降低平均延迟。batch size的设置要根据GPU显存和延迟要求来调。我试过batch size32时吞吐量最高延迟也能接受。4.3 多模态翻译的“信息丢失”多模态翻译模块把图片翻译成文本时一定会丢失信息。比如鞋子的“脚感”、衣服的“垂坠感”这些触觉和动态信息静态图片根本表达不出来。如果过度依赖翻译后的文本就会导致召回结果“看起来像但买回来不对”。我的经验是多模态翻译的结果只作为“召回信号”之一不能作为唯一依据。最终排序时还是要结合原始的图片向量相似度。也就是说文本翻译负责“粗筛”图片向量负责“精排”。两者加权融合权重根据品类调整。比如鞋子品类图片向量权重可以高一些0.6因为鞋型、配色很重要衣服品类文本翻译权重可以高一些0.5因为材质、风格描述更重要。4.4 长尾query的“过度生成”生成式模型有个毛病你给它一个长尾query它非要“脑补”出一堆不存在的意图。比如用户搜“aj1 禁穿 2016”模型可能生成“适合收藏”、“限量款”、“高价值”这些标签。但实际上用户可能只是想买个二手自穿对“收藏价值”根本不关心。过度生成会导致召回结果偏向“高价”、“收藏级”商品反而把普通自穿款挤掉了。解决办法是“意图置信度过滤”。让模型在生成结构化query时同时输出每个字段的置信度。如果某个字段的置信度低于阈值比如0.6就不参与匹配。这样能避免模型“自作主张”地添加用户没表达的意图。4.5 离线索引更新的“一致性窗口”商品库是动态变化的每天都有新商品上架、旧商品下架、价格调整。生成式索引如果更新不及时就会出现“用户搜到了但点进去发现已下架”或者“价格对不上”的情况。这个“一致性窗口”如果太长用户体验会严重受损。我的方案是“增量更新全量重建”结合。增量更新是针对新上架商品和价格变动商品实时生成指纹并更新索引延迟控制在分钟级。全量重建是每周一次用最新的模型和规则重新生成全库指纹修正增量更新中积累的误差。增量更新用流式处理框架比如Flink全量重建用离线批处理框架比如Spark。两者通过版本号管理确保在线服务读取的索引版本是一致的。5. 常见问题速查与排查技巧5.1 召回结果与query意图不符这是最常见的问题。排查思路是“从query拆解开始逐层往下查”。排查层级检查项可能原因解决办法query拆解结构化query的字段是否准确模型对长尾query理解偏差增加few-shot示例覆盖更多长尾场景粗筛category和price_band过滤是否过严硬过滤条件设置太窄放宽硬过滤阈值增加候选集软匹配attributes和scenes权重是否合理权重配置偏向错误字段用AB测试调整权重参考业务数据精排生成式匹配模型是否过拟合训练数据分布与线上不一致增加线上数据回流重新训练我踩过的一个坑是query拆解时把“送女朋友”错误地拆成了“女性”“礼物”但用户实际想送的是“中性款”香水。后来在prompt里加了“注意区分收礼人性别和商品适用性别”问题才解决。5.2 多模态翻译结果不稳定同一个商品图片两次翻译结果差异很大。这通常是模型推理的随机性导致的。解决办法是固定随机种子并且对翻译结果做“多数投票”用同一个模型跑三次取出现频率最高的描述作为最终结果。如果三次结果差异都很大就标记为“低质量翻译”降权处理。5.3 在线延迟突然飙升延迟飙升通常有三个原因模型推理负载过高、索引查询变慢、网络抖动。排查顺序是先看GPU利用率如果超过80%说明推理负载过高需要扩容或者降级再看索引查询的P99延迟如果超过50ms说明索引需要优化比如增加分片、调整缓存策略最后看网络如果跨机房调用延迟抖动可能是网络问题需要做就近部署。5.4 新商品召回不出来新上架商品如果生成式索引还没更新就召回不出来。解决办法是“实时索引通道”新商品上架后立即触发一个轻量级的指纹生成任务用蒸馏后的小模型把指纹写入实时索引。实时索引和离线索引通过商品ID做合并在线查询时优先读实时索引。这样新商品的召回延迟可以控制在1分钟以内。5.5 生成式指纹的存储成本千万级商品的生成式指纹如果每个指纹1KB总存储量就是10GB。加上多版本、多模型可能膨胀到50GB。这个量级对于分布式存储来说不算大但查询时的IO开销需要考虑。我的做法是“冷热分离”热商品最近30天有销量的指纹放在内存数据库比如Redis里冷商品指纹放在磁盘数据库比如HBase里。在线查询时先查热数据如果没命中再查冷数据。这样能把P99查询延迟控制在20ms以内。6. 生成式召回后续还能怎么玩生成式召回在得物交易搜索里的落地目前看还只是开了个头。我个人的判断是接下来有几个方向值得深挖。第一个方向是生成式召回的“可解释性”。现在生成式匹配模型给出一个分数但为什么是这个分数很难解释。如果能生成一段“匹配理由”比如“该商品为白色低帮运动鞋符合您对‘简约通勤’的需求且价格在预算内”那不仅能提升用户信任还能为后续的推荐和广告提供依据。第二个方向是生成式召回与生成式排序的融合。现在召回和排序是分开的召回负责“找出来”排序负责“排好序”。未来可以用一个统一的生成式模型直接生成“排序后的商品列表”中间不再区分召回和排序阶段。这需要模型对商品库有更强的“记忆”和“推理”能力目前看还有距离但方向是清晰的。第三个方向是多模态生成式召回的实时化。现在用户上传图片后还要等异步翻译结果。未来如果多模态模型的推理速度能降到100ms以内就可以做到完全实时。这需要模型压缩和硬件加速的进一步突破。我在实际落地中最大的体会是生成式召回不是“银弹”它解决的是传统向量检索在交易场景下的“意图理解”和“长尾覆盖”问题但它本身也引入了新的工程复杂度和成本。要不要上取决于你的业务场景里长尾query占比有多高多模态信息有多重要以及团队有没有足够的工程能力去维护这套链路。如果长尾query占比不到10%那优化传统向量检索可能更划算。但如果像得物这样潮流商品更新极快、用户query极度口语化、图片信息权重极高那生成式召回就是值得投入的方向。
返回列表