# 火山引擎免费额度单日限制合入 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 渠道配置映射表)。