v0.0.16 — 修复 Anthropic 流式计费 usage 双计与缓存语义
修复 Anthropic / Vertex Claude / AWS Bedrock Claude 渠道流式请求中 usage 被双计(input/cache 令牌按约两倍扣费)的问题,并统一 Anthropic 缓存计费语义:cache read 折入 prompt 计价、补齐 AWS 渠道此前完全缺失的 cache 统计。
中文
🐛 问题修复
- 修复 Anthropic 流式计费「usage 双计」(issue #13):
- 新版 Messages API 下
message_start与message_delta都携带整段请求的累计 usage(message_delta重复message_start的 input/cache 字段并带上最终output_tokens)。 - 原实现按
+=当作增量累加,导致input_tokens/cache_read_input_tokens被计两遍,典型场景多扣约 50%(如 3.5-sonnet 下 4522 vs 正确 3000)。 - 现改为对累计值取 max 合并,并兼容旧形态(
message_delta仅带 output、input 为 0)不丢message_start的 input 计数。
- 新版 Messages API 下
- 修复 cache read 语义错配造成的欠费:Anthropic 的
input_tokens与cache_read/cache_creation_input_tokens互斥且不含彼此,而共享计费公式按 OpenAI「cached ⊆ prompt」扣减(input×(prompt−cached)),导致 cache read 被从 prompt 中重复扣减、按 read 价计费的同时又丢了一次 input 价;现归一化把 read 折入 prompt,公式自动还原出input×input + readPrice×read的正确金额。 - 修复 AWS Bedrock Claude 渠道 cache 完全不参与计费:流式与非流式路径此前都没有把
cache_read_input_tokens写入PromptTokensDetails.CachedTokens,现统一补齐。 - 修复 cache_creation(写入令牌)解析后从不计费:
cache_creation_input_tokens此前仅被解析、未进入 usage;现折入 prompt 按输入价计费(真实写入价约为 1.25×input,此为已知近似,见 #13)。
🔧 重构
- 新增
relay/adaptor/anthropic/usage.go:ClaudeUsage2OpenAI(Claude→OpenAI usage 归一化)与MergeClaudeUsage(累计流式事件取 max 合并)。 - native Anthropic / Vertex AI Claude / AWS Bedrock Claude 三条消费路径统一复用上述 helper,消除三处手写累计逻辑的漂移。
🧪 测试
relay/adaptor/anthropic/main_test.go:message_deltafixture 从旧形态(input_tokens: 0)更新为真实累计形态,避免继续掩盖双计 bug。- 新增
TestClaudeUsage2OpenAI/TestMergeClaudeUsage行为单测:覆盖累计序列不双计、旧形态兼容、read/creation 折入、cached ⊆ prompt不变式。
⚠️ 升级注意事项
- 零数据库迁移、零配置变更。
- 计费口径调整:修复后 Anthropic 渠道不再双计,扣费恢复正常;
prompt_tokens消费日志将包含折入的 cache read/creation,口径与 OpenAI 一致(历史消费记录不追溯修正)。 - 运行验证:
go build ./...;go test ./relay/adaptor/anthropic/ ./relay/billing/ratio/ ./model/ ./controller/ ./middleware/。