fix: v5 恢复 v2 骨架,修正 v4 误拦

v4(stable = balance - BUFFER)把「剩余余额」当「从 0 累计的上限」,
U>0 时低估初始池:15:09:51 实测 Bal=596,869(剩 59.7 万)却被
usage 1,696,135 >= 296,869 全拦。守恒反推(U+B=2,293,004)证明
v2 公式数学正确——B 滞后收敛后满足 B = B0 - U,今日消耗 1.696M <
B0 2.293M 无扣费(此前「超余额 13.8 万扣费」基于滞后快照的推断
不成立)。v5 = 恢复 v2(stable = usage + balance - BUFFER),
残留风险仅同步时点 B 滞后(13:36 高估 ~50 万),由 BUFFER + 低余额
加密同步覆盖。文档同步:volc-quota-notes §7.3/§7.5、merge-auto-consume §4.5。
This commit is contained in:
vibe-code
2026-08-12 07:21:13 +00:00
parent d9c7b1406d
commit 97484cb7f8
5 changed files with 100 additions and 67 deletions
+55 -39
View File
@@ -7,8 +7,9 @@
> - 2026-08-12 对话澄清(扣费口径、余额 API 滞后、限额方案演进)
> - 2026-08-12 生产日志观察(deepseek-v4-flash-ga-260731)
>
> 代码现状:v4 已实施(2026-08-12,见 §7.3);工作区在 HEAD `c6c1224` 之上仅含 v4 改动。
> v2/v3 内容保留为历史论证。
> 代码现状:v5 = 恢复 v2 骨架(`stable_limit = usage + balance − BUFFER`),2026-08-12 修正;
> v4(balance−BUFFER 冻结快照)当天实施后即发现误拦已回退,见 §7.3/§7.5。
> 工作区在 HEAD `c6c1224` 之上含 v5 修正。
---
@@ -117,9 +118,13 @@ Set Redis limit:dynamic:volcengine:remaining:deepseek-v4-flash-ga-260731 = 1,258
| StableLimit(v2) | 动态限额 | usage + balance − BUFFER(随 usage 膨胀,见 §7.1) |
**Today > Rem 的原因**:Today 是单日流量,Rem 是存量余额快照,两套口径本就不该比较。
今日消耗可以暂时大于余额显示值(先采后返),但按 §2 口径,**超出部分实际已扣费**。
火山网页「今日采集量 1,696,135/2,000,000」对应 Today 与 2M 配额,与余额无关。
**扣费结论(2026-08-12 15:09 实测修正)**:14:59:51 同步 U=1,696,135 + B=596,869,
守恒反推今日初始免费池 B0 = 2,293,004 → 今日消耗 1,696,135 < B0 → **当日无扣费**。
此前「超余额 13.8 万已扣费」的推断基于 13:36 滞后快照(B=1,558,307 高估真实剩余
约 50 万),不成立。判定扣费要用「守恒初始池」(U+B 反推)而非任意时点快照。
---
## 6. Redis key 与日志口径(速查)
@@ -130,25 +135,29 @@ Set Redis limit:dynamic:volcengine:remaining:deepseek-v4-flash-ga-260731 = 1,258
|---|---|---|
| `daily_usage:{北京日期}:{model}:{hash}` | LiteLLM 成功回调 INCR + 消耗任务 INCR | 当日采集量,TTL 48h,北京 00:00 滚动 |
| `limit:dynamic:volcengine:remaining:{model}` | 守护线程写 | 余额 − BUFFER(同步频率驱动、展示) |
| `limit:dynamic:volcengine:stable_limit:{model}` | 守护线程写 | 稳定限额(v2:usage+balance−BUFFER) |
| `limit:dynamic:volcengine:stable_limit:{model}` | 守护线程写 | 稳定限额(v5:usage+balance−BUFFER) |
| `consume:last_run:{日期}` | 消耗任务 | 23:00 当日去重,TTL 48h |
### 6.2 关键日志
- `🚫 [PRE-BLOCK] {model} daily limit reached ({usage}+{reserve}/{limit})`:请求前闸门 429
- `📊 [Usage] {model}:{hash}: +{tokens} (Today: X | Rem: Bal | Limit: Y)`:成功记账
- `📅 [Quota] ...`:每日额度汇总(v4 设计,未实施)
---
## 7. 限额方案演进
### 7.1 v2(现状,HEAD c6c1224):`stable_limit = usage + balance − BUFFER`
### 7.1 v2(HEAD c6c1224 原式,v5 已恢复):`stable_limit = usage + balance − BUFFER`
- 意图:`usage + balance` = 当日初始可用池,消耗中恒定 → 限额恒定
- **失效点**:该式假设 balance 随消耗实时递减;实测滞后 → usage 涨 balance 不动 →
池膨胀(2026-08-12:2.80M → 3.26M)→ 「余额耗尽 → 限额 0」防线失效 → 放行到扣费区
- 案例:余额 1,558,307 时 EffectiveLimit 仍取 2M,今日采到 1,696,135(超余额 13.8 万)未被拦
- 意图:`usage + balance` = 当日初始免费池(守恒 B0),消耗中恒定 → 限额恒定
- **数学正确性(2026-08-12 15:09 实测确认)**:B 滞后收敛后确实满足 B = B0 − U
(14:59:51:U=1,696,135 + B=596,869 = B0=2,293,004,与理论剩余 597,004 几乎一致)。
同步时 stable = B0 − BUFFER,usage 累计撞线 = 用到剩 BUFFER 停止 —— 语义正确
- **残留风险(非公式错误,是快照时点问题)**:同步时 B 若滞后(13:36 高估真实剩余
约 50 万)→ stable 虚高 → 多放行滞后窗口内消耗。由 BUFFER + 低余额加密同步
(600s/300s)+ burst 触发覆盖;收敛后池回到守恒值
- 案例:13:36 快照 B=1,558,307 为滞后值(真实剩余 ≈1,051,183),并非「余额不足」;
今日无扣费(见 §5)
### 7.2 v3(尝试后否决,已回滚):昨日锚 `effective = min(2M, 昨日采集量 × 系数)`
@@ -158,53 +167,60 @@ Set Redis limit:dynamic:volcengine:remaining:deepseek-v4-flash-ga-260731 = 1,258
今日可用 = min(2M, 余额) ≈ 2M,与昨日无关
- 附:系数 <1.0 还会引发「今日少采 → 明日返还更少」的日复一日递减陷阱(0.9 系数 5 日降至 66%)
### 7.3 v4(2026-08-12 已实施):冻结快照
### 7.3 v4(2026-08-12 实施后当天发现错误,已回退):冻结快照
```
stable_limit = max(0, balance − BUFFER) # 冻结快照,同步时算一次
effective_limit = min(2M 采集配额, stable_limit) # 2M 防白烧;余额红线防扣费
stable_limit = max(0, balance − BUFFER) # ❌ 错误:把「剩余余额」当「从 0 累计的上限」
```
- 唯一改动点:同步循环 stable_limit 从 `usage + balance − BUFFER` 改为 `balance − BUFFER`
(`volc_limit_sync.py` active_monitor_loop 同步段;debug 行 Pool 字段移除,改 Bal 口径)
- 数学等价于「本地实时扣减余额」:以最近快照余额为当日免费池上限,
usage 本地逐请求实时累计,撞线即拦,不再等 API
- 行为测试(2026-08-12,fake Redis 全过):冻结不膨胀 / 今日 1.696M 撞 1.258M 即拦 /
余额 2M 可用 1.7M(与昨日无关)/ stable 缺失兜底 900K / 次日返还解锁 / 余额 < BUFFER 全拦
- 效果对照(与 v2 现状):
- 设计初衷:余额 API 滞后 → 冻结快照防池膨胀
- **错误实证(15:09:51 生产日志)**:Bal=596,869(真实剩余 59.7 万),
stable = 296,869,usage=1,696,135 ≥ 296,869 → `[PRE-BLOCK] … (1,696,135+16/296,869)` 误拦。
账上有真实免费额度却全拦 —— 因为 stable 应是「今日累计上限」(= B0 − BUFFER),
而 balance 是「剩余」(= B0 − U);U>0 时两者相差 U,直接替换导致低估、误拦
- 仅在同步时点 U=0(日初/刚返还)巧合正确(doubao 场景 stable=2.2M 无碍)
- 教训:**「剩余额度」不能当「累计限额」用**;两者通过 `usage + balance` 桥接(v5)
| 场景 | v2 现状 | v4 |
|---|---|---|
| 余额 2M,昨日 10K | 可用 ≈2M | min(2M, 1.7M)=1.7M,不锁死 ✓ |
| 余额 1.558M,今日已采 1.696M | 不拦(膨胀到 3.26M) | 立即拦(1.696 ≥ 1.258)→ 止损 |
| 明日余额跳涨(返还 1.696M) | — | 红线升 1.4M,自动解锁 |
### 7.4 待观察项(2026-08-12)
- 与消耗任务防线「余额快照 − 已烧 ≤ 0 停」同一把尺子(merge-auto-consume.md §4.4)
- 连带改动:`get_effective_limit` 兜底链不变(stable → FALLBACK_LIMIT 90 万);
文档同步(merge-auto-consume.md §4.2、AGENTS.md 限额描述)
- **BUFFER(现 30 万)**:防「同步时点 B 滞后窗口内的消耗」。13:36 实测高估约 50 万
> 30 万 BUFFER → 若滞后窗口内流量大,v2 会多放行到虚高 stable;可调大(如 50 万,env)
- **部署**:v5 已改(工作区),需重启 litellm 容器加载;重启在生产主机由用户执行
### 7.4 实施后待观察项(2026-08-12)
### 7.5 v5(2026-08-12 修正,当前):恢复 v2 骨架
- **BUFFER(现 30 万,未调大)**:防「余额 API 滞后窗口内的消耗」。实测 20 万内不动 + 10 万冗余;
滞后上限未知,若观察同步间隔内(burst 阈值 50 万)烧穿,调大(如 50 万,env 可调)
- **部署**:代码已改(工作区),需重启 litellm 容器加载(挂载文件);重启在生产主机由用户执行
```
stable_limit = max(0, usage + balance − BUFFER)
```
- 与 v2(§7.1)公式相同,区别在**论证与认识**:v2 数学正确(B 收敛后 = B0 − U),
不需要冻结快照;v4 的「剩余当上限」误拦由「usage + balance 桥接」天然避免
- 实测验证(14:59:51 同步 + 15:09:51 生产日志):U=1,696,135、B=596,869 →
stable=1,993,004 → 今日剩余可用 296,869(账上 59.7 万用到剩 30 万 BUFFER)✓
- 防扣费语义不变:usage 撞 stable = 剩余恰为 BUFFER 时停,扣费结构性杜绝;
balance < BUFFER(U=0)→ stable=0 → 全拦
- 保留:`get_effective_limit` 兜底链(stable → FALLBACK_LIMIT 90 万)、pre-block reserve、
软踢/恢复、低余额加密同步(600s/300s)
---
## 8. 排障速查(今日结论汇总)
1. 看到 Today > Rem 不是异常,先分清口径(§5);但**按 §2 口径,超余额部分已在扣费**,应立即收闸
2. 余额显示不动 ≠ 余额充足,是 API 滞后;以最近快照 + BUFFER 为准
3. 判断「还能免费采多少」:`min(2M, 最近余额快照 − BUFFER) − 今日已采`(v4 已落地)
1. 看到 Today > Rem 不是异常,先分清口径(§5);判扣费用「守恒初始池」(U+B 反推),
不要用任意时点快照(13:36 滞后快照曾误判「超余额扣费」,实际无扣费)
2. 余额显示不动 ≠ 余额充足,是 API 滞后;同步快照 + BUFFER 兜滞后窗口
3. 判断「还能免费采多少」:`(usage + balance − BUFFER) − 今日已采`(v5 已落地)
4. 消耗任务 23:00 直连 Ark 绕过 LiteLLM 闸门(防自杀),其自身 clamp:`plan ≤ 2M − usage`、
`plan ≤ 余额快照 − 已烧 − BUFFER`,停止条件三闭环
5. 扣费既成事实不可挽回(如 08-12 的 137,828);能做的只有止损(收闸)与次日恢复(返还)
5. 余额滞后收敛后守恒成立(B = B0 − U);30 天过期蒸发是余额下跌的另一来源,
与消耗扣减区分(如 08-12 余额 1,558,307 → 596,869,其中约 50 万为滞后修正 + 过期)
---
## 9. 待确认/风险清单
- [ ] 余额 API 滞后上限实测(决定 BUFFER 是否调大,现 30 万)
- [x] v4 方案批准与实施(2026-08-12,§7.3;待生产主机重启生效)
- [ ] 余额 API 滞后上限实测(决定 BUFFER 是否调大,现 30 万;13:36 实测高估 ~50 万)
- [x] v4 误拦发现与回退(2026-08-12 15:09 生产日志实证,§7.3)
- [x] v5 恢复 v2 骨架(2026-08-12,§7.5;待生产主机重启生效)
- [ ] 消耗任务口径是否同步收紧(可选:其停止条件与闸门同一把尺子已满足)
- [ ] 空窗期(0:00–返还到账)行为观察:v4 下余额红线自动收紧,确认无异常误杀
- [ ] 空窗期(0:00–返还到账)行为观察:v5 下余额红线自动收紧,确认无异常误杀