コストと使用状況を追跡する
Claude Agent SDK でトークン使用状況を追跡し、コストを見積もり、プロンプトキャッシングを設定する方法を学びます。
Claude Agent SDK は、Claude との各インタラクションの詳細なトークン使用情報を提供します。このガイドでは、使用状況を適切に追跡し、特に並列ツール使用とマルチステップ会話を扱う場合のコスト報告を理解する方法について説明します。
完全な API ドキュメントについては、TypeScript SDK リファレンスおよび Python SDK リファレンスを参照してください。
total_cost_usd および costUSD フィールドはクライアント側の推定値であり、信頼できる請求データではありません。SDK は、modelPricing テーブルが有効でない限り、ビルド時にバンドルされた価格表からローカルで計算します。以下の場合に実際の請求額から乖離する可能性があります。
- 価格が変更される
- インストールされている SDK バージョンがモデルを認識しない
- クライアントがモデル化できない請求ルールが適用される
SDK がモデル化する請求ルールの 1 つは、データレジデンシー価格です。レスポンスの usage が inference_geo: "us" を報告する場合、SDK はそのレスポンスのトークンのリスト価格に 1.1 を乗算します。Web 検索などのリクエストごとの料金は乗算されません。TypeScript Agent SDK v0.3.239 以降、または Python Agent SDK v0.2.144 以降が必要です。
これらのフィールドは開発の洞察と概算予算作成に使用してください。信頼できる請求については、使用状況とコスト API または Claude Console の使用状況ページを使用してください。これらのフィールドからエンドユーザーに請求したり、財務上の決定をトリガーしたりしないでください。
トークン使用量を理解する
TypeScript と Python SDK は、異なるフィールド名で同じ使用量データを公開しています。
- TypeScript は、各アシスタントメッセージ(
message.message.id、message.message.usage)でステップごとのトークン分解を提供し、結果メッセージのmodelUsage経由でモデルごとのコストを提供し、結果メッセージの累積合計を提供します。 - Python は、各アシスタントメッセージで
message.usageとmessage.message_idとしてステップごとのトークン分解を提供し、結果メッセージのmodel_usage経由でモデルごとのコストを提供し、結果メッセージのtotal_cost_usdとして累積合計を提供します。
両方の SDK は同じ基盤となるコストモデルを使用し、同じ粒度を公開しています。違いはフィールド命名とステップごとの使用量がネストされている場所にあります。
コスト追跡は、SDK がどのように使用量データをスコープするかを理解することに依存しています。
query()呼び出し: SDK のquery()関数の 1 回の呼び出し。単一の呼び出しは複数のステップを含むことができます。Claude が応答し、ツールを使用し、結果を取得し、再度応答します。各呼び出しは最後に 1 つのresultメッセージを生成します。ただし、ストリーミング入力モードでは、1 つのquery()呼び出しが複数のユーザーターンを実行し、各ターンが独自のresultメッセージを発行します。- ステップ:
query()呼び出し内の単一のリクエスト/レスポンスサイクル。各ステップはトークン使用量を含むアシスタントメッセージを生成します。 - セッション: セッション ID でリンクされた一連の
query()呼び出し(resumeオプションを使用)。セッション内の各query()呼び出しは、独立してそれ自身のコストを報告します。
次の図は、単一の query() 呼び出しからのメッセージストリームを示しており、各ステップでトークン使用量が報告され、最後に累積推定値が表示されます。
各ステップはアシスタントメッセージを生成します
Claude が応答すると、1 つ以上のアシスタントメッセージを送信します。TypeScript では、各アシスタントメッセージには、ネストされた BetaMessage(message.message 経由でアクセス)が含まれており、id とトークン数(input_tokens、output_tokens)を含む usage オブジェクトがあります。Python では、AssistantMessage データクラスは message.usage と message.message_id 経由で同じデータを直接公開しています。Claude が 1 つのターンで複数のツールを使用する場合、そのターンのすべてのメッセージは同じ ID を共有するため、二重計算を避けるために ID でデデュプリケートしてください。
結果メッセージは累積推定値を提供します
query() 呼び出しが完了すると、SDK は total_cost_usd と累積 usage を含む結果メッセージを発行します。TypeScript では SDKResultMessage として型付けされ、Python では ResultMessage として型付けされます。複数の query() 呼び出しを行う場合(例えば、マルチターンセッションで)、各結果はその個別の呼び出しのコストのみを反映します。推定合計のみが必要な場合は、ステップごとの使用量を無視して、この単一の値を読むことができます。
ストリーミング入力モードでは、各ターンが独自の結果メッセージを発行します。ストリーミング入力モードでコール合計を読む方法については、ストリーミング入力モードでコストを追跡するを参照してください。
ストリーミング入力モードでコストを追跡する
ストリーミング入力モードでは、1 つの query() 呼び出しが複数のユーザーターンを実行し、各ターンが独自の結果メッセージを出力します。結果フィールドのスコープは異なります。
usage: そのターンのみをカバーし、その中でもメインエージェントループのみで、実行したサブエージェントはカバーしません。total_cost_usdとmodelUsage、または Python のmodel_usage: これまでの呼び出し全体の実行合計を保持します。
アプリが /clear、/reset、または /new を送信しない呼び出しでは、結果全体を合計するのではなく、最新の結果を読んで呼び出し合計を取得してください。
実行合計は、アプリがこれら 3 つのコマンドのいずれかを送信するたびにリセットされ、query() 呼び出し内では他に何もリセットしません。会計に重要な 3 つの結果があります。
/clearターンの独自の結果: リセット以降に実行されたもののみをカバーし、新しいsession_idを保持します。- その後のすべての結果: そのリセットからカウントを続けます。
- 各
/clearの前の最後の結果: 前のリセット以降のターンの合計を保持します。
呼び出し全体を合計するには、各 /clear の前の最後の結果を呼び出しの最終結果に追加します。/clear ターン自体を含むその他のすべての結果は、後の結果に置き換えられます。
TypeScript では、SDK は各リセットで SDKConversationResetMessage も出力するため、ストリームからリセットを検出できます。Python では、SDK は同様に ConversationResetMessage を出力します。Python SDK v0.2.137 より前では、Python イテレータはそのメッセージをドロップしたため、これらのバージョンではアプリが送信する /clear ターンからリセットを自分でカウントしてください。
maxBudgetUsd、または Python の max_budget_usd は同じ実行合計と比較されるため、/clear はバジェットもリセットします。
クエリの総コストを取得する
結果メッセージは、TypeScript では SDKResultMessage として、Python では ResultMessage として型付けされており、query() 呼び出しのエージェントループの終了を示します。これには total_cost_usd が含まれており、その呼び出し内のすべてのステップにわたる累積推定コストです。Python ではこのフィールドはオプションとして型付けされているため、読み取る前に None でないことを確認してください。成功結果とエラー結果の両方がこれを含みますが、セッションクラッシュ後の総コストの復旧の最終結果はゼロになる可能性があります。
セッションを使用して複数の query() 呼び出しを行う場合、各結果はその個別の呼び出しのコストのみを反映します。ストリーミング入力モードでは、ストリーミング入力モードでのコスト追跡で説明されているように呼び出し総額を読み取ります。
3 つの結果レベルのフィールドは、エージェントが サブエージェント を生成する場合に何をカウントするかが異なります。ツリー全体のトークンアカウンティングには modelUsage または Python では model_usage を使用してください。usage フィールドはネストが発生するとすぐに過小カウントされます。
| フィールド | サブエージェントアクティビティ |
|---|---|
usage |
除外。トップレベルのエージェントループのみをカウントするため、サブエージェント内で消費されたトークンは追加されません |
total_cost_usd |
含まれます。トップレベルループと並行してサブエージェントリクエストをカウントします |
modelUsage / model_usage |
含まれます。トップレベルループと並行してサブエージェントリクエストをカウントし、モデル別に分類されます |
シングルメッセージ入力モードでは、最終ターンの終了時にバックグラウンドサブエージェントがまだ実行中の場合、Claude Code は 終了時のバックグラウンドタスクで説明されているキャップまで、結果を発行する前にそれらを待機します。結果の total_cost_usd、duration_api_ms、および modelUsage または Python では 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}`);
}
from claude_agent_sdk import query, ResultMessage
import asyncio
async def main():
try:
async for message in query(prompt="Summarize this project"):
if isinstance(message, ResultMessage):
print(f"Total cost: ${message.total_cost_usd or 0}")
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the branch above has already run;
# connection or process failures yield no result message.
print(f"Session ended with an error: {error}")
asyncio.run(main())
サブエージェントが total_cost_usd に追加できる量を制限するには、クエリで 深さ、同時実行性、および支出制限 を設定してください。
ステップごと、モデルごとの使用状況を追跡する
このセクションの例では TypeScript フィールド名を使用しています。Python では、ステップごとの使用状況に対応するフィールドは AssistantMessage.usage と AssistantMessage.message_id であり、モデルごとの内訳に対応するフィールドは ResultMessage.model_usage です。
ステップごとの使用状況を追跡する
各アシスタントメッセージには、ネストされた BetaMessage(message.message でアクセス)が含まれており、id とトークン数を含む usage オブジェクトがあります。Claude がツールを並列で使用する場合、複数のメッセージが同じ id を共有し、同一の使用状況データを持ちます。既にカウントした ID を追跡し、重複をスキップして合計が膨らまないようにしてください。
重複排除されたステップごとの値は、入力トークンとキャッシュトークンについては正確です。ステップごとの output_tokens はプレースホルダーであるため、結果メッセージから出力トークンを読み取ってください。
次の例は、すべてのステップ全体で入力トークンを累積し、各ユニークなメインループメッセージ ID を 1 回だけカウントしてサブエージェントメッセージをスキップし、メインループをカバーする結果メッセージから出力合計を読み取ります。
import { query } from "@anthropic-ai/claude-agent-sdk";
const seenIds = new Set<string>();
let totalInputTokens = 0;
let resultOutputTokens = 0;
try {
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "assistant" && !message.parent_tool_use_id) {
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;
}
}
if (message.type === "result") {
// Per-step output_tokens is a placeholder; the result message
// carries the accumulated output total.
resultOutputTokens = message.usage.output_tokens;
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result, so the
// input total below still reflects 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: ${resultOutputTokens}`);
モデルごとの使用状況を内訳する
結果メッセージには modelUsage が含まれており、これはモデル名からモデルごとのトークン数とコストへのマップです。これは複数のモデルを実行する場合(たとえば、サブエージェント用に Haiku、メインエージェント用に Opus)に便利で、トークンがどこに使用されているかを確認したい場合に役立ちます。
各エントリの costBasis は、そのモデルの最新リクエストに価格を付けた価格表を示します。list はリスト価格、managed は modelPricing テーブル、または unknown はどちらもモデル ID に一致しなかった場合です。このフィールドには Claude Code v2.1.246 以降が必要です。
次の例はクエリを実行し、使用されたモデルごとのコストとトークンの内訳を出力します。
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() 呼び出しを行う場合(例えば、マルチターンセッションや異なるユーザー間)、合計を自分で累積する必要があります。ストリーミング入力モードでは、ストリーミング入力モードでコストを追跡するで説明されているように各呼び出しの合計を読み取ります。セッションクラッシュで終了した呼び出しについては、セッションクラッシュ後に合計を復旧するを参照してください。
以下の例は、2 つの 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)}`);
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:
try:
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}")
except Exception as error:
# A single-shot query() raises 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.
print(f"Call failed: {error}")
print(f"Total spend: ${total_spend:.4f}")
asyncio.run(main())
エラー、キャッシング、出力トークン数を処理する
正確なコスト追跡のために、アシスタントメッセージのプレースホルダー出力カウント、失敗した会話が消費したトークン、およびキャッシュトークン価格を考慮してください。
結果メッセージから出力トークンを読み取る
Claude Code は、レスポンスが開始されたときに API が報告した使用状況からアシスタントメッセージを構築するため、メッセージの output_tokens は、レスポンスが生成される前に API が message_start で報告したカウントのみです。1 つの API レスポンスは複数のアシスタントメッセージを生成でき、それぞれが同じプレースホルダーを保持しています。
API はレスポンスの終了時に実際の出力カウントを報告し、Claude Code はそれを結果メッセージに追加します。結果の usage から、または詳細なモデル別の内訳については modelUsage から出力トークンを読み取ります。
レスポンスの出力カウントがストリーミング中に増加するのを監視するには、includePartialMessages を設定するか、Python では include_partial_messages を設定し、各 message_delta ストリームイベントから usage を読み取ります。TypeScript では SDKPartialAssistantMessage として、Python では StreamEvent として型付けされています。
失敗した会話のコストを追跡する
成功とエラーの両方の結果メッセージには usage と total_cost_usd が含まれます。Python では両方のフィールドはオプションとして型付けされているため、読み取る前に None でないことを確認してください。
会話が途中で失敗した場合でも、失敗の時点までトークンを消費しています。すべての結果メッセージからコストデータを読み取ります。その subtype が success であるか、エラーサブタイプの 1 つであるかに関わらず。一部のエラー結果では、usage は呼び出しが費やした額より少なく報告します。
- セッションクラッシュ後の
error_during_execution: すべてのコストフィールドがゼロになる可能性があります。 error_max_budget_usd:usageは予算を超えたレスポンスを除外しますが、total_cost_usdとmodelUsageはそれを含みます。
選択肢がある場合は、usage ではなく total_cost_usd または modelUsage から計算してください。
セッションクラッシュ後に合計を復旧する
Claude Code プロセスがクラッシュすると、最終的な error_during_execution 結果を発行して終了します。シングルショットモードとストリーミング入力モードの両方で同様です。その結果は usage、total_cost_usd、および modelUsage がゼロになる可能性があるため、それより前に到着したものから呼び出しの合計を復旧してください。ステップ 1 は以前の結果が存在するときはいつでも完全な合計を復旧します。ステップ 2 のフォールバックはメインループの入力とキャッシュトークンのみを復旧します。
- クラッシュの前のターンの結果を使用します。ストリーミング入力モードでは、呼び出しの開始以降またはそれ以降の実行中の合計を保持します。その結果があなたを助けることができない場合はステップ 2 に進んでください。
- 呼び出しはシングルショットであるため、以前の結果は存在しません。
- クラッシュは最初のターンで発生しました。
- クラッシュの前のターンは
/clear自体であったため、その結果はリセットのみをカバーしています。
- 代わりにアシスタントメッセージの
usageを合計し、各 API レスポンスを 1 回カウントします。ステップごとの使用状況を追跡する例が行うように。シングルショットモードでは、すべてを合計します。ストリーミング入力モードでは、最後の結果の後に到着したものを合計します。これにより、メインループの入力とキャッシュトークンが得られます。サブエージェントの使用状況はこの方法では復旧できず、出力トークンや USD コストも復旧できません。ステップごとのoutput_tokensはプレースホルダーであるためです。
キャッシュトークンを追跡する
Agent SDK は自動的にプロンプトキャッシングを使用して、繰り返されるコンテンツのコストを削減します。キャッシングを自分で設定する必要はありません。使用状況オブジェクトには、キャッシュ追跡用の 2 つの追加フィールドが含まれています。
cache_creation_input_tokens: 新しいキャッシュエントリを作成するために使用されたトークン(標準入力トークンより高いレートで課金されます)。cache_read_input_tokens: 既存のキャッシュエントリから読み取られたトークン(削減されたレートで課金されます)。
キャッシング節約を理解するために、これらを input_tokens とは別に追跡してください。TypeScript では、これらのフィールドは Usage オブジェクトで型付けされています。Python では、ResultMessage.usage 辞書のキーとして表示されます(例えば、message.usage.get("cache_read_input_tokens", 0))。
プロンプトキャッシュ TTL を 1 時間に延長する
あなた自身のターンは、メイン会話 TTL バケットに分類されます。Claude Code がそれらと一緒にインラインで実行するヘルパーと共に。Claude Code が会話外で行う要求(サブエージェントなど)には、別の TTL 制御があります。
あなた自身のターンのキャッシュエントリは、API キーで認証するか、Amazon Bedrock、Google Cloud の Agent Platform、Microsoft Foundry、または AWS 上の Claude Platformで実行する場合、デフォルトで 5 分の TTL を使用します。ワークロードが同じシステムプロンプトとコンテキストに対して多くの短いセッションを実行し、セッション間に 5 分以上のギャップがある場合、キャッシュはセッション間で期限切れになり、各新しいセッションは完全な入力価格を支払います。
キャッシュ書き込みで 1 時間の TTL をリクエストするには、ENABLE_PROMPT_CACHING_1H環境変数を設定します。シェルまたはコンテナ環境でエクスポートするか、options.env を通じて渡すことができます。
次の例は、Amazon Bedrock で実行されているエージェントの 1 時間 TTL を有効にします。CLAUDE_CODE_USE_BEDROCK を設定するため、Amazon Bedrockの動作する AWS 認証情報が必要です。それらがない場合、クエリは失敗します。
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())
import { query } from "@anthropic-ai/claude-agent-sdk";
const options = {
env: {
...process.env,
CLAUDE_CODE_USE_BEDROCK: "1",
ENABLE_PROMPT_CACHING_1H: "1",
},
};
for await (const message of query({ prompt: "Summarize this project", options })) {
console.log(message);
}
1 時間の TTL でのキャッシュ書き込みは、5 分の書き込みより高いレートで課金されるため、これを有効にすると、より高い書き込みコストとより多くのキャッシュ読み取りがトレードオフされます。詳細については、プロンプトキャッシング価格を参照してください。Claude サブスクリプション内でプランの含まれた使用状況では、この変数を設定せずに、あなた自身のターンで 1 時間の TTL を取得し、Claude Code がそれらの横で行うヘルパー要求の一部でも取得します。Claude Code は、使用クレジットを引き出すと、これらのターンを 5 分の TTL に落とします。
ENABLE_PROMPT_CACHING_1H は、両方のバケット内のすべてのリクエストで 1 時間の TTL をリクエストします。各バケットの TTL を個別に選択するには、代わりにこれらの制御を使用してください。それぞれは 5m または 1h を取り、ENABLE_PROMPT_CACHING_1H より優先されます。
- メイン会話:
CLAUDE_CODE_PROMPT_CACHE_TTL環境変数、またはpromptCacheTtl設定 - その他すべて:
CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL環境変数、またはsubagentPromptCacheTtl設定
promptCacheTtl を 1h に設定すると、使用クレジットを引き出している間、メイン会話で 1 時間のキャッシュを保持します。完全な優先順位については、TTL を自分で選択するを参照してください。
関連ドキュメント
- TypeScript SDK リファレンス - 完全な API ドキュメント
- SDK 概要 - SDK の使用を開始する
- SDK パーミッション - ツールパーミッションの管理