跳至正文

应用配额与费用预算 ​

本页阅读位置

完成第一轮对话后,按当前业务需求深入。Spring 常规声明优先使用 RegistrationManifest 与注解;本页的底层 register / publish 或直连方法供协议细化与兼容集成参考。

在控制台选择应用,打开 配额与预算,添加策略即可对新任务和模型发送生效。所有匹配策略同时约束额度,支持叠加分钟速率、日/月 token 与金额预算;无需修改 Agent 或业务 SDK 聊天请求。

配置顺序 ​

  1. 给模型声明 capabilities.contextWindow、maxOutputTokens,发布固定版本。金额策略需要同币种的 pricing.currency/inputPerMillion/outputPerMillion。
  2. 添加应用级策略,设置并发任务、周期任务请求、模型请求、token 或金额上限。留空表示不限制,零表示禁止;金额输入十进制字符串,如 "10.00"。
  3. 按租户、用户或模型增加策略,选择 UTC MINUTE/HOUR/DAY/MONTH 窗口。比如每用户每分钟 5 次任务,加全应用每天 USD 10 的预算。
  4. 保存原因并检查 周期使用量 与 模型预留与结算。旧配置未设规则时保持全局执行槽和 Agent 根预算;已有任务也计入新并发规则。

规则范围和计数 ​

字段用途
scope=APP, value=*当前应用独立额度
scope=TENANT使用服务端可信 tenantId;* 为每租户独立分桶
scope=USER使用可信 tenantId + subjectId;同名用户跨租户独立;* 为每用户独立额度
scope=MODEL精确 scope/models/id@version;* 为各固定模型版本独立额度
maxConcurrentRuns未终结业务 Run 数;等待审批也占用。MODEL 不接受此字段
maxRunRequests原周期成功接受的新 Run;幂等返回旧 Run 不再计数。MODEL 不接受此字段
maxConcurrentModels活动模型发送预留数,跨周期计算;UNKNOWN 不继续占活动并发
maxModelRequests进入发送边界的调用尝试;失败、备用尝试、合成探测都计入适用规则
maxTokens供应商实际 token 加未确认预留;不是 Agent 的字符 budgetUnits
maxAmount + currency已结算金额加保留的上界金额;固定版本价目,供应商核对金额可修正同币种结算
unknownPriceModeREJECT 禁止未知价格;SEPARATE 使用显式 maxUnpricedRequests,禁止同时配置金额上限
enabled=false停止新请求约束,保留既有预留、周期与结算事实

用户 Context 内的 tenantId/userId 不改变额度身份。合成探测没有业务用户身份,只匹配 APP/MODEL;它不能借用用户规则绕开应用预算。

已有策略标识的范围、选择值、周期、币种不可修改;修改上限或启停可以原位保存。变更维度请创建新标识,预算窗口和旧预留独立保留。移除规则是管理员明确放宽预算的操作,应记录原因。

HTTP 配置与读取 ​

先 GET /v1/apps/{app}/quotas 取得 revision;未配置返回 revision 0。APP_ADMIN 或 PLATFORM_ADMIN 可写;业务 USER 无权读取应用预算明细。

http
PUT /v1/apps/support/quotas
Authorization: Bearer <应用管理员凭据>
If-Match: 0
Content-Type: application/json
json
{
  "policies": [
    {"id":"requests-minute","scope":"USER","period":"MINUTE","maxRunRequests":5,"maxConcurrentRuns":2},
    {"id":"daily-budget","scope":"APP","period":"DAY","maxModelRequests":1000,"maxTokens":1000000,"maxAmount":"10.00","currency":"USD","unknownPriceMode":"REJECT"}
  ],
  "reason":"设置客服应用的调用与日预算"
}

GET /quotas/usage?limit=20&offset=0 读取历史周期桶;GET /quota-reservations?limit=20&offset=0 读取模型预留,路径均在 /v1/apps/{app}。分页 1–100,offset 0–1000000;返回 items/total/limit/offset。配置冲突 412,请刷新后重新确认,SDK 不自动重试写请求。

Java 与 Kotlin SDK ​

java
var current = client.quotaPolicies().toCompletableFuture().get();
var policy = new QuotaPolicy(Map.of(
    "id", "daily-budget", "scope", "APP", "period", "DAY",
    "maxAmount", "10.00", "currency", "USD"));
client.configureQuotaPolicies(List.of(policy), "配置日预算",
    ((Number) current.get("revision")).longValue()).toCompletableFuture().get();
var usage = client.quotaUsage(20, 0).toCompletableFuture().get();
var reservations = client.quotaReservations(20, 0).toCompletableFuture().get();
kotlin
import dev.sparktide.sdk.QuotaPolicy
import dev.sparktide.sdk.kotlin.*

val current = client.getQuotaPolicies()
client.configureQuotas(
    listOf(QuotaPolicy(mapOf("id" to "daily-budget", "scope" to "APP",
        "period" to "DAY", "maxAmount" to "10.00", "currency" to "USD"))),
    "配置日预算", (current.getValue("revision") as Number).toLong())
val usage = client.getQuotaUsage(limit = 20)
val reservations = client.getQuotaReservations(limit = 20)

QuotaPolicy 接受严格字段、非负整数限额、十进制金额,构造后不可变;客户端凭据须管理身份。业务聊天仍使用自己的可信业务凭据,429 错误码向调用方返回,不能通过换幂等键绕过预算。

预留、未知与核对 ​

预留输入上界为发布模型的 contextWindow,输出上界为本次 max_completion_tokens,token 预留取两者之和。金额按输入/输出价目以十进制计算并向上保留 12 位精度。这个保守上界通常大于实际请求,可能在余额仍大于实际平均费用时拒绝请求;应按模型上界规划余额,避免缩小声明伪造费用容量。

只有响应按协议完整终结且有完整 prompt/completion/total 整数回执才能自动结算。取消、超时、断流、不完整回执进入 UNKNOWN 并保留额度;流中途的用量即使三个数字齐全,也不作为最终费用释放依据。供应商账本仍显示收到的原始回执,两者口径不同。

业务调用在 运行记录 → 模型调用账本 → 核对供应商计量 对账。使用现有 reconcileModelInvocation / Kotlin recordModelReconciliation,携带当前 revision、最终供应商用量、证据与可选账单;配额自动按绝对新事实调整,不重复收费,不改变任务失败/取消状态,也不重放请求。

合成探测在 配额与预算 → 模型预留与结算 → 探测配额对账 操作;接口为 POST /v1/apps/{app}/quota-reservations/{id}/reconcile,If-Match 为预留 revision,正文与模型账本核对一致。只允许已结束探测,保留原探测回执和健康结论,仅修正额度事实;同一入口拒绝业务调用,避免绕过业务账本。

java
var evidence = ModelUsageReconciliation.builder(10, 5, 15,
    "供应商最终计量", "invoice:20260930:probe-request")
    .billedCost("USD", "0.00003").build();
client.reconcileQuotaProbe(reservationId, evidence, revision);

Kotlin 使用 reconcileSyntheticProbeQuota(id, evidence, revision)。证据不得填真实密钥或原始对话;未知计量不能以零替代。探测原结果不会因人工费用核对变成成功。

失败处理和预算边界 ​

错误码处理
QUOTA_EXCEEDED等待原周期结束,核对 UNKNOWN 或经管理员调整限额;不要自动重试发送
QUOTA_PRICE_UNKNOWN发布已知价目版本,或明示采用无金额上限的 SEPARATE 未知价额度
QUOTA_TOKEN_BOUND_UNKNOWN为固定模型版本声明真实 contextWindow
QUOTA_CURRENCY_MISMATCH配额币种与模型价目一致,不隐式汇率换算
REVISION_MISMATCH重新读取并确认配置或预留,避免覆盖他人核对

跨周期晚回执结算原桶,不把旧费用扣到当天。UNKNOWN 的旧周期金额不凭空消失,但新 UTC 周期有新窗口;并发模型数跨周期计算。供应商超出声明上界的用量或后到真实账单照实记录,后续发送会受限;已经发生的外部费用无法撤销。本地硬预算保护的是已知价目下的预留与结算,不构成对不可信供应商账单的绝对上限保证。

探测配额拒绝不作为供应商传输故障,不清空原故障窗口或已验证能力。业务范围规则、发布价目与健康探测身份隔离保持有效。

升级与回滚 ​

V12 新增 st_quota_config/st_quota_bucket/st_quota_reservation,保留旧历史;单活和显式 PostgreSQL 集群模式共用 Store.atomic 锁保证预留一致,网络不进事务。上线前备份数据库,先验证规则和 UNKNOWN 核对流程。回滚先停止新业务/探测、导出预算事实并完成核对,新增表保留;旧服务不执行配额拦截,恢复流量前须有外部预算控制或明确接受旧限制。

文档来源与验证记录

状态:已确认;日期:2026-09-30;责任人:SparkTide 维护者;关联任务:M06;来源:Quotas、Runs、ModelInvocations、ModelHealth、OpenAPI、Java/Kotlin SDK 与配额行为测试。

适用版本:0.1 发布线 · 最近核对:2026-10-09 · SparkTide 产品文档

汇聚智能,驱动涌现。