SpyBara
Go Premium

agent-sdk/cost-tracking.md 2026-09-17 05:00 UTC to 2026-09-18 23:58 UTC

This page contains 1 addition and 1 deletion.

2026
Wed 9 22:58 Fri 18 23:58 Tue 22 23:59

Lacak biaya dan penggunaan

Pelajari cara melacak penggunaan token, memperkirakan biaya, dan mengonfigurasi prompt caching dengan Claude Agent SDK.

Claude Agent SDK menyediakan informasi penggunaan token yang terperinci untuk setiap interaksi dengan Claude. Panduan ini menjelaskan cara melacak penggunaan dengan benar dan memahami pelaporan biaya, terutama ketika menangani penggunaan alat paralel dan percakapan multi-langkah.

Untuk dokumentasi API lengkap, lihat referensi SDK TypeScript dan referensi SDK Python.

Pahami penggunaan token

TypeScript dan Python SDK mengekspos data penggunaan yang sama dengan nama field yang berbeda:

  • TypeScript menyediakan breakdown token per-step pada setiap pesan asisten (message.message.id, message.message.usage), biaya per-model melalui modelUsage pada pesan hasil, dan total kumulatif pada pesan hasil.
  • Python menyediakan breakdown token per-step pada setiap pesan asisten sebagai message.usage dan message.message_id, biaya per-model melalui model_usage pada pesan hasil, dan total kumulatif pada pesan hasil sebagai total_cost_usd.

Kedua SDK menggunakan model biaya yang sama dan mengekspos granularitas yang sama. Perbedaannya adalah dalam penamaan field dan di mana penggunaan per-step bersarang.

Pelacakan biaya bergantung pada pemahaman tentang bagaimana SDK membatasi data penggunaan:

  • query() call: satu invokasi dari fungsi query() SDK. Satu panggilan dapat melibatkan beberapa langkah: Claude merespons, menggunakan tools, mendapatkan hasil, dan merespons lagi. Setiap panggilan menghasilkan satu pesan result di akhir, kecuali dalam mode input streaming, di mana satu panggilan query() membawa beberapa giliran pengguna dan setiap giliran memancarkan pesan result miliknya sendiri.
  • Step: satu siklus request/response dalam panggilan query(). Setiap langkah menghasilkan pesan asisten dengan penggunaan token.
  • Session: serangkaian panggilan query() yang terhubung oleh ID sesi (menggunakan opsi resume). Setiap panggilan query() dalam sesi melaporkan biayanya secara independen.

Diagram berikut menunjukkan aliran pesan dari satu panggilan query(), dengan penggunaan token dilaporkan pada setiap langkah dan perkiraan kumulatif di akhir:

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. 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.
1

Setiap langkah menghasilkan pesan asisten

Ketika Claude merespons, ia mengirimkan satu atau lebih pesan asisten. Di TypeScript, setiap pesan asisten berisi BetaMessage bersarang (diakses melalui message.message) dengan id dan objek usage dengan hitungan token (input_tokens, output_tokens). Di Python, dataclass AssistantMessage mengekspos data yang sama secara langsung melalui message.usage dan message.message_id. Ketika Claude menggunakan beberapa tools dalam satu giliran, semua pesan dalam giliran itu berbagi ID yang sama, jadi deduplikasi berdasarkan ID untuk menghindari penghitungan ganda.

2

Pesan hasil memberikan perkiraan kumulatif

Ketika panggilan query() selesai, SDK memancarkan pesan hasil dengan total_cost_usd dan usage kumulatif, diketik sebagai SDKResultMessage di TypeScript dan ResultMessage di Python. Jika Anda membuat beberapa panggilan query(), misalnya dalam sesi multi-giliran, setiap hasil hanya mencerminkan biaya panggilan individual itu. Jika Anda hanya membutuhkan total perkiraan, Anda dapat mengabaikan penggunaan per-step dan membaca nilai tunggal ini.

Dalam mode input streaming, setiap giliran memancarkan pesan hasil miliknya sendiri. Lihat Track costs in streaming input mode untuk cara membaca total panggilan dalam mode itu.

Lacak biaya dalam mode input streaming

Dalam mode input streaming, satu panggilan query() membawa beberapa giliran pengguna dan setiap giliran memancarkan pesan hasilnya sendiri. Bidang hasil berbeda dalam cakupan:

  • usage: mencakup hanya giliran itu, dan di dalamnya hanya loop agen utama, bukan subagen apa pun yang dijalankannya.
  • total_cost_usd dan modelUsage, atau model_usage dalam Python: membawa total berjalan untuk seluruh panggilan sejauh ini.

Dalam panggilan di mana aplikasi Anda tidak pernah mengirim /clear, /reset, atau /new, baca hasil terbaru untuk total panggilan daripada menjumlahkan hasil.

Total berjalan dimulai ulang setiap kali aplikasi Anda mengirim salah satu dari tiga perintah itu, dan di dalam panggilan query() tidak ada yang lain yang mengatur ulang mereka. Tiga hasil penting untuk akuntansi Anda:

  • Hasil giliran /clear itu sendiri: mencakup hanya apa yang telah berjalan sejak pengaturan ulang, dan membawa session_id baru.
  • Setiap hasil kemudian: terus menghitung dari pengaturan ulang itu.
  • Hasil terakhir sebelum setiap /clear: menyimpan total untuk giliran sejak pengaturan ulang sebelumnya.

Untuk menghitung total seluruh panggilan, tambahkan hasil terakhir dari sebelum setiap /clear ke hasil akhir panggilan. Setiap hasil lainnya, termasuk hasil giliran /clear itu sendiri, digantikan oleh hasil yang lebih baru.

Dalam TypeScript, SDK juga memancarkan SDKConversationResetMessage pada setiap pengaturan ulang, sehingga Anda dapat mendeteksi pengaturan ulang dari aliran. Dalam Python, SDK juga memancarkan ConversationResetMessage. Sebelum Python SDK v0.2.137, iterator Python menghilangkan pesan itu, jadi pada versi tersebut hitung pengaturan ulang sendiri dari giliran /clear yang dikirim aplikasi Anda.

maxBudgetUsd (TypeScript) atau max_budget_usd (Python) dibandingkan dengan total berjalan yang sama, jadi /clear juga memulai anggaran ulang.

Dapatkan total biaya dari sebuah query

Pesan hasil, yang diketik sebagai SDKResultMessage di TypeScript dan ResultMessage di Python, menandai akhir dari loop agen untuk panggilan query(). Ini mencakup total_cost_usd, biaya perkiraan kumulatif di semua langkah dalam panggilan tersebut. Di Python, bidang ini diketik sebagai opsional, jadi periksa bahwa itu bukan None sebelum Anda membacanya. Hasil sukses dan kesalahan keduanya membawanya, meskipun hasil akhir dari kerusakan sesi mungkin membawanya dengan nilai nol.

Jika Anda menggunakan sesi untuk membuat beberapa panggilan query(), setiap hasil hanya mencerminkan biaya dari panggilan individual tersebut. Dalam mode input streaming, baca total panggilan seperti yang dijelaskan dalam Lacak biaya dalam mode input streaming.

Tiga bidang tingkat hasil berbeda dalam apa yang mereka hitung ketika agen menelurkan subagen. Gunakan modelUsage, atau model_usage di Python, untuk akuntansi token seluruh pohon; bidang usage kurang menghitung segera setelah nesting terjadi.

Bidang Aktivitas Subagen
usage Dikecualikan. Menghitung hanya loop agen tingkat atas, jadi token yang dikonsumsi di dalam subagen tidak ditambahkan
total_cost_usd Disertakan. Menghitung permintaan subagen bersama loop tingkat atas
modelUsage / model_usage Disertakan. Menghitung permintaan subagen bersama loop tingkat atas, dipecah menurut model

Dalam mode input pesan tunggal, ketika subagen latar belakang masih berjalan di akhir giliran terakhir, Claude Code menunggu mereka, hingga batas yang dijelaskan dalam tugas latar belakang saat keluar, sebelum memancarkan hasilnya. total_cost_usd, duration_api_ms, dan modelUsage hasil, atau model_usage di Python, mencakup pekerjaan yang dilakukan selama penantian tersebut.

Contoh berikut mengulangi aliran pesan dari panggilan query() dan mencetak total biaya ketika pesan result tiba:

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}`);
}

Untuk membatasi berapa banyak subagen dapat menambah total_cost_usd, atur batas kedalaman, konkurensi, dan pengeluaran pada query.

Lacak penggunaan per-langkah dan per-model

Contoh-contoh di bagian ini menggunakan nama field TypeScript. Di Python, field yang setara adalah AssistantMessage.usage dan AssistantMessage.message_id untuk penggunaan per-langkah, dan ResultMessage.model_usage untuk rincian per-model.

Lacak penggunaan per-langkah

Setiap pesan asisten berisi BetaMessage bersarang (diakses melalui message.message) dengan objek id dan usage yang berisi hitungan token. Ketika Claude menggunakan tools secara paralel, beberapa pesan berbagi id yang sama dengan data penggunaan yang identik. Lacak ID mana yang sudah Anda hitung dan lewati duplikat untuk menghindari total yang membengkak.

Contoh berikut mengakumulasi token input di semua langkah, menghitung setiap ID pesan loop utama yang unik hanya sekali dan melewati pesan subagen, serta membaca total output dari pesan hasil, yang mencakup loop utama:

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}`);

Rincian penggunaan per model

Pesan hasil mencakup modelUsage, peta nama model ke hitungan token per-model dan biaya. Ini berguna ketika Anda menjalankan beberapa model (misalnya, Haiku untuk subagen dan Opus untuk agen utama) dan ingin melihat ke mana token pergi.

Setiap costBasis entri mengatakan tabel harga mana yang menentukan harga permintaan terbaru model itu: list untuk harga daftar, managed untuk tabel modelPricing, atau unknown ketika tidak ada yang cocok dengan ID model. Field memerlukan Claude Code v2.1.246 atau lebih baru.

Contoh berikut menjalankan kueri dan mencetak rincian biaya dan token untuk setiap model yang digunakan:

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}`);
}

Akumulasi biaya di seluruh beberapa panggilan

Setiap panggilan query() mengembalikan total_cost_usd miliknya sendiri. SDK tidak menyediakan total tingkat sesi, jadi jika aplikasi Anda melakukan beberapa panggilan query(), misalnya dalam sesi multi-putaran atau di seluruh pengguna yang berbeda, akumulasikan totalnya sendiri. Dalam mode input streaming, baca total setiap panggilan seperti yang dijelaskan dalam Track costs in streaming input mode. Untuk panggilan yang berakhir dalam kerusakan, lihat Recover totals after a session crash.

Contoh berikut menjalankan dua panggilan query() secara berurutan, menambahkan total_cost_usd setiap panggilan ke total yang berjalan, dan mencetak biaya per-panggilan dan gabungan:

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)}`);

Menangani kesalahan, caching, dan jumlah token output

Untuk pelacakan biaya yang akurat, pertimbangkan jumlah output placeholder pada pesan asisten, token yang dikonsumsi percakapan yang gagal, dan harga token cache.

Baca token output dari pesan hasil

Claude Code membangun setiap pesan asisten dari penggunaan yang dilaporkan API ketika respons dimulai, jadi output_tokens pesan hanya merupakan jumlah yang dilaporkan API pada message_start, sebelum respons dihasilkan. Satu respons API dapat menghasilkan beberapa pesan asisten, dan setiap satu membawa placeholder yang sama.

API melaporkan jumlah output nyata di akhir respons, dan Claude Code menambahkannya ke pesan hasil. Baca token output dari usage hasil, atau dari modelUsage untuk rincian per-model.

Untuk menonton jumlah output respons tumbuh saat streaming, atur includePartialMessages, atau include_partial_messages di Python, dan baca usage dari setiap acara stream message_delta, diketik sebagai SDKPartialAssistantMessage di TypeScript dan StreamEvent di Python.

Lacak biaya pada percakapan yang gagal

Pesan hasil kesuksesan dan kesalahan keduanya mencakup usage dan total_cost_usd; di Python kedua bidang diketik sebagai opsional, jadi periksa bahwa mereka bukan None sebelum Anda membacanya.

Jika percakapan gagal di tengah jalan, Anda masih mengonsumsi token hingga titik kegagalan. Baca data biaya dari setiap pesan hasil, terlepas dari apakah subtype-nya adalah success atau salah satu subtipe kesalahan. Pada beberapa hasil kesalahan, usage melaporkan lebih sedikit daripada yang dihabiskan panggilan:

  • error_during_execution setelah kerusakan sesi: setiap bidang biaya dapat dinolkan.
  • error_max_budget_usd: usage menghilangkan respons yang melampaui anggaran, sementara total_cost_usd dan modelUsage menyertakannya.

Jika Anda memiliki pilihan, hitung dari total_cost_usd atau modelUsage daripada usage.

Pulihkan total setelah kerusakan sesi

Ketika proses Claude Code mogok, ia mengeluarkan hasil error_during_execution akhir dan keluar, dalam mode input single-shot dan streaming sama-sama. Hasil itu mungkin membawa usage, total_cost_usd, dan modelUsage yang dinolkan, jadi pulihkan total panggilan dari apa yang tiba sebelumnya. Langkah 1 memulihkan total penuh kapan pun hasil sebelumnya ada; fallback di langkah 2 memulihkan hanya token input dan cache loop utama.

  1. Gunakan hasil giliran sebelum kerusakan. Dalam mode input streaming, ia menyimpan total berjalan sejak awal panggilan atau sejak /clear terakhir. Lanjutkan ke langkah 2 sebagai gantinya ketika hasil itu tidak dapat membantu Anda:
    • Panggilan adalah single-shot, jadi tidak ada hasil sebelumnya.
    • Kerusakan terjadi pada giliran pertama.
    • Giliran sebelum kerusakan adalah /clear itu sendiri, jadi hasilnya hanya mencakup reset.
  2. Jumlahkan usage pada pesan asisten sebagai gantinya, menghitung setiap respons API sekali, seperti yang dilakukan contoh Track per-step usage. Dalam mode single-shot, jumlahkan semuanya; dalam mode input streaming, jumlahkan yang tiba setelah hasil terakhir. Ini memberi Anda token input dan cache loop utama. Penggunaan subagent tidak dapat dipulihkan dengan cara ini, begitu juga token output atau biaya USD, karena per-step output_tokens adalah placeholder.

Lacak token cache

Agent SDK secara otomatis menggunakan prompt caching untuk mengurangi biaya pada konten berulang. Anda tidak perlu mengonfigurasi caching sendiri. Objek penggunaan mencakup dua bidang tambahan untuk pelacakan cache:

  • cache_creation_input_tokens: token yang digunakan untuk membuat entri cache baru (dikenakan biaya pada tingkat lebih tinggi daripada token input standar).
  • cache_read_input_tokens: token yang dibaca dari entri cache yang ada (dikenakan biaya pada tingkat berkurang).

Lacak ini secara terpisah dari input_tokens untuk memahami penghematan caching. Di TypeScript, bidang-bidang ini diketik pada objek Usage. Di Python, mereka muncul sebagai kunci dalam dict ResultMessage.usage (misalnya, message.usage.get("cache_read_input_tokens", 0)).

Perpanjang TTL cache prompt ke satu jam

Giliran Anda sendiri jatuh dalam bucket TTL percakapan utama, bersama dengan pembantu yang Claude Code jalankan inline dengan mereka. Permintaan yang Claude Code buat di luar percakapan itu, seperti subagents, memiliki kontrol TTL terpisah.

Entri cache untuk giliran Anda sendiri menggunakan TTL 5 menit secara default ketika Anda mengautentikasi dengan kunci API atau menjalankan pada Amazon Bedrock, Agent Platform Google Cloud, Microsoft Foundry, atau Claude Platform on AWS. Jika beban kerja Anda menjalankan banyak sesi pendek terhadap prompt sistem dan konteks yang sama dengan celah lebih lama dari 5 menit di antara mereka, cache kedaluwarsa di antara sesi dan setiap sesi baru membayar harga input penuh.

Untuk meminta TTL 1 jam pada penulisan cache, atur variabel lingkungan ENABLE_PROMPT_CACHING_1H. Anda dapat mengekspornya di lingkungan shell atau container Anda, atau meneruskannya melalui options.env.

Contoh berikut mengaktifkan TTL 1 jam untuk agen yang berjalan di Amazon Bedrock. Karena menetapkan CLAUDE_CODE_USE_BEDROCK, itu memerlukan kredensial AWS yang berfungsi untuk Amazon Bedrock; tanpanya kueri gagal.

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())

Penulisan cache dengan TTL 1 jam ditagih pada tingkat lebih tinggi daripada penulisan 5 menit, jadi mengaktifkan ini menukar biaya penulisan lebih tinggi untuk lebih banyak pembacaan cache. Lihat prompt caching pricing untuk detail. Pada langganan Claude dalam penggunaan yang disertakan rencana Anda, Anda mendapatkan TTL 1 jam pada giliran Anda sendiri, dan pada beberapa permintaan pembantu yang Claude Code buat di samping mereka, tanpa menetapkan variabel ini, dan Claude Code menjatuhkan giliran tersebut ke TTL 5 menit setelah Anda menarik pada usage credits.

ENABLE_PROMPT_CACHING_1H meminta TTL 1 jam pada setiap permintaan di kedua bucket. Untuk memilih TTL untuk setiap bucket secara terpisah, gunakan kontrol ini sebagai gantinya. Masing-masing mengambil 5m atau 1h dan mengambil prioritas atas ENABLE_PROMPT_CACHING_1H:

Menetapkan promptCacheTtl ke 1h menjaga cache 1 jam pada percakapan utama sementara Anda menarik pada usage credits. Untuk urutan prioritas lengkap, lihat choose the TTL yourself.