每年秋天,老张都会去同一家川菜馆。他有个雷打不动的规矩:十次点菜,九次点最爱的水煮鱼,剩下一次闭着眼睛乱点一个从没吃过的菜。妻子笑他:“都吃十年了,你还试什么?”老张却说:“只吃水煮鱼,我永远不知道新来的师傅把回锅肉炒得有多香;可要是回回都乱点,我可能连吃一礼拜难以下咽的菜。”守住心头好,还是冒险尝一次鲜?这个两难,就是“探索与利用”的困境。 推荐系统每天都在替千万个“老张”点菜。纯按历史行为推荐用户喜欢的内容,点击率好看,用户却很快被锁进信息茧房;一味推荐新奇内容,用户又因为看不到想看的而流失。如何花最小的代价探清新兴趣、又不放弃已知的偏好?本文用“点菜”这个隐喻,带你拆解三种经典策略:掷骰子式的 Epsilon-greedy、乐观打分式的 UCB,以及贝叶斯“心里过一遍”的汤普森采样,最后聊聊探索率衰减与上下文感知探索。
探索利用策略是推荐系统打破信息茧房、应对冷启动的核心武器,掌握 Epsilon-greedy / UCB / Thompson 的取舍,是推荐算法工程师解决“多样性 vs 点击率”矛盾的必修内功。
可视化演示
推荐系统在探索新兴趣与利用已知偏好间权衡:Epsilon-greedy随机探索,UCB用置信上界,Thompson采样后验分布。切换步骤对比三种策略。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Epsilon-greedy策略 以ε概率随机探索,1-ε利用最优 探索强度越高,短期收益越低 a=argmax Q(a) w.p. 1-ε ε衰减可平衡探索与利用
两难困境本质
老张的难题,本质上是“胃”和“菜单”的矛盾:胃只有一个,菜单却无穷无尽。点水煮鱼,这顿稳了,却可能错过新师傅的回锅肉;点回锅肉,万一翻车,这顿就毁了。推荐系统面对的是同样的问题——每一次给用户推什么内容,都在“利用已知偏好”和“探索未知兴趣”之间二选一。
在推荐系统里,“利用”指依据用户历史行为选择点击概率最高的内容,短期指标好看;“探索”指主动尝试低频、冷门或没有历史记录的内容,短期可能点击率下滑,但能换回“用户到底喜欢什么”的新信息。困境在于:信息本身有成本,每次决策只能顾一头。如果永远利用,用户看到的全是同类内容,逐渐被困进信息茧房;如果永远探索,用户天天看到不感兴趣的东西,很快流失。
为了量化“探索的代价”,业界引入“遗憾”(Regret)的概念:假设有一个上帝视角的“最优策略”,每轮都点最好的一道菜,我们与它的差距就是遗憾。
回到老张的饭桌:遗憾就是每次闭眼点新菜后,心里那句“早知道还是点水煮鱼”。推荐算法的目标不是消灭遗憾——只要探索,遗憾必然存在;而是让同样多的遗憾,换来尽可能多的新认知。
- 最优收益 r\*上帝视角下最好那道菜的期望美味度,相当于“全菜单最好吃的一道菜”。
- 理想总收益若每轮都点最棒的那道菜,T 顿饭后累积的完美收益。
- 实际累计收益我们策略真实吃到的 T 顿饭收益总和,探索踩的坑都会扣在这里。
- 遗憾差值二者相减,就是“因为不知道哪道菜最好而错过的美味”。
Epsilon贪心
老张的“十次九次水煮鱼、一次乱点”,是个人类版的 ε-greedy。这里的 ε 就是那个“乱点”的概率——比如 0.1,意味着十次里有一次彻底交给命运。推广到推荐系统,策略变成:以 ε 的概率随机推荐一个冷门或新内容,以 1−ε 的概率推荐当前模型打分最高的内容。
这个策略的数学描述非常简单。假设 Q_t(a) 是到第 t 轮为止,动作 a(比如推荐某篇新闻)获得的平均反馈分数,“当前最优”就是分数最高的动作:
ε-greedy 像一把公平的骰子:它不歧视任何一道没吃过的菜,哪怕是九成概率难吃的怪味汤,也会被随机翻牌。公平是优点,也是缺点——聪明人不会把宝贵的胃浪费在明显可疑的菜上。下一节的 UCB,正是给这张骰子装上了“方向感”。
- 平均反馈 Q_t(a)动作 a 到目前为止的历史平均得分,好比“这道菜的历次好评率”。
- argmax 取最优在候选动作里挑分数最高的那个,对应“点评分最高的菜”。
- 1−ε 利用大部分轮次按最优解来,保障短期收益不崩盘。
- ε 随机探索小概率完全随机,让每个没试过的菜都有机会被端上桌。
UCB置信上界
老张慢慢发现,光靠“随机”尝鲜太亏了。于是他换了思路:每道菜在他心里不是固定分数,而是一个“信心区间”。水煮鱼试过一百次,区间窄得像一根线;回锅肉只试过两次,区间宽得能装下整张菜单。他给自己定下规矩:每次优先点“区间上限”最高的菜——回锅肉的区间上限要是超过了水煮鱼,就值得再试一次。
这就是 UCB(Upper Confidence Bound,置信上界)的核心:给每个动作的估计值加一个“不确定性奖励”,试得越少、奖励越大,从而把探索集中到“有潜力但还没验证”的选项上。公式如下:
UCB 是“有原则的乐观”:它不盲目,每次尝新都是因为那道菜的上限确实值得期待;它也不固执,一旦某道新菜试了几次仍平平无奇,信心区间会迅速收窄,老张果断回归水煮鱼。比起掷骰子,UCB 把每一次探索都花在刀刃上。
- 平均分 Q_t(a)这道菜当前的好评均值,代表“已知信息”。
- 试吃次数 N_t(a)动作 a 被选择的次数,分母越大,不确定性越小。
- 对数时间 ln t总轮数 t 取对数,保证不确定性不会因为重复试验而彻底消失。
- 乐观加分项试得越少的菜,加分越多;试得越多,加分趋近于零,最终回归均值排序。
汤普森采样
再后来,老张进化出一套更高级的心理模型:他对每道菜都保存了一条“美味度分布曲线”。水煮鱼试过几百次,曲线又尖又细,稳稳锁在 9 分;回锅肉只试过两次,曲线又矮又胖,从 2 分一直拖到满分。每次点菜前,他闭眼从每道菜的曲线里各抽一个值,谁抽出来的数大就点谁。
这就是汤普森采样(Thompson Sampling):为每个动作维护一个“参数的后验分布”,每次决策时从分布里抽样,按抽样结果选最大的。优点是它天然做到“概率匹配”——一道菜是真正最优的概率有多高,被点中的概率就有多高。
汤普森采样的妙处在于不用人为调“乐观系数”,分布的形状自己会说话:没验证的菜曲线又矮又胖,“爆冷抽中”的概率天然更高;已验证的菜曲线又尖又细,赢了也赢得有限。老张不再需要记住复杂的规则,只需要一个会抽签的大脑。
- Beta 后验分布用 Beta(α, β) 刻画“这道菜真好吃”的概率分布,α 大则曲线右移,β 大则曲线左移。
- 反馈计数更新点完菜后好评给 α 加 1,差评给 β 加 1,曲线随之更新。
- 从分布抽样每轮从每条曲线抽一个瞬时“美味度”,矮胖曲线偶尔会抽出高分值。
- 按抽样排名抽到最大 θ 的动作获得这次决策权,实现“不确定性越大越容易被选中”。
探索率衰减
老张六十岁后,发现自己的舌头越来越“念旧”——年轻时逢新必试,现在十次里难得乱点一次。这不是坏事:几十年积累让他对菜单了如指掌,新菜翻车概率也见识够了,把胃留给最稳的菜是理性的选择。推荐系统同理:冷启动阶段对用户一无所知,需要高探索;跑久了历史数据充足,探索的边际价值自然下降。
把这种直觉写成公式,就是探索率衰减:让 ε 随轮数 t 指数下降。常用的指数衰减形式如下:
但要警惕:衰减到 0 不等于万事大吉。现实世界没有静止的菜单——饭店会换师傅、会推新菜,用户口味也会漂移。所以工程上普遍给探索率设一个下限 ε_min(比如 0.01),保证系统永远保留“万一”的机会。老张也一样:嘴上说念旧,遇到新招牌菜,照样会不动声色地加一单。
- 初始探索率 ε₀系统刚启动或新用户冷启动时的探索强度,通常设 0.2~0.5。
- 衰减因子 γ接近 1 衰减慢、接近 0 衰减快,控制“经验积累后多快转向利用”。
- 指数降温t 增大时 γᵗ 指数趋近 0,探索率从 ε₀ 平滑滑向 0。
上下文感知探索
老张的“乱点”其实是看心情的:雨天想喝汤,他就去试没喝过的汤;夏天想清爽,他敢尝试凉拌新菜;请客吃饭,他绝不冒险,只点最有把握的招牌。同样是探索,方向完全不同。推荐系统也该如此——不同用户、不同场景、不同时刻,探索的策略应该不同,这就是上下文感知探索。
纯粹的 ε-greedy 对所有用户一视同仁地随机,而上下文感知探索把“用户是谁、在什么时间、什么设备上”这些特征塞进决策。最有代表性的是 LinUCB:它用特征线性模型预估每个候选内容的收益,同时为每个内容维护一个随数据更新的协方差矩阵,算出“上下文相关的置信区间”,再按上界排序:
于是探索不再是“瞎碰运气”,而是“猜哪里可能有惊喜”:深夜刷视频的用户,可以多推一点小众纪录片;刚注册的新用户,可以多点开未知领域。老张若是年轻二十岁,大概也会一边翻菜单,一边念叨:“今天这天气,适合试那道新上的酸汤鱼。”
- 特征向量 x把用户时段、内容类别、设备等编码成数值向量,相当于“这顿饭的天气和心情”。
- 线性预估 xᵀθ̂特征与权重内积,得到这个上下文下该动作的预估收益。
- 协方差逆 A⁻¹动作 a 历史数据的协方差矩阵之逆,数据越多、越自信,该项越小。
- 上下文置信区间结合当前特征算出的不确定性宽度,控制探索幅度。
AI 应用场景
新闻 App 新用户冷启动
阶段:冷启动策略 / 内容召回
解决的问题:新用户没有行为历史,纯热门推荐冷冰冰,纯随机推荐点击率惨淡。传统做法是推全站热门,结果新用户看到的都是大众爆款,既留不下印象,也探索不出个性。用带探索的 bandit 策略,可以在“快速摸清口味”和“保证基本体验”之间找平衡。
具体案例:一款资讯 App 对新注册用户使用 ε=0.3 的 ε-greedy 跑前 200 次请求,其中 30% 的流量在几十个内容类别间随机试探;同时用 UCB 给每个类别维护点击均值与置信区间,探索方向自动偏向“试得少但上限高”的类别。三天后用户画像成型,ε 衰减到 0.05,转入正常利用模式。
电商新品曝光与流量分配
阶段:排序层 / 流量调控
解决的问题:新品没有点击数据,按 CTR 排序永远排不进去,“好酒也怕巷子深”。传统做法是人工给新品加固定曝光位,既不科学也浪费流量。用汤普森采样给每个新品维护 Beta(好评,差评) 分布,自动决定曝光配额,新品有翻身机会,烂品快速降温。
具体案例:某电商平台的“新品气泡位”用 Thompson Sampling 决定展示概率:上架第一天每个新品都是 Beta(1,1) 均匀分布,曝光机会均等;随着加购和点击反馈回流,表现好的新品分布右移、获得更多曝光,表现差的自然沉底。上线后新品动销率提升约 18%。
视频推荐防信息茧房
阶段:策略调优 / 重排
解决的问题:纯 CTR 优化让用户永远看到同类视频,留存率和时长长期走低。传统做法是人工挑一批“调性内容”强行插入,简单粗暴且打扰用户。用上下文感知探索,把“深夜、通勤、周末”等场景特征和“用户近期观看多样性”作为上下文,动态决定探索强度。
具体案例:某视频平台发现用户连续看同品类超过 20 条后,对该用户上调探索权重,用 LinUCB 在“影视解说、纪录片、小众游戏”等低曝光品类中挑选候选,插入信息流第 5 和第 12 位。结果显示探索带来的次留率提升高于点击率的小幅下降,长期收益为正。
Python 演示
import numpy as np class Bandit: """三臂老虎机: 每个臂有一个真实的中奖概率, 算法看不到""" def __init__(self, true_probs): self.true_probs = np.array(true_probs) self.K = len(true_probs) self.Q = np.zeros(self.K) # 平均收益估计 self.N = np.zeros(self.K) # 每个臂被拉的次数 self.t = 0 # 总步数 def pull(self, a): reward = 1.0 if np.random.rand() < self.true_probs[a] else 0.0 self.N[a] += 1 self.Q[a] += (reward - self.Q[a]) / self.N[a] self.t += 1 return reward def choose_epsilon_greedy(bandit, epsilon=0.1): if np.random.rand() < epsilon: return np.random.randint(bandit.K) return int(np.argmax(bandit.Q)) def choose_ucb(bandit, c=1.0): if np.any(bandit.N == 0): return int(np.argmin(bandit.N)) bonus = c * np.sqrt(np.log(bandit.t + 1) / bandit.N) return int(np.argmax(bandit.Q + bonus)) def choose_thompson(bandit): alpha = 1.0 + bandit.N * bandit.Q beta = 1.0 + bandit.N - bandit.N * bandit.Q samples = np.random.beta(alpha, beta) return int(np.argmax(samples)) def run_once(strategy, T=2000, epsilon=0.1, c=1.0): bandit = Bandit([0.3, 0.5, 0.8]) total = 0.0 for _ in range(T): if strategy == 'eps': a = choose_epsilon_greedy(bandit, epsilon) elif strategy == 'ucb': a = choose_ucb(bandit, c) else: a = choose_thompson(bandit) total += bandit.pull(a) return total if __name__ == '__main__': for name in ['eps', 'ucb', 'thompson']: avg = np.mean([run_once(name) for _ in range(50)]) print(name, '平均累计收益:', round(avg, 1))
self.Q[a] += (reward - self.Q[a]) / self.N[a]增量式平均:把新奖励逐步揉进历史均值,无需存全部历史数据。if np.random.rand() < epsilon: return np.random.randint(bandit.K)掷骰子:小概率随机挑臂,这就是 ε-greedy 的探索。bonus = c * np.sqrt(np.log(bandit.t + 1) / bandit.N)试得次数越少的臂,不确定性加分越大,UCB 的“乐观”来源。np.argmax(bandit.Q + bonus)按“平均分 + 加分”的总分排序,选出本轮的动作。alpha = 1.0 + bandit.N * bandit.Q用累计奖励近似 Beta 分布的 α 参数(成功次数)。samples = np.random.beta(alpha, beta)从每条后验分布抽样,让概率分布自己说话。bandit = Bandit([0.3, 0.5, 0.8])三臂真实中奖率,只用来生成奖励,算法永远看不到。np.mean([run_once(name) for _ in range(50)])重复 50 轮取平均,抵消随机波动后再对比策略优劣。
常见误区
误区既然探索能发现新兴趣,那把 ε 调到 0.5 甚至更高,用户岂不是天天有惊喜?反正系统要的是长期价值,多探索没坏处。
正解探索是有成本的。ε=0.5 意味着每两次推荐就有一次完全随机,这些流量大概率点击率崩盘,用户还没等到“惊喜”就先流失了。真正高效的探索应该像 UCB 那样集中在“值得试”的选项上,而不是对全部选项无差别撒网。
为何常见:只看到探索解锁新兴趣的收益,没核算随机探索的期望损失——样本效率被忽略了。
误区UCB 计算的“置信上界”听起来很权威,那它选出来的应该就是全局最优的那个菜,跟着它点准没错。
正解上界是“乐观估计”而不是真实分数。UCB 选的是“上限最高的选项”,本质是在利用与不确定性之间取平衡,早期仍可能被高波动的假数据带偏。它的价值不在单次准确,而在于长期遗憾有理论保证,收敛到最优。
为何常见:把“上界最大”误当成“期望最高”,混淆了探索信号和利用信号。
误区贝叶斯后验更新要维护完整分布,线上每秒几万次请求,算力根本撑不住,这方法只能活在论文里。
正解伯努利奖励下 Beta 分布是共轭先验,只需维护 (α, β) 两个计数器,更新是常数级开销;更复杂的模型也有变分推断、重参数化等近似手段。Netflix、谷歌等公司都有大规模落地案例。
为何常见:课本先讲抽象贝叶斯理论,容易让人误以为部署成本高不可攀,忽略了共轭先验带来的工程简化。
误区系统跑得够久、数据够多了,把 ε 直接降成 0,从此只做利用,反正用户口味已经摸透了。
正解用户兴趣会漂移、内容池会更新、新品不断上架,静态的最优很快变成动态的次优。工程上普遍设 ε_min 保底探索,或用 UCB 这类自带不确定性的策略兜底,让系统永远保留一条“发现新可能”的通道。
为何常见:把“收敛”理解成“终态”,忘了推荐系统是开放动态环境,菜单永远在变。
面试题
Q1. 推荐系统出现信息茧房,最可能的原因是?
- A.过度利用用户已知偏好← 正确答案
- B.过度探索未知新内容
- C.用户对推荐完全不信任
- D.线上模型训练速度太慢
答案:A。信息茧房是“永远只推荐用户喜欢的内容”导致的恶性循环,即过度利用、缺乏探索。探索不足时,用户看不到圈外内容,认知被锁死,正如老张十年只点水煮鱼,从不知道回锅肉有多香。B 是过度探索,会导致体验下降而非茧房。
Q2. Epsilon-greedy 中 ε=0 时,算法会怎么做?
- A.永远随机探索新内容
- B.永远选择当前最优动作← 正确答案
- C.以一半概率选择最优动作
- D.完全停止推荐服务
答案:B。ε 是随机探索概率,ε=0 意味着从来不掷骰子,每次都选当前平均收益最高的动作,即纯利用。这就像老张取消了“闭眼点新菜”的规矩,从此顿顿水煮鱼,短期稳定但长期可能错过更好选择。
Q3. UCB 公式中 sqrt(ln t / N_t(a)) 的主要作用是?
- A.放大历史平均收益的数值
- B.给被选次数少的动作加分← 正确答案
- C.固定探索率的大小
- D.消除奖励中的随机噪声
答案:B。ln t 随总轮数缓慢增长,N_t(a) 是动作 a 被选的次数,试得越少该项越大,相当于“乐观加分”。它让 UCB 把探索机会优先给还没验证的选项,就像老张优先考虑信心区间很宽的回锅肉,而不是已经摸透的水煮鱼。
Q4. 汤普森采样中 Beta 分布建模的是?
- A.动作之间的时序依赖关系
- B.每个动作是最优的后验概率← 正确答案
- C.用户特征的线性权重
- D.推荐内容的实时热度
答案:B。伯努利奖励下,Beta(α, β) 描述“这个动作真实最优概率”的后验分布,α、β 分别累计好评和差评。每次从分布抽样并按抽样值排名,就是让“分布的形状自己说话”——没验证的菜曲线胖、爆冷概率高。
Q5. 下列哪些属于多臂老虎机的探索策略?
- A.Epsilon-greedy 策略← 正确答案
- B.UCB 置信上界法← 正确答案
- C.二分查找算法
- D.汤普森采样法← 正确答案
答案:ABD。Epsilon-greedy、UCB、Thompson Sampling 是三种经典 bandit 探索策略。二分查找是确定性的有序数据搜索算法,属于另一种问题域,既没有收益估计也没有探索利用权衡,像是“按菜单页码找菜”,而不是“决定试哪道菜”。
Q6. 探索率随时间衰减的根本目的是?
- A.减少模型训练的算力开销
- B.后期转向利用并降低长期遗憾← 正确答案
- C.让随机性完全消失
- D.提高线上请求的吞吐量
答案:B。冷启动阶段信息贫乏,探索的边际价值最高;随着数据积累,探索的收益递减、成本凸显,因此衰减探索率、更多利用已知最优,能让长期遗憾更小。这和“老张年纪越大越少乱点”同理。随机性完全消失是手段而非目的,且现实中还要保底探索。
Q7. 相比纯随机探索,UCB 的优势有哪些?
- A.探索集中于高不确定性的选项← 正确答案
- B.具备更优的理论遗憾界← 正确答案
- C.不需要任何历史数据
- D.自动平衡探索与利用← 正确答案
答案:ABD。UCB 的加分项只青睐“试得少”的选项,所以探索有方向而非撒网,且文献给出对数级遗憾界。它天然把探索和利用统一到“上界排序”里,无需手工切分流量。但它同样需要历史数据估计均值,C 说反了。
Q8. 新用户冷启动阶段,合理的探索设置是?
- A.比老用户更低的探索率
- B.比老用户更高的探索率← 正确答案
- C.完全不进行任何探索
- D.仅推荐全站最热门内容
答案:B。新用户没有行为历史,必须靠探索快速摸清口味,所以冷启动阶段应显著提高探索率,等画像成型再衰减。这好比新客人第一次进店,服务员总得让他多试几道菜,才知道他吃不吃辣。
Q9. 上下文感知探索可能利用哪些特征?
- A.用户历史停留时长← 正确答案
- B.当前请求时段← 正确答案
- C.设备型号← 正确答案
- D.随机种子编号
答案:ABC。上下文感知探索把“用户、场景、设备”等真实影响兴趣的特征编码进决策——深夜和中午想看的内容不同,手机和电视的使用习惯也不同。随机种子只是模拟实验用的随机数来源,与用户兴趣无关。
Q10. 遗憾(Regret)的正确含义是?
- A.最优策略与当前策略累计收益之差← 正确答案
- B.探索次数占总决策次数的比例
- C.模型训练损失的累计值
- D.推荐结果的用户流失比例
答案:A。Regret = T × r* − Σ r_t,即上帝视角“每轮都点最好菜”的累计收益,减去我们实际策略吃到的收益。它衡量的是由于信息不足(探索不够)或选择失误(利用不当)而错过的收益,是 bandit 算法最核心的评价指标。