feat: 优化火山引擎配额同步策略

- 添加硬限制: doubao-seed-code 480w/日, 其他模型 180w/日
- 强制北京时间(UTC+8)计算日期,确保 Docker 容器时区无关
- 移除'忽略小跌'逻辑,Pool 下跌时立即接受(更保守的风控)
- 优化轮询间隔适配小时级 API 延迟(减少无效请求)
This commit is contained in:
kim
2026-01-30 00:39:06 +08:00
parent dd8cbe5f63
commit f16af28dfe
+43 -28
View File
@@ -120,11 +120,10 @@ VOLC_MANAGED_PAIRS = set()
# Format: "clean-model-name": limit_in_tokens
# Or with hash: "clean-model-name:hash": limit_in_tokens
HARD_DAILY_LIMITS = {
# 示例 Examples:
# "doubao-pro-32k": 10_000_000, # Limit Doubao Pro to 10M tokens/day
# "deepseek-v3": 5_000_000, # Limit DeepSeek V3 to 5M tokens/day
# Specific endpoint limit / 特定端点限额
# "deepseek-v3-2-251201:ba0383d3": 1_600_000,
# Specific Limit for Doubao Code
"doubao-seed-code-preview-251028": 4_800_000,
# Default Limit for all other models (Universal Fallback)
"__DEFAULT__": 1_800_000,
}
# ==========================================
@@ -245,9 +244,12 @@ def get_signed_headers(action, version, body_dict, service="billing"):
# 🎯 Limit Logic (Unified)
# ==========================================
def get_usage_key(clean_model, api_base=None):
# Enforce Beijing Time (UTC+8) for daily key rotation at 00:00 CST
# Beijing 00:00 = UTC 16:00 (Previous Day) -> simple offset: UTC_timestamp + 8 hours
now = time.time()
adjusted_time = now - 3600 # UTC+1 split
date_str = time.strftime("%Y-%m-%d", time.gmtime(adjusted_time))
beijing_time_ts = now + (8 * 3600)
date_str = time.strftime("%Y-%m-%d", time.gmtime(beijing_time_ts))
suffix = f":{generate_api_base_hash(api_base)}" if api_base else ""
return f"daily_usage:{date_str}:{clean_model}{suffix}"
@@ -267,8 +269,15 @@ def get_static_limit(clean_model, api_base):
# 3. Fuzzy Match
for quota_model, limit_val in HARD_DAILY_LIMITS.items():
if quota_model == "__DEFAULT__":
continue
if ":" not in quota_model and quota_model in clean_model:
return limit_val
# 4. Universal Default Fallback
if "__DEFAULT__" in HARD_DAILY_LIMITS:
return HARD_DAILY_LIMITS["__DEFAULT__"]
return None
@@ -834,7 +843,10 @@ def active_monitor_loop():
try:
time.sleep(CHECK_INTERVAL)
now = time.time()
today_str = datetime.datetime.now().strftime("%Y-%m-%d")
# Enforce Beijing Time for daily operations
beijing_time_ts = now + (8 * 3600)
today_str = time.strftime("%Y-%m-%d", time.gmtime(beijing_time_ts))
# Idle Check
usage_key_global = f"daily_usage:{today_str}:global_total"
@@ -863,20 +875,22 @@ def active_monitor_loop():
# < 100w -> 60min (3600s)
# >= 100w -> 60min (3600s)
# Determine Base Sync Interval based on global risk
# < 100k -> 5 min (Emergency but limit API calls due to latency)
# < 300k -> 5 min (Safe Sailing)
# < 500k -> 10 min (Speed Mode)
# < 800k -> 30 min (Normal Mode)
# >= 800k -> 60 min (High Tide Mode)
# Determine Base Sync Interval based on global risk (Optimized for Hourly Latency)
# Since API updates are hourly, frequent polling provides no new info and wastes resources.
# We trust Redis Usage for real-time gating.
# < 100k -> 5 min (Emergency check for the update moment)
# < 300k -> 10 min
# < 500k -> 20 min
# < 800k -> 45 min
# >= 800k -> 60 min
if global_min_remaining < 100_000:
base_interval = 300 # 5 minutes (Increased from 2m)
elif global_min_remaining < 300_000:
base_interval = 300 # 5 minutes
elif global_min_remaining < 500_000:
elif global_min_remaining < 300_000:
base_interval = 600 # 10 minutes
elif global_min_remaining < 500_000:
base_interval = 1200 # 20 minutes
elif global_min_remaining < 800_000:
base_interval = 1800 # 30 minutes
base_interval = 2700 # 45 minutes
else:
base_interval = 3600 # 60 minutes
@@ -986,12 +1000,11 @@ def active_monitor_loop():
# Sum usage across all configured endpoints for this model (usually just one)
for h in target_hashes:
# Replicate get_usage_key logic
# UTC+1 split logic from get_usage_key
# Replicate get_usage_key logic (Beijing Time UTC+8)
now_ts = time.time()
adjusted_time = now_ts - 3600
beijing_time_ts = now_ts + (8 * 3600)
usage_date = time.strftime(
"%Y-%m-%d", time.gmtime(adjusted_time)
"%Y-%m-%d", time.gmtime(beijing_time_ts)
)
u_key = f"daily_usage:{usage_date}:{target}:{h}"
val = redis_client.get(u_key)
@@ -1037,14 +1050,16 @@ def active_monitor_loop():
redis_client.setex(peak_key, 172800, int(current_peak))
# 2. DROP DETECTION (Resource Expiry)
# If pool drops MASSIVELY (>20%) below historical peak, it's likely an expiry.
# We accept this drop. If it was just a glitch, Rule #1 will fix it next time it bounces back.
elif (
total_pool < (historical_peak * 0.8) and historical_peak > 0
):
# 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.
elif total_pool < historical_peak and historical_peak > 0:
drop_ratio = (
historical_peak - total_pool
) / historical_peak
if DEBUG_MODE:
print(
f"DEBUG: 📉 Expiry/Drop Detected ({int(historical_peak):,} -> {int(total_pool):,}) - Adjusting Limit Down.",
f"DEBUG: 📉 Pool Drop Detected ({int(historical_peak):,} -> {int(total_pool):,}) - Ratio: {drop_ratio:.1%} - Adjusting Limit Down.",
flush=True,
)
current_peak = total_pool