SpyBara
Go Premium

agent-sdk/cost-tracking.md 2026-07-15 22:00 UTC to 2026-07-16 22:59 UTC

This page contains 8 additions and 0 deletions.

2026
Fri 3 23:00 Fri 10 17:00 Thu 16 22:59

追蹤成本和使用情況

了解如何追蹤 token 使用情況、估計成本,以及使用 Claude Agent SDK 配置 prompt caching。

Claude Agent SDK 為每次與 Claude 的互動提供詳細的 token 使用資訊。本指南說明如何正確追蹤使用情況和理解成本報告,特別是在處理平行工具使用和多步驟對話時。

如需完整的 API 文件,請參閱 TypeScript SDK 參考 和 Python SDK 參考。

了解 token 使用情況

TypeScript 和 Python SDK 使用不同的欄位名稱公開相同的使用資料:

  • TypeScript 在每個助手訊息上提供每步 token 細分(message.message.id、message.message.usage),通過結果訊息上的 modelUsage 提供每個模型的成本,以及結果訊息上的累積總計。
  • Python 在每個助手訊息上提供每步 token 細分(message.usage、message.message_id),通過結果訊息上的 model_usage 提供每個模型的成本,以及結果訊息上的累積總計(total_cost_usd 和 usage 字典)。

兩個 SDK 使用相同的基礎成本模型並公開相同的粒度。差異在於欄位命名和每步使用情況的嵌套位置。

成本追蹤取決於理解 SDK 如何限定使用資料的範圍:

  • query() 呼叫: SDK 的 query() 函數的一次調用。單次呼叫可能涉及多個步驟(Claude 回應、使用工具、獲取結果、再次回應)。每次呼叫在末尾產生一個 result 訊息。
  • 步驟: query() 呼叫中的單個請求/回應週期。每個步驟產生帶有 token 使用情況的助手訊息。
  • 會話: 由會話 ID 連結的一系列 query() 呼叫(使用 resume 選項)。會話中的每個 query() 呼叫獨立報告其自己的成本。

下圖顯示來自單個 query() 呼叫的訊息流,在每個步驟報告 token 使用情況,並在末尾顯示累積估計:

圖表顯示一個查詢產生兩個步驟的訊息。步驟 1 有四個共享相同 ID 和使用情況的助手訊息(計數一次),步驟 2 有一個具有新 ID 的助手訊息,最終結果訊息顯示估計的 total_cost_usd。
1

每個步驟產生助手訊息

當 Claude 回應時,它發送一個或多個助手訊息。在 TypeScript 中,每個助手訊息包含一個嵌套的 BetaMessage(通過 message.message 存取),具有 id 和一個 usage 物件,其中包含 token 計數(input_tokens、output_tokens)。在 Python 中,AssistantMessage 資料類別通過 message.usage 和 message.message_id 直接公開相同的資料。當 Claude 在一個回合中使用多個工具時,該回合中的所有訊息共享相同的 ID,因此按 ID 去重以避免重複計數。

2

結果訊息提供累積估計

當 query() 呼叫完成時,SDK 發出一個結果訊息,其中包含 total_cost_usd 和累積 usage。這在 TypeScript(SDKResultMessage)和 Python(ResultMessage)中都可用。如果您進行多個 query() 呼叫(例如,在多回合會話中),每個結果只反映該個別呼叫的成本。如果您只需要估計的總計,您可以忽略每步使用情況並讀取此單一值。

取得查詢的總成本

結果訊息(TypeScript、Python)標記 query() 呼叫的代理迴圈的結束。它包含 total_cost_usd,即該呼叫中所有步驟的累積估計成本。這適用於成功和錯誤結果。如果您使用會話進行多個 query() 呼叫,每個結果只反映該個別呼叫的成本。

當代理產生子代理時,三個結果層級的欄位在計算內容上有所不同。使用 modelUsage 或 Python 中的 model_usage 進行整個樹狀結構的權杖計算;usage 欄位一旦發生巢狀就會低估。

欄位 子代理活動
usage 已排除。僅計算頂層代理迴圈,因此子代理內消耗的權杖不會被加入
total_cost_usd 已包含。計算子代理請求以及頂層迴圈
modelUsage / model_usage 已包含。計算子代理請求以及頂層迴圈,按模型細分

以下範例遍歷來自 query() 呼叫的訊息流,並在 result 訊息到達時列印總成本:

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

try {
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "result") {
console.log(`Total cost: $${message.total_cost_usd}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, it still carried total_cost_usd and the
// branch above has already run; connection or process failures yield
// no result message.
console.error(`Session ended with an error: ${error}`);
}

追蹤每步和每個模型的使用情況

本節中的範例使用 TypeScript 欄位名稱。在 Python 中,等效欄位是 AssistantMessage.usage 和 AssistantMessage.message_id 用於每步使用情況,以及 ResultMessage.model_usage 用於每個模型的細分。

追蹤每步使用情況

每個助手訊息包含一個嵌套的 BetaMessage(通過 message.message 存取),具有 id 和 usage 物件,其中包含 token 計數。當 Claude 並行使用工具時,多個訊息共享相同的 id 和相同的使用資料。追蹤您已經計數的 ID,並跳過重複項以避免膨脹的總計。

以下範例累積所有步驟中的輸入和輸出 token,每個唯一訊息 ID 只計數一次:

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

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

try {
  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;
      }
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result, so the
  // totals below still reflect the steps that ran before the failure.
  console.error(`Session ended with an error: ${error}`);
}

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

按模型細分使用情況

結果訊息包含 modelUsage,一個模型名稱到每個模型 token 計數和成本的映射。當您執行多個模型(例如,子代理使用 Haiku,主代理使用 Opus)並想查看 token 的去向時,這很有用。

以下範例執行查詢並列印每個使用的模型的成本和 token 細分:

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

try {
  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}`);
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result. If the
  // failure was an error result, the per-model breakdown above has already
  // printed; connection or process failures yield no result message.
  console.error(`Session ended with an error: ${error}`);
}

累積多個呼叫的成本

每個 query() 呼叫返回其自己的 total_cost_usd。SDK 不提供會話級別的總計,因此如果您的應用程式進行多個 query() 呼叫(例如,在多回合會話中或跨不同使用者),請自行累積總計。

以下範例順序執行兩個 query() 呼叫,將每個呼叫的 total_cost_usd 加到運行總計中,並列印每個呼叫和合併的成本:

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) {
try {
for await (const message of query({ prompt })) {
if (message.type === "result") {
totalSpend += message.total_cost_usd;
console.log(`This call: $${message.total_cost_usd}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, this call's cost was already counted;
// connection or process failures yield no result message. Continue
// with the next prompt.
console.error(`Call failed: ${error}`);
}
}

console.log(`Total spend: $${totalSpend.toFixed(4)}`);

處理錯誤、快取和 token 差異

為了準確的成本追蹤,請考慮失敗的對話、快取 token 定價和偶爾的報告不一致。

解決輸出 token 差異

在罕見情況下,您可能會觀察到具有相同 ID 的訊息的不同 output_tokens 值。當發生這種情況時:

  1. 使用最高值: 一組中的最終訊息通常包含準確的總計。
  2. 優先使用結果訊息: 結果訊息中的 total_cost_usd 反映 SDK 在所有步驟中的累積估計,因此比自己求和每步值更可靠。它仍然是一個估計值,可能與您的實際帳單不同。
  3. 報告不一致: 在 Claude Code GitHub 儲存庫 提交問題。

追蹤失敗對話的成本

成功和錯誤結果訊息都包含 usage 和 total_cost_usd。如果對話在中途失敗,您仍然消耗了到失敗點為止的 token。無論其 subtype 如何,始終從結果訊息讀取成本資料。

追蹤快取 token

Agent SDK 自動使用 prompt caching 來減少重複內容的成本。您不需要自己配置快取。使用物件包含兩個額外的欄位用於快取追蹤:

  • 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))。

將 prompt 快取 TTL 延長至一小時

當您使用 API 金鑰進行身份驗證或在 Amazon Bedrock、Google Cloud 的 Agent Platform 或 Microsoft Foundry 上執行時,SDK 寫入的快取項目預設使用 5 分鐘的 TTL。如果您的工作負載針對相同的系統提示和上下文執行許多短會話,且它們之間的間隔超過 5 分鐘,快取會在會話之間過期,每個新會話都會支付完整的輸入價格。

要請求快取寫入的 1 小時 TTL,請設定 ENABLE_PROMPT_CACHING_1H 環境變數。您可以在 shell 或容器環境中匯出它,或通過 options.env 傳遞它。

以下範例為在 Amazon Bedrock 上執行的代理啟用 1 小時 TTL:

from claude_agent_sdk import ClaudeAgentOptions, query
import asyncio


async def main():
options = ClaudeAgentOptions(
env={
"CLAUDE_CODE_USE_BEDROCK": "1",
"ENABLE_PROMPT_CACHING_1H": "1",
},
)

async for message in query(prompt="Summarize this project", options=options):
print(message)


asyncio.run(main())

具有 1 小時 TTL 的快取寫入按比 5 分鐘寫入更高的費率計費,因此啟用此功能會用更高的寫入成本換取更多的快取讀取。有關詳細資訊,請參閱 prompt caching 定價。Claude 訂閱使用者已自動獲得 1 小時 TTL,不需要設定此變數。