跳到主要内容

计费(Usage & Billing)

Aidy 的计费是根据 Provider 的 provider_pricings 价格表进行计费的。

记账单位:Credit

Aidy 内的计费不关心法币,使用整数 Credit 作为记账单位。内部所有计费、配额、余额、账单数据结构也统一使用整数 Credit

法币与 Credit 的换算由业务侧负责,不属于 router 核心职责,建议采用 1 USD = 1_000_000 Credit / 1 CNY = 1_000_000 Credit(相当于四位小数的计费精度)。

配置

计费的配置在 Provider 的 provider_pricings 价格表。其中的 pricing 字段在 API 中返回的是一个 google.protobuf.Struct JSON 结构,但其实际格式应当为 ext.billing.Pricing 的 ProtoJSON 表示。

Pricing Proto

信息

adjustments 的定义和支持目前仍处于调整阶段,请勿使用。

计费口径

所有 rate 数值都表示「每 1M Token 消耗的 Credit」

当前支持四个文本计费项:

  • textInput 未缓存输入价格
  • textOutput 输出价格
  • textInputCacheRead 缓存读取价格
  • textInputCacheWrite 缓存写入价格

计费时将按照最终结果四舍五入得到的整数 Credit 进行结算。

示例

最简单的 basePricing

{
"basePricing": {
"textInput": 500,
"textOutput": 1500
}
}

带 cache 定价:

{
"basePricing": {
"textInput": 500,
"textOutput": 1500,
"textInputCacheRead": 50,
"textInputCacheWrite": 800
}
}

带 adjustment 的完整结构示例:

{
"basePricing": {
"textInput": 500,
"textOutput": 1500
},
"adjustments": [
{
"mode": "ADJUSTMENT_MODE_MULTIPLIER",
"when": {
"serviceTier": "priority"
},
"values": {
"textInput": 2,
"textOutput": 2
}
}
]
}

计费时机

目前,仅在请求正常结束且上游返回了 usage 信息时才会进行计费。

  1. 未配置消费者时,不计费
  2. Tenant 或 Route 允许缺失模型价格,且未配置对应模型的价格表时,不计费
  3. 请求错误时,不计费
  4. 上游未返回 usage 信息时,不计费(不做费用估算)

另外,所有的结算采用后付费,在并发请求时可能出现负数余额。

  • 不做预扣
  • 请求进入时检查只要有可用余额就允许,不预判本次请求最终会不会欠费
    • 另外,只要余额为负数就不允许请求 —— 即使对应模型实际上未配置价格表(相当于免费)
  • 请求完成后按实际 usage 进行计费

对于别名情况,将按照最终请求的模型进行计费。

对于别名情况,缺失价格检查也按最终请求到上游的模型判断。默认情况下,如果最终模型没有配置 provider pricing,请求会在转发前被拒绝;只有当 Tenant 或 Route 的 allow_missing_model_pricing 任意一个为 true 时才允许继续。

请求日志

请求级计费信息现在存在两个 ext-field:

  • ext_fields.usage:统计请求的 usage / credit
  • ext_fields.billing:记录扣减的 consumer 的 Credit 情况

Proto

示例:

{
"usage": {
"status": "available",
"billed_model": "gpt-4o-mini",
"input_tokens": 10,
"cached_read_tokens": 0,
"output_tokens": 2,
"total_tokens": 12,
"reasoning_tokens": 0,
"billed_status": "calculated",
"billed_credit": 12,
"billed_error": null
},
"billing": {
"status": "settled",
"consumer_id": "cs_xxx",
"consumer_api_key_id": "cak_xxx",
"settled_credit": 12,
"ledger_entry_ids": [
"cle_xxx",
"cle_yyy"
],
"error": null
}
}

字段语义:

  • usage.status:usage 可用性,当前为 availableestimatedunavailable
  • usage.input_tokens:未缓存输入 token 数;当上游同时返回总输入和缓存读取输入时,记录为 max(raw_input_tokens - cached_read_tokens - cached_creation_tokens, 0)
  • usage.cached_read_tokens / usage.cached_creation_tokens:缓存读取 / 缓存写入输入 token 数
  • usage.total_tokens:输入总量加输出 token;输入总量包含未缓存输入、缓存读取输入和缓存写入输入
  • usage.output_tokens:上游输出 token 数;不会扣除 reasoning token
  • usage.reasoning_tokens:上游返回的 reasoning token 数,仅作为 telemetry 明细记录,当前不单独计费
  • usage.billed_status:计费计算状态,当前为 calculatedfailedskipped
  • usage.billed_credit:按 pricing 计算出的本次 credit 消耗事实
  • usage.billed_error:计费计算错误;成功或未尝试计费时为 null
  • billing.status:当前为 settledsettle_failed
  • billing.settled_credit:本次实际写账并扣减的 credit;失败时固定为 0
  • billing.ledger_entry_ids:本次结算生成的账本条目 ID 列表

补充说明:

  • usage 只负责记录事实,不直接修改余额
  • billing 才表示 consumer / API key 的实际扣费结果
  • 上游未返回 usage 时按 upstream > provider 的 missing_usage_policy 处理:estimate 会估算 token 并以 usage.status = "estimated" 继续计费;fail 会输出 usage.status = "unavailable"usage.billed_status = "skipped",不写 billed_credit,客户端模型响应不受影响
  • 如果请求本身计算出了费用,但主体是 unlimited credit,则可能出现 usage.billed_credit > 0billing.settled_credit = 0
  • request_logs 同时承担“请求日志摘要 + 请求级 billing 事实”角色,因此 (tenant_id, request_id) 必须唯一

账本 metadata

请求结算时写入 credit_ledger_entries.metadata 的审计上下文:

当前至少覆盖这些字段:

  • route_id
  • requested_model
  • source
  • operation

数据库里该列保存的是上面这个 message 的 ProtoJSON 表示。