API Key 软预算
所有模型的普通对话、工具调用和原生透传统一采用软预算。图片生成、按秒、按查询等已有模型计费维度保留;仅对话中的托管工具次数不额外收费。每次实际请求上游前检查 Key、用户、团队、组织及项目的可用余额;任一适用层级耗尽即拒绝新请求。已有的固定额度分配、模型权限、RPM/TPM 限制仍独立生效。
- 可用余额大于零就允许本次请求完成;不按模型完整上下文预占,不由预算模块注入 4096 Token 输出上限。
- 正常完成后按实际输入、输出、缓存 Token 计费;请求开始时冻结价格,保留缓存期限及价格分档语义。
- 单次或并发请求可能超支,余额变成负数后拒绝后续请求。一个 CLI 任务包含多次请求,不保证整个多轮任务都完成。
- 客户端的输出限制保持原值,其他协议转换/上游协议必填参数规则不变。
- 搜索等工具次数不额外收费,响应和日志仍保留原始 usage。软预算不等于网关实现了所有上游工具或跨协议能力。
- 缺失、冲突用量或不完整价格不编造费用,日志标记未定价。账单存储失败会保留待结算记录;恢复前新请求可返回 503,防止将未知存储状态当成余额。
响应头:X-XHub-Budget-State: token_only、X-XHub-Budget-Guarantee: soft、X-XHub-Billing-Scope: tokens_only、X-XHub-Tool-Costs: excluded。不再产生整窗预占响应头。
升级与历史账单
历史预占记录不会自动清空。旧版本产生的 submitted/uncertain/settling 记录继续计入占用,须通过原对账流程核实后结算或释放。切换版本应停止旧网关接收新请求并等待在途请求完成,避免混跑两套准入策略。不要用删除预占表、清空 Redis 或重置用户消费的方式迁移。
本页面保留原文件名以兼容已有链接。下方是旧实现说明,仅供核对旧记录,不代表当前准入行为。
历史:硬预算实现
API Key 硬额度
当 Key、所属用户、团队、组织或项目任一层有预算上限时,每次实际调用上游前,XHub 在 PostgreSQL 事务中预占本次费用上界。多个网关实例共享同一预占记录;重试是新的尝试,需要新的预占。全部层级余额足够才会外发。
输出上限和可用余额
未声明输出上限的有限额请求默认使用 4096 Token;部署声明的更小输出上限会进一步收紧默认值。合法的显式上限会保留,超过部署上限或同时提交多个上限字段会被拒绝。上限写入经过历史恢复、护栏和协议转换后的最终上游 JSON,包括原生协议路径。
| 实际上游协议 | 输出字段 |
|---|---|
| Responses | max_output_tokens |
| Messages | max_tokens |
| Chat Completions | 可信能力声明中的 max_completion_tokens,或受支持的 max_tokens |
Chat 同时支持两种字段时使用包含隐藏推理的 max_completion_tokens。仅声明旧 max_tokens 的部署默认不能执行显式推理请求。若供应商已明确保证该字段包含隐藏推理,管理员可在 model_info 设置布尔 max_tokens_includes_reasoning: true,并填写非空 max_tokens_semantics_source 文档来源;字段名称、供应商名称或一次返回 200 都不能替代这个语义认证。字符串 "true" 不算认证。Messages 的 thinking.budget_tokens 必须小于总输出上限。达到输出上限可能返回长度截断/未完成状态,客户端应处理该状态。
输入按部署可信的整个输入窗口预占,不使用字符数推算 Token。因此,即使提示词很短,余额也可能不足以覆盖一次预占。预占不是已消费金额;可靠完整的用量到达后,按本次冻结费率结算实际费用,并在同一事务释放差额。
以下响应头用于检查本次已准入尝试:X-XHub-Max-Output-Tokens、X-XHub-Budget-Input-Bound、X-XHub-Budget-Reserved、X-XHub-Budget-Reservation-Id、X-XHub-Budget-State。流开始后,响应头中的状态不会追踪最终结算状态,最终状态应回读 Key 详情。
部署必须提供可信计费信息
输入窗口从部署 model_info、litellm_params、匹配的模型目录依次查找 max_input_tokens 或 context_length。Chat 还需要可信的 supported_parameters。模型名称或协议兼容标签本身不能证明这些能力。
以下是虚构的配置结构示例,不是 GPT、DeepSeek、Grok 或 Claude 的真实规格/价格。管理员必须按已验证供应商合同填入真实上限和价格;填写一个较小的数字不能让上游自动遵守该输入窗口。缺少可信信息时应保持拒绝。
{
"model_name": "budgeted-text-example",
"litellm_params": {
"model": "provider-text-model",
"input_cost_per_token": 0.000001,
"output_cost_per_token": 0.000002,
"cache_read_input_token_cost": 0.0000001
},
"model_info": {
"pricing_source": "manual",
"max_input_tokens": 32768,
"max_output_tokens": 8192,
"supported_parameters": ["max_completion_tokens"]
}
}此例无写缓存时,4096 输出的预占至少为 32768 × 0.000001 + 4096 × 0.000002 = 0.04096 USD;这不是该请求最终账单。价格字段按每 Token USD 填写。手工定价必须完整,不会用目录价格偷偷补齐缺失项。目录定价模式下,价格字段的 null 表示清除覆盖,继续使用完整目录契约;非 null 的非法覆盖仍明确拒绝。缓存读取、缓存写入及 1 小时写缓存需要各自对应费率;条件价格、缺失或矛盾的阶梯价格、未覆盖的计费维度不能按零费用放行。
本版严格预算支持具备可信上界的文字生成、客户端工具往返,以及统一 token 价格的用户图片输入。图片沿用可信完整输入窗口预占,不估算图片像素 token;input_images_included 冻结在计价快照中。上游图片 token 明细必须属于总输入 token 的子集,结算不重复收费,冲突或越界保留待核对占用。原生 Messages 支持 Read 等客户端工具返回图片;工具图片的跨协议桥接仍明确拒绝。独立图片收费、图片生成、音视频、服务器执行的工具/搜索、远程历史引用、未知费用维度以及未认证的字段会明确拒绝。全链路都没有预算上限的请求保持原有兼容路径;不能用取消预算限制作为宣称硬额度已生效的手段。
上下文分档价格
目录的 pricing_rules_v2 是分档原始契约;旧平面 rates / input_cost_per_token 可能仅由第一档生成,不能代表整个上下文窗口。本版在请求开始时冻结全部可达档位、原始输入/输出区间和每档 USD 费率。预占使用各收费维度的最坏可达费率,实际结算按实测输入总量与输出量选择冻结档位;独立缓存读、缓存写计数计入输入上下文,缓存命中不把长上下文变成短档。更新目录不影响已经外发请求的价格。
原始档位必须完整覆盖声明窗口及输出上限,没有区间缺口或内部重叠,并提供明确的 unit_price_usd、正整数 unit_size 和对应 unit_name。零美元是有效价格,缺少 USD 字段不是零,也不会从人民币展示价格猜汇率。动态条件、未知计费维度、混合缓存 TTL 等仍拒绝。
当前目录没有声明相邻区间共享阈值的开闭语义。例如 [0, 272000] 与 [272000, 99999999] 在实测输入恰为 272000 时不能擅自选高档或低档。预占覆盖两者;如果两档完整费率相同可以结算,否则保留 uncertain 占用并记录 ambiguous catalog pricing boundary,不生成可靠费用。管理员须依据供应商明确的阈值合同核对,不得改小输入窗口或把首档复制成手工价来绕过认证。
错误与待核对占用
| HTTP / 错误码 | 含义与处理 |
|---|---|
400 invalid_request |
上限或请求参数无效;修正请求后再调用。 |
400 unsupported_budget |
无法证明费用上界;补齐可信配置,或使用已支持的能力。 |
429 budget_reservation_exceeded |
可用余额不足以预占本次上界;降低合法输出上限或按管理流程调整预算。 |
503 quota_unavailable |
无法可靠读取或持久化额度状态,或升级前旧队列未清空;恢复存储并核对队列。 |
超时、取消、截断流、缺失/冲突/非法用量、超出声明上界等情况,不能证明上游免费。已提交尝试的占用保留为待核对状态,既不会凭超时自动退款,也不会把未知费用显示为可靠的零费用。上游违反声明时,网关保留证据和占用;网关无法控制供应商实际向其账户收取的金额。
正常达到输出上限时,Responses 的 status=incomplete 且 incomplete_details.reason=max_output_tokens 是明确终态。原生旁路会保留该状态和原始输出;终态自带完整、可靠用量时按实测费用结算并释放差额,即使工具参数字符串恰好被上限截断。客户端不能执行残缺参数。完整的 Responses 终态无需等待上游关闭 HTTP 连接;缺失或不可靠的终态用量仍保留待核对占用。
Key 详情展示 budget_pending 与授权可见的 budget_reservations。状态包括 reserved、submitted、settling、uncertain;尝试 ID 和原因用于管理员关联上游账单。这里不提供一键释放或按 TTL 自动清理。需要人工核对的占用,应先停止相关调用、保存价格快照和上游账单,并由运维按经审查的恢复方案处理,不能直接批量删除记录。
已收到完整用量但结算事务暂时失败时,独立 usage_pending 快照用于幂等重放;只有实际账单事务成功才释放占用。PostgreSQL 整库不可写的持久化边界仍见 Issue #35;已有预占会保守保留,未证明费用的请求不能当作已结算。
升级和配置切换
- 停止相关范围的新调用,等待在途请求结束,核对并排空旧 Redis 账单和 PostgreSQL
usage_pending。不能清空 Redis 来冒充结算完成。 - 所有网关节点升级到包含预占逻辑的版本;禁止旧版本写入者与新版本混跑后宣称硬额度保证。
- 核实模型输入窗口、输出字段和完整费率,再配置预算。把无限额改为有限额也必须先排空在途请求:旧的无限额调用无法事后补上费用上界。
- 使用专用有限额 Key 验证缺省上限、并发拒绝、实际用量结算和 Key 详情,再恢复流量。
已有有限额度之间的调整需要同时覆盖已消费和预占金额。组织按固定周期管理预算时,旧周期尝试仍保留用于对账,但不会占用组织的新周期预算;用户、Key 等其他层级仍按各自预算规则计算。