fix: 限额峰值改为首锁+余额门控重锁,修复越算越多

原 Smart Peak 逻辑把每次用量增长误判为余额恢复(Jump)锁更高峰值,
叠加火山 AvailableAmount 更新滞后,stable_limit 当天一路抬升
(399,836 -> 599,511)且闸门永不触发,额度实际被烧穿。

新策略(volc:peak_pool 当日键):
- 首次同步锁定当日峰值(usage + balance)
- 仅 balance 自身净上涨(新资源包/对账回补 >=50k)按发放增量抬峰
- pool 回落时 Drop 收紧,永不回升
- usage 驱动的 pool 上涨一律不得抬高限额
新增 volc:last_balance 键记录上次余额快照
This commit is contained in:
root
2026-08-11 02:53:18 +00:00
parent f74f228322
commit 729e5c7bc3
+40 -20
View File
@@ -1308,21 +1308,32 @@ def active_monitor_loop():
dynamic_key = f"limit:dynamic:volcengine:remaining:{target}"
# ==========================================
# 🏔️ Smart Peak Tracking (Auto-Correction)
# 🏔️ Daily Peak Lock (First-Sync + Balance-Gated Re-Lock)
# ==========================================
# Strategy:
# 1. Capture Jumps (Recovery): If Balance jumps UP, trust it immediately. (Fixes latency)
# 2. Capture Drops (Expiry): If Balance drops HUGE (>20%), trust it. (Fixes expiry)
# - Why trust drops? Because if it's a false drop (glitch), Step 1 will fix it
# automatically on the next sync when it "Jumps" back up.
# 背景:AvailableAmount 是各资源包实例的实时剩余,但火山统计有
# 更新滞后(高用量时段会短暂冻结,实测 20 万 token 消耗内余额不动)。
# 旧逻辑把每次用量增长误判为"余额恢复"(Jump)锁更高峰值,
# 导致 stable_limit 越算越多(当天 399,836 -> 599,511 一路抬升)。
# 修正策略(日内限额单调可控):
# 1. 首次同步锁定当日峰值(= usage + balance 的总配额估计);
# 2. 仅当 balance 自身净上涨(新资源包发放/对账回补,≥50k)
# 时,按新增额度抬高峰值 —— 幅度 = 历史峰值 + 发放增量,
# 绝不把滞后虚高的 usage 一起算进去;
# 3. balance 回落(额度扣减追上用量)时 Drop 收紧;
# 4. usage 增长驱动的 pool 上涨一律不得抬高限额。
# 实测:协作奖励计划包每自然日发放、偶发一天 2 个,故必须有第 2 条;
# 次日 00:00 (CST) 自动重建当日峰值。
total_pool = current_usage + balance
peak_key = f"volc:peak_pool:{today_str}:{target}"
# Short-term memory (Last seen value)
# Short-term memory (Last seen value) - 仅用于日志对比/增量计算
last_pool_key = f"volc:last_seen_pool:{target}"
last_pool_val = redis_client.get(last_pool_key)
last_pool = float(last_pool_val) if last_pool_val else 0.0
last_balance_key = f"volc:last_balance:{target}"
last_balance_val = redis_client.get(last_balance_key)
last_balance = float(last_balance_val) if last_balance_val else 0.0
# Long-term memory (Day's High Water Mark)
old_peak_val = redis_client.get(peak_key)
@@ -1330,21 +1341,31 @@ def active_monitor_loop():
current_peak = historical_peak
# 1. JUMP DETECTION (Recharge / Latency Resolved)
# If pool jumps significantly (>5%) from last seen, it's a fresh, true value.
if total_pool > (last_pool * 1.05) and last_pool > 0:
if DEBUG_MODE:
# 1. INITIALIZATION (First sync of the day): lock once
if historical_peak == 0:
if DEBUG_MODE and last_pool > 0:
print(
f"DEBUG: 📈 Balance Jump ({int(last_pool):,} -> {int(total_pool):,}) - Locking New Peak.",
f"DEBUG: 📌 Locking Daily Peak ({int(last_pool):,} -> {int(total_pool):,}) - First Sync Today.",
flush=True,
)
current_peak = total_pool
redis_client.setex(peak_key, 172800, int(current_peak))
# 2. DROP DETECTION (Resource Expiry)
# If pool drops (even small amounts), we accept it.
# Why? Because keeping a phantom high peak is dangerous.
# If it was a glitch, Rule #1 will fix it next time it bounces back.
# 2. RECHARGE (Balance-driven upward re-lock)
# 新资源包发放 / API 对账回补 → balance 自身净上涨 ≥50k。
# 只把"发放增量"加进已锁定的峰值,不重算整个滞后 pool。
elif last_balance > 0 and (balance - last_balance) >= 50000:
grant_delta = int(balance - last_balance)
current_peak = historical_peak + grant_delta
if DEBUG_MODE:
print(
f"DEBUG: 🆕 New Quota Detected (balance {int(last_balance):,} -> {int(balance):,}, +{grant_delta:,}) - Re-locking Daily Peak to {int(current_peak):,}.",
flush=True,
)
redis_client.setex(peak_key, 172800, int(current_peak))
# 3. DROP DETECTION (Resource Expiry / latency catch-up)
# pool 回落时收紧限额;回落之后保持不变,绝不回升。
elif total_pool < historical_peak and historical_peak > 0:
drop_ratio = (
historical_peak - total_pool
@@ -1357,13 +1378,12 @@ def active_monitor_loop():
current_peak = total_pool
redis_client.setex(peak_key, 172800, int(current_peak))
# 3. INITIALIZATION / DRIFT
elif historical_peak == 0 or total_pool > historical_peak:
current_peak = total_pool
redis_client.setex(peak_key, 172800, int(current_peak))
# 4. NO USAGE-DRIVEN RE-LOCK: 用量增长(balance 不变)不得抬高限额。
# (旧逻辑的 Bug 就在这里:把滞后虚高当余额恢复。)
# Always update "Last Seen" for next comparison
redis_client.setex(last_pool_key, 86400, int(total_pool))
redis_client.setex(last_balance_key, 86400, int(balance))
# Calculate Stable Limit
safety_margin = max(current_peak * 0.15, 250000)