流式调用 Claude 时,token 计量为什么和账单对不上

举报
yd_231261900 发表于 2026/11/07 11:35:39 2026/11/07
【摘要】 做过一段时间接入的人大概都遇到过:客户端统计的输出 token 是 0,账单上却有费用;或者同一段系统提示重复调用,费用一次比一次低,自己却说不出原因。问题多半出在 usage 字段的读取位置和缓存字段的理解上。一、usage 在不同返回模式下的位置不一样非流式响应里,usage 在顶层一次给全:input_tokens、output_tokens,开了缓存还有 cache_creation...

做过一段时间接入的人大概都遇到过:客户端统计的输出 token 是 0,账单上却有费用;或者同一段系统提示重复调用,费用一次比一次低,自己却说不出原因。问题多半出在 usage 字段的读取位置和缓存字段的理解上。

一、usage 在不同返回模式下的位置不一样

非流式响应里,usage 在顶层一次给全:input_tokens、output_tokens,开了缓存还有 cache_creation_input_tokens 和 cache_read_input_tokens。流式响应则拆成两段:message_start 事件的 message 里带 input_tokens,output_tokens 通常只是很小的初始值;真正完整的输出计数在 message_delta 事件的 usage 里,message_stop 之后不会再补。

只读 message_start 的客户端,输出计数会一直偏小甚至为 0。正确做法是在 message_delta 时覆盖写入,message_stop 时落一次最终值。如果中途连接断开,这一轮的 output_tokens 就拿不到准确数字,需要在网关层用请求日志兜底。

二、缓存字段决定成本结构,不读懂就会算错

prompt caching 的机制是:命中的部分按缓存读取计价,未命中的部分按缓存写入计价,两者倍率不同。请求里要显式加 cache_control 断点,短的提示不会触发缓存。验证方式很直接:拿一段较长的 system prompt 连续调两次,第二次的 cache_read_input_tokens 应该明显大于 0,而 cache_creation_input_tokens 接近 0。如果两次数字完全一样,说明缓存没生效,或者入口没透传这两个字段。

Token5u 的返回体里这两个字段是分开透传的,对着 usage 就能判断缓存有没有真正命中,做成本核算时不用靠估算。

三、截断和重试会制造 “看不见” 的重复计量

max_tokens 设小了,模型会在中途停下,stop_reason 变成 max_tokens,但已经生成的部分照常计费,业务侧却当成失败重跑一次,等于同一段内容算了两遍。自动重试同理:SDK 对 5xx 默认会重发,如果不区分 “已产生输出” 和 “未产生输出”,费用会悄悄翻倍。

建议在网关层做三件事:记录 request_id 与每轮的 usage;按 request_id 去重后再汇总;对 stop_reason 为 max_tokens 的请求单独打标,便于回看是不是参数给得太保守。日志字段齐全的入口,对账时能直接对着时间戳和 usage 逐条比,Token5u 的请求记录属于这类,省去了自己拼日志的功夫。

总结

流式下 usage 分两处给,缓存字段要单独看是否命中,截断和重试则会带来重复计量。把这三处埋点做对,账单和客户端统计才能对得上。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。