Python bandit 算法的线上探索-利用

2次阅读

bandit库choose_arm()不返回概率分布是设计使然;线上ab测试需可解释性时应改用contextual-bandits或手写算法,或重载方法自算softmax/thompson采样。

Python bandit 算法的线上探索-利用

bandit 算法线上部署时,bandit 库的 choose_arm() 不返回概率分布?

它确实不返回,这是设计使然——bandit 库(如 bandit PyPI 包)默认只做动作选择,不暴露内部置信度或采样分布。线上 AB 测试需要“探索-利用”可解释性时,这会卡住。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 改用 contextual-bandits 或手写 epsilon_greedy/ucb1,它们天然支持返回 arm_probsupper_bounds
  • 若必须用原生 bandit,得重载 choose_arm() 方法,把 self.valuesself.counts 拿出来自己算 softmax 或 Thompson 采样
  • 注意:直接读 self.values 是平均奖励,不是后验分布;Thompson 场景下没维护 beta 参数,不能直接采样

线上服务中,epsilon_greedyepsilon 该不该随请求量衰减?

不该在请求粒度上实时衰减。线上流量有峰谷、冷启动、AB 切流,按请求数线性衰减 epsilon 会导致高峰时段探索不足、低峰时过度扰动。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 按「天」或「小时」做阶梯衰减,例如每天 0 点将 epsilon 乘以 0.95,且下限设为 0.02
  • 更稳妥的是绑定业务指标:当某臂的 click_through_rate 连续 3 小时稳定在 ±0.5% 内,才触发 epsilon *= 0.8
  • 绝对不要用 epsilon = 1 / log(t+1) 这类公式——t 是全局计数器,但线上多实例部署时各节点 t 不一致,会导致行为不可复现

thompson_samplingpython 中用 scipy.stats.beta.rvs 抽样慢?

是的,尤其在 QPS > 500 的服务里,每次调用 rvs 带来约 0.3ms 开销,叠加锁和 GIL,容易成为瓶颈。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 预生成一批 beta 样本(比如 10000 个),存在内存队列里,用完再批量重采——能压到 0.02ms/次
  • numpy.random.Generator.beta 替代 scipy.stats.beta.rvs,快 3–5 倍,且支持 batch 抽样:rng.beta(a, b, size=100)
  • 别在热路径里做 a=successes+1b=failures+1 这种计算——提前存好 alphabeta 字段,避免重复加法

线上灰度阶段,bandit 模型状态怎么持久化才不丢探索?

最常踩的坑是只存最终 arm 选择结果,不存每个臂的 successesfailuresvalues/counts,重启后变回纯随机探索,等于白跑两天。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 每 30 秒异步写一次全量状态到 redis Hash,key 用 bandit:campaign_123:state,field 是 arm_0_successesarm_1_counts
  • 加载时用 Redis.hgetall() + 类型转换,别依赖 json —— int 字段被读成字符串会导致后续除零或类型错误
  • 务必加版本号字段 schema_version,升级算法逻辑时靠它跳过旧状态或触发迁移脚本

真正难的不是选哪个算法,而是让 successesfailures 在机器重启、蓝绿发布、突发扩容之间对得上。状态错一位,探索就偏一整周。

text=ZqhQzanResources