写作

生成式 AI 的计费边界

可靠计费依赖于准确区分任务何时被接纳、完成、交付、结算或冲正,而不只是维护一张价目表。

生成式 AI 产品的计费,最开始通常像一道乘法题:统计 Token、图片、秒数或请求次数,查询价格,然后扣除 Credits。

直到产品开始重试、fallback、异步执行、接受取消,或者在超时之后仍然收到结果。

这时,最困难的问题已经不是“这个模型成本多少”,而是:

哪一个事件真正赋予了产品向用户收费的权利?

这是一个伪装成算术的状态与 authority 问题。

报价、预留与结算是不同事件

一条有用的计费生命周期,会把几个很容易混在一起的时刻分开:

  1. Quote——按照当前输入向用户展示预计价格;
  2. Reservation——确认余额或额度充足,并临时预留;
  3. Acceptance——记录产品或外部执行方已经接纳任务;
  4. Completion——确认任务到达一个有效的终态结果;
  5. Delivery——让结果能够被用户长期、稳定地获取;
  6. Settlement——把预留转化为最终扣费;
  7. Reversal——当约定结果没有交付时,释放或冲正相应费用。

对于快速文本请求,这些时刻可能几乎同时发生。对于媒体生成、批处理、研究任务或其他长任务,它们之间可能相隔数分钟。

如果产品把它们压缩成一次数据库更新,每一条异常执行路径最终都会变成计费特例。

任务生命周期与资金生命周期相关,但并不相同

一个生成任务可能处于 queuedrunningsucceededfailedcancelled;一条计费记录则可能处于 reservedsettledreleasedreversed

我们很容易把任务状态直接映射为计费状态,但真实世界没有这么对称。

本地 Timeout 不能证明外部任务失败;发出取消请求不能证明取消已经被接受;收到成功响应不能证明输出通过了产品校验;文件生成完成,如果产品没有成功保存并展示,也不能算作已经交付。

因此,计费需要独立而明确的状态转换规则。它应该依据任务生命周期提供的证据,而不是对任务状态作出想当然的推断。

最危险的转换通常是:过早退款,然后自动重试。如果原任务只是执行缓慢,产品可能随后收到两份有效结果,却没有为任何一份完成结算,或者把同一项昂贵任务提交了两次。

先定义可计费结果,再实现扣费

不同能力需要不同的成功定义。

对于流式文本,Contract 可能取决于是否已经产生有用内容;对于生成图片,完成可能意味着获得一个产品能够保存和展示的有效资产;对于异步任务,执行方接纳、任务完成和用户交付可能是三个不同事实。

这个定义至少应该回答:

  • 用户购买的究竟是什么?
  • 结果需要通过怎样的校验才算可用?
  • 部分输出是否具有价值?
  • 执行成功但交付失败时怎么办?
  • 工作被接纳之后,用户取消会发生什么?
  • 界面报告超时之后返回的迟到结果如何处理?

如果没有这份 Contract,success 就会等同于当前集成恰好返回的状态,计费行为也会随着执行路径的变化而不断漂移。

在产品另有约定之前,重试属于内部成本

如果产品自动重试一次暂时故障,或者 fallback 到另一条路径,用户通常认为自己只请求了一个结果,而不是购买了多次基础设施尝试。

这可以形成一条有用的默认边界:

  • 用户为产品承诺的结果付费;
  • 系统承担内部恢复尝试产生的成本;
  • 新增用户扣费必须对应另一个经过用户授权的工作单位。

这并不意味着重试没有成本,而是把成本放在正确的位置:基础设施毛利与路由质量,而不是用户余额。

当一次失败尝试仍然产生上游费用时,这个区分尤其重要。如果每个结果都需要多次付费尝试,最终成功率可以很高,单位经济却可能很差。

因此,产品计费与外部成本核算应该共享关联标识,但它们不应该被当作同一本 Ledger。

幂等同时保护资金与任务

网络重试无法避免。客户端可能不知道请求是否已经到达服务端;Worker 可能完成工作,却在确认完成之前失败;Callback 也可能被重复投递。

Exactly-once Delivery 很少是一个可靠前提。更现实的目标,是让副作用具备幂等性。

同一个业务操作在多次传输重试之间,应该拥有稳定身份。这个身份至少需要保护两个副作用:

  • 外部任务不会被意外提交两次;
  • 用户不会因为同一个已接纳结果被扣费两次。

单纯使用 HTTP Request ID 通常太窄,因为一次重试会生成新的 Request。真正有用的 Key 应该代表用户授权的那一个工作单位。

幂等也需要保存长期结果。如果系统已经无法找回原始任务、Artifact 或结算记录,只返回一句“已经处理过”并不足够。

Balance 是 Projection,不是审计记录

可变余额很适合读取,却无法解释当前数字是怎样形成的。

可靠计费需要不可变或 Append-only 的事件,保存每次变化的原因:预留、结算、释放、人工调整、过期或冲正。当前余额可以作为这些事件派生或经过校验的 Projection。

这在调查以下问题时非常重要:

  • 这项工作被扣费了一次还是两次?
  • 使用的是哪一个价格版本?
  • 一次退款是在释放预留,还是冲正已经结算的费用?
  • 调整是自动发生,还是人工操作?
  • 哪项任务与交付结果可以证明这次结算合理?

直接覆盖一个数字,可能修复了用户看到的余额,却同时摧毁了判断这次修复是否正确所需要的证据。

价格必须在决策边界被版本化

价格会变化,模型会被重新路由,促销会开始或结束,输入参数也可能影响费用。

一个任务如果在某个价格下开始,就不应该仅仅因为稍后完成,而使用另一个价格结算。计费决策需要保存当时的 Pricing Context:版本、输入、货币或 Credits 单位,以及产生报价的规则。

这并不要求向用户暴露内部 Provider 经济,而是要求产品保住自己作出的承诺。

同样的原则也适用于长期折扣与订阅额度。使用今天的配置重新计算历史,不是 Reconciliation,而是在事件发生之后重写 Contract。

对账需要三个视角

生成式 AI 计费通常至少包含三种彼此相关的真相:

  • 用户权益——用户看到的报价、预留、扣费与返还;
  • 产品执行——哪些工作被接纳、尝试、完成并交付;
  • 外部成本——基础设施或上游服务最终报告了什么。

它们不会永远即时一致。Callback 可能迟到,外部账单可能使用不同聚合周期,内部校验也可能拒绝一个外部执行成功的结果。

Reconciliation 的目标是解释这些差异,而不是通过静默修改强迫数字一致。

一个可信的系统应该能够从任意一笔扣费,追溯到经过授权的工作、执行证据、交付的 Artifact,以及属于它的外部成本记录。

计费是产品承诺的一部分

用户不会把计费体验成一个后端子系统。他们感受到的是展示的价格是否被遵守,失败是否消耗余额,取消是否真正有效,以及一次修正能否被解释。

最好的计费设计,应该从一份普通人可以理解的 Contract 开始:

  • 用户购买的是什么;
  • 什么时候预留价值;
  • 哪个事件产生最终扣费;
  • 失败、Timeout、取消与迟到完成分别如何处理;
  • 用户怎样查看并质疑结果。

这些边界一旦清楚,算术通常才是最简单的部分。

可靠计费意味着:在 Happy Path、重试路径、恢复路径与对账路径上作出同一份承诺,并保留足够证据证明这份承诺确实被遵守。

文章数据

次阅读条评论

讨论

评论区

关于文章本身,也欢迎留下不同意见或补充。

留下评论

评论会立即公开,并可在当前浏览器中删除。

发布时会进行一次隐私友好的人机验证。