拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

交易搜索新范式:生成式召回如何突破向量检索天花板

交易搜索新范式:生成式召回如何突破向量检索天花板

两年前我们团队做召回方案评审的时候,听到最多的一句话就是“再加一路向量召回吧”。那阵子整个圈子都在卷embedding、双塔、ANN索引,得物交易搜索自然也顺着主流做了不少向量化改造,效果确实有提升。但越往后越明显,向量检索解决的只是“看起来相似”,解决不了“理解得透”。得物这个交易场景比较特殊,用户搜索词和商品文本之间隔着大量网络黑话、型号别称、联名梗,比如搜“倒钩”其实要的是AJ1倒钩球鞋,搜“熊猫”要的是Dunk熊猫配色,搜“小闪电”要知道指的是Air Jordan 1的特定配色。这些词在商品标题里通常根本不存在,纯靠语义表示去逼近,天花板很低。所以去年开始,我们把重心从向量检索挪开,试着让生成式模型直接参与召回,让系统先“读懂”用户这句话,再自动构造候选集。这篇文章就把我们在得物交易搜索里做生成式召回的思路、落地和踩坑过程完整梳理一遍,给还在拼命堆向量路数的团队一个参考。

1. 得物交易搜索的召回困境:向量检索卷不动的那部分

1.1 交易搜索的“黑话”问题

得物是一个潮玩和潮流服饰的交易平台,商品以限量球鞋、服饰、潮玩为主。这类商品有一个共同特点:用户怎么叫它,和商品文档怎么写它,经常是两套语言。

商品标题通常由运营和商家维护,走的是相对规范的写法,比如“Nike Air Jordan 1 Retro High OG 复刻 篮球鞋”。“但用户搜索时不会这么说话,圈子里的人会说‘倒钩’‘熊猫’‘小闪电’‘大魔王’‘黑脚趾’,这些都是用户的自然语言,也是交易搜索里最典型的‘黑话’。如果系统只会拿query去商品标题里做字面匹配,甚至只会拿query的embedding去商品embedding里做相似度计算,很大概率找不回这些词对应的商品。

这就是交易搜索和通用搜索的本质区别:通用搜索里用户搜“苹果”,意图可能模棱两可,但交易搜索里用户搜“倒钩”,他脑子里的目标是非常清晰的一双鞋。检索系统要面对的不是“理解个大概”,而是“精确理解到具体商品属性级别”。这种语义gap小则让召回结果不准,大则直接导致无结果。

1.2 向量检索擅长什么,解决不了什么

向量检索能在过去几年成为主流,是因为它确实解决了字面匹配解决不了的问题:同义改写、跨语言、上下位概念。比如用户搜“跑步鞋”,商品标题里写的是“运动鞋”,字面匹配可能漏掉,但向量表示能把两个句子拉近。

但在得物交易搜索里,向量检索有几个绕不开的短板:

  • 精确属性表达困难。用户搜“AJ1 44码”,这里的“44码”是硬约束。embedding做的是“整体的相似性”,它很难把“尺码必须等于44”这种精确条件在向量空间里完整表达出来,最后还是得靠属性过滤。
  • 交易意图建模薄弱。搜“倒钩 值得买吗”和搜“倒钩 全新”,用户意图完全不一样,一个偏评测比价,一个偏交易购买,但embedding很可能把它们编码成很接近的表示,因为字面太相似了。
  • 新词和热点词冷启动慢。一个梗要在社交媒体上发酵一阵子才会出现在商品标题里,模型训练数据里更是没有。等向量模型能表征它的时候,热点已经过去了。
  • 组合条件很难一次表达。“求一双灰色的Aj1倒钩,40-42码,价格2000以内”,这种多个槽位的组合查询在向量检索里基本只能退化成多路召回后再做精排,召回阶段经常顾此失彼。

我做了一张对比表,方便大家直观感受向量检索在交易搜索里的能力边界:

查询类型典型query字面匹配向量检索实际效果
黑话昵称“熊猫”差中容易召回到熊猫玩偶等无关商品
精确属性“AJ1 44码”中中需要靠过滤兜底,向量本身表达不了
组合意图“灰色倒钩 两千内”差差多条件相互干扰,召回分散
热点新词“新出的xx联名”差差模型没学过,表示质量极差

1.3 “多路召回”堆砌的收益递减

向量检索有短板,大家自然想到的就是多路召回:文本一路、向量一路、swing这种行为序列一路、热销榜一路,各路召回再合并去重,喂给粗排精排。我们团队很早期就把这套体系搭起来了,路数从最初的五六路涨到接近二十路,效果也确实是涨的。

但越往后,收益递减越明显。新增一路召回,带来的增量候选越来越少,反而引入三个问题:

  • 重复率飙升。各路召回都在竞相召回热门商品,合并后大量重复,排序压力变大,真实增量候选没多少。
  • 维护成本变高。每路都要保索引、调参、做监控,接近二十路的规模,光排查“某一路上线导致整体指标波动”就能把人耗干。
  • 长尾无结果问题依旧。多路召回本质上是同一思想的不同变体:在既有商品集合里“找相似”。如果商品集合本身和用户query差距太大,路数再多也是零相乘等于零。

我们后来统计了一个数字:新增的召回路,对头部热门词基本没有增量,对长尾query的召回率提升也极其有限。真正让效果起飞的场景,往往不是多一路相似检索,而是换一种完全不同的召回思路。这也是我们开始认真琢磨生成式召回的契机。

2. 从“近似匹配”到“意图重构”:生成式召回的思路转变

2.1 一句话说清生成式召回是什么

传统的召回链路无论做多少路,本质都是同一个范式:给定一个query,在已有商品集合里找一个“和它最相似”的子集。区别只在于“相似”怎么定义,有的用词频,有的用向量距离,有的用行为共现。

生成式召回把这个问题重新定义了一遍:先让模型根据query生成一个用户意图的结构化表达,再基于这个表达去构造候选集。换句话说,召回不再是被动的“找”,而是主动的“重构”加“筛选”。

打个比方:传统召回是拿着一张小照片在人群里找对应的人,照片不清晰或者对方换了衣服,基本就找不到了;生成式召回是先听目击者描述,画出一张嫌疑画像,再拿着画像去人群里比对。画像可能比原来的照片更抽象,但它抓住了“关键属性”,反而能覆盖更多外观变化。

在我们的实践里,生成式召回具体做了两件事:

  1. 意图画像生成:把“倒钩 灰色 44 两千内”这种口语query,解析成“品牌=Air Jordan,型号=AJ1,系列=倒钩,颜色=灰色,尺码=44,价格区间=0-2000,交易意图=求购”的结构化画像。
  2. 候选集重构:拿着这份画像,在商品索引里做精确的属性筛选和条件匹配,生成一批候选。

这套流程的本质是把“表示学习”的比拼,转成了“意图理解+知识运用”的比拼。后者能处理前者处理不了的精确条件和组合逻辑,这是范式层面的一次变化。

2.2 生成式模型在召回链路里能干哪些活

围绕生成式召回,我们在实验里发现LLM能承担好几类职责,每类的技术难度和收益都不一样:

  • Query语义解析:把raw query拆解成语义槽位,识别类目、品牌、型号、颜色、尺码、价格段、交易意图。这是收益最大的一类,也是后续所有动作的基础。
  • 黑话翻译和别名归一:把“熊猫”归一为“Dunk Low Retro White Black”,把“倒钩”归一为“AJ1 Reverse Swoosh”。这一步解决的是向量模型吃不动的新词、圈层词。
  • 属性补全:用户可能只说了“灰水泥”,模型可以根据商品知识库补全“Air Jordan 4 灰水泥配色”,从而精确到具体SKU系列。
  • 候选描述生成:让模型生成一段“理想商品描述”,再用这段描述做伪文档检索。这种方式适合商品文档本身质量差、索引稀疏的场景。
  • 直接生成候选商品ID:在上下文里塞入用户历史行为序列和热门商品ID,让模型直接输出最可能的候选商品ID列表。这个方案更激进,对模型能力和上下文窗口要求都高一些,我们当成兜底和补充来用。

需要说明的是,这五类不是每一步都必须做。我们的实践里,收益最稳定的是前两类,即query解析和黑话归一。这两类做扎实了,召回效果就能有明显提升,后面三类属于锦上添花。

2.3 为什么生成式能突破表示学习的上限

理解了生成的几种方式,再回到一个根本问题:凭什么生成式能做到向量检索做不到的事?

我觉得有三点值得说。

第一,向量检索的边界由语料决定。一个query能不能被召回,取决于query和商品文档的表示是否足够接近。如果“倒钩”这个词在商品标题里从来没出现过,训练阶段也没在描述文本里和AJ1共同出现过太多次,表示学习就很难把它俩拉近。而生成式模型预训练阶段读过的数据里,包含大量社区讨论、社交媒体帖子、百科条目,模型的“世界知识”天然覆盖了语言和商品之间的连接,不需要显式依赖当前商品库里的文本。

第二,生成式可以做组合推理。向量检索的本质是整体相似度,它很难同时满足“灰色且价格低于2000且尺码44”这种条件组合。LLM可以把这些条件显式解析出来,再交给确定性的过滤和筛选逻辑去执行。一个负责“理解”,一个负责“精确”,组合起来上限远高于纯表示匹配。

第三,生成结果可解释、可控。向量召回出了错很难说清为什么这两个句子相似,生成式召回至少能输出一个结构化的画像,我们能检查是哪个槽位解析错了。上线排查时,这种可解释性价值极高,能省下大量定位问题的精力。

3. 生成式召回落地的具体方案:画像生成、候选构造与校验

3.1 整体链路:从query到商品画像

我们在得物交易搜索里的生成式召回落地结构,大致可以分成四层:

  • 接入层:接收搜索query,同时带上用户的浏览和购买序列作为上下文。
  • 理解层:LLM将query解析成结构化的商品画像,输出为一份JSON。
  • 执行层:基于画像中的类目、品牌、颜色、尺码、价格区间等字段,向商品索引发起检索,并对关键字段做条件过滤。
  • 兜底层:生成结果未通过校验时,降级到原有文本+向量召回链路。

核心的设计决策是:LLM不直接生成候选商品,而是生成中间的结构化画像,再交给传统检索引擎执行筛选。这样做有两个好处:一是避免模型幻觉直接污染候选集,二是可以复用已经搭好的索引和检索基础设施,不需要为生成式单独建一套存储和检索体系。

画像的JSON结构我们是这么约定的:

{ "semantic_slots": { "category": ["运动鞋"], "brand": ["Nike"], "product_line": ["Air Jordan 1"], "nickname": ["倒钩", "Reverse Swoosh"], "color": ["灰色"], "size_range": ["40", "41", "42"], "price_range": [0, 2000], "condition": ["全新", "二手"] }, "trade_intent": { "type": "buy", "scene": "求购", "premium": false }, "confidence": 0.87 }

这个JSON的设计花了我们不少时间。一开始字段定得太多,模型输出不稳定,后来收敛到十几个关键槽位,稳定性和可用性都显著提升。经验是:画像字段宁少勿多,只留能给召回带来实际约束能力的字段,那些对过滤没有帮助的槽位不要放进来。

3.2 候选集构造的两种路径

画像生成之后,下一步是怎么从画像得到候选商品集。我们在工程上实现了两条路径,互为补充。

路径A是画像转检索条件。把JSON里的字段翻译成检索引擎里的查询语句。类目、品牌、系列、颜色做精确匹配或倒排匹配,尺码和价格做区间过滤。这条路径适合绝大多数场景,因为它完全复用了我们现有的倒排索引和属性索引,性能稳定,逻辑可控。

路径B是模型直接生成候选ID。把用户最近浏览和收藏的商品ID列表、当前query的画像、热度榜前N个商品ID一起塞进上下文,让模型直接输出它认为最相关的候选ID集合。这条路径的适用场景是那些画像转检索条件后仍然匹配不到结果的极端长尾query。我们把它设计成紧急兜底方案,不会默认开启。

两条路径跑完都会进入同一个合并器,和向量、文本、swing等其他路的召回结果合并,再做去重和粗排。

3.3 输出校验与兜底策略

生成式模型最大的风险是输出不可控。我们在这上面踩过很多坑,最终形成了一套四层校验机制:

  • 格式校验:用JSON Schema检查输出是否是可解析的JSON,字段类型是否正确。
  • 枚举校验:品牌、类目、颜色这些字段必须落在我们维护的合法枚举表里。模型输出一个库里不存在的品牌直接判无效。
  • 逻辑校验:尺码区间和价格区间是否符合常识,比如价格上限不该为负数、尺码不该是字母。
  • 置信度阈值:模型输出越低置信度的解析结果,越要降级处理,宁可走传统召回也不要硬吃生成结果。

这里有一个经验教训:生成式召回的上限再高,也必须在“宁缺毋滥”的前提下使用。宁可用传统召回结果顶上让用户体验平稳,也不能让一张错误画像把原本能召回的候选全过滤掉,导致无关结果甚至无结果。

3.4 技术选型:为什么在Java技术栈里用LangChain4j

得物后端整体以Java为主,我们的搜索工程代码也基本都在Java生态内。引入生成式能力时,团队其实纠结过要不要单独起一个什么服务来调LLM,让Java服务通过HTTP去访问。后来决定维持Java单栈,引入LangChain4j作为接入层框架。

选择LangChain4j有几个现实原因:

  • Java生态里直接调LLM接口要自己处理prompt模板管理、JSON输出解析、上下文组装这些琐碎但容易出错的事,LangChain4j把这些抽象做得比较成熟。
  • 它的AI Service层可以直接定义一个Java接口,把“输入query返回画像JSON”声明成一次方法调用,团队里Java工程师上手成本低。
  • 它支持prompt模板、输出解析器、多轮上下文管理,正好覆盖我们画像生成这个核心场景。

实际使用中,我们把prompt模板、few-shot示例和输出解析器都放在LangChain4j的配置层管理,业务代码里只看到一次queryIntentService.parse(query, context)调用,维护起来清爽很多。

4. 与多路召回协同编排:合并、去重、评测与灰度

4.1 生成式召回在多路召回里的角色定位

必须承认一点:生成式召回不是来“消灭”向量检索或其他召回路的,它是来给整个召回体系补一块短板的。

得物交易搜索目前仍是多路召回体系,向量路、文本路、行为序列路都在正常服役。生成式召回在体系里的定位是“高质增量路”和“长尾修复路”。它的使命不是和向量路抢头部query,而是把那些向量路和文本路都搞不定的黑话query、组合条件query接住。

这一块理解上的分歧,我们内部也争论过很久。有的同学主张把生成式召回做成默认强制走一遍,我坚持把它放在“增量”和“兜底”两个位置上。理由很简单:生成式能力当前的延迟和成本都高于传统召回,把它用在所有query上是浪费;而且头部query传统召回表现已经足够好,生成式对它们的边际收益很低。

4.2 结果合并与去重策略

多路召回合并时,去重策略直接决定增量收益能不能体现出来。我们为每路召回的结果打上source标签,生成式召回的结果标记为gen,然后在合并器里做两层处理。

第一层是按商品ID去重,不同路召回同一商品时保留得分更高路的来源,但把生成式路召回的来源信息记下来作为后续排序的上下文信号。第二层是控制重叠率,如果生成式召回的候选与向量路重叠超过一定比例,说明这一路的增量价值有限,会把生成式结果中与已有候选重复的部分降权。

合并器的设计还考虑了一个细节:不能让生成式结果的增量全部集中在热门商品上。生成式模型天然对热门商品更熟悉,容易反复输出头部候选,如果不去控制,生成式召回会变成第N路热门商品召回,失去意义。我们做了候选池层面的多样性约束,限制同一品牌、同一系列在生成式结果里的占比。

4.3 离线与在线评测指标

生成式召回上线前,我们设计了专门的评测方案,而不是直接拿整个召回链路的所有指标笼统看。

离线上重点看这几个指标:

指标说明我们的目标
Recall@K候选集里是否包含目标商品长尾query显著提升
HitRate至少命中一个有效商品的比例下降无结果率
增量覆盖率生成式结果中与其他路不重复的比例不低于40%
画像解析准确率槽位解析与人工标注的一致性核心槽位不低于90%

在线指标里,我们最关心的是无结果率、搜索点击率和交易转化率。考虑到交易搜索的属性,转化指标最终一定比单纯的点击指标更重要。灰度时按类目切分,先选潮流球鞋这种黑话浓度最高的类目跑,验证有效后再逐步扩到服饰和潮玩。

4.4 灰度与迭代节奏

灰度策略上,我们坚持“慢启动、带降级”。先切5%流量观察画像解析成功率和召回增量,确认没有明显性能回退后,再逐步放开到10%、20%、50%。

迭代节奏是两周一个版本。第一版只做query理解和黑话归一,解决无结果问题;第二版加入组合条件解析,提升精确召回能力;第三版才把直接生成候选ID的激进方案放进来对比。整体走下来,一个明显的变化是:带型号别称和黑话的query,无结果率显著下降,之前向量检索和文本检索都空手而归的很多长尾词,现在能拿回有效候选了。价格条件和尺码条件这类精确滤过的场景,召回结果也更贴合用户实际需求。

5. 实际踩过的坑:延迟、幻觉、长尾和成本

5.1 延迟:搜索主链路放不下一整个LLM

第一个坑来自性能。搜索主链路的延迟预算通常按50到100毫秒设计,一次LLM调用的延迟普遍在百毫秒级起步,直接把生成式塞进主链路是不现实的。

我们的解法是把LLM调用从主链路里“拆出去、缓下来”:

  • 热点query离线预生成:对高频query,离线批量生成画像并缓存,线上直接读缓存。
  • 在线异步首猜:用户输入过程中,利用搜索联想和上一轮搜索结果旁路异步触发生成,等用户真正提交搜索时结果已就绪。
  • 低延迟推理:在线实时场景用蒸馏后的小参数量模型,推理快一档,只处理缓存未覆盖的中长尾。

这套组合下来,真正在线实时跑LLM的query占比控制在很小的范围内,主链路延迟基本不受影响。如果要给一个实操建议,就是不要把生成式召回设计成“每条query都必须经过”的强制环节,把它设计成缓存优先、小流量实时的增强环节,工程上会更顺畅。

5.2 属性幻觉:一本正经地胡说八道

生成式召回另一个大坑是属性幻觉。模型在生成画像时,可能信心十足地把一个不存在的配色当成系列属性,或者把品牌映射错误。比如“灰水泥”这个query,模型可能会写成“Nike Air Force 1 水泥灰”,实际用户想要的可能是“Air Jordan 4 Rain or Shine”那种灰水泥配色,品牌和系列都需要对齐到具体商品知识库里。

我们一开始对幻觉的警惕不够,以为解析出结构化字段就万事大吉,结果线上出现了一批“标签完全对但商品完全错”的召回。后来把校验机制补上,又把商品知识库里的合法品牌、系列、昵称对列表灌给模型做约束,幻觉比例才降到可控范围。

经验是:生成式召回里,校验层和模型层同等重要。宁可多写一层枚举校验,也不能把模型的输出当可信输入直接进检索。

5.3 长尾与头部的平衡

第三个坑是资源分配。我们早期把生成式能力均匀铺到所有query上,线上看效果平平,甚至头部词的指标还有轻微抖动。原因前面提过,头部热门词传统召回已经很成熟,生成式很难提供增量,反而可能因为画像解析偏差把原来能召回的候选过滤掉。

后来我们加了query分级:头部query完全走缓存和传统召回,不做生成;中等热度query做缓存优先的生成式补充;真正的长尾、低频、黑话query才走实时的生成式解析。这样一调整,整体收益成本比明显改善。总结起来就是:生成式召回该用在“传统手段明显失效”的地方,而不是全面铺开。

5.4 成本与收益的真实账本

最后说成本。LLM调用的token成本和GPU成本都比传统检索高一个量级。我们控制成本的方式主要是三块:

  • 尽量用缓存命中吸收高频流量,缓存命中率稳定在高位。
  • prompt设计走简洁路线,few-shot控制在少量精选示例,不塞大段冗余指令。
  • 画像解析用小参数量模型为主,大模型只用于离线生成示例和困难case复核。

算下来,边际成本是可控的,但这件事一定要在立项时就规划清楚,等项目跑起来再控制成本和延迟,改动成本会高很多。我们的感觉是,这套方案的收益主要集中在长尾转化和无结果率这类指标上,如果业务场景本身没有明显的语义gap、没有黑话新词、没有复杂组合条件,那生成式召回带来的增量可能不值得这份成本。

最后再分享一点个人体会。做完这个项目,我的感觉是:信息检索系统的演进,从字面匹配到向量检索,解决的是“相似”问题;从向量检索到生成式召回,解决的是“理解”问题。得物交易搜索里大量黑话、圈层词、组合条件的场景,天然适合生成式这套玩法。但如果你的业务场景词表稳定、商品文档规范、用户query直白,可能向量检索加多路召回已经够用,不用盲目追这个方向。技术选型这事,永远是场景决定范式,而不是范式决定场景。

返回列表