Skip to content
站长自营API 中转

国内开发者可试试 ZZSwitch

统一 Base URL、Key 和余额,适合 OpenCode / Claude Code / Codex 等工具接入。

站长自营API 中转

正在比较模型套餐?可以把多个 AI API 接到一个网关里

ZZSwitch 是我自己运营的统一 API 网关,适合需要国内支付、兑换码充值、多模型切换和 OpenAI 兼容接口的开发者。不是 OpenCode 官方服务。

Claude Agent SDK 提供每次 query() 的 token 用量与费用估算。通过 result message 的 total_cost_usd 字段可获取单次调用总费用;多步对话中需对 assistant message 按 ID 去重避免重复计数。注意 cost 字段为本地估算,定价变更或不识别模型时可能与实际账单不一致。要查看缓存节省,需单独跟踪 cache_creation_input_tokens 和 cache_read_input_tokens。对于跨会话累计,需手动累加每次 query() 的 total_cost_usd。

Claude Agent SDK 费用与用量追踪

本指南说明如何用 Claude Agent SDK 追踪 token 用量、估算费用,以及配置提示缓存。了解这些内容能帮你在开发阶段掌握成本,并为预算做粗略参考。

total_cost_usdcostUSD 字段是客户端估算值,不是权威结算数据。SDK 在本地根据构建时捆绑的价格表计算,因此当以下情况发生时,这些值可能与实际账单不同:

  • 价格发生变动
  • 安装的 SDK 版本无法识别所用模型
  • 客户端无法建模的计费规则生效

请将这些字段用于开发洞察和大致预算。权威账单请使用 Usage and Cost APIClaude Console 中的用量页面。不要依据这些字段向终端用户收费或触发财务决策。

理解 token 用量

TypeScript 和 Python SDK 暴露的用量数据相同,但字段命名不同:

  • TypeScript:每个 assistant message 提供每步 token 分解(message.message.idmessage.message.usage),result message 上通过 modelUsage 提供按模型的费用,以及累积总数。
  • Python:每个 assistant message 提供每步 token 分解(message.usagemessage.message_id),result message 上通过 model_usage 提供按模型的费用,以及累积总数(total_cost_usdusage 字典)。

两个 SDK 使用相同的底层成本模型,暴露出相同的粒度。差异在于字段命名和每步用量的嵌套位置。

成本追踪依赖于理解 SDK 如何划分用量数据的作用域:

  • query() 调用:一次调用可能包含多个步骤(Claude 响应、使用工具、获取结果、再次响应)。每次调用最终产生一个 result 消息。
  • 步骤(Step)query() 调用内部的单个请求/响应周期。每个步骤产生带有 token 用量的 assistant messages。
  • 会话(Session):通过会话 ID(使用 resume 选项)连接的一系列 query() 调用。会话中的每个 query() 调用独立报告自身成本。

下图展示了一次 query() 调用中的消息流,每个步骤报告 token 用量,末尾显示累积估算:

Diagram showing a query producing two steps of messages. Step 1 has four assistant messages sharing the same ID and usage (count once), Step 2 has one assistant message with a new ID, and the final result message shows the estimated total_cost_usd.

当 Claude 响应时,会发送一个或多个 assistant message。在 TypeScript 中,每个 assistant message 包含一个嵌套的 BetaMessage(通过 message.message 访问),其中有 idusage 对象(包含 input_tokensoutput_tokens)。在 Python 中,AssistantMessage 数据类通过 message.usagemessage.message_id 直接暴露相同数据。当 Claude 在一次 turn 中使用多个工具时,该 turn 中的所有消息共享同一个 ID,因此需要按 ID 去重以避免重复计数。

query() 调用完成时,SDK 会发出一个 result message,其中包含 total_cost_usd 和累积的 usage。这在 TypeScript(SDKResultMessage)和 Python(ResultMessage)中均可获得。如果你进行了多次 query() 调用(例如在多轮会话中),每个 result 仅反映该次调用的成本。如果只需要总估算,可以忽略每步用量而直接读取这个单一值。

获取单次查询的总费用

result message(TypeScriptPython)标志着一次 query() 调用的 agent 循环结束。它包含 total_cost_usd,即该调用中所有步骤的累积估算成本。这对成功和错误结果都有效。如果你使用会话进行多个 query() 调用,每个 result 只反映该次调用的成本。

以下示例迭代 query() 调用的消息流,并在 result 消息到达时打印总成本:

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({ prompt: "Summarize this project" })) {
  if (message.type === "result") {
    console.log(`Total cost: $${message.total_cost_usd}`);
  }
}
python
from claude_agent_sdk import query, ResultMessage
import asyncio


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


asyncio.run(main())

追踪每步用量和按模型用量

本节示例使用 TypeScript 字段名。在 Python 中,等效字段是 AssistantMessage.usageAssistantMessage.message_id(每步用量),以及 ResultMessage.model_usage(按模型分解)。

追踪每步用量

每个 assistant message 包含一个嵌套的 BetaMessage(通过 message.message 访问),其中有 idusage 对象(包含 token 计数)。当 Claude 并行使用工具时,多个消息共享相同的 id,且用量数据相同。跟踪你已经计数的 ID 并跳过重复,以避免膨胀的统计。

并行工具调用会产生多个 assistant message,其嵌套的 BetaMessage 共享相同的 id 和相同的用量。务必按 ID 去重以获得准确的每步 token 计数。

以下示例累加所有步骤的输入和输出 token,每个唯一消息 ID 仅计数一次:

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

const seenIds = new Set<string>();
let totalInputTokens = 0;
let totalOutputTokens = 0;

for await (const message of query({ prompt: "Summarize this project" })) {
  if (message.type === "assistant") {
    const msgId = message.message.id;

    // Parallel tool calls share the same ID, only count once
    if (!seenIds.has(msgId)) {
      seenIds.add(msgId);
      totalInputTokens += message.message.usage.input_tokens;
      totalOutputTokens += message.message.usage.output_tokens;
    }
  }
}

console.log(`Steps: ${seenIds.size}`);
console.log(`Input tokens: ${totalInputTokens}`);
console.log(`Output tokens: ${totalOutputTokens}`);

按模型分解用量

result message 包含 modelUsage,这是一个模型名称到 token 计数和成本的映射。当运行多个模型时(例如子代理使用 Haiku,主 agent 使用 Opus),这有助于了解 token 走向。

以下示例执行查询并打印每个模型使用的成本和 token 分解:

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({ prompt: "Summarize this project" })) {
  if (message.type !== "result") continue;

  for (const [modelName, usage] of Object.entries(message.modelUsage)) {
    console.log(`${modelName}: $${usage.costUSD.toFixed(4)}`);
    console.log(`  Input tokens: ${usage.inputTokens}`);
    console.log(`  Output tokens: ${usage.outputTokens}`);
    console.log(`  Cache read: ${usage.cacheReadInputTokens}`);
    console.log(`  Cache creation: ${usage.cacheCreationInputTokens}`);
  }
}

在多次调用间累积成本

每个 query() 调用返回自身的 total_cost_usd。SDK 不提供会话级别的总计,因此如果你的应用进行了多个 query() 调用(例如在多轮会话中或跨不同用户),需要自己累加。

以下示例顺序执行两个 query() 调用,将每个调用的 total_cost_usd 添加到运行总计中,并输出每次调用和合计的成本:

typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

// Track cumulative cost across multiple query() calls
let totalSpend = 0;

const prompts = [
  "Read the files in src/ and summarize the architecture",
  "List all exported functions in src/auth.ts"
];

for (const prompt of prompts) {
  for await (const message of query({ prompt })) {
    if (message.type === "result") {
      totalSpend += message.total_cost_usd;
      console.log(`This call: $${message.total_cost_usd}`);
    }
  }
}

console.log(`Total spend: $${totalSpend.toFixed(4)}`);
python
from claude_agent_sdk import query, ResultMessage
import asyncio


async def main():
    # Track cumulative cost across multiple query() calls
    total_spend = 0.0

    prompts = [
        "Read the files in src/ and summarize the architecture",
        "List all exported functions in src/auth.ts",
    ]

    for prompt in prompts:
        async for message in query(prompt=prompt):
            if isinstance(message, ResultMessage):
                cost = message.total_cost_usd or 0
                total_spend += cost
                print(f"This call: ${cost}")

    print(f"Total spend: ${total_spend:.4f}")


asyncio.run(main())

处理错误、缓存和 token 不一致

为了准确追踪成本,需要处理失败的对话、缓存 token 定价以及偶尔的报告不一致。

输出 token 不一致如何解决

极少数情况下,相同 ID 的消息中 output_tokens 值可能不同。这时:

  1. 使用最大值: 该组中的最后一条消息通常包含准确的合计。
  2. 优先使用 result message: result message 中的 total_cost_usd 反映 SDK 在所有步骤上的累积估算,因此比你自己对各步求和更可靠。它仍然是估算值,可能与实际账单不同。
  3. 报告不一致:Claude Code GitHub 仓库 中提交 issue。

在失败对话中追踪成本

无论是成功还是错误结果消息,都包含 usagetotal_cost_usd。如果对话中途失败,你仍然消耗了失败点之前的 token。无论 result message 的 subtype 是什么,始终从中读取成本数据。

追踪缓存 token

Agent SDK 自动使用提示缓存来降低重复内容的成本。你无需自行配置缓存。usage 对象包含两个额外的缓存跟踪字段:

  • cache_creation_input_tokens:用于创建新缓存条目的 token(费率高于标准输入 token)。
  • cache_read_input_tokens:从现有缓存条目中读取的 token(费率较低)。

将这些与 input_tokens 分开跟踪,以了解缓存节省。在 TypeScript 中,这些字段已在 Usage 对象上定义。在 Python 中,它们作为键出现在 ResultMessage.usage 字典中(例如 message.usage.get("cache_read_input_tokens", 0))。

将提示缓存 TTL 延长至一小时

默认情况下,当使用 API 密钥认证或在 Amazon Bedrock、Google Cloud Vertex AI、Microsoft Foundry 上运行时,SDK 写入的缓存条目 TTL 为 5 分钟。如果你对相同的系统提示和上下文运行许多短会话,且会话间隔超过 5 分钟,那么缓存会在会话之间过期,每个新会话都将支付全价输入费用。

要请求缓存写入使用 1 小时 TTL,设置 ENABLE_PROMPT_CACHING_1H 环境变量。可以在 shell 或容器环境中导出,或者通过 options.env 传递。

以下示例为在 Bedrock 上运行的 agent 启用 1 小时 TTL:

python
options = ClaudeAgentOptions(
    env={
        "CLAUDE_CODE_USE_BEDROCK": "1",
        "ENABLE_PROMPT_CACHING_1H": "1",
    },
)
typescript
const options = {
  env: {
    ...process.env,
    CLAUDE_CODE_USE_BEDROCK: "1",
    ENABLE_PROMPT_CACHING_1H: "1",
  },
};

1 小时 TTL 的缓存写入费率高于 5 分钟写入,因此启用它是以更高的写入成本换取更多缓存读取。参见提示缓存定价。Claude 订阅用户已自动获得 1 小时 TTL,无需设置此变量。

相关文档

常见问题

total_cost_usd 与实际账单不一致怎么办?

total_cost_usd 是客户端本地估算,基于构建时捆绑的价格表计算。定价变更、SDK 版本不识别模型或计费规则无法建模时,估算值会与账单产生偏差。如需权威数据,请使用 Usage and Cost API 或 Claude Console 用量页面。

并行工具调用时如何避免重复计数 token?

当 Claude 在一次 turn 中调用多个工具时,所有 assistant message 共享同一个 id 和相同的用量数据。在代码中维护一个 Set<string> 记录已处理的消息 ID,遇到重复 ID 时跳过计数即可。

如何追踪多个模型(如 Haiku 和 Opus)各自的花费?

result message 的 modelUsage(TypeScript)或 model_usage(Python)字段是一个映射,键为模型名称,值为该模型的 token 计数和费用。遍历该映射即可获得每个模型的详细开销。

站长自营API 中转

ZZSwitch API 中转

统一接入多家模型,支持兑换码充值。