1. Look-Alike技术的前世今生:从广告到推荐
第一次听说Look-Alike这个词是在2016年的一次广告技术分享会上。当时一位来自某头部广告平台的技术负责人正在讲解他们如何帮助广告主精准触达目标用户。他举了个例子:某奢侈品牌想投放新品广告,但只有5万VIP客户数据,通过Look-Alike技术最终找到了50万潜在客户,投放ROI提升了3倍多。
这个案例让我印象深刻。后来在做推荐系统时,我发现新物品冷启动面临的问题简直如出一辙:一个新上架的物品,只有少量初始用户与之交互,如何快速找到更多可能喜欢的用户?于是我开始尝试将广告领域的Look-Alike技术迁移到推荐系统。
核心思想其实很简单:物以类聚,人以群分。无论是广告还是推荐,本质上都是在解决"如何找到相似人群"的问题。广告领域用种子用户(如已购买客户)找相似人群进行投放;推荐系统则用种子用户(如点击过新物品的用户)找相似人群进行推荐。
但具体实现上,推荐系统的Look-Alike有几点特殊之处:
- 动态性更强:广告的种子用户通常较稳定,而推荐系统的种子用户会随着物品曝光不断变化
- 实时性要求高:广告可以接受小时级更新,推荐系统通常需要分钟级响应
- 特征维度更丰富:除了用户画像,还要考虑用户行为序列、上下文特征等
2. 工程化落地的三大核心问题
2.1 种子用户的选择与处理
在小红书的实践中,我们发现种子用户的选择直接影响最终效果。最初我们简单地将所有有过正向交互(点击、点赞、收藏等)的用户都作为种子,结果发现效果并不理想。后来通过数据分析发现:
- 行为深度很重要:收藏用户的权重应该大于点赞用户,点赞用户权重大于点击用户
- 时间衰减很关键:最近3天的交互比1个月前的交互更有参考价值
- 异常用户要过滤:某些"点赞狂魔"用户会干扰种子群体的代表性
最终我们的种子用户处理流程如下:
def process_seed_users(item_id): # 获取最近7天有过交互的用户 raw_users = get_interacted_users(item_id, days=7) # 按行为类型加权 weighted_users = [] for user in raw_users: weight = 0 if user.has_clicked(): weight += 1 if user.has_liked(): weight += 3 if user.has_collected(): weight += 5 if user.has_shared(): weight += 8 weighted_users.append((user, weight)) # 过滤异常用户(交互频次超过3σ) mean = np.mean([w for _,w in weighted_users]) std = np.std([w for _,w in weighted_users]) filtered_users = [u for u,w in weighted_users if w <= mean + 3*std] return filtered_users2.2 用户相似度的计算艺术
计算用户相似度是Look-Alike的核心。我们尝试过多种方法:
基于用户画像的相似度:
- 优点:可解释性强
- 缺点:稀疏特征效果差,且很多用户画像不完整
基于协同过滤的相似度:
- 使用UserCF计算共同交互物品
- 问题:新物品的种子用户本身交互少,数据稀疏
基于Embedding的相似度:
- 使用双塔模型输出的用户向量
- 最终方案:结合短期行为序列和长期兴趣的混合向量
我们最终采用的方案是动态权重混合相似度:
sim(u1, u2) = α·sim_embedding(u1, u2) + β·sim_behavior(u1, u2) + γ·sim_profile(u1, u2)其中α、β、γ根据物品冷启阶段动态调整:
- 冷启初期(交互<100):α=0.8, β=0.2, γ=0
- 中期(100-1000):α=0.5, β=0.3, γ=0.2
- 后期(>1000):α=0.3, β=0.3, γ=0.4
2.3 近线更新与向量检索的工程实践
在线上服务时,我们遇到了几个关键挑战:
挑战1:特征向量实时性
- 初期方案:每天全量更新一次
- 问题:新物品黄金曝光期在前6小时,日更完全不够
- 解决方案:构建近线更新管道(更新延迟<5分钟)
挑战2:向量检索性能
- 需要支持:1000QPS,平均延迟<20ms
- 对比测试了多种向量数据库:
| 数据库 | 百万级检索延迟 | 准确率 | 内存占用 |
|---|---|---|---|
| FAISS | 15ms | 98% | 2GB |
| Annoy | 25ms | 95% | 1.5GB |
| HNSW | 10ms | 99% | 3GB |
最终选择HNSW作为线上引擎,并做了以下优化:
- 分层构建索引:热物品在内存,冷物品在SSD
- 异步刷新机制:每5分钟增量更新索引
- 动态剪枝:自动淘汰14天无交互的物品向量
3. 小红书的具体实现案例
3.1 整体架构设计
小红书的Look-Alike召回通道架构分为三个主要部分:
信号收集层:
- 实时消费用户行为日志
- 过滤无效交互(如误点击)
- 生成种子用户集合
特征计算层:
- 从用户特征库获取种子用户向量
- 计算加权平均向量作为物品表征
- 加入时间衰减因子(最近交互权重更高)
在线服务层:
- 向量检索服务(HNSW)
- AB测试分流
- 降级策略(当新物品无足够种子用户时)
3.2 关键参数调优
在灰度测试阶段,我们通过大量AB测试确定了最优参数组合:
种子用户数量阈值:
- <10:不启用Look-Alike(信号太少)
- 10-50:放宽相似度阈值(σ=1.5)
50:严格相似度阈值(σ=1.0)
向量更新策略:
- 初始冷启阶段:每新增5个种子用户触发更新
- 稳定阶段:每5分钟定时更新
- 爆款物品:每分钟强制更新
召回数量控制:
- 根据物品冷启阶段动态调整
- 公式:recall_num = min(50, max(10, sqrt(seed_users)*5))
3.3 效果评估与迭代
上线后关键指标变化:
| 指标 | 前7天均值 | 上线后变化 |
|---|---|---|
| 新物品CTR | 1.2% | +35% |
| 新物品7日留存 | 15% | +22% |
| 冷启时长 | 72小时 | 缩短至28小时 |
但我们也发现了一些问题:
- 某些垂类(如美妆)效果显著,但其他类目(如数码)提升有限
- 凌晨时段效果较差(可能与用户活跃度有关)
- 长尾物品的种子用户积累过慢
针对这些问题,我们做了以下优化:
- 类目差异化策略:美妆类降低相似度阈值,数码类增加内容特征权重
- 引入时间上下文:在用户向量中加入时段特征
- 结合内容特征:当行为信号不足时,用物品内容embedding辅助
4. 避坑指南与实用建议
在实际落地过程中,我们踩过不少坑,这里分享几个关键经验:
坑1:种子用户质量不均
- 现象:某些物品的种子用户都是低活用户,导致扩散效果差
- 解决方案:增加种子用户活跃度过滤,只选择月活≥15天的用户
坑2:冷启动阶段的"马太效应"
- 现象:少数物品获得大量曝光,多数物品得不到足够种子用户
- 应对策略:
- 设置单物品最大曝光上限
- 人工运营干预(给优质长尾物品初始流量)
坑3:特征穿越问题
- 发现:用未来数据计算历史相似度,导致离线评估虚高
- 修复:严格按时间切分训练/评估数据
对于想要尝试Look-Alike技术的团队,我的建议是:
- 从小场景开始:先选择一个特定类目或场景试点
- 监控种子用户质量:建立种子用户画像分析报表
- 动态调整策略:不同冷启阶段需要不同参数
- 结合其他召回方式:Look-Alike不是银弹,需要与内容召回、协同过滤等配合使用
最后分享一个实用技巧:当新物品完全没有种子用户时,可以用物品发布者的粉丝用户作为初始种子,这在小红书场景下特别有效,因为用户与创作者的关系往往暗示了兴趣偏好。