SDK 在每个 AssistantMessage 中提供逐步 token 用量,在最终 ResultMessage 中提供累计估算费用。total_cost_usd 是客户端本地估算值,不能作为权威计费依据,实际账单以 Anthropic Console 或 Usage API 为准。

核心机制

三个层级的用量数据:

  • 每步(per-step):每个 AssistantMessage 包含该步的 token 用量(input_tokens、output_tokens)
  • 每模型(per-model):ResultMessage 的 model_usage/modelUsage 字段,按模型分组统计
  • 累计(cumulative):ResultMessage 的 total_cost_usd 和 usage,覆盖整个 query() 调用

并行工具调用的去重:Claude 在一轮中并行调用多个工具时,多条 AssistantMessage 共享同一个 ID 和相同的 usage 数据。统计时必须按 ID 去重,否则会重复计算。

跨多次 query() 的累计:SDK 不提供会话级别的总费用,需在应用层手动累加每次 query() 的 total_cost_usd。

关键细节

获取单次 query() 总费用:

async for message in query(prompt="Summarize this project"):
    if isinstance(message, ResultMessage):
        print(f"Total cost: ${message.total_cost_usd or 0:.4f}")

按步骤统计(需去重):

seen_ids = set()
total_input = 0
async for message in query(prompt="..."):
    if isinstance(message, AssistantMessage) and message.message_id not in seen_ids:
        seen_ids.add(message.message_id)
        total_input += message.usage.get("input_tokens", 0)

缓存 Token 追踪:

  • cache_creation_input_tokens:创建缓存条目的 token(费率更高)
  • cache_read_input_tokens:从缓存读取的 token(费率更低)

延长缓存 TTL 到 1 小时(默认 5 分钟):

options = ClaudeAgentOptions(env={"ENABLE_PROMPT_CACHING_1H": "1"})

与其他概念的关联

  • agent-loop - ResultMessage 中的费用字段
  • observability - 通过 OpenTelemetry 导出 token 指标到外部系统
  • sessions - 多次 query() 调用的费用需手动累加

实践要点

  • 错误结束的 query()(error_max_turns 等)也有 total_cost_usd,已消耗的 token 仍计费
  • Python 中 total_cost_usd 和 usage 是 Optional,错误路径可能为 None,需要 guard
  • 订阅计划用户已自动获得 1 小时缓存 TTL,无需设置 ENABLE_PROMPT_CACHING_1H
  • 多模型场景(主 Agent 用 Opus,子 Agent 用 Haiku)可通过 model_usage 分别查看各模型费用