Files
litellm-config/merge-volc-limit-into-newapi.md
T

8.2 KiB
Raw Blame History

火山引擎免费额度单日限制合入 new-api 的可行性分析

日期:2026-08-05 背景:litellm 目前唯一实质用途是 volc_limit_sync.py(火山引擎免费资源包的单日用量限制)。考虑将该功能合入 new-api(另一台服务器的 ~/workspace/new-api,deploy 分支 fork),从而退役 litellm。 证据来源:volc_limit_sync.py(本仓库)与 /root/workspace/new-api 源码(HEAD e4324841,2026-08-01,upstream QuantumNous/new-api 活跃)。

一、现状:volc_limit_sync.py 的四个核心能力

单文件 1393 行,挂在 LiteLLM 回调上,由后台守护线程驱动:

能力 实现 位置
火山余额同步 SigV4 签名调 ListResourcePackages,分页拉取资源包;normalize_volc_name 去后缀归一化;按监控模型聚合余额 fetch_all_packages / process_packages_breakdown
动态限额(Peak-Buffer) PeakPool = 当日用量 + 余额;峰池跟踪(余额跳升 >5% 立即信任、骤降接受、初始化/漂移取当前值);stable_limit = PeakPool − 15% margin(下限 25w);与静态 HARD_DAILY_LIMITS(含 api_base hash 精确匹配、模糊匹配、__DEFAULT__ 兜底)取小得 effective_limit get_effective_limit + active_monitor_loop
当日用量计数 成功回调 INCRBY total_tokens → Redis daily_usage:{北京日期}:{clean_model}:{api_base_hash};北京时间 00:00 滚动,TTL 2 天 _record_usage / get_usage_key
超限停用/恢复 soft_evict_from_router 把 router 中 model_name 重命名为 xxx-limit-reached 软踢;北京时间早 7–13 点每 30 分钟、其余 4 小时检查恢复;启动时 startup_audit 预踢超额模型 soft_evict_from_router / restore_blocked_models / startup_audit

监控模型自动发现:从 config.yaml 解析 volcengine/ 前缀 + HUOSHAN_BASE_URL/volcengineapi 的条目,构建 MONITORED_MODEL_PAIRS(模型名 + api_base hash);常规版本号模型自动推导别名,特殊别名走 MANUAL_MONITORED_MODEL_ALIASES。

要点:按「模型 + 端点」粒度限制;成功后被动踢(滞后一个请求);靠直接改 LiteLLM router 内部结构实现,较为 hacky。

二、new-api 现状调查结论

✅ 可直接复用的机制

  • volcengine 是原生渠道:relay/channel/volcengine/ 完整适配器(constant.ChannelTypeVolcEngine,adaptor.go:242),支持 chat/embedding/images/TTS,GetRequestURL 走 /api/v3/...。
  • 渠道状态机:Status:1=启用 / 2=手动禁用 / 3=自动禁用(common/constants.go:252-254);service.DisableChannel / EnableChannel(service/channel.go:19-36);自动禁用链路 processChannelError → ShouldDisableChannel + AutoBan(controller/relay.go:399-404)。
  • 定时任务基建:通用 SystemTaskRunner(DB 租约去重、多 master 互斥、ScheduledSystemTaskHandler 接口 Type/Run/Enabled/Interval/NewPayload,service/system_task.go:29-44;main.go:151-152 启动)。另有订阅配额每日重置任务 StartSubscriptionQuotaResetTask(ticker 1min 批量重置,含 daily 对齐次日 0 点的 calcNextResetTime,model/subscription.go:352-381,main.go:129)。
  • 用量数据:quota_data 表按 模型 × 渠道 × 小时 聚合(LogQuotaData 截断到小时,model/usedata.go:78-81);logs 表有每次请求 token 明细(RecordConsumeLog,model/log.go:343)。按模型查当日用量现成。
  • 渠道级限流范式:service/channel_rate_limit.go(Redis 固定窗口 RPM 检查,relay 重试循环内排除被限渠道并 429)——与「每日限额」几乎同构,是最佳参考实现。
  • 渠道额外设置 JSON 扩展范式:ChannelOtherSettings(relaykit/dto/channel_settings.go:68-91,含 RateLimitEnabled/RateLimitRPM/RateLimitTPM)——每日限额字段可照此扩展。
  • 程序化渠道管理 API:POST /api/channel/:id/status(启停)、PUT /api/channel/(改配置)、GET /api/channel/(列表)(router/channel-router.go:39-90)——旁路方案 B 的基础。

❌ 完全缺失的(全仓库 grep DailyLimit/每日限额 0 命中)

  • 渠道/模型的每日额度限额字段与执行逻辑(Channel 表只有累计 UsedQuota,只增不减)。
  • 令牌配额每日重置(一次性扣减;subscription 每日重置是唯一先例)。
  • 火山余额同步(适配器只转发、不查账)。

三、可行性结论:可行,且 new-api 架构上更合适

  1. 可请求前拦截:渠道选择在 middleware.Distribute / controller.Relay 重试循环(controller/relay.go:204-210,与 RPM 限流同款位置)完成,可在请求发出前跳过超限渠道——优于现状「成功后才踢」,杜绝超限瞬间的漏网请求。
  2. 停用/恢复有现成状态机:无需 hack router 内部结构;自动恢复可借鉴周期渠道测试的 PassiveRecovery 模式(controller/channel-test.go:1024)。
  3. 同步任务有框架:火山余额同步做成一个 ScheduledSystemTaskHandler,天然多 master 安全。
  4. litellm 可退役:合并后 litellm + redis + postgres 三个容器下线,消除一个攻击面(docker-compose 注释已提示 litellm 1.82.7/1.82.8 被投毒)。

四、两条合入路径对比

A. 改 fork 源码(Go 实现) B. 不改源码:独立守护进程 + 管理 API
做法 在 deploy fork 上加每日限额功能(字段 + 检查点 + 同步任务 + 前端) 改造 volc_limit_sync.py 去掉 litellm 依赖:查 new-api DB/Redis 统计当日用量 → 调 POST /api/channel/:id/status 停/启渠道;余额同步逻辑原样保留
拦截时机 请求前(跳过渠道 / 429) 成功后停渠道(与现状一致,滞后一个请求)
成本 Go 开发 + 前端表单 + fork 维护 Python 改造 + 一个常驻进程
优点 彻底、架构最干净、UI 可配置 不碰 Go、可快速上线、可作 PoC
缺点 工作量大;upstream 更新极频繁需持续同步 无法请求前拦截;多一个系统要运维

倾向推荐 A:已在用带定制功能的 deploy fork(RPM 限流、订阅重置、系统任务均为 fork 自加),fork 维护成本已存在;A 方案下「超限恢复」可与渠道自动测试/恢复机制统一。

五、路径 A 改造点清单

  1. ChannelOtherSettings 扩展每日限额配置:DailyLimitEnabled / DailyLimitTokens / 火山余额同步开关等。
  2. 新增 service/channel_daily_limit.go:当日用量计数(Redis INCR,北京时间滚动,仿 service/channel_rate_limit.go 固定窗口)。
  3. 检查点:controller/relay.go:204-210 重试循环内跳过超限渠道(或直接 429)。
  4. 新增 SystemTaskHandler:火山余额同步(SigV4 ListResourcePackages + 归一化 + Peak-Buffer 动态限额),结果写 Redis/DB。
  5. 超限处理:渠道级用 DisableChannel;粒度注意——litellm 按「模型」限,new-api 需按「渠道 + 模型」统计(quota_data 有 ChannelID+ModelName 双维度,正合适)。
  6. 前端渠道编辑表单加每日限额字段。
  7. 迁移 config.yaml:别名 1:N 映射(如 doubao-seed-nothink → 3 个上游模型)在 new-api 中 model_mapping 是 1:1,需用「多个渠道声明同一对外模型名 + 权重轮询」实现。

六、风险提示

  • Peak-Buffer 算法是多年调出来的业务资产(跳升信任 / 骤降接受 / 15% 边际 / 30w 缓冲 / 空闲感知 + 突发检测的动态同步间隔),移植时须完整保留,勿简化。
  • fork 分支特殊性:系统任务 / RPM 限流 / 订阅重置等基建上游 main 没有;若目标是反哺上游,需在纯上游上重新评估。
  • 密钥暴露面:迁移后 new-api 直接持有火山 AK/SK(目前只存在于 litellm 服务器 env),需评估。
  • 北京时间语义:每日重置必须按 UTC+8 对齐(现有 get_usage_key 与订阅重置 calcNextResetTime 均有先例)。

七、后续可选动作

  1. 路径 A 详细技术设计(数据模型 + 关键函数签名 + 前端字段)。
  2. 路径 B 快速 PoC(可运行的旁路守护进程验证效果)。
  3. 仅迁移规划(config.yaml 别名 → new-api 渠道配置映射表)。