hyapp-server/docs/幸运礼物产品方案.md

25 KiB
Raw Blame History

Lucky Gift Product Design

本文档定义语音房幸运礼物的产品规则。幸运礼物使用金币赠送,奖励也返还金币

当前代码实现以 docs/幸运礼物线上落地文档.md 为准。已落地版本不是固定概率表模型,而是后台配置 multiplier_ppms 多个倍率,服务端按 RTP 窗口、三层奖池和风控容量在运行时自动生成候选权重;因此本文中“概率表/权重表”只保留为产品抽象,不代表后台可以直接配置固定命中概率。

Positioning

Object Meaning
用户 用金币赠送幸运礼物,获得房间表现和概率金币奖励
主播 正常获得礼物贡献和房间热度,不参与控制开奖结果
房间 获得飘屏、热度、本地榜、互动气氛
平台 用奖池和风控控制整体返还率,不控制单个用户输赢

核心原则:

Rule Decision
先扣费再抽奖 只有金币扣费成功后才进入幸运礼物抽奖
先过滤再随机 先根据奖池水位和风控阈值过滤奖档,再执行随机
抽后不改结果 随机结果生成后必须落日志,不允许后台强改
整体控阈值 控制平台、房间、礼物、用户维度的风险敞口
规则可解释 前台展示基础概率、奖励范围、低水位规则和上限
结果可审计 每次抽奖保存规则版本、奖池快照、随机材料和发奖状态

User Experience

用户在礼物面板选择幸运礼物,支付金币后出现三类结果:

Result User Feedback
未命中奖励 礼物正常送出,房间展示普通幸运礼物消息
命中小额奖励 礼物正常送出,返还金币到账,房间展示轻量提示
命中大奖励 礼物正常送出,返还金币到账,房间展示飘屏或强化特效

金币奖励必须以实际到账为准。若账务补偿中,客户端展示“奖励处理中”,不能提前展示“已到账”。

Three Pool Model

三层奖池仍然是资金水位和风险敞口模型,不能被新手、中级、高级体验池替代。体验池只决定同一次抽奖可见的奖档分布,实际能不能发奖仍然由平台、房间、礼物三层水位以及全站/礼物基础 RTP 窗口共同决定。

Platform Pool

平台总奖池控制全站幸运礼物的整体返还率。

Field Meaning
platform_pool_balance 当前全站可用幸运奖励金币
platform_reserve_floor 平台最低安全水位
platform_target_payout_rate 平台目标返还率
platform_daily_payout_limit 平台每日最大奖励支出

平台奖池低于安全水位时,大额奖档不可参与随机;被过滤奖档的概率质量进入未中奖奖档,不重新分配给其他奖档。

Room Pool

房间奖池控制单房间爆奖能力。热门房可以积累更高水位,冷房不能打穿平台预算。

Field Meaning
room_pool_balance 房间当前可用幸运奖励金币
room_reserve_floor 房间最低安全水位
room_hourly_payout_limit 房间小时最大奖励支出
room_daily_payout_limit 房间每日最大奖励支出

房间奖池只影响本房间,不允许直接挪用其他房间水位。需要运营活动加成时,必须通过平台奖池或活动预算显式补贴。

Gift Pool

礼物奖池控制不同幸运礼物的成本结构。

Field Meaning
gift_pool_balance 某个幸运礼物当前可用奖励金币
gift_reserve_floor 礼物最低安全水位
gift_target_payout_rate 礼物目标返还率
gift_max_single_payout 礼物单次最高奖励

低价礼物适合高频小奖,高价礼物适合低频大奖。不同礼物必须使用独立概率表和独立水位,不要共用一个不可解释的全局概率。

Five Layer Control Model

幸运礼物 V2 使用五层控制模型。三层资金水位继续负责“能不能付”,五层控制负责“钱怎么算、体验怎么呈现、补贴归谁”。

Layer Product Role Cost Accounting Hard Boundary
全站 RTP 控制窗口 保证全站基础返奖成本 计入 base_reward_coins,进入全站基础 RTP 不能被房间气氛、活动补贴污染
礼物 RTP 子窗口 控制单个幸运礼物成本结构 同一笔 base_reward_coins 同时进入礼物基础 RTP 单礼物不能长期借其他礼物的 RTP
用户体验池 新手、中级、高级奖档和节奏 不单独记成本,只选择基础候选奖档 不承诺单用户 RTP
房间气氛池 控制房间爆点、共享奖励、飘屏强度 计入 room_atmosphere_reward_coins 或表现预算 不回写 Room Cell 核心状态
活动预算池 节日、榜单、运营补贴 计入 activity_subsidy_coins 独立预算,不能冲抵基础 RTP

用户看到的总返奖拆成三类:

effective_reward_coins = base_reward_coins
                       + room_atmosphere_reward_coins
                       + activity_subsidy_coins

成本口径必须分开:

Metric Formula Meaning
base_rtp sum(base_reward_coins) / sum(coin_spent) 平台承诺和风控使用的基础 RTP
gift_base_rtp sum(base_reward_coins by gift_id) / sum(coin_spent by gift_id) 单礼物成本健康度
effective_rtp sum(effective_reward_coins) / sum(coin_spent) 用户实际感受到的总返还
subsidy_cost sum(room_atmosphere_reward_coins + activity_subsidy_coins) 运营和房间气氛额外成本

运营要提高娱乐性时,优先调整体验池、房间气氛池和活动预算池;不要直接把基础 RTP 拉高。基础 RTP 是平台成本底线,不是用户体感的唯一来源。

Experience Pools

新手池、中级池、高级池是同一个幸运礼物规则下的三个体验配置。它们不单独拥有金币余额,不直接绕过平台、房间、礼物三层奖池,不承诺单个用户固定 RTP。

Pool Entry Rule Product Shape Payout Boundary
novice 用户当前幸运礼物累计付费抽数较低,或处于新手保护期 高频小奖、少量返还、禁止超高倍大奖 单次奖励上限最低,避免新用户误解为高波动博彩
intermediate 用户已经完成基础体验但未进入高频阶段 小奖和中等奖混合,中奖频率下降 允许中等奖,不允许消耗高级奖池预算
advanced 高频幸运礼物用户或高价幸运礼物 低频高倍、强调飘屏和房间表现 单次奖励上限最高,但必须被总 RTP、三层水位和风控同时约束

默认分池建议按付费抽数切换,服务端只使用 UTC 计数,不使用客户端本地时间:

Pool Default Draw Range Notes
novice [1, 2000] 首次体验阶段,奖档更密但倍数更低
intermediate [2001, 20000] 常规用户阶段,保留中等奖表现
advanced [20001, +∞) 高频阶段,大奖概率更低但上限更高

分池只影响基础候选奖档和表现节奏。总返还率必须由全站 RTP 控制窗口和礼物 RTP 子窗口共同收敛,不能依赖三个体验池各自“碰运气”。

Stage Feedback

阶段反馈是体验反馈,不是单用户保底。默认在新手池内按付费抽数进度触发:125%50%75%100% of novice_draw_limit

Feedback Type Cost Accounting Allowed Behavior
进度反馈 presentation_only 展示阶段、进度、动画、房间幸运值,不发金币
小额反馈奖 base_rtp or activity_subsidy 如果发金币,必须抽前进入基础候选或活动预算候选
阶段完成提示 presentation_only 告知用户已离开新手池或进入常规池

阶段反馈不能绕过 RTP、三层水位和风控上限。任何“第 N 抽必给金币”的设计都必须先占用明确预算,否则会把基础 RTP 控制窗口打穿。

RTP Control Model

单纯固定概率表不能保证 10w 次上下浮动不超过 1%100w 次上下浮动不超过 0.5%,尤其是高级池包含高倍奖时。幸运礼物必须使用“概率体验 + 整数 RTP 控制窗口”的组合模型。

控制规则:

Rule Decision
控制口径 每次抽奖同时进入全站 RTP 窗口和礼物 RTP 子窗口
控制窗口 默认 global_window_draws=100000,礼物子窗口可按流量配置更大窗口
RTP 输入 使用 target_rtp_ppm 保存,例如 95% = 950000
目标支出 window_target_payout = floor((window_wager * target_rtp_ppm + carry_ppm) / 1000000)
余数处理 除不尽的 ppm 余数进入下一个窗口的 carry_ppm
候选过滤 每次抽奖前过滤三层水位、风控、体验池奖档和窗口剩余可支付额
随机范围 只在过滤后的候选奖档中随机,随机后不允许后台改结果
窗口补偿 全站或礼物窗口剩余抽数不足以自然追平目标时,抽前启用基础 RTP 补偿候选奖档

窗口内每次抽奖都维护两个整数:

global_remaining_draws = global_window_draws - global_window_paid_draws
global_remaining_payout = global_window_target_payout - global_window_base_payout

gift_remaining_draws = gift_window_draws - gift_window_paid_draws
gift_remaining_payout = gift_window_target_payout - gift_window_base_payout

候选奖档必须满足:

base_reward_coins <= global_remaining_payout
base_reward_coins <= gift_remaining_payout

global_remaining_payout - base_reward_coins
  <= global_min_future_max_reward * (global_remaining_draws - 1)

gift_remaining_payout - base_reward_coins
  <= gift_min_future_max_reward * (gift_remaining_draws - 1)

其中 *_min_future_max_reward 是对应窗口后续任意体验池至少能支付的单次最大基础返奖。这个约束保证窗口不会因为前面连续未中奖而在最后几抽无法追平基础 RTP。

达成条件:

Sample Size Required Result Control Requirement
100000 paid draws 全站基础 RTP 与目标 RTP 绝对偏差 < 1% 一个完整全站控制窗口内目标支出按整数配额结清
1000000 paid draws 全站基础 RTP 与目标 RTP 绝对偏差 < 0.5% 十个完整全站控制窗口累计偏差只剩整数余数
单礼物流量达到配置窗口 礼物基础 RTP 收敛到礼物目标 礼物子窗口独立结清,不能长期靠全站窗口兜底

这个保证只适用于控制口径内的总 paid draws不适用于单个用户、单个房间或单个很小流量分桶。单个用户仍然可能亏损或盈利平台只能承诺全站和礼物基础 RTP 收敛。

如果三层奖池水位、风控硬上限或钱包入账失败导致基础返奖无法支付,系统必须记录 rtp_underpay 风险事件并降低基础 RTP不能透支奖池或抽后篡改结果。房间气氛和活动补贴也不能用于“补平”基础 RTP只能提高用户看到的 effective_rtp

Risk Layer

风控层不在抽奖后篡改结果,只在抽奖前决定是否允许参与、是否降低可用奖档、是否进入人工观察。

Threshold Product Meaning
max_single_payout 单次最大奖励金币
max_user_daily_payout 单用户每日最大奖励金币
max_device_daily_payout 单设备每日最大奖励金币
max_room_hourly_payout 单房间每小时最大奖励金币
max_anchor_daily_related_payout 单主播关联奖励风险上限
max_activity_period_payout 活动周期最大奖励金币
max_user_hit_count_window 单用户窗口期最大命中次数

上限制定依据:

expected_payout(window) = paid_draw_capacity(window)
                        * gift_price
                        * target_rtp_ppm
                        / 1000000

single_cap <= min(gift_sub_window_target_payout, single_event_risk_budget)
hourly_cap >= expected_payout(user_hour_window) * volatility_factor
daily_cap >= expected_payout(user_day_window) * volatility_factor

默认建议:

Limit Base Formula Why
单次上限 gift_price * max_allowed_multiplier 控制单事件最大曝光,直接决定是否允许 100x/500x
小时上限 expected_hourly_payout * 1.5~3.0 覆盖正常波动,同时限制短时异常套利
日上限 expected_daily_payout * 1.2~2.0 覆盖高活跃用户正常体验,同时保护单日预算
高水位开高倍 min(global_headroom, gift_headroom, pool_headroom) >= high_reward 只有此前少付或奖池积累足够时,才允许高倍进入候选

如果小时或日上限低于对应窗口的期望基础返奖,系统将无法同时满足用户上限和全站 RTP。此时必须降低目标 RTP、降低用户可抽容量、提高上限或把额外体验放到活动预算池而不是让基础 RTP 窗口透支。

高水位定义:

rtp_headroom = remaining_base_payout
             - remaining_draws * gift_price * target_rtp_ppm / 1000000

high_multiplier_enabled = global_rtp_headroom >= tier_reward
                       && gift_rtp_headroom >= tier_reward
                       && platform_pool_headroom >= tier_reward
                       && room_pool_headroom >= tier_reward
                       && gift_pool_headroom >= tier_reward

基础最小版本暂时只验证 global_rtp_headroomgift_rtp_headroom。接入真实奖池后,必须同时校验平台、房间、礼物三层水位。

线上标准强制口径:

Control Required Behavior
全站 RTP 窗口 每一笔付费抽奖都进入,base_reward_coins 必须按窗口整数配额结清
礼物 RTP 子窗口 同一笔基础返奖同时进入礼物窗口,单礼物不能借其他礼物的成本
平台/房间/礼物三层池 每抽先按 pool_rate_ppm 入池,再按责任权重支付基础返奖;任一层低于 reserve floor 时过滤对应奖档
新手/中级/高级体验池 只控制候选奖档和节奏,不持有预算,不承诺单用户 RTP
单次/小时/日/设备/房间/主播上限 抽前过滤所有会超过剩余额度的付费候选,抽后只更新计数
高水位高倍 只有全站窗口、礼物窗口、三层池水位同时满足高倍奖励时100x/500x 才能进候选
房间气氛池 独立预算,只提升房间爆点和共享奖励,不写入基础 RTP
活动预算池 独立补贴,只提高 effective_rtp,不能冲抵基础 RTP 欠付
钱包和房间表现 扣费必须先成功;返奖和房间表现通过 outbox 重试,不能在持有奖池锁时调用外部 RPC

触发阈值后的产品动作:

Action When
拒绝参与 用户、设备、房间或活动已达到硬上限
低水位模式 奖池不足以支付完整奖档
仅小奖模式 大奖风险超出当前窗口预算
人工观察 主播、用户、设备、支付来源存在明显关联异常
活动暂停 平台总返还率或投诉风险超过运营阈值

Reward Configuration

每个幸运礼物最小配置:

Field Meaning
gift_id 幸运礼物 ID
gift_price 单个礼物金币价格
pool_rate 每笔礼物进入幸运奖池的比例
target_payout_rate 长期目标返还率
target_rtp_ppm RTP 控制窗口使用的目标返还率
control_window_draws RTP 控制窗口 paid draws 数
gift_rtp_window_draws 单礼物 RTP 子窗口 paid draws 数
experience_pool_rules 新手、中级、高级分池进入规则
room_atmosphere_rule 房间爆点、共享奖励和表现规则
activity_budget_id 当前可用活动补贴预算 ID
reserve_floor 最低安全水位
max_single_payout 单次最高奖励金币
max_user_daily_payout 单用户每日最高奖励金币
max_room_hourly_payout 单房间小时最高奖励金币
probability_table_version 概率表版本
enabled_reward_tiers 当前启用奖档

示例权重表只表达结构,不作为正式运营参数。体验池权重用于表现节奏,不直接决定总 RTP。

Pool Tier Reward Base Weight Availability
novice none 0 270000 always
novice rebate_0_5x gift_price * 0.5 200000 pool safe
novice rebate_1x gift_price * 1 350000 pool safe
novice small_2x gift_price * 2 140000 pool safe
novice small_5x gift_price * 5 35000 pool safe
novice small_10x gift_price * 10 5000 pool safe
intermediate none 0 760000 always
intermediate rebate_1x gift_price * 1 100000 pool safe
intermediate small_2x gift_price * 2 80000 pool safe
intermediate medium_5x gift_price * 5 45000 pool safe and user limit safe
intermediate medium_20x gift_price * 20 13000 high water only
intermediate medium_50x gift_price * 50 2000 high water only
advanced none 0 900000 always
advanced small_2x gift_price * 2 50000 pool safe
advanced medium_5x gift_price * 5 30000 pool safe
advanced large_20x gift_price * 20 15000 high water only
advanced large_100x gift_price * 100 4500 high water only
advanced jackpot_500x gift_price * 500 500 high water and risk safe

奖池低水位时,如果 large_100x 不可用,它的权重必须进入 none不能转给其他奖档。RTP 控制窗口需要追平目标时,只能在抽前选择当前可支付的补偿奖档,不能在随机后把未中奖改成中奖。

V2 Draw Algorithm

V2 抽奖算法把“基础返奖”和“娱乐补贴”分开算。基础返奖负责 RTP房间气氛和活动补贴负责体验。

input:
  command_id, user_id, room_id, gift_id, gift_price, paid_at_ms

state:
  global_rtp_window
  gift_rtp_window(gift_id)
  platform_pool, room_pool(room_id), gift_pool(gift_id)
  user_experience_state(user_id, gift_id)
  room_atmosphere_pool(room_id)
  activity_budget(optional)
  risk_counters

标准算法:

1. 用 command_id 做幂等查询,已有结果直接返回
2. 选择用户体验池novice / intermediate / advanced
3. 计算阶段反馈点;反馈只产生展示事件或已预算候选,不直接发未预算金币
4. 锁定全站 RTP 窗口和礼物 RTP 子窗口
5. 锁定平台、房间、礼物三层资金水位
6. 锁定房间气氛池和可用活动预算
7. 读取风险计数和用户窗口状态
8. 计算基础返奖容量:
   global_base_capacity
   gift_base_capacity
   platform_capacity
   room_capacity
   gift_capacity
   risk_capacity
9. 计算单次、小时、日、设备、房间、主播和活动周期剩余额度
10. 计算高倍奖档水位;只有全站、礼物和三层奖池高水位都足够时才开放高倍
11. 从体验池生成基础候选奖档
12. 过滤所有无法同时满足全站 RTP、礼物 RTP、三层水位和风控的基础奖档
13. 生成房间气氛候选:飘屏、共享红包、房间幸运值、表现强化
14. 生成活动补贴候选:限时加奖、榜单补贴、节日额外返奖
15. 合并候选并执行一次随机
16. 写入抽奖事实、窗口快照、预算快照和随机审计材料
17. 更新全站 RTP 窗口和礼物 RTP 子窗口,仅写入 base_reward_coins
18. 更新房间气氛池和活动预算,仅写入各自补贴支出
19. 提交事务
20. 事务后通过 wallet-service 发金币,通过 room-service/腾讯云 IM 做房间表现

候选奖档必须带预算来源:

Budget Source Pays Coins Counts In Base RTP Typical Use
base_rtp yes yes 常规小奖、中奖、大奖
room_atmosphere optional no 房间红包、共享奖励、飘屏强化
activity_subsidy yes no 节日加奖、榜单补贴、限时返利
presentation_only no no 动画、称号、房间幸运值

随机前必须完成过滤。随机后只能落账、补偿或返回 pending不能把结果改成另一个奖档。

Draw Flow

标准流程:

读取规则版本
按用户累计付费抽数选择 novice/intermediate/advanced 体验池
读取平台、房间、礼物奖池水位
读取或创建全站 RTP 窗口和礼物 RTP 子窗口
读取房间气氛池和活动预算
读取用户、设备、房间、主播、活动风控计数
过滤不可支付、不可触发或会破坏基础 RTP 窗口追平能力的基础奖档
生成基础返奖、房间气氛、活动补贴候选奖档
执行随机
写入抽奖结果日志
发放金币奖励
广播房间表现

不可接受流程:

先随机
发现超预算
后台改成未中奖

Room Presentation

幸运礼物产生两类房间表现:

Event Owner
礼物送出消息 room-service
房间热度变化 room-service
房间本地礼物榜 room-service
幸运奖励结果 activity-service 决策,room-service 转成房间表现
房间消息投递 腾讯云 IM

activity-service 不直接持有 Room Cell不修改麦位、禁言、在线态和房间榜。它只返回幸运礼物决策结果并通过事件让房间系统表现出来。

Compliance Baseline

产品默认遵守以下红线:

Red Line Decision
不允许空奖池承诺大奖 当前奖池无法支付时,大奖档必须不可用
不删除抽奖记录 抽奖、奖池、发奖记录按审计周期保存

Metrics

上线后必须监控这些指标:

Metric Reason
lucky_gift_gmv 幸运礼物金币消耗
lucky_base_reward_payout 基础 RTP 金币奖励支出
room_atmosphere_payout 房间气氛和共享奖励支出
activity_subsidy_payout 活动补贴支出
base_rtp 基础返还率,平台成本口径
effective_rtp 用户可见返还率,含补贴
gift_base_rtp 单礼物基础返还率
pool_balance_by_scope 平台、房间、礼物水位
room_atmosphere_balance 房间气氛预算水位
activity_budget_balance 活动补贴预算水位
hit_rate_by_tier 各奖档命中率
reward_credit_latency 金币到账延迟
risk_reject_count 风控拒绝次数
pending_reward_count 待补偿发奖数量
complaint_rate 用户争议风险

V1 Scope

首版只做:

Included Excluded
三层奖池 主备热同步
固定概率表版本 个性化概率
抽前风控阈值 抽后改结果
金币奖励 现金、实物、提现
房间飘屏和系统消息 跨房 PK 大奖池
抽奖日志和补偿 后台人工指定某用户中奖