Files
cpa-plugin/docs/modules/billing-and-pricing.md
T
2026-08-15 22:31:12 +08:00

8.7 KiB

额度与计费

模块定位

额度与计费负责回答三个问题:一次请求是否还可以开始、请求实际产生了多少成本、该用户当前还剩多少可用额度。

每个用户 Key 拥有独立的美元额度账户、重置周期和并发上限。系统没有套餐、订阅或充值订单,管理员直接分配额度。

当前能力

能力 当前实现
用户额度 每个 Key 独立设置本周期美元额度
请求扣费 根据最终 Token Usage 和模型价格结算
自动重置 支持不重置、每日、每周和每月
手动重置 管理员可立即开始新额度周期
并发限制 每个 Key 独立限制同时执行的请求数
价格规则 支持基础价格、长上下文价格和 Fast 倍率
参考价格 搜索并显式导入 models.dev 供应商级价格,刷新前展示差异
计费账目 永久记录扣费、额度调整和周期重置
请求拦截 余额、并发或价格不满足时在上游调用前拒绝

额度账户

每个 Key 创建时同时创建一个额度账户,默认值为:

属性 默认值
本周期额度 $0
已用金额 $0
可用余额 $0
自动重置 不重置
并发上限 4

三项金额的关系始终为:

可用余额 = 本周期额度 - 本周期已用金额

金额在数据库中以微美元整数保存,管理接口使用最多六位小数的美元字符串,避免浮点累计误差。

修改额度只改变本周期额度,不会清空已经产生的消费。例如额度为 $10、已用 $3 时,将额度改为 $5,余额会变为 $2

请求准入与结算

计费采用“请求前准入、请求后结算”的软限制:

  1. 请求开始前读取当前额度周期。
  2. 如果已经到达重置时间,先执行周期重置。
  3. 余额必须大于零。
  4. 当前并发必须小于用户并发上限。
  5. 为 Request ID 创建并发占用后放行请求。
  6. 请求终态到达时释放并发占用。
  7. 最终 Usage 到达后计算成本、增加已用金额并写入扣费账目。

系统不会在请求开始前估算并冻结最大费用,因此最后一个或多个并发请求可能让余额变成负数。负余额会被保留,之后的新请求不再放行,直到管理员提高额度或开始新周期。

同一个 Request ID 的重复准入不会重复占用并发;同一条 Usage 的重复回调也不会重复扣费。插件重新启动时会释放上次进程遗留的未关闭并发占用。

并发限制

并发上限可以设置为 1–64。计数基于已经准入且尚未收到请求终态的 Request ID。

  • 达到上限时,新请求返回 HTTP 429 和 billing_concurrency_exceeded
  • 成功、失败、拒绝或取消的请求进入终态后都会释放名额。
  • 重复或迟到的终态回调不会重复释放或破坏计数。

并发限制只控制同时执行数量,不限制单位时间请求次数或 Token 数量。

额度重置

重置方式 行为
none 永不自动重置
daily 按天开始新周期
weekly 每七天开始新周期
monthly 按月开始新周期
手动重置 立即结束当前周期并开始新周期

未指定首次重置时间时,系统以 Key 创建时间作为周期锚点计算下一次重置。周期计算使用 Asia/Shanghai 时区;月度锚点在较短月份不存在时使用该月最后一天。

重置后:

  • 本周期已用金额归零;
  • 新周期额度沿用当前额度设置;
  • 可用余额恢复为完整额度;
  • 旧周期余额不结转;
  • 历史周期和账目继续保留。

自动重置在读取额度状态或执行请求准入时检查,不依赖常驻定时任务。

模型价格

每个模型使用精确模型名称维护一套价格策略,价格单位为 $ / 1M Token

基础价格

价格项 计费对象
输入 排除缓存读取和缓存写入后的普通输入 Token
缓存读取 Cache Read Token
缓存写入 Cache Write/Creation Token
输出 Output Token

普通输入 Token 的计算方式为:

普通输入 = 输入 Token - 缓存读取 Token - 缓存写入 Token

长上下文价格

价格策略可以设置输入 Token 门槛,并选择“大于”或“大于等于”。请求达到门槛时,输入、缓存读取、缓存写入和输出四项价格整体切换到长上下文价格,不与基础价格混用。

Fast 价格

当请求标记为 Fast、Priority 或同等快速服务档位,并且该模型启用 Fast 计价时,系统对完整请求成本应用一次倍率。倍率以精确分数保存,默认界面值为 2.5

系统先选择基础或长上下文档位,再应用 Fast 倍率,最后对整次请求执行一次四舍五入。

models.dev 参考目录

models.dev 只提供候选参考价格,不直接参与在线计费。插件仅在管理员点击“更新目录”时下载 catalog.json,把能够由当前计费模型准确表达的供应商级 Token 价格规范化后保存到本地缓存。用户请求、认证、额度检查和最终扣费都不会访问外网。

管理员可以把任意目录价格导入任意本地模型,本地模型名与参考模型名不必一致。导入后,本地价格保存其 models.dev 供应商、模型、目录 revision 和获取时间;实际计费仍读取 SQLite 中已经确认的本地价格。

目录映射规则:

  • 输入和输出价格必须存在;
  • 缓存价格缺失时使用输入价格,避免把缓存错误计为免费;
  • 只支持一个可完整表示的长上下文档位;
  • 独立音频或推理价格无法由当前四类 Token 表达时不提供导入;
  • 输入、输出和缓存全部为零的条目不自动认定为免费;
  • Fast 倍率是本地业务规则,导入和刷新不会改变它。

刷新目录会先返回所有已关联价格的变化和已下架来源。页面只有在管理员确认后才更新发生变化的本地价格;取消确认不会改动账单。人工保存某个模型价格会把来源切换为“手动配置”,以后的目录刷新不再跟随它。

下载或解析失败时继续使用最后一次成功缓存,本地有效价格保持不变。目录下载有超时和体积限制,解析、写缓存和发布新索引成功后才替换旧版本。

价格缺失

允许访问的模型必须存在价格配置。系统在 CPA 已经选择上游后、真正访问模型服务前再次检查实际模型价格。

价格不存在时返回 HTTP 503 和 billing_price_unavailable,不会把未知成本的请求发送到上游。历史迁移数据仍可能因为当时没有价格而显示为成本不可用。

管理员首次补充某个模型价格时,系统按固定小批次补算该模型尚未定价的历史 Usage。补算使用缺失成本专用索引,不会一次性把全部历史载入内存;每批独立提交,在线认证、额度检查和新用量写入可以继续执行。

不可变账目

账目类型 含义 金额方向
charge 一次最终 Usage 产生的扣费 负数
quota_change 管理员修改本周期额度 增加为正,减少为负
cycle_reset 自动或手动开始新周期 新周期完整额度

每条账目保存用户 Key、额度周期、变动金额、变动后余额和发生时间,请求扣费还会保存模型。账目结构预留 Request ID 和 Execution ID,但当前目标 CPA 的 Usage 契约不提供这两个字段,因此实际扣费账目通常为空,不使用时间推测结果改写不可变账目。

账目只追加、不修改、不删除,并通过唯一事件标识避免重复写入。额度状态用于快速读取当前余额,账目用于解释余额变化过程。

拒绝结果

条件 HTTP 状态 错误码
余额小于或等于零 429 billing_quota_exhausted
并发达到上限 429 billing_concurrency_exceeded
额度数据库不可用 503 billing_unavailable
模型没有价格 503 billing_price_unavailable

这些拒绝发生在访问实际模型服务之前,并进入请求终态记录。

模块边界

本模块负责:

  • 模型价格和确定性成本计算;
  • 参考价格目录缓存、显式导入和确认更新;
  • 用户额度、余额和额度周期;
  • 并发请求准入;
  • 请求结束后的实际扣费;
  • 不可变计费账目。

本模块不负责:

  • 套餐、订阅、充值、支付和退款;
  • 按分钟、按日或按月的额外速率限制;
  • 请求开始前的费用预估或资金冻结;
  • 用户 Key 的身份认证和模型权限;
  • 上游服务本身的账单对账。