缓存计费看起来只是三项相加未缓存输入、缓存输入和输出。但账本真正麻烦的地方是同一个请求重试后会不会扣两次以及不同单位会不会悄悄截掉小数。把金额先算成浮点美元再乘一百万并不能因为最后调用了int就变成整数记账。更清楚的做法是先选足够细的整数单位费率和数量都在该单位里计算。Python decimal文档解释了十进制金额与二进制浮点表示的差别需要小数费率时也可以使用带明确舍入规则的Decimal。先分桶再去重下例使用虚构的整数费率单位是“每Token纳美元”。它们不是任何厂商报价。输入总量已经包含缓存输入因此未缓存部分应是二者之差不能重复收费。一个请求ID若再次出现既要识别重复也要检查用量是否被换掉。from dataclasses import dataclass dataclass(frozenTrue) class Usage: input_tokens: int cached_tokens: int output_tokens: int def cost_nano(usage): values (usage.input_tokens, usage.cached_tokens, usage.output_tokens) if any(type(v) is not int or v 0 for v in values): raise ValueError(nonnegative integer counts required) if usage.cached_tokens usage.input_tokens: raise ValueError(cached input exceeds total input) rates (100, 20, 300) # fictional nano-USD per token return ((usage.input_tokens - usage.cached_tokens) * rates[0] usage.cached_tokens * rates[1] usage.output_tokens * rates[2]) class Ledger: def __init__(self): self.receipts {} self.total 0 def settle(self, request_id, usage): if request_id in self.receipts: old_usage, cost self.receipts[request_id] if old_usage ! usage: raise ValueError(same ID with different usage) return cost cost cost_nano(usage) self.receipts[request_id] (usage, cost) self.total cost return cost ledger Ledger() u Usage(100, 40, 10) assert ledger.settle(r1, u) 9800 assert ledger.settle(r1, u) 9800 and ledger.total 9800 try: ledger.settle(r1, Usage(101, 40, 10)) except ValueError: pass else: raise AssertionError(conflicting duplicate accepted) print(integer cost, duplicate settlement, conflicting retry: PASS)预冻结需要另一个状态机这个内存账本已在本地验证整数计算和幂等语义但没有处理进程崩溃或并发事务。生产环境需要持久化请求ID、预留金额、实际结算状态及补偿记录不能把Python字典当成财务数据库。输出上限也要统一如果按2048个输出Token预留发送给后端的上限却允许8192就不能称为悲观冻结。取消以后已经生成的Token是否计费必须按服务实际用量处理而不是一律全额退款。10 月9日Runway更新加入了项目额度上限说明生成任务的成本控制正在进入项目层它与逐次结算仍是不同功能。项目上限限制预算账本解释实际花费。两者都需要不能互相代替。官方更新真实服务的价格、缓存字段和舍入规则应另行从其官方文档读取本文没有付费调用也没有验证供应商账单。