From b7df36bb4ebd5827fa1c4e320ce4be8204382ca8 Mon Sep 17 00:00:00 2001 From: vibe-code Date: Tue, 11 Aug 2026 13:38:32 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20dynamic=20=E9=99=90=E9=A2=9D=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E6=97=B6=20fallback=20=E4=BF=9D=E5=AE=88=E5=85=9C?= =?UTF-8?q?=E5=BA=95=EF=BC=88FALLBACK=5FLIMIT=2090=E4=B8=87=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 免费模型余额常态 <2M(昨日采多少返多少),stable_limit 缺失窗口 (首次同步前/新增模型/TTL 过期)此前 fallback 裸奔到静态 2M, 余额不足的模型会被烧穿扣费。改为 min(static, FALLBACK_LIMIT=90万)。 --- AGENTS.md | 2 +- merge-auto-consume.md | 2 ++ volc_limit_sync.py | 14 +++++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b6ba14d..59361e1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ - **核心逻辑**:通过 `quota_interceptor` 拦截请求,并通过 `DailyLimitHandler` 记录用量到 Redis。后台 `active_monitor_loop` 守护线程定期从火山引擎 API 同步配额到 Redis。 - **架构**:主逻辑在 `volc_limit_sync.py`(限额 + 同步守护 + 每日消耗调度),消耗任务拆分在 `volc_consume.py`(每日北京时间 23:00 由守护线程延迟导入触发;见 `merge-auto-consume.md`)。LiteLLM 通过 `config.yaml` 中 `callbacks: ["volc_limit_sync.proxy_handler_instance"]` 加载回调,模块加载时自动启动后台同步线程。 - **关键文件**: - - `volc_limit_sync.py`: **核心文件**,包含同步守护线程(`active_monitor_loop`)、LiteLLM 回调(`DailyLimitHandler` + `quota_interceptor`)、限额计算(v2 简化:`stable_limit = usage + balance − BUFFER`)、模型屏蔽/恢复、以及每日 23:00 消耗任务调度(`_maybe_trigger_daily_consume`,SETNX 去重)。 + - `volc_limit_sync.py`: **核心文件**,包含同步守护线程(`active_monitor_loop`)、LiteLLM 回调(`DailyLimitHandler` + `quota_interceptor`)、限额计算(v2 简化:`stable_limit = usage + balance − BUFFER`,dynamic 缺失时 fallback `FALLBACK_LIMIT` 90 万兜底)、模型屏蔽/恢复、以及每日 23:00 消耗任务调度(`_maybe_trigger_daily_consume`,SETNX 去重)。 - `volc_consume.py`: 消耗任务模块(每日 23:00 触发;手动 `python volc_consume.py --dry-run` / `--force`)。复用 volc_limit_sync 的拉包/归一化/用量记账设施,直连 Ark API 洗即将过期的免费资源包(防 30 天过期蒸发)。 - `config.yaml`: LiteLLM 配置文件,包含模型定义和回调配置。 - `docker-compose.yml`: 容器编排,仅挂载 `config.yaml` 和 `volc_limit_sync.py`。 diff --git a/merge-auto-consume.md b/merge-auto-consume.md index 9ffa81b..ec90c50 100644 --- a/merge-auto-consume.md +++ b/merge-auto-consume.md @@ -188,6 +188,8 @@ HARD_DAILY_LIMITS → 统一 2M(采集上限;doubao-seed-code-preview-251028 - 消耗任务 23:00 烧(usage 计入):池不变 → 滞后窗口内限额偏松 ≤ BUFFER ✓ - 余额耗尽:池 − 30 万 ≤ 0 → 限额 0 → 全拦,扣费结构性杜绝 ✓ +**fallback(stable_limit 缺失窗口)**:免费模型余额常态 < 2M(昨日采多少返多少),若 dynamic 缺失(首次同步前/新增模型/TTL 过期)时裸奔到静态 2M,余额不足的模型会被烧穿扣费。故 fallback 用保守值 `FALLBACK_LIMIT = min(static, 90万)`(env 可调),宁可短时收紧不可裸奔。 + **与消耗任务同构**:限额放行条件 = `balance − BUFFER ≥ 0`;消耗任务停止条件 = `余额快照 − 已烧 ≤ 0`——同一把尺子。 ### 4.3 简化后保留/删除清单 diff --git a/volc_limit_sync.py b/volc_limit_sync.py index 097077f..963c9fb 100644 --- a/volc_limit_sync.py +++ b/volc_limit_sync.py @@ -95,6 +95,11 @@ SYNC_INTERVAL = 60 CHECK_INTERVAL = 10 THRESHOLD = 300000 +# stable_limit 缺失时(首次同步前/新增模型/TTL 过期)的保守兜底限额。 +# 免费模型余额常态 < 2M(昨日采多少返多少),若 fallback 裸奔到采集上限 2M, +# 余额不足的模型会被烧穿扣费。宁可短时收紧,不可裸奔。 +FALLBACK_LIMIT = int(os.getenv("FALLBACK_LIMIT", "900000")) + # Redis Config REDIS_HOST = os.getenv( "REDIS_HOST", "redis" @@ -437,9 +442,12 @@ def get_effective_limit(clean_model, api_base, current_usage=None): except (ValueError, TypeError): effective_limit = calculate_effective_limit(static_limit, None) else: - # Fallback: If daemon hasn't calculated stable limit yet, use old logic? - # Or just use static. Safer to wait for daemon. - effective_limit = calculate_effective_limit(static_limit, None) + # Fallback: 如果 daemon 尚未计算 stable limit(首次同步前/新增模型/TTL 过期), + # 用保守兜底(FALLBACK_LIMIT),绝不裸奔到采集上限 —— 免费模型余额常态 < 2M, + # 裸奔 2M 会把余额不足的模型烧穿扣费。 + fallback = float(static_limit) if static_limit is not None else float(FALLBACK_LIMIT) + fallback = min(fallback, float(FALLBACK_LIMIT)) + effective_limit = calculate_effective_limit(fallback, None) # Legacy fallback (Optional: Enable if you want immediate loose limits before first sync) # dynamic_remaining = redis_client.get(f"limit:dynamic:volcengine:remaining:{clean_model}")