Tracciare costi e utilizzo
Scopri come tracciare l'utilizzo dei token, stimare i costi e configurare la memorizzazione nella cache dei prompt con Claude Agent SDK.
Claude Agent SDK fornisce informazioni dettagliate sull'utilizzo dei token per ogni interazione con Claude. Questa guida spiega come tracciare correttamente l'utilizzo e comprendere la segnalazione dei costi, soprattutto quando si affrontano usi paralleli di strumenti e conversazioni multi-step.
Per la documentazione API completa, consulta il riferimento TypeScript SDK e il riferimento Python SDK.
I campi total_cost_usd e costUSD sono stime lato client, non dati di fatturazione autorevoli. L'SDK li calcola localmente da una tabella dei prezzi inclusa al momento della compilazione, a meno che non sia in vigore una tabella modelPricing. Possono divergere da ciò che viene effettivamente fatturato quando:
- i prezzi cambiano
- la versione dell'SDK installata non riconosce un modello
- si applicano regole di fatturazione che il client non può modellare
Una regola di fatturazione che l'SDK modella è la determinazione dei prezzi per la residenza dei dati. Quando la usage di una risposta segnala inference_geo: "us", l'SDK moltiplica il prezzo di listino dei token di quella risposta per 1,1. Le tariffe per richiesta come la ricerca web non vengono moltiplicate. Richiede TypeScript Agent SDK v0.3.239 o successivo, oppure Python Agent SDK v0.2.144 o successivo.
Utilizza questi campi per approfondimenti di sviluppo e budget approssimativi. Per la fatturazione autorevole, utilizza l'API di utilizzo e costi o la pagina Utilizzo nella Claude Console. Non fatturare gli utenti finali o attivare decisioni finanziarie da questi campi.
Comprendere l'utilizzo dei token
Gli SDK TypeScript e Python espongono gli stessi dati di utilizzo con nomi di campi diversi:
- TypeScript fornisce suddivisioni dei token per fase su ogni messaggio dell'assistente (
message.message.id,message.message.usage), costo per modello tramitemodelUsagesul messaggio risultato, e un totale cumulativo sul messaggio risultato. - Python fornisce suddivisioni dei token per fase su ogni messaggio dell'assistente come
message.usageemessage.message_id, costo per modello tramitemodel_usagesul messaggio risultato, e il totale cumulativo sul messaggio risultato cometotal_cost_usd.
Entrambi gli SDK utilizzano lo stesso modello di costo sottostante ed espongono la stessa granularità. La differenza è nella denominazione dei campi e nel modo in cui l'utilizzo per fase è annidato.
Il tracciamento dei costi dipende dalla comprensione di come l'SDK delimita i dati di utilizzo:
- Chiamata
query(): una singola invocazione della funzionequery()dell'SDK. Una singola chiamata può coinvolgere più fasi: Claude risponde, utilizza strumenti, ottiene risultati e risponde di nuovo. Ogni chiamata produce un messaggioresultalla fine, tranne in modalità input streaming, dove una chiamataquery()comporta più turni dell'utente e ogni turno emette il proprio messaggioresult. - Fase: un singolo ciclo richiesta/risposta all'interno di una chiamata
query(). Ogni fase produce messaggi dell'assistente con utilizzo dei token. - Sessione: una serie di chiamate
query()collegate da un ID di sessione tramite l'opzioneresume. I risultati di una chiamata ripresa segnalano la spesa totale della sessione, non solo quella della chiamata stessa. Vedere Accumulare i costi su più chiamate per come i totali si trasferiscono.
Il diagramma seguente mostra il flusso di messaggi da una singola chiamata query(), con l'utilizzo dei token segnalato ad ogni fase e la stima cumulativa alla fine:
Ogni fase produce messaggi dell'assistente
Quando Claude risponde, invia uno o più messaggi dell'assistente. In TypeScript, ogni messaggio dell'assistente contiene un BetaMessage annidato (accessibile tramite message.message) con un id e un oggetto usage con conteggi dei token (input_tokens, output_tokens). In Python, la dataclass AssistantMessage espone gli stessi dati direttamente tramite message.usage e message.message_id. Quando Claude utilizza più strumenti in un turno, tutti i messaggi in quel turno condividono lo stesso ID, quindi deduplicare per ID per evitare il doppio conteggio.
Il messaggio risultato fornisce la stima cumulativa
Quando la chiamata query() si completa, l'SDK emette un messaggio risultato con total_cost_usd e usage cumulativo, tipizzato come SDKResultMessage in TypeScript e ResultMessage in Python. Se è necessario solo il totale stimato, è possibile ignorare l'utilizzo per fase e leggere questo singolo valore.
Se si effettuano più chiamate query() indipendenti, ogni risultato riflette solo il costo di quella singola chiamata. Una chiamata che riprende una sessione conta anche la spesa precedente della sessione.
In modalità input streaming, ogni turno emette il proprio messaggio risultato. Vedere Tracciare i costi in modalità input streaming per come leggere i totali delle chiamate in quella modalità.
Tracciare i costi in modalità di input in streaming
In modalità di input in streaming, una singola chiamata query() contiene più turni utente e ogni turno emette il proprio messaggio di risultato. I campi del risultato differiscono in ambito:
usage: copre solo quel turno, e all'interno di esso solo il ciclo principale dell'agente, non eventuali subagenti che ha eseguito.total_cost_usdemodelUsage, omodel_usagein Python: portano il totale cumulativo per l'intera chiamata fino a quel momento, più qualsiasi spesa ripristinata quando la chiamata ha ripreso una sessione.
In una chiamata in cui la vostra app non invia mai /clear, /reset, o /new, leggete il risultato più recente per i totali della chiamata piuttosto che sommare i risultati.
I totali cumulativi ricominciamo ogni volta che la vostra app invia uno di questi tre comandi, e all'interno di una chiamata query() nient'altro li ripristina. Tre risultati sono importanti per la vostra contabilità:
- Il risultato del turno
/clear: copre solo ciò che è stato eseguito dal ripristino, e porta un nuovosession_id. - Ogni risultato successivo: continua a contare da quel ripristino.
- L'ultimo risultato prima di ogni
/clear: contiene il totale per i turni dal ripristino precedente.
Per totalizzare l'intera chiamata, aggiungete l'ultimo risultato prima di ogni /clear al risultato finale della chiamata. Ogni altro risultato, incluso quello del turno /clear, è sostituito da uno successivo.
In TypeScript, l'SDK emette anche un SDKConversationResetMessage ad ogni ripristino, quindi potete rilevare i ripristini dal flusso. In Python, l'SDK emette analogamente un ConversationResetMessage. Prima della versione Python SDK v0.2.137, l'iteratore Python ha eliminato quel messaggio, quindi su quelle versioni contate i ripristini voi stessi dai turni /clear che la vostra app invia.
maxBudgetUsd (TypeScript) o max_budget_usd (Python) conta solo la spesa della chiamata stessa: i totali ripristinati da una sessione ripresa non contano rispetto ad esso, e un /clear avvia il budget da capo.
Ottenere il costo totale di una query
Il messaggio di risultato, tipizzato come SDKResultMessage in TypeScript e ResultMessage in Python, segna la fine del ciclo dell'agente per una chiamata query(). Include total_cost_usd, il costo stimato cumulativo su tutti i passaggi in quella chiamata. Una chiamata che riprende una sessione conta anche la spesa precedente della sessione. Due avvertenze si applicano quando leggete il valore:
- In Python il campo è tipizzato come opzionale, quindi verificate che non sia
Noneprima di leggerlo. - I risultati di successo e di errore lo portano entrambi, anche se il risultato finale di un crash della sessione potrebbe portarlo azzerato.
In modalità di input in streaming, leggete i totali delle chiamate come descritto in Track costs in streaming input mode.
I tre campi a livello di risultato differiscono in ciò che contano quando l'agente genera subagenti. Utilizzate modelUsage, o model_usage in Python, per la contabilità dei token dell'intero albero; il campo usage sottoconta non appena si verifica l'annidamento.
| Campo | Attività del subagente |
|---|---|
usage |
Escluso. Conta solo il ciclo dell'agente di primo livello, quindi i token consumati all'interno dei subagenti non vengono aggiunti |
total_cost_usd |
Incluso. Conta le richieste dei subagenti insieme al ciclo di primo livello |
modelUsage / model_usage |
Incluso. Conta le richieste dei subagenti insieme al ciclo di primo livello, suddiviso per modello |
In modalità di input a messaggio singolo, quando i subagenti in background sono ancora in esecuzione alla fine del turno finale, Claude Code li attende, fino al limite descritto in background tasks at exit, prima di emettere il risultato. Il total_cost_usd, duration_api_ms e modelUsage del risultato, o model_usage in Python, includono il lavoro svolto durante l'attesa.
I seguenti esempi iterano sul flusso di messaggi da una chiamata query() e stampano il costo totale quando arriva il messaggio 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())
Per limitare quanto i subagenti possono aggiungere a total_cost_usd, impostate i limiti di profondità, concorrenza e spesa sulla query.
Tracciare l'utilizzo per step e per modello
Gli esempi in questa sezione utilizzano nomi di campi TypeScript. In Python, i campi equivalenti sono AssistantMessage.usage e AssistantMessage.message_id per l'utilizzo per step, e ResultMessage.model_usage per i dettagli per modello.
Tracciare l'utilizzo per step
Ogni messaggio dell'assistente contiene un BetaMessage annidato (accessibile tramite message.message) con un id e un oggetto usage con i conteggi dei token. Quando Claude utilizza gli strumenti in parallelo, più messaggi condividono lo stesso id con dati di utilizzo identici. Tenere traccia degli ID che hai già contato e saltare i duplicati per evitare totali gonfiati.
I valori per step deduplicati sono accurati per i token di input e cache. L'output_tokens per step è un placeholder, quindi leggi i token di output dal messaggio di risultato.
L'esempio seguente accumula i token di input in tutti gli step, contando ogni ID di messaggio del loop principale univoco una sola volta e saltando i messaggi dei subagent, e legge il totale di output dal messaggio di risultato, che copre il loop principale:
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}`);
Dettagliare l'utilizzo per modello
Il messaggio di risultato include modelUsage, una mappa del nome del modello ai conteggi dei token per modello e al costo. Questo è utile quando esegui più modelli (ad esempio, Haiku per i subagent e Opus per l'agente principale) e desideri vedere dove vanno i token.
Il costBasis di ogni voce indica quale tabella dei prezzi ha determinato il prezzo della richiesta più recente di quel modello: list per il prezzo di listino, managed per una tabella modelPricing, o unknown quando nessuno dei due corrisponde all'ID del modello. Il campo richiede Claude Code v2.1.246 o successivo.
L'esempio seguente esegue una query e stampa il costo e il dettaglio dei token per ogni modello utilizzato:
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}`);
}
Accumulare i costi su più chiamate
Ogni chiamata query() restituisce total_cost_usd sui suoi risultati. Come combinare i valori dipende dal fatto che le chiamate condividano una sessione:
- Chiamate indipendenti, senza opzione
resumeocontinue: ogni risultato copre solo la propria chiamata, quindi aggiungete i totali voi stessi, come fanno gli esempi seguenti. - Chiamate che riprendono la stessa sessione: Claude Code salva i totali della sessione nel suo transcript quando il processo esce normalmente e li ripristina quando una chiamata successiva riprende o effettua il fork della sessione. Ogni risultato include già la spesa precedente della sessione. Leggete l'ultimo risultato per il totale della sessione; sommare i risultati conta due volte la spesa ripristinata. Prima della v2.1.277, una sessione che avevate ripreso tramite l'SDK o
claude -piniziava i suoi totali a zero, quindi i risultati di ogni chiamata coprivano solo quella chiamata.
In modalità input streaming, leggete il totale di ogni chiamata come descritto in Track costs in streaming input mode. Per una chiamata che si è conclusa con un crash, vedere Recover totals after a session crash.
I seguenti esempi eseguono due chiamate query() in sequenza, aggiungono il total_cost_usd di ogni chiamata a un totale progressivo e stampano sia il costo per singola chiamata che il costo combinato:
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())
Gestire errori, caching e conteggi dei token di output
Per un tracciamento accurato dei costi, tenere conto del conteggio di output segnaposto sui messaggi dell'assistente, dei token che una conversazione non riuscita ha consumato e dei prezzi dei token della cache.
Leggere i token di output dal messaggio di risultato
Claude Code costruisce ogni messaggio dell'assistente dall'utilizzo che l'API ha segnalato quando la risposta è iniziata, quindi il output_tokens del messaggio è solo il conteggio che l'API aveva segnalato a message_start, prima che la risposta fosse generata. Una risposta API può produrre diversi messaggi dell'assistente, e ognuno di essi porta lo stesso segnaposto.
L'API segnala il conteggio di output reale alla fine della risposta, e Claude Code lo aggiunge al messaggio di risultato. Leggere i token di output dal usage del risultato, o da modelUsage per una suddivisione per modello.
Per osservare il conteggio di output di una risposta crescere mentre viene trasmesso in streaming, impostare includePartialMessages, o include_partial_messages in Python, e leggere usage da ogni evento di flusso message_delta, tipizzato come SDKPartialAssistantMessage in TypeScript e StreamEvent in Python.
Tracciare i costi su conversazioni non riuscite
Sia i messaggi di risultato di successo che di errore includono usage e total_cost_usd; in Python entrambi i campi sono tipizzati come opzionali, quindi verificare che non siano None prima di leggerli.
Se una conversazione non riesce a metà strada, hai comunque consumato token fino al punto del fallimento. Leggere i dati di costo da ogni messaggio di risultato, indipendentemente dal fatto che il suo subtype sia success o uno dei sottotipi di errore. Su alcuni risultati di errore, usage segnala meno di quanto la chiamata ha speso:
error_during_executiondopo un arresto anomalo della sessione: ogni campo di costo può essere azzerato.error_max_budget_usd:usageomette la risposta che ha superato il budget, mentretotal_cost_usdemodelUsagela includono.
Dove hai la scelta, contabilizzare da total_cost_usd o modelUsage piuttosto che da usage.
Recuperare i totali dopo un arresto anomalo della sessione
Quando il processo Claude Code si arresta in modo anomalo, emette un risultato error_during_execution finale e esce, sia in modalità input single-shot che in streaming. Quel risultato può portare usage, total_cost_usd e modelUsage azzerati, quindi recuperare i totali della chiamata da ciò che è arrivato prima. Il passaggio 1 recupera i totali completi ogni volta che esiste un risultato precedente; il fallback nel passaggio 2 recupera solo i token di input e cache del ciclo principale.
- Utilizzare il risultato del turno prima dell'arresto anomalo. In modalità input streaming, contiene il totale in esecuzione descritto in Track costs in streaming input mode. Passare al passaggio 2 invece quando quel risultato non può aiutarti:
- La chiamata era single-shot, quindi non esiste alcun risultato precedente.
- L'arresto anomalo è avvenuto al primo turno.
- Il turno prima dell'arresto anomalo era il
/clearstesso, quindi il suo risultato copre solo il ripristino.
- Sommare invece il
usagesui messaggi dell'assistente, contando ogni risposta API una volta, come fa l'esempio Track per-step usage. In modalità single-shot, sommare tutti; in modalità input streaming, sommare quelli arrivati dopo l'ultimo risultato. Questo ti dà i token di input e cache del ciclo principale. L'utilizzo dei subagent non è recuperabile in questo modo, e nemmeno i token di output o il costo in USD, perché iloutput_tokensper passaggio è un segnaposto.
Tracciare i token della cache
L'Agent SDK utilizza automaticamente prompt caching per ridurre i costi su contenuti ripetuti. Non è necessario configurare il caching da soli. L'oggetto usage include due campi aggiuntivi per il tracciamento della cache:
cache_creation_input_tokens: token utilizzati per creare nuove voci della cache (addebitati a una tariffa più alta rispetto ai token di input standard).cache_read_input_tokens: token letti da voci della cache esistenti (addebitati a una tariffa ridotta).
Tracciare questi separatamente da input_tokens per comprendere i risparmi della cache. In TypeScript, questi campi sono tipizzati sull'oggetto Usage. In Python, appaiono come chiavi nel dizionario ResultMessage.usage (ad esempio, message.usage.get("cache_read_input_tokens", 0)).
Estendere il TTL della cache del prompt a un'ora
I tuoi turni rientrano nel bucket TTL della conversazione principale, insieme ai helper che Claude Code esegue inline con essi. Le richieste che Claude Code effettua al di fuori di quella conversazione, come i subagent, hanno un controllo TTL separato.
Le voci della cache per i tuoi turni utilizzano un TTL di 5 minuti per impostazione predefinita quando ti autentichi con una chiave API o esegui su Amazon Bedrock, Agent Platform di Google Cloud, Microsoft Foundry, o Claude Platform on AWS. Se il tuo carico di lavoro esegue molte sessioni brevi rispetto allo stesso prompt di sistema e contesto con gap più lunghi di 5 minuti tra di essi, la cache scade tra le sessioni e ogni nuova sessione paga il prezzo di input completo.
Per richiedere un TTL di 1 ora sulle scritture della cache, impostare la variabile di ambiente ENABLE_PROMPT_CACHING_1H. Puoi esportarla nel tuo ambiente shell o container, o passarla attraverso options.env.
L'esempio seguente abilita il TTL di 1 ora per un agente in esecuzione su Amazon Bedrock. Poiché imposta CLAUDE_CODE_USE_BEDROCK, richiede credenziali AWS funzionanti per Amazon Bedrock; senza di esse la query non riesce.
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);
}
Le scritture della cache con un TTL di 1 ora sono fatturate a una tariffa più alta rispetto alle scritture di 5 minuti, quindi abilitare questo scambia un costo di scrittura più elevato per più letture della cache. Vedi prompt caching pricing per i dettagli. Su un abbonamento Claude all'interno dell'utilizzo incluso nel tuo piano, ottieni il TTL di 1 ora sui tuoi turni, e su alcune delle richieste helper che Claude Code effettua accanto a essi, senza impostare questa variabile, e Claude Code riduce quei turni al TTL di 5 minuti una volta che stai attingendo ai crediti di utilizzo.
ENABLE_PROMPT_CACHING_1H richiede il TTL di 1 ora su ogni richiesta in entrambi i bucket. Per scegliere un TTL per ogni bucket separatamente, utilizza invece questi controlli. Ognuno accetta 5m o 1h e ha la precedenza su ENABLE_PROMPT_CACHING_1H:
- Conversazione principale: la variabile di ambiente
CLAUDE_CODE_PROMPT_CACHE_TTL, o l'impostazionepromptCacheTtl - Tutto il resto: la variabile di ambiente
CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL, o l'impostazionesubagentPromptCacheTtl
Impostare promptCacheTtl a 1h mantiene la cache di 1 ora sulla conversazione principale mentre stai attingendo ai crediti di utilizzo. Per l'ordine di precedenza completo, vedi choose the TTL yourself.
Documentazione correlata
- Riferimento TypeScript SDK - Documentazione API completa
- Panoramica SDK - Introduzione all'SDK
- Autorizzazioni SDK - Gestione delle autorizzazioni degli strumenti