“一起购买的好商品” 推荐模型升级

发布: (2025年12月11日 GMT+8 14:59)
11 min read

Source: Woowahan Tech

在 Baedal Minjok(배달의민족)不仅可以进行食物外送,连买菜也可以实现当天送达,你知道吗?

Baemin 的买菜·购物服务除了 Baemin B‑Mart,还入驻了超市、便利店、花店、电子产品等各种卖家,让你可以快速收到各种商品。我们从用户进入服务的那一刻起,到完成购买的整个旅程,提供 个性化推荐、一起浏览的商品推荐、实时趋势排名、购物车推荐、支付前的追加商品推荐 等多种推荐,帮助用户发现最合适的商品。

推荐
图 1. “买菜·购物” 服务的多种推荐

本文将分享 基于用户购物车中商品的关联商品推荐 的购物车推荐模型的改进过程。面向熟悉推荐系统和基础机器学习概念的读者,分享我们的试错与改进经验,展示如何超越单纯的嵌入相似度,理解用户 购物车中商品的上下文,并推荐可以一起购买的商品,从而提升推荐性能。

购物车推荐
图 2. 购物车推荐

现有模型介绍及不足

最初的购物车推荐模型为了快速落地和实现便利,采用了基于订单数据的 Item2Vec 方法。我们把用户的订单历史视为一段句子,将订单中的商品视为单词(Word),使用 Skip‑gram 方式进行训练,并基于 嵌入相似度 来推荐当前购物车中的商品。

然而在模型运行过程中,我们发现了几项与购物车推荐目标相冲突的问题。

替代品偏向

Item2Vec 模型会把同一订单中一起出现的商品映射到相似的向量空间。于是具有相似购买模式的商品会拥有相似的嵌入。

举例来说,当用户把 牛奶 放入购物车时:

期望的推荐实际的推荐
麦片面包 等与牛奶 一起购买 的商品其他品牌的 牛奶 系列商品

如果仅依赖嵌入相似度,推荐结果会倾向于同一品类的替代品,导致 推荐多样性大幅下降。跨品类销售(Cross‑selling)需要能够提出多样的补充商品。

缺乏序列上下文

用户将商品放入购物车的顺序蕴含了购买意图。但 Item2Vec 只学习商品的共现关系,无法捕捉顺序信息。

用户购物车顺序合适的推荐
1[方便面, 五花肉, 生菜]烧烤所需的 大蒜
2[五花肉, 生菜, 方便面]与方便面搭配的 泡菜

Item2Vec 无法区分这些序列差异。因此我们将 理解已放入商品的顺序,并自然地推荐下一个可能的商品 作为模型改进的目标。

考虑购买上下文的推荐模型

要“了解商品在什么上下文中被放入”,不仅要建模 商品之间的关系,还要考虑 放入的顺序。为此我们构建了 两阶段(2‑stage)流水线

  • Stage 1. 基于图的商品·类目嵌入 – 将订单数据结构化为图,使用 Node2Vec 生成嵌入。
  • Stage 2. 基于上下文的下一个商品预测 – 将 Stage 1 生成的嵌入作为输入,使用 Transformer 模型学习购物车序列并预测下一个可能加入的商品。

Stage 1. 基于图的商品·类目嵌入

长尾商品的订单频次低,容易出现数据稀疏问题。Node2Vec 通过 随机游走(Random Walk) 生成序列,能够有效学习结构关联性。

图的定义

图
图 3. 基于共同购买数据的图示例

节点类型

类型说明
商品节点订单数据中出现的单个商品(如 五花肉酱料
类目节点商品所属的类目(如 肉类蔬菜

边 & 权重

  • Item‑Item – 商品之间的连接。基于订单数据的 关联规则(Association Rule) 赋予关联度权重,避免热门商品过度偏向。
  • Item‑Category – 商品与类目之间的连接。即使是新商品或没有订单的商品,也可以通过类目节点获得嵌入,从而缓解 Cold Start 问题。

序列生成与嵌入学习

在图上执行 加权随机游走(Weighted Random Walk),生成虚拟节点序列。例如:

[韩国产五花肉 500g → "肉类" → 无抗生素猪颈肉 500g → 有机生菜 → 国内产蒜瓣 → "蔬菜" → …]
[Roommo 意大利面 → "意面/意大利面" → 巴里拉意面 → 国内产蒜瓣 → 无糖番茄酱 → "酱料" → …]

将这些序列输入 Node2Vec,学习 商品·类目嵌入。得到的嵌入凝聚了购买模式的关联性,并在 Stage 2 中作为 Transformer 的输入使用。

Stage 2. 基于 Transformer 的序列推荐

把购物车中的商品视为一个序列,分析“已放入的商品”,预测用户最有可能接下来放入的商品。

模型架构
图 4. 模型架构

训练数据构造

从订单数据中利用购物车顺序构造训练样本:

[ \text{Input: } [i_1, i_2, \dots, i_{t-1}] ;\rightarrow; \text{Target: } i_t ]

输入嵌入

每个商品将 商品嵌入类目嵌入 进行拼接,并加上 位置嵌入

[ h_i = [e_{\text{item}}(i) ; e_{\text{category}}(i)] + e_{\text{pos}}(i) ]

对于 Cold Start 商品,商品嵌入可能较弱,但通过类目嵌入的补足仍能得到有效表示。

Transformer 上下文学习

  • Masked Self‑Attention – 参考 SASRec,使用因果掩码(Causal Masking),保证每个时刻只能看到之前的商品,防止目标信息泄露。
  • Feed Forward Network – 对 Self‑Attention 的输出进行非线性变换,学习更丰富的表示。

该结构使得即使是相同的商品组合,只要顺序不同,也能产生不同的推荐。例如 [方便面, 五花肉, 生菜] → 大蒜,而 [五花肉, 生菜, 方便面] → 泡菜,模型会给予较高权重。

训练配置与 Loss 函数

  • 多任务学习(Multi‑Task Learning) – 同时预测下一个 商品类目,将两任务的 loss 加权求和。
  • Focal Loss – 缓解热门商品与长尾商品之间的类别不平衡,对难样本给予更大关注,强化长尾商品的学习。

实验结果与评估

预测结果对比

下面展示了在相同购物车上下文下,Item2Vec(AS‑IS)和改进模型(TO‑BE)给出的推荐示例。

推荐结果对比
图 5. 推荐模型预测结果对比

Item2Vec 基于嵌入相似度,倾向于推荐 相同品类 的商品;改进模型则主要提供 考虑上下文的补充商品

离线评估

我们针对多个卖家(Seller)对比了现有模型(Item2Vec)和改进模型的表现。评估数据使用模型训练期间之后的订单记录,并将 购物车中商品的顺序 作为特征,最后一个商品作为真实标签。

卖家类型卖家Hit Rate@10(提升幅度)类目多样性(平均)
超市卖家 A51% ↑7.04 → 8.13
卖家 B71% ↑7.38 → 8.35
卖家 C120% ↑8.57 → 8.38
便利店卖家 D54% ↑3.51 → 4.98
卖家 E40% ↑4.80 → 6.51
卖家 F87% ↑5.51 → 7.11

主要结果

  • 与原始 Item2Vec 相比,Hit Rate@10 提升了 40 %~120 %。在数据稀疏的长尾卖家(C、F)上提升尤为显著,这归功于 Transformer 的 Self‑Attention 能在少量数据中有效捕捉上下文。
  • 大多数卖家的 推荐多样性 均有所提升。模型不再局限于同一类目的相似商品,而是能够提出 多种可能一起购买的商品。卖家 C 虽然在准确率上提升显著,但多样性略有下降,这与其长尾特性有关。
  • 超市和便利店两大场景均表现出一致的性能提升,说明模型在不同业务域中都具备良好的鲁棒性。
Back to Blog

相关文章

阅读更多 »

我们像代码一样重构文化

团队介绍:Commerce Web Frontend开发团队(以下简称“커머프팀”)是负责배달의민족所有商务服务和平台,以及从back office到后端物流系统的web client领域的庞大团队。原本负责不同服务的团队汇聚成一个大团队,构成了배달의민족所梦想的商务…