想象一下这样一幕:一家互联网公司突然空降了一位新同事小艾。主管看着他的入职简历,心里七上八下——这人到底擅长什么?该把他放进哪个项目组?拉他进核心团队吧,万一能力不匹配就翻车了;让他先打杂吧,又怕埋没了天才。更头疼的是,公司的内部系统里,没有任何关于他的历史绩效记录。 这就是推荐系统的“冷启动”困境。当一个新物品(新电影、新商品、新帖子)刚上架时,系统对它的了解少得可怜——没有点击、没有收藏、没有购买记录。本文要讲的,就是一套帮助系统快速认识新人的方法组合:先翻简历(内容 Embedding 召回)判断大致方向,再用老 HR 的经验(元学习)一眼猜出他的类型,最后通过试用期任务(Bandit 探索利用)边试边调,让新人快速释放价值。
冷启动是推荐系统的经典难题,掌握 Embedding 召回 + 元学习 + Bandit 的组合拳,是推荐算法工程师从“调参”走向“搭建冷启动系统”的关键一跃。
目录
可视化演示
展示内容Embedding新物品向量召回、元学习MAML少样本快速适应、Bandit算法探索利用权衡三大策略,通过模式切换理解冷启动问题的多维度解决方案。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Embedding召回:内容向量近邻检索 新物品通过内容特征(文本/图片)编码为高维Embedding向量 在向量空间中通过余弦相似度检索最近邻,实现零交互召回 sim(i,j) = cos(emb_i, emb_j) = emb_i·emb_j / (||emb_i||·||emb_j||) 内容Embedding让新物品在无交互数据时也能被有效召回
冷启动挑战:新同事的“黑盒”困局
新同事小艾第一天入职,主管打开内部系统想给他分配任务,结果发现他的档案几乎是空白的——没有过往项目、没有绩效记录、没有协作评价。主管懵了:我该信什么?推荐系统里,任何一个“新物品”上线时,系统面对的就是这样一个黑盒。
这种“没有历史交互数据”的困境,就叫冷启动。它分三类:物品冷启动(新商品没点击记录)、用户冷启动(新注册用户没有偏好)、系统冷启动(整个平台从零起步)。它们的共同病根是数据稀疏——模型没有样本可学,就像主管没有绩效记录可看。
工程师的突破口是“内容特征”:标题、标签、类目、封面图这些天生就有的信息,可以编码成数值向量,用来计算物品之间的相似度。最常用的度量是余弦相似度,它只看两个向量的“方向”是否一致:
有了这套“简历相似度打分”,主管至少能判断小艾和团队里哪位老员工风格最接近,从而推测他大概适合哪类项目。冷启动的第一块地基,就这样打下来了。
- 内容向量 x_i把物品 i 的标题、类目、图文等原始内容编码成一组数值,就像把简历的每条经历结构化。
- 点积运算对两个向量逐位相乘再求和,衡量它们在所有维度上的同步程度。
- 模长归一化用每个向量的长度去除,消除“篇幅长短”带来的干扰,只保留方向信息。
- 余弦相似度归一化后的点积,值域在 [-1, 1],越接近 1 表示内容越相似。
内容Embedding召回:翻简历定方向
主管拿到小艾的简历后,第一件事不是逐字细读,而是快速浏览关键词、项目标签、作品方向,在脑海里把小艾归入“营销型”或“算法型”候选池。这一步粗筛,在推荐系统里叫“召回”。
Embedding 就是把内容“嵌入”到一个低维向量空间,让语义相近的内容彼此靠近。业界常用的双塔模型(DSSM)有左右两座塔:一座编码用户侧信息,一座编码物品侧信息,两边各自产出向量,再用内积算匹配分。新物品没有交互,就把内容特征灌进物品塔,照样能算出它与用户的匹配度:
离线把海量新物品的内容向量建好索引(比如用 Faiss),线上收到用户请求时做最近邻检索,几十毫秒就能拉回 Top-K 候选。主管把几百份简历粗筛成五个人,小艾成功进入了面试池——但池里五个人,到底该录用谁?这就要靠下面的“老 HR 直觉”和“试用期观察”了。
- 用户塔输出 q把用户近期的点击序列与画像特征编码成查询向量,好比主管手头的一沓“项目需求简报”。
- 物品塔输出 k把新物品的标题、类目、图文内容编码成待匹配向量,好比小艾的简历摘要。
- 余弦匹配分数对 q 与 k 做归一化内积,分数越高说明“简历越对口”。
- Top-K 截断对全部新物品算完分后,只保留最高分的 K 个进入下一环节。
元学习快速适应:老HR的直觉
如果一位带过两百名新人的老 HR 在场,他只需聊五分钟就能大致预判:这孩子是“稳健执行型”还是“脑洞创新型”,该从严培养还是放手试错。这种“见过大量新人后沉淀出的识人直觉”,就是元学习。
元学习(Meta-learning)研究的是“学会如何学习”。对推荐系统来说,每个新物品都是一次“新的学习任务”:物品刚上架,只有少量数据,需要一个能快速适应的模型。MAML(Model-Agnostic Meta-Learning)是其中最经典的算法,它训练的不是某个任务上的参数,而是一组“初始化参数”——就像老 HR 的大脑被无数新人的成长轨迹打磨过,遇到新面孔时,只要一两次观察就能微调出准确的判断:
老 HR 面试完两百个人后,他的识人心法不断被校准。如今面对小艾,他看了一眼简历和五分钟对话,心里就有了七八成把握。但把握再大,也要经过试用期验证——这就进入了探索与利用的博弈。
- 内循环更新用任务 τ_i 的少量样本对参数 θ 做一步梯度下降,得到“先试试”的临时参数 θ',相当于 HR 用五分钟面试对初始判断做微调。
- 临时参数评估每个任务在 θ' 上的损失,代表“快学一步之后的效果”。
- 外循环求和把所有任务上“快学后的损失”加起来,让初始参数在“快学一步”这件事上总体最好。
- 元参数更新对初始参数 θ 做梯度更新,让“学习能力”本身越变越强。
探索利用博弈:试用期的两难
小艾正式进组了。主管面临一个两难:直接让他负责核心项目(利用),万一能力不够,项目就毁了;让他先做无关痛痒的杂活(探索),虽然安全,但试不出真实能力,还可能让天才耗尽耐心。
这就是经典的“探索-利用困境”(Exploration vs Exploitation,EE)。推荐系统里,“利用”是推荐当前最看好的老爆款,“探索”是推荐一些不确定但可能成为新爆款的物品。冷启动的新物品恰恰需要探索来收集反馈,但探索太多,推荐质量下降、用户体验变差;探索太少,新物品永远没有出头之日。
最简单的策略是 ε-greedy:以 ε 的概率随机探索,否则选当前最优。进阶的思路是用“不确定性”驱动探索——哪个物品的置信上界高,就优先展示哪个。上界由两部分组成:当前的平均收益加上一个随尝试次数衰减的探索红利:
主管的试用期策略不是一成不变:前期多安排不同任务观察小艾(探索加成大),后期小艾能力清晰后就把核心任务集中给他(加成衰减,转为利用)。
- 平均奖励估计每个臂目前观察到的平均点击率,好比主管对新人的现有绩效印象。
- 不确定性加成被尝试次数 n_a 越少,根号值越大,鼓励优先把机会给“还看不太准”的臂。
- 乐观总分均值加不确定度,形成“乐观估计”,每一轮选择上限最高的臂。
- 衰减平衡时间 t 越久,所有臂都被尝试过,探索加成整体变小,系统越来越偏向利用。
Bandit算法家族:动态调兵遣将
同样是“试用期观察”,不同主管有不同风格。激进派喜欢“谁上限高就重点培养谁”——这像 UCB 策略;稳健派习惯“心里给每个人打个概率分,再按概率抽签”——这像汤普森采样;数据派还会把学历、内推等背景信息也纳入判断——这就成了 LinUCB。
Bandit 问题又叫“多臂老虎机”:一排老虎机(臂),每拉一次摇臂得到一个随机奖励,问题是如何在有限次的拉臂中最大化总收益。推荐系统里,每个候选物品是一条臂,点击就是奖励。Bandit 算法天然适配冷启动——因为它在反馈不足时主动设计实验,用实时反馈快速收敛:
不同主管风格没有绝对好坏:UCB 更快聚焦潜力股但可能错失“慢热型”员工;汤普森采样更平稳;LinUCB 把简历特征也用上了,是“经验+数据”双驱动。聪明的团队会按业务特性选择。
- 特征预测项把物品内容特征 x 与参数 θ 做内积,直接读出“潜力分”,对应 HR 结合简历背景做评估。
- 协方差矩阵记录臂 a 历史特征的外积累加,样本越多矩阵越“厚”,不确定度越小。
- 置信区间项xᵀ A⁻¹ x 是当前信息量下的方差估计,开根号后就是边界宽度,越没验证过的特征越宽。
- 贪心选臂取“潜力+不确定度”最大的臂,兼顾评估与弥补未知。
策略组合实战:完整入职流程
成熟公司的 HR 部门不会单打独斗,而是把几招串成一套标准流程(SOP):第一步翻简历初筛(Embedding 召回),第二步老 HR 预判类型(元学习初始化),第三步试用期动态调岗(Bandit 探索),第四步转正定岗集中资源(收敛利用)。四步环环相扣。
真实推荐系统也是如此:新物品上线后先走内容 Embedding 召回进入候选池;再用元学习训练出的模型给一个预测初始分(而不是从零开始);展示阶段由 Bandit 模块控制探索流量,边收集反馈边更新;数据积累到阈值后,模型切回常规精排,把新物品当老物品对待。
工程上三个模块如何协同是关键。实践中的做法是在排序层给新物品注入一个“探索加成项”,总得分写成三部分的加权和:
完整 SOP 让主管不再靠拍脑袋:初筛保证候选人池里没有离谱的人,HR 直觉让起点不至于太低,试用期制度让潜力股不被埋没,转正集中资源让能力最大化变现。新员工从入职到独当一面,时间被压缩到最短——这正是冷启动策略组合的意义。
- Embedding 相似度分内容与用户偏好的匹配度,保证“方向对”。
- 元学习预测分用跨场景学到的快速适应模型输出预估点击率,保证“起点高”。
- Bandit 探索加成根据当前观测不确定性动态增减,保证“机会均等”。
- 加权融合α、β、γ 控制三个信号的比例,线上用在线调参不断迭代。
AI 应用场景
场景一:内容社区新笔记冷启动
阶段:召回 → 探索 → 精排
解决的问题:新笔记发布后头几十分钟没有互动,若按老笔记的排序逻辑分发,新内容会永远沉没。传统做法是人工加权或统一加曝光,既慢又容易误伤。
具体案例:某美妆社区一篇新品教程发布后,系统用内容 Embedding 把笔记召回到 1000 个“近期关注美妆”的用户池里,再用汤普森采样在 5% 的曝光中试行,若点击率超过阈值则逐步递增流量至全量分发。新笔记的冷启动周期从 3 天缩短到 6 小时。
场景二:电商新品起量
阶段:特征编码 → 元学习预测 → Bandit 调优
解决的问题:新品无销量、无评价,CTR 模型预测方差大;固定加权容易给烂品过多流量,不给量又会漏掉爆款。
具体案例:某智能音箱新品上架,商品塔用标题与属性图产出一个内容向量,元学习模型给出初始预估点击率,再用 UCB 控制前 1000 次曝光去探索,等数据积累到 500 次点击后切回常规精排。该爆款起量速度比同类快 40%。
场景三:广告新素材试投
阶段:Embedding 相似匹配 → Bandit 预算分配
解决的问题:信息流广告平台的新素材没有历史转化数据,直接大预算投放风险高,人工试投又太慢。
具体案例:广告主上传三组新视频素材,系统先用内容 Embedding 匹配历史最优素材库预估基础 CTR,再用 ε 衰减策略从高探索率逐步过渡到利用,实时回流点击与转化信号决定是否加预算。最终用总预算的 12% 换来了 90% 的消耗确定性。
Python 演示
import numpy as np class UCBBandit: def __init__(self, n_arms): self.n_arms = n_arms self.pulls = np.zeros(n_arms) self.rewards = np.zeros(n_arms) self.t = 0 def select(self): scores = np.empty(self.n_arms) for i in range(self.n_arms): if self.pulls[i] == 0: scores[i] = float('inf') else: mu = self.rewards[i] / self.pulls[i] bonus = np.sqrt(2 * np.log(self.t + 1) / self.pulls[i]) scores[i] = mu + bonus return int(np.argmax(scores)) def update(self, arm, reward): self.pulls[arm] += 1 self.rewards[arm] += reward self.t += 1 def embedding_recall(user_vec, item_vecs, top_k=5): user_norm = user_vec / (np.linalg.norm(user_vec) + 1e-8) item_norms = item_vecs / (np.linalg.norm(item_vecs, axis=1, keepdims=True) + 1e-8) scores = item_norms @ user_norm top_idx = np.argsort(scores)[::-1][:top_k] return top_idx, scores[top_idx] def simulate_cold_start(n_items=50, n_rounds=500, dim=16, top_k=5): rng = np.random.default_rng(42) user_vec = rng.normal(size=dim) item_vecs = rng.normal(size=(n_items, dim)) true_ctrs = rng.uniform(0.05, 0.4, size=n_items) cand_idx, _ = embedding_recall(user_vec, item_vecs, top_k) bandit = UCBBandit(top_k) for _ in range(n_rounds): arm = bandit.select() reward = 1 if rng.random() < true_ctrs[cand_idx[arm]] else 0 bandit.update(arm, reward) ctr_est = bandit.rewards / np.maximum(bandit.pulls, 1) return cand_idx, ctr_est, bandit.pulls if __name__ == '__main__': cand, est, pulls = simulate_cold_start() for rank, idx in enumerate(cand): print('Top{} item{} ctr={:.2f} pulls={}'.format( rank + 1, idx, est[rank], int(pulls[rank])))
scores = item_norms @ user_norm用向量内积一次性算出所有物品与用户的内容相似度,对应正文里的 Embedding 召回。if self.pulls[i] == 0: scores[i] = float('inf')从未被选过的候选获得最高优先级,保证探索不会漏掉任何人。bonus = np.sqrt(2 * np.log(self.t + 1) / self.pulls[i])探索红利项:选中次数越少,加成越大。reward = 1 if rng.random() < true_ctrs[cand_idx[arm]] else 0用真实点击率模拟用户反馈,驱动 Bandit 更新。ctr_est = bandit.rewards / np.maximum(bandit.pulls, 1)归一化得到每个候选的点击率估计,冷启动后交给精排使用。
常见误区
误区既然内容 Embedding 能算出相似度,直接把最相似的物品推给用户不就行了吗?为什么还要搞 Bandit 探索?
正解内容相似只能说明“外貌像”,不能说明“内在好”。一部电影的预告片风格像爆款,正片却可能烂尾,只有实际点击和完播率才能暴露真实质量。Embedding 解决的是“从哪找新人”的问题,EE/Bandit 解决的是“如何验证新人”的问题,二者缺一不可。
为何常见:Embedding 的效果直观可见,容易让人误以为“相似 = 优质”,忽略了内容质量存在信息衰减。
误区元学习不就是把老数据训练的模型拿来当初始值吗?这和迁移学习有什么区别?
正解迁移学习确实复用初始化,但元学习更进一步:它的初始参数是专门为“快速适应”优化的,训练目标不是老任务效果最好,而是“新任务上快学几步后效果最好”。好比普通主管的经验来自个人经历,而 MAML 得到的初始参数是被上千个任务的“学习过程”训练出来的。
为何常见:两者都有“预训练 → 微调”的外壳,表象相似导致混淆。
误区UCB 公式里有 argmax,每轮都选上限最高的臂,这不就是贪心吗?
正解贪心只选当前平均收益最高的臂,UCB 在均值上加了一个随选择次数递减的“探索红利”——未被充分验证的臂会因为不确定度高而获得额外加分。随着数据积累,红利收缩,才逐渐过渡到纯利用。
为何常见:只盯着 argmax 的形式,忽略了公式中不确定性项的主导作用。
误区新物品没反馈,那就把探索概率调高一点,让新物品快速积累数据。
正解探索不是免费的。ε-greedy 中 ε 越高,推荐精度越差,用户体验和收入直接受损,甚至因大量无效曝光让新物品的“坏印象”被错误累积。成熟做法是用 UCB 或汤普森采样把探索“定向”到不确定性高的物品上,而非无差别随机。
为何常见:直观上认为“多试就能快”,没有把探索的机会成本算进账。
误区有了 Bandit 算法,就不用训练 CTR 模型了,让它自己去探索就行。
正解Bandit 擅长“少量臂、快速反馈”的小规模在线决策,而正式推荐的精排模型需要处理海量物品、复杂特征与长期序贯依赖。实践中 Bandit 通常只作为冷启动阶段的“探索插件”叠加在 CTR 模型之上,数据积累后立即退场,而不是替代模型。
为何常见:Bandit 在论文里看起来很“自适应”,让人误以为它能取代深度学习模型。
面试题
Q1. 推荐系统里的“冷启动”核心困境是什么?
- A.服务器资源不足模型跑不动
- B.新物品新用户缺乏历史数据← 正确答案
- C.推荐算法太简单效果不佳
- D.用户增长太快系统不稳定
答案:B。冷启动的本质是“数据冷”:新物品没有点击、新用户没有行为历史,模型无从下手。服务器资源与算法复杂度属于工程和模型问题,用户增长过快也不是冷启动的本体问题。
Q2. 内容 Embedding 在新物品召回中的角色是什么?
- A.直接预测新物品的点击率
- B.把内容编码成向量做相似检索← 正确答案
- C.替代排序模型做最终打分
- D.记录用户的所有历史行为
答案:B。Embedding 将标题、类目等内容编码成稠密向量,召回阶段靠向量相似度把新物品捞进候选池。点击率预测和最终排序是下游环节,Embedding 本身不承担这些任务。
Q3. MAML 元学习的核心思想是什么?
- A.用大模型蒸馏出小模型
- B.学习快速可适应的初始参数← 正确答案
- C.收集更多标注数据来训练
- D.用强化学习替换监督学习
答案:B。MAML 采用双层优化:内层在新任务上快学几步,外层让初始参数在“快学后的表现”上最优——也就是学会学习。蒸馏、扩数据、替换学习范式都与 MAML 的训练目标无关。
Q4. UCB 公式中 √(2ln t / n_a) 的作用是什么?
- A.让被选次数多的臂获得更高加成
- B.给不确定性高的臂额外探索红利← 正确答案
- C.消除随机噪声对结果的影响
- D.压平平均奖励的波动幅度
答案:B。n_a 越小,根号值越大,意思是“被了解得越少,越值得再试一次”。它给不确定性附加探索加分。A 说反了方向,C 和 D 与公式的实际作用无关。
Q5. 汤普森采样的核心机制是什么?
- A.每轮选择平均奖励最高的臂
- B.从每个臂的奖励分布中采样再比较← 正确答案
- C.按固定概率随机切换所有臂
- D.把所有臂的奖励求平均分给每个臂
答案:B。汤普森采样为每个臂维护一个后验分布(如 Beta 分布),每轮从各分布中采样,选采样值最大的臂。它通过分布宽度自然兼顾均值与不确定性,而非只看均值或纯随机。
Q6. LinUCB 相比标准 UCB 的最大改进是什么?
- A.使用了深度神经网络替代线性模型
- B.用物品特征向量参与置信区间计算← 正确答案
- C.不再需要任何用户反馈信号
- D.把探索概率固定为不变常数
答案:B。LinUCB 假设奖励与特征之间存在线性关系,把置信区间推广为 xᵀA⁻¹x 的形式,让“特征上更像好物品”的臂获得更紧凑的置信上界。它不是深度模型、不能没有反馈、也不固定探索率。
Q7. 冷启动全链路中 Embedding 召回与 Bandit 探索是什么关系?
- A.两者功能重叠只需保留一个
- B.召回提供候选集探索负责验证← 正确答案
- C.召回与探索在同一层工作
- D.两者互斥不能同时部署
答案:B。Embedding 把“看起来值得试”的新物品捞出(候选从哪来),Bandit 在候选池内分配试错流量(哪个值得给量)。它们分属不同链路层级,配合而非互斥。
Q8. 以下哪些属于冷启动问题的常见类型?
- A.物品冷启动新商品无数据← 正确答案
- B.用户冷启动新用户无偏好← 正确答案
- C.系统冷启动平台从零开始← 正确答案
- D.内容特征冷启动非主流类型
答案:ABC。冷启动的三大经典类型是物品、用户与系统冷启动。内容特征不是冷启动的类型,它恰恰是缓解冷启动的手段——用内容特征弥补交互数据的缺失。
Q9. 关于 ε-greedy 策略,下列说法正确的有?
- A.以一定概率随机探索其余利用← 正确答案
- B.探索比例越高推荐精度越差← 正确答案
- C.探索比例必须固定不可调整
- D.属于多臂老虎机的简单策略← 正确答案
答案:ABD。A 是 ε-greedy 的定义,B 是探索与利用的代价权衡,D 说明它属于 Bandit 策略家族。C 错误:ε 既可以随时间衰减,也可以自适应调整,没有“必须固定”的限制。
Q10. 关于 MAML 的两层优化,下列说法正确的是?
- A.内层在单个任务上快速梯度更新← 正确答案
- B.外层汇总所有任务的快学结果← 正确答案
- C.内层更新步数越多元学习越好
- D.外层目标是让初始参数快速适应← 正确答案
答案:ABD。A、B 是 MAML 内外两层的结构定义,D 是整体训练目标。C 错误:内层更新步数过多会让元梯度失效(退化为在任务局部最优上做文章),并不是越多越好。