SpyBara
Go Premium

agent-sdk/cost-tracking.md 2026-09-11 23:01 UTC to 2026-09-12 03:02 UTC

This page contains 127 additions and 59 deletions.

2026
Sat 12 03:02 Fri 18 23:58 Tue 22 23:59

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.

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 tramite modelUsage sul messaggio risultato, e un totale cumulativo sul messaggio risultato.
  • Python fornisce suddivisioni dei token per fase su ogni messaggio dell'assistente come message.usage e message.message_id, costo per modello tramite model_usage sul messaggio risultato, e il totale cumulativo sul messaggio risultato come total_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 funzione query() dell'SDK. Una singola chiamata può coinvolgere più fasi: Claude risponde, utilizza strumenti, ottiene risultati e risponde di nuovo. Ogni chiamata produce un messaggio result alla fine, tranne in modalità input streaming, dove una chiamata query() comporta più turni dell'utente e ogni turno emette il proprio messaggio result.
  • 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 (utilizzando l'opzione resume). Ogni chiamata query() all'interno di una sessione segnala il proprio costo in modo indipendente.

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:

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

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.

2

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 si effettuano più chiamate query(), ad esempio in una sessione multi-turno, ogni risultato riflette solo il costo di quella singola chiamata. Se è necessario solo il totale stimato, è possibile ignorare l'utilizzo per fase e leggere questo singolo valore.

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_usd e modelUsage, o model_usage in Python: portano il totale cumulativo per l'intera chiamata fino a quel momento.

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 nuovo session_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, o max_budget_usd in Python, viene confrontato con lo stesso totale cumulativo, quindi un /clear avvia anche 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. In Python il campo è tipizzato come opzionale, quindi verificate che non sia None prima 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.

Se utilizzate sessioni per effettuare più chiamate query(), ogni risultato riflette solo il costo di quella singola chiamata. 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}`);
}

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.

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 il suo total_cost_usd. L'SDK non fornisce un totale a livello di sessione, quindi se la vostra applicazione effettua più chiamate query(), ad esempio in una sessione multi-turno o tra diversi utenti, accumulate i totali voi stessi. 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)}`);

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_execution dopo un arresto anomalo della sessione: ogni campo di costo può essere azzerato.
  • error_max_budget_usd: usage omette la risposta che ha superato il budget, mentre total_cost_usd e modelUsage la 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.

  1. Utilizzare il risultato del turno prima dell'arresto anomalo. In modalità input streaming, contiene il totale in esecuzione dall'inizio della chiamata o dall'ultimo /clear. 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 /clear stesso, quindi il suo risultato copre solo il ripristino.
  2. Sommare invece il usage sui 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é il output_tokens per 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())

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:

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.