训练过 AI 模型的人应该都有这种体验:模型刚初始化时像一张白纸,完全不会;训着训着开始掌握一些规律,仿佛"开窍"了。但如果这时候你让它一直按已经验证过的路径走,很快就会发现性能卡在某个平台,怎么调都上不去。问题就出在一个被反复提起但经常被低估的概念上——探索与利用的平衡,在整个 AI 训练过程中,它就像方向盘后面的那点余量,转少了掉进局部最优,转多了直接失控撞墙。
这篇文章我想聊聊我在实际做模型训练、调参、上线过程中,对探索与利用这一对矛盾体的理解。不只是把 epsilon-greedy、UCB、Thompson 采样这些经典策略摆出来,更重要的是,告诉你为什么这个平衡点没有标准答案,以及我们在真实项目里是怎么调、怎么踩坑、怎么拿指标去判断"当前探索是过火还是不足"的。适合正在写强化学习代码的人、做推荐系统策略的人,或者刚刚接触在线学习、想搞明白"模型为什么越训越菜"的读者。
1. 一个随机动作,决定你的模型是"学渣"还是"学霸"
1.1 先讲清楚:什么是探索,什么是利用
探索和利用这两个词从字面上不难理解。探索是指尝试那些你不太确定效果的动作,比如推荐系统里给用户展示从未见过的新品;利用则是选择当前估计收益最高的动作,比如继续推荐用户点过的品类。两者之间的取舍,贯穿了强化学习、多臂老虎机、广告竞价、搜索排序等几乎所有在线决策问题。
一句话概括:探索是用短期的表现下降,去换取长期的信息增量;利用则是立刻兑现当前的信息优势。听起来很简单,但实际训练里,探索和利用是互相排斥的——你给某个用户推了新品,他就看不到你精心挑选的爆款;你把一条数据拿去尝试新策略,就没办法用它来继续巩固旧策略的判断。
我比较喜欢拿吃饭打比方。你常去一家拉面馆,味道稳定,永远不踩雷,这叫利用。可如果你一年到头只吃这一家,那这座城市里其他好吃的东西和你永远没关系,哪天这家馆子关张了,你就傻眼。探索就是隔三差五去试试隔壁新开的店,可能踩雷,但长期下来你的"美食地图"会丰富得多。AI 训练里的道理一模一样:模型需要一点"不务正业"的举动,才能积累起对环境的完整认识。
1.2 为什么这个平衡点没有标准答案
很多人第一次接触探索与利用时,会本能地问:探索比例设成多少合适?10%?20%?其实这个问题没有通解,因为不同任务的最优平衡点取决于三个因素:不确定性的大小、奖励信号的强弱、以及决策总次数。
举个例子,假设你有 1000 次决策机会,两个动作中一个期望收益是 1.0、另一个是 0.9,差距很小。这时候你得多花一些探索次数才能确定谁更好。反过来,如果一个动作的收益是 10、另一个是 0.1,那你探索几次就能分清,剩下的全部用来利用就好。再比如,如果你有 100 万次决策机会,你完全可以大方地把前面 5% 的时间都拿来探索,后面慢慢收敛;可如果只有 100 次机会,探索占比就得斤斤计较。
正因如此,我看很多人的训练代码里写死了 epsilon=0.1,却不问一句这个值从哪来的,这很危险。同样是 0.1 的探索比例,放在一个状态空间只有 10 个的玩具环境里,和放在一个真实工业级推荐系统里,后果完全不是一个量级。平衡是一个动态过程,不是一个固定常数。这一点在后面讲调参的时候会反复出现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从 epsilon-greedy 到 Thompson 采样:三套经典平衡策略的取舍逻辑
2.1 epsilon-greedy:最简单,但别小看
epsilon-greedy 恐怕是所有入门教程里第一个介绍的策略。它的逻辑很直白:以概率 epsilon 随机选择一个动作,以概率 1-epsilon 选择当前估计最优的动作。因为实现简单,它几乎是所有 baseline 必备的探索策略。
但越是简单的东西越容易用错。很多人觉得 epsilon=0.1 就万事大吉,忽略了它的一个关键缺陷:均匀随机探索会一视同仁地对待所有非最优动作。假设有两个动作,一个是次优的(收益 0.8),另一个是极差的(收益 0.1),epsilon 仍然会以同样的概率去试那个极差动作,浪费不少预算。
我曾在一次模拟实验里对比过:同样的 5000 轮决策,epsilon=0.1 的累计收益,居然比后面要讲的 UCB 低了一截,就是因为它在那些明显没希望的动作上浪费了太多机会。当然,epsilon-greedy 并非一无是处。它最大的优点是可解释性强、线上可控性好,上线出问题时你可以很清楚地告诉团队"我把探索系数从 0.1 调到了 0.05"。
2.2 UCB:用置信区间做决策
UCB(Upper Confidence Bound)的核心思想是:不要盲目随机探索,而是对每个动作估计一个"可能的最高收益",然后选择这个上界最高的动作。公式上通常会写成 均值 + sqrt(2 * ln(N) / n_i),其中 N 是总决策次数,n_i 是动作 i 被尝试的次数。
直觉上,这个公式做了两件事:第一项奖励那些历史收益高的动作;第二项奖励那些尝试次数少、不确定性高的动作。一个动作如果只被试过几次,第二项就会很大,哪怕它的当前均值不高,也会被选出来再试一次;一旦你试多了发现它不行,置信区间缩窄,它很快就会让位给更优的动作。
UCB 让我觉得最妙的一点是,它让探索不再是"广撒网",而是有方向地试探那些潜力尚未被证伪的动作。缺点是它对收益分布的假设比较敏感,如果收益方差极大,置信区间可能被个别极端值带偏。我在实际项目里用 UCB 时,通常会先对奖励做分位数截断或归一化,不然一个异常点击就能让策略抽风好几天。
2.3 Thompson 采样:贝叶斯的直觉打法
Thompson 采样是我个人比较偏爱的一种策略。它的逻辑是:对每个动作的真实收益持有一个概率分布的信念(先验),每一轮先从这个信念分布中采样一个值,然后选择采样值最大的动作。随着观察增加,信念分布不断更新,那些"可能是最优"的动作自然会被更频繁地探索。
这样做的好处是探索的强度自动适应不确定性。如果两个动作的收益差异不明确,后验分布重叠部分很大,Thompson 采样会交替尝试它们;如果某个动作已经被证明碾压其他动作,后验分布几乎不再重叠,策略就会基本锁定最优动作,不再浪费预算。
用代码实现 Thompson 采样并不难。如果奖励是二值的(比如点击/未点击),可以用 Beta 分布来建模;如果是连续奖励,通常用正态分布并维护均值和方差。下面是二值奖励场景下最简单的一版:
python复制import numpy as np
def thompson_sampling(alpha, beta, n_rounds):
rewards = 0
for _ in range(n_rounds):
samples = np.random.beta(alpha, beta)
action = np.argmax(samples)
# 这里用模拟的真实奖励更新
reward = np.random.binomial(1, true_probs[action])
rewards += reward
alpha[action] += reward
beta[action] += 1 - reward
return rewards
注意,这里的 true_probs 在真实系统里是不知道的,在离线模拟里只是用来生成奖励。Thompson 采样在不少 benchmark 里表现都优于 epsilon-greedy,尤其在奖励噪声比较大的场景下优势更明显。
三种策略我整理过一个对比表,方便以后选型:
| 策略 | 实现难度 | 探索方式 | 适用场景 | 主要风险 |
|---|---|---|---|---|
| epsilon-greedy | 低 | 均匀随机 | 状态简单、团队迭代快 | 探索预算浪费在坏动作上 |
| UCB | 中 | 不确定性驱动 | 动作数不多、收益稳定 | 对异常值敏感 |
| Thompson 采样 | 中 | 后验采样驱动 | 奖励噪声大、在线长期运行 | 先验设置不当影响收敛 |
3. 从论文到线上:我把平衡参数调崩的几次经历
3.1 场景复盘:一个商品推荐的 A/B 实验
理论聊完,聊聊真实项目。有一回我在做一个商品推荐策略的迭代,线上原本跑的是 epsilon=0.02 的 greedy 策略,整体点击率很稳,但问题也很明显——新品几乎永远得不到曝光。团队提需求:能不能把探索加大一点,让新品有机会被用户看到。
我当时很天真地把 epsilon 从 0.02 拉到了 0.15,结果实验一开,点击率直接掉了接近 20%。问题出在哪?探索的量是上去了,但探索的"方向"是全然随机的。商品池子里有大量低质量长尾商品,随机探索的绝大部分预算都落在这些商品上,用户自然是拒绝的。更麻烦的是,用户负反馈一多,模型学习到的状态分布也跟着偏移,连带影响了原有利用部分的效果。
后来我做了两个改动。第一,分层探索:先把商品按照热度分成头部、腰部、长尾三个集合,探索只在腰部集合里进行,头部基本不探索,长尾用单独的机制处理。第二,探索后重新归一化奖励:凡是探索动作产生的点击,在更新模型时要打一个衰减系数,避免单次探索结果的偶然性污染整体估计。改完之后,点击率回来了,新品的曝光量也慢慢起来了。
3.2 学习率、温度参数与熵正则,三个最容易搞混的旋钮
调试探索与利用平衡时,大家经常把三个旋钮搞混:学习率、softmax 温度、熵正则系数。它们各有侧重,但都会影响模型的"冒险程度"。
学习率控制参数更新的步长,本意不是探索,但学习率过大会放大噪声,让参数跳来跳去,行为上看起来像在探索;学习率过小又会锁死在局部最优。很多人发现模型收敛慢,第一反应是调学习率,其实更该调整的是探索策略。
softmax 温度参数控制的是动作分布的光滑程度。温度越高,动作概率越接近均匀分布,模型的行为越随机;温度越低,模型越倾向于最高分的动作。它和 epsilon 的区别在于:epsilon 是在最优动作和完全随机之间做二元选择,而温度是给所有动作按分数分配概率,是一种"软探索"。
熵正则则是在损失函数里加一项策略熵,鼓励模型不要过早把概率集中到一个动作上。系数设大了,模型会变得很"平均主义",什么动作都试;设小了,熵正则形同虚设。这三个旋钮的职责边界,我在实际中是这样区分的:学习率管的是收敛速度,温度管的是策略的随机性,熵正则管的是对不确定性的长期惩罚。
3.3 衰减曲线怎么设:固定值、线性衰减还是自适应
无论用哪种探索策略,几乎都逃不掉一个问题:探索量应该怎么随时间衰减?我见过三种常用做法,也踩过对应的坑。
固定值最简单,比如全程 epsilon=0.1。好处是代码一目了然,坏处是浪费——模型后期已经掌握了大部分信息,你还让它保持 10% 的随机尝试,就是在白白牺牲收益。
线性衰减适合训练轮数固定的离线任务。比如总共 10000 轮,epsilon 从 0.5 均匀降到 0.01。这种方案的可控性最好,但我踩过的坑是:如果线性衰减到 0 后又重启训练,模型会对新环境完全失去探索能力,表现会断崖式下降。
指数衰减或者自适应衰减更适合在线场景。一个我后来经常用的做法是:根据当前策略熵来决定探索强度。每过一段窗口,统计模型输出的动作分布熵,如果熵已经很低,说明策略很自信,就把 epsilon 调小;如果熵还很高,说明模型还在摸索阶段,保持较大的探索量。这等于给探索配了一个反馈控制器,虽然代码复杂一点,但状态切换时比固定衰减平滑很多。
4. 高维世界里的探索困境:当奖励信号近乎为零
4.1 奖励稀疏:你都找不到"对的路径"
探索与利用的平衡,在低维环境里相对好调,真正让人头疼的是奖励稀疏的场景。想象一个迷宫,agent 走很多步,只有到达出口才有一个 +1 的奖励。在探索阶段,随机游走几乎不可能走到出口,于是你永远得不到正向信号,模型也就无从学习。
我做过一个机器人控制模拟,目标是从初始位置把物体推到目标点,但奖励只在推到位时给一次。前期模型经常一整轮训练都没见过一次正向奖励,策略完全是在乱撞。后来我们采用了两条路:第一是奖励塑形,给中间状态加一些过程性奖励,比如物体离目标近了就给一点小分,让模型在探索过程中能收到渐进的反馈;第二是引入内在奖励,用"预测误差大"作为探索的驱动力——模型会对那些它无法预测的状态产生好奇心,主动去看没见过的区域。
这种做法背后的思路值得记住:当外部奖励太稀疏时,不要指望纯探索能撞大运,你需要人为地制造一条"奖励梯度"。不然平衡策略调得再好,也没有东西可学。
4.2 策略坍塌:越训练越保守的恶性循环
奖励稀疏带来的一个副作用是策略坍塌。什么叫坍塌?就是模型在训练过程中逐渐把动作分布收缩到少数几个动作上,看起来训练日志里动作熵越降越低,非常"自信",但实际上它只是发现了某个局部最优,并且因为探索不足,永远走不出去。
坍塌的本质是利用机制在自我强化。当前最优动作被选得多,它积累了更多正样本,估计变得更准,于是下一轮更可能被选中,形成滚雪球效应。如果模型的结构容量也有限,其他动作的估值会被挤压得越来越差,模型就彻底锁死在一条路上。
我在诊断这种问题时,最看重的指标就是动作熵。如果熵在训练中期就开始一路俯冲接近 0,我就知道模型不是在"学会",而是在"僵化"。缓解手段不外乎三招:加大熵正则、给最优动作的估计加扰动、以及在采样时限制同一个动作的连续被选次数。这些方法都不优雅,但能救命。
4.3 状态空间爆炸:先探索哪里,本身就是一道算法题
比奖励稀疏更绝望的是状态空间爆炸。真实场景里状态往往是高维的,图像、文本、用户行为序列,随便拉出来都有几百万维的潜在组合。探索算法面对的局面是:绝大多数状态你从来没去过,也根本没时间去全部走一遍。这时候"均匀随机探索"在数学上就没有意义了,因为你随机采样的点落在任何有价值区域附近的概率都趋近于零。
我的应对思路有三个层次。第一层,特征工程压缩状态空间,把连续状态离散化,或者用 embedding 降维,让探索在低维空间里进行,这是成本最低的做法。第二层,先模仿后探索,用一个已有的启发式策略或者历史日志产生初始策略,只在它的邻域内做小范围探索,而不是从零开始瞎走。第三层,近端探索,在动作层面加噪声而不是在状态层面随机跳转,比如高斯策略在均值动作附近采样,这样既保留了探索的随机性,又把探索限制在安全范围内。
一句话总结我的体会:高维空间里的探索,第一原则是"别乱走"。你需要的不是更多的随机,而是更好的先验和更聪明的方向。
5. 只盯 loss 曲线远远不够:探索程度的度量与诊断
5.1 三个线上可观测指标:行为熵、特征覆盖率、回退比例
调试许久后我越来越意识到一个问题:很多人只盯训练 loss 曲线,loss 降了就以为万事大吉。但如果你的目标是做在线决策,那探索程度的验收必须看一组额外的指标。
首先是行为熵。统计策略在每个决策点输出动作分布的熵,熵太高说明模型还在"乱猜",熵太低说明探索不足、策略固化。这个指标可以在训练日志里很容易地累积出来,不需要额外埋点。
其次是特征覆盖率。比如推荐系统里,过去一个时间窗口内,有多少候选特征或者商品被实际曝光过。覆盖率长期偏低,往往意味着长尾和新内容没有探索机会,短期指标再好,长期生态一定会出问题。
第三个是回退比例,或者说新旧策略下的动作重合率。把当前策略和上一版本策略在相同输入上的输出做对比,如果重合率过高,说明新策略几乎没有探索新的动作,只是理论上"更好",实际没有新信息。
这三个指标各有侧重,我把它们整理成一张诊断表:
| 指标 | 我一般怎么算 | 探索过度的信号 | 探索不足的信号 |
|---|---|---|---|
| 行为熵 | 对策略输出分布求熵 | 持续上升且无收敛迹象 | 下降得过快、趋近 0 |
| 特征覆盖率 | 曝光特征去重数 / 候选特征总数 | 覆盖率极高但利用率低 | 长尾特征长期为 0 |
| 回退比例 | 新旧策略输出动作相同的比例 | 回退比例骤降 | 回退比例长期接近 100% |
5.2 用"摇臂模拟"在离线环境验证平衡策略
线上调探索参数风险高,一个错误的 epsilon 改动可能让整个活动周期的数据都受影响。所以我强烈建议:在离线环境里先用多臂老虎机模拟把策略验证一遍。虽然模拟环境和真实线上有差距,但至少能帮你排除掉那些理论上一眼就能看出问题的设置。
模拟的步骤很固定。第一步,定义动作和真实奖励分布,这些分布可以基于历史数据统计得到;第二步,实现你要验证的策略,比如 epsilon-greedy 或者 UCB;第三步,模拟跑 N 轮,记录累计收益和 regret;第四步,换一组参数,重复对比。
下面是个极简的对比脚本,核心代码不长:
python复制import numpy as np
true_probs = [0.1, 0.2, 0.15, 0.25]
def run_epsilon_greedy(n_rounds, epsilon):
counts = np.zeros(len(true_probs))
rewards = 0.0
for _ in range(n_rounds):
if np.random.random() < epsilon:
action = np.random.randint(len(true_probs))
else:
action = np.argmax(counts) # 实际中应基于收益均值
reward = np.random.binomial(1, true_probs[action])
rewards += reward
counts[action] += 1
return rewards
for eps in [0.01, 0.05, 0.1, 0.2]:
print(f"epsilon={eps:.2f}, total_reward={run_epsilon_greedy(5000, eps):.1f}")
这个脚本刻意简化了,真实评估里还要加自适应衰减、奖励归一化、冷启动这些机制,但核心思路足够用了。我自己每次调探索参数前,都会先把这种模拟跑一遍,至少能定出一个大致的量级,再上线上灰度。
5.3 上线后如何判断探索是否过火
离线模拟总是乐观的,真正的考验在上线。探索过火最常见的线上表现是:短期指标下降,但早期又看不出来到底是在伤害用户还是仅仅在尝试新东西。我的经验是分层看指标。
第一层看即时反馈,点击率、转化率、完成率这些,探索过火通常会导致它们明显下滑。第二层看延迟反馈,比如用户次日回访、长期留存、内容生态多样性,这一层不会在几天内出结果,但恰恰是探索带来的长期价值所在。所以判断探索是否过火,不能只看周报,至少要观察一个完整的用户生命周期。
如果收到报警说训练 loss 异常升高、行为熵突然飙升、回报方差变大,我一般会先做一个保守操作:把探索系数降一半,同时保留一份完整日志用于复盘。不要一上来就回退到旧版本,那样你会永远不知道新策略到底有没有潜力。探索参数回退要平滑,不要做断崖式切换,否则模型在其他维度上也会被带崩。
6. 收尾:一点个人经验,供参考
探索与利用的平衡,说到底是"信息与收益"的权衡,落到训练上就成了一个调参问题。我自己的习惯是:先宽后紧、看熵调参、离线模拟先行。每次拿到一个新任务,先给足探索预算,把环境的轮廓摸清楚,再逐步收紧;收紧的过程中紧盯行为熵和特征覆盖率,一旦发现熵塌了,就回一点探索量;任何探索策略改动,先离线验证至少一个量级,再上线上灰度,绝不拿用户当小白鼠。
最后再分享一个不算技巧的技巧:每次调探索参数,我都会在实验记录里额外写一行"探索日志",记录当时的探索策略、参数、行为熵的变化趋势,以及半个月后的线上指标。时间长了之后,这些日志汇总起来,就能看到不同场景下探索参数设置的规律。这个习惯帮我避开了很多重复踩坑。如果你也在和探索与利用搏斗,不妨试试这套笨办法——它确实管用。
