为什么你的推荐系统越做越“笨”?一文讲透电商个性化推荐全链路:从召回到在线排序
作者:Echo_Wish
很多人觉得,推荐系统不就是“猜你喜欢”吗?
点开淘宝、京东、拼多多、小红书,首页全都是推荐;刷抖音、快手,视频一条接一条。
看起来很简单,其实背后是一套极其复杂的大数据系统。
很多刚接触推荐系统的人,一开始总喜欢研究模型,今天Transformer,明天DeepFM,后天DIN,好像模型越复杂,推荐效果就越好。
实际上,在真正的大厂里,模型的重要性可能只占整个推荐系统的一部分。
真正决定推荐效果的,是整条推荐链路。
今天,就和大家聊聊一套真正的电商推荐系统到底是怎么工作的。
推荐系统,不是一个模型,而是一条流水线
假设一个电商平台有:
- 商品数量:5000万
- 用户数量:3亿
- 每秒请求:首页推荐10万次
如果每次打开首页,都让AI计算5000万个商品哪个最好……
服务器三分钟就冒烟了。
所以,大厂都会采用一套经典架构:
用户请求
│
▼
召回(Recall)
│
▼
粗排(PreRank)
│
▼
精排(Rank)
│
▼
重排(ReRank)
│
▼
在线推荐结果
整个过程,其实就是不断"筛人"。
5000万商品
↓
几千个
↓
几百个
↓
几十个
↓
最终20个推荐商品。
第一关:召回——先把可能喜欢的找出来
很多人误认为:
推荐系统就是排序。
其实不是。
排序之前,第一件事情叫召回。
什么意思?
举个例子。
假设你昨天搜索:
篮球鞋
今天系统第一步不会考虑全部商品,而是先找:
篮球鞋
运动鞋
耐克
李宁
阿迪
Jordan
篮球装备
这些可能相关的商品。
一般一次召回:
5000万商品
↓
3000件商品
那么问题来了:
怎么召回?
最常见的方法有很多。
例如:
热门召回
热门商品:
hot_products = redis.zrevrange(
"hot_products",
0,
999
)
协同过滤:
买了A的人
↓
也买了B
例如:
user_history = [
"iPhone",
"AirPods"
]
可以查询:
SELECT product_id
FROM item_cf_result
WHERE history_item='iPhone';
Embedding召回更常见。
例如:
用户行为编码成向量:
user_vector = model.encode(user_behavior)
商品提前离线生成Embedding:
item_vector = model.encode(item_info)
然后利用Faiss近邻搜索:
D, I = index.search(
user_vector,
1000
)
直接得到1000个候选商品。
速度通常:
几十毫秒以内
这就是为什么现在越来越多推荐系统喜欢:
向量召回。
第二关:粗排——快速淘汰90%的候选
召回出来以后,还有几千件商品。
这时候如果直接跑Deep Learning:
服务器依旧压力巨大。
怎么办?
先来一次粗排。
通常使用:
- LR
- GBDT
- XGBoost
- LightGBM
例如:
score = (
ctr * 0.6
+ cvr * 0.4
)
或者:
features = [
click_rate,
price,
brand_score,
category_score
]
score = lgb.predict(features)
粗排目标只有一个:
快。
例如:
3000件
↓
300件
耗时:
5~10ms
第三关:精排——真正开始用AI思考
真正的大模型,一般都放在这里。
例如:
DIN
DeepFM
DCN
Wide&Deep
MMoE
越来越多平台开始接入:
Transformer Ranking。
例如:
inputs = {
"user": user_feature,
"item": item_feature,
"context": context
}
score = rank_model.predict(inputs)
输出:
CTR
CVR
GMV
停留时长
购买概率
例如:
商品A
CTR:
0.61
CVR:
0.32
最终:
0.53
商品B:
CTR:
0.48
CVR:
0.58
最终:
0.56
最后:
B排前面。
这里已经不仅仅是在预测点击,而是在预测:
用户真正会不会买。
第四关:重排——别让首页全是一样的商品
很多推荐系统做到这里,就结束了。
结果首页变成这样:
篮球鞋
篮球鞋
篮球鞋
篮球鞋
篮球鞋
篮球鞋
用户马上就烦了。
所以还有一步:
ReRank(重排)。
例如:
加入多样性。
代码很简单:
selected = []
categories = set()
for item in ranked_items:
if item.category not in categories:
selected.append(item)
categories.add(item.category)
这样首页可能变成:
篮球鞋
运动裤
运动手环
篮球
运动袜
水杯
体验立刻提升。
还有:
去重:
if item.brand in showed_brand:
continue
还有:
新品扶持。
例如:
if item.is_new:
score += 0.05
还有:
利润提升。
例如:
score = (
ctr_score
* 0.7
+
profit_score
* 0.3
)
所以真正上线以后:
排序结果并不是模型说了算。
而是:
模型 + 业务规则。
在线服务:真正拼的是延迟,而不是准确率
很多人训练模型的时候:
AUC做到:
0.92
特别开心。
结果上线以后:
首页响应:
800ms
用户早就划走了。
推荐系统有一句很经典的话:
宁可99%的准确率在100毫秒内完成,也不要99.9%的准确率等用户一秒钟。
因此,线上系统更关注的是:
- 特征缓存(Redis、本地Cache)
- Embedding预计算
- ANN近似搜索
- 模型量化
- ONNX/TensorRT推理
- 异步特征加载
- 特征服务(Feature Store)
- 多级缓存
例如:
key = f"user:{user_id}:profile"
profile = redis.get(key)
if profile is None:
profile = load_from_feature_store(user_id)
真正成熟的平台,很多用户画像、商品画像都会提前计算好,而不是等请求来了再临时处理。这样既降低了数据库压力,也能保证推荐接口稳定地控制在几十毫秒级。
数据闭环,才是推荐系统真正的生命力
推荐结束,并不是结束。
真正优秀的推荐系统,一定会形成数据闭环:
曝光
│
点击
│
收藏
│
加购
│
购买
│
评价
│
日志回流
│
离线训练
│
模型更新
│
重新上线
举个例子,一个用户连续一周都在浏览露营装备,那么系统就应该逐渐提升相关商品的权重;如果用户突然开始关注婴儿用品,推荐策略也要尽快完成“兴趣迁移”。这背后依赖的不是某一个神奇模型,而是持续不断的数据反馈和模型迭代。
很多团队上线模型后就不再关注数据质量,结果用户行为发生变化,模型却还停留在几个月前的数据上,推荐效果自然越来越差。这也是为什么很多企业开始建设实时特征平台、实时训练和在线学习能力,让推荐系统真正具备“边学习边成长”的能力。
写在最后
这些年接触了不少推荐项目,我越来越认同一个观点:推荐系统本质上不是算法竞赛,而是一项系统工程。
真正决定效果的,不只是某个排名模型,也不是某篇论文里的新结构,而是召回是否全面、特征是否准确、排序是否合理、重排是否兼顾体验,以及整条数据链路是否能够快速反馈和持续优化。
很多团队把大量时间花在提升模型几个百分点的指标上,却忽略了日志采集、特征一致性、缓存命中率、在线延迟等基础能力。可在真实业务中,用户不会因为AUC提升了0.003而感知明显变化,却一定会因为推荐内容单一、页面加载缓慢或兴趣变化得不到响应而流失。
所以,如果你正在搭建一套电商个性化推荐系统,不妨把视野放宽一些:从召回、粗排、精排、重排到在线服务和数据闭环,每一个环节都值得认真打磨。 当整条链路协同运转时,推荐系统才能真正做到“既懂用户,又跑得快”,这也是现代大数据与AI融合最有价值的实践之一。