Rastrear custo e uso
Aprenda como rastrear o uso de tokens, estimar custos e configurar prompt caching com o Claude Agent SDK.
O Claude Agent SDK fornece informações detalhadas de uso de tokens para cada interação com Claude. Este guia explica como rastrear adequadamente o uso e entender o relatório de custos, especialmente ao lidar com usos de ferramentas paralelas e conversas em múltiplas etapas.
Para documentação completa da API, consulte a referência do SDK TypeScript e a referência do SDK Python.
Os campos total_cost_usd e costUSD são estimativas do lado do cliente, não dados de faturamento autoritários. O SDK os calcula localmente a partir de uma tabela de preços incluída no momento da compilação, portanto, podem divergir do que você é realmente cobrado quando:
- os preços mudam
- a versão do SDK instalada não reconhece um modelo
- regras de faturamento se aplicam que o cliente não consegue modelar
Use esses campos para obter informações de desenvolvimento e orçamento aproximado. Para faturamento autoritário, use a API de Uso e Custo ou a página de Uso no Console Claude. Não fature usuários finais ou dispare decisões financeiras a partir desses campos.
Entender o uso de tokens
Os SDKs TypeScript e Python expõem os mesmos dados de uso com nomes de campos diferentes:
- TypeScript fornece divisões de tokens por etapa em cada mensagem do assistente (
message.message.id,message.message.usage), custo por modelo viamodelUsagena mensagem de resultado, e um total cumulativo na mensagem de resultado. - Python fornece divisões de tokens por etapa em cada mensagem do assistente (
message.usage,message.message_id), custo por modelo viamodel_usagena mensagem de resultado, e o total acumulado na mensagem de resultado (total_cost_usde dicionáriousage).
Ambos os SDKs usam o mesmo modelo de custo subjacente e expõem a mesma granularidade. A diferença está na nomenclatura dos campos e onde o uso por etapa está aninhado.
O rastreamento de custos depende de entender como o SDK define o escopo dos dados de uso:
- Chamada
query(): uma invocação da funçãoquery()do SDK. Uma única chamada pode envolver múltiplas etapas (Claude responde, usa ferramentas, obtém resultados, responde novamente). Cada chamada produz uma mensagemresultno final. - Etapa: um único ciclo de solicitação/resposta dentro de uma chamada
query(). Cada etapa produz mensagens do assistente com uso de tokens. - Sessão: uma série de chamadas
query()vinculadas por um ID de sessão (usando a opçãoresume). Cada chamadaquery()dentro de uma sessão relata seu próprio custo independentemente.
O diagrama a seguir mostra o fluxo de mensagens de uma única chamada query(), com uso de tokens relatado em cada etapa e a estimativa cumulativa no final:
Cada etapa produz mensagens do assistente
Quando Claude responde, ele envia uma ou mais mensagens do assistente. Em TypeScript, cada mensagem do assistente contém uma BetaMessage aninhada (acessada via message.message) com um id e um objeto usage com contagens de tokens (input_tokens, output_tokens). Em Python, a classe de dados AssistantMessage expõe os mesmos dados diretamente via message.usage e message.message_id. Quando Claude usa múltiplas ferramentas em um turno, todas as mensagens nesse turno compartilham o mesmo ID, portanto, deduplicar por ID para evitar contagem dupla.
A mensagem de resultado fornece a estimativa cumulativa
Quando a chamada query() é concluída, o SDK emite uma mensagem de resultado com total_cost_usd e usage cumulativo. Isso está disponível tanto em TypeScript (SDKResultMessage) quanto em Python (ResultMessage). Se você fizer múltiplas chamadas query() (por exemplo, em uma sessão multi-turno), cada resultado reflete apenas o custo dessa chamada individual. Se você só precisar do total estimado, pode ignorar o uso por etapa e ler este único valor.
Obter o custo total de uma query
A mensagem de resultado (TypeScript, Python) marca o final do loop do agente para uma chamada query(). Ela inclui total_cost_usd, o custo estimado cumulativo em todas as etapas dessa chamada. Isso funciona tanto para resultados de sucesso quanto de erro. Se você usar sessões para fazer múltiplas chamadas query(), cada resultado reflete apenas o custo dessa chamada individual.
Os exemplos a seguir iteram sobre o fluxo de mensagens de uma chamada query() e imprimem o custo total quando a mensagem result chega:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "result") {
console.log(`Total cost: $${message.total_cost_usd}`);
}
}
from claude_agent_sdk import query, ResultMessage
import asyncio
async def main():
async for message in query(prompt="Summarize this project"):
if isinstance(message, ResultMessage):
print(f"Total cost: ${message.total_cost_usd or 0}")
asyncio.run(main())
Rastrear uso por etapa e por modelo
Os exemplos nesta seção usam nomes de campos TypeScript. Em Python, os campos equivalentes são AssistantMessage.usage e AssistantMessage.message_id para uso por etapa, e ResultMessage.model_usage para divisões por modelo.
Rastrear uso por etapa
Cada mensagem do assistente contém uma BetaMessage aninhada (acessada via message.message) com um id e um objeto usage com contagens de tokens. Quando Claude usa ferramentas em paralelo, múltiplas mensagens compartilham o mesmo id com dados de uso idênticos. Rastreie quais IDs você já contou e pule duplicatas para evitar totais inflacionados.
Chamadas de ferramentas paralelas produzem múltiplas mensagens do assistente cuja BetaMessage aninhada compartilha o mesmo id e uso idêntico. Sempre deduplicar por ID para obter contagens de tokens por etapa precisas.
O exemplo a seguir acumula tokens de entrada e saída em todas as etapas, contando cada ID de mensagem único apenas uma vez:
import { query } from "@anthropic-ai/claude-agent-sdk";
const seenIds = new Set<string>();
let totalInputTokens = 0;
let totalOutputTokens = 0;
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;
}
}
}
console.log(`Steps: ${seenIds.size}`);
console.log(`Input tokens: ${totalInputTokens}`);
console.log(`Output tokens: ${totalOutputTokens}`);
Dividir o uso por modelo
A mensagem de resultado inclui modelUsage, um mapa de nome de modelo para contagens de tokens por modelo e custo. Isso é útil quando você executa múltiplos modelos (por exemplo, Haiku para subagentos e Opus para o agente principal) e deseja ver para onde os tokens estão indo.
O exemplo a seguir executa uma query e imprime o custo e a divisão de tokens para cada modelo usado:
import { query } from "@anthropic-ai/claude-agent-sdk";
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}`);
}
}
Acumular custos em múltiplas chamadas
Cada chamada query() retorna seu próprio total_cost_usd. O SDK não fornece um total no nível da sessão, portanto, se sua aplicação fizer múltiplas chamadas query() (por exemplo, em uma sessão multi-turno ou entre diferentes usuários), acumule os totais você mesmo.
Os exemplos a seguir executam duas chamadas query() sequencialmente, adicionam o total_cost_usd de cada chamada a um total em execução e imprimem tanto o custo por chamada quanto o custo combinado:
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) {
for await (const message of query({ prompt })) {
if (message.type === "result") {
totalSpend += message.total_cost_usd;
console.log(`This call: $${message.total_cost_usd}`);
}
}
}
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:
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}")
print(f"Total spend: ${total_spend:.4f}")
asyncio.run(main())
Lidar com erros, caching e discrepâncias de tokens
Para rastreamento de custos preciso, leve em conta conversas falhadas, preços de tokens em cache e inconsistências ocasionais de relatórios.
Resolver discrepâncias de tokens de saída
Em casos raros, você pode observar valores diferentes de output_tokens para mensagens com o mesmo ID. Quando isso ocorre:
- Use o valor mais alto: a mensagem final em um grupo normalmente contém o total preciso.
- Prefira a mensagem de resultado: o
total_cost_usdna mensagem de resultado reflete a estimativa acumulada do SDK em todas as etapas, portanto, é mais confiável do que somar valores por etapa você mesmo. Ainda é uma estimativa e pode diferir da sua conta real. - Relate inconsistências: abra problemas no repositório GitHub Claude Code.
Rastrear custos em conversas falhadas
Tanto as mensagens de resultado de sucesso quanto de erro incluem usage e total_cost_usd. Se uma conversa falhar no meio do caminho, você ainda consumiu tokens até o ponto de falha. Sempre leia dados de custo da mensagem de resultado independentemente de seu subtype.
Rastrear tokens em cache
O Agent SDK usa automaticamente prompt caching para reduzir custos em conteúdo repetido. Você não precisa configurar caching você mesmo. O objeto de uso inclui dois campos adicionais para rastreamento de cache:
cache_creation_input_tokens: tokens usados para criar novas entradas de cache (cobrados a uma taxa mais alta do que tokens de entrada padrão).cache_read_input_tokens: tokens lidos de entradas de cache existentes (cobrados a uma taxa reduzida).
Rastreie esses separadamente de input_tokens para entender a economia de caching. Em TypeScript, esses campos são digitados no objeto Usage. Em Python, eles aparecem como chaves no dicionário ResultMessage.usage (por exemplo, message.usage.get("cache_read_input_tokens", 0)).
Estender o TTL do cache de prompt para uma hora
As entradas de cache escritas pelo SDK usam um TTL de 5 minutos por padrão quando você se autentica com uma chave de API ou executa no Amazon Bedrock, Google Cloud Vertex AI ou Microsoft Foundry. Se sua carga de trabalho executa muitas sessões curtas contra o mesmo prompt do sistema e contexto com lacunas maiores que 5 minutos entre elas, o cache expira entre sessões e cada nova sessão paga o preço de entrada completo.
Para solicitar um TTL de 1 hora em escritas de cache, defina a variável de ambiente ENABLE_PROMPT_CACHING_1H. Você pode exportá-la em seu ambiente de shell ou contêiner, ou passá-la através de options.env.
O exemplo a seguir habilita TTL de 1 hora para um agente executando no Bedrock:
options = ClaudeAgentOptions(
env={
"CLAUDE_CODE_USE_BEDROCK": "1",
"ENABLE_PROMPT_CACHING_1H": "1",
},
)
const options = {
env: {
...process.env,
CLAUDE_CODE_USE_BEDROCK: "1",
ENABLE_PROMPT_CACHING_1H: "1",
},
};
Escritas de cache com TTL de 1 hora são cobradas a uma taxa mais alta do que escritas de 5 minutos, portanto, habilitar isso troca custo de escrita mais alto por mais leituras de cache. Consulte preços de prompt caching para detalhes. Os usuários de assinatura Claude já recebem TTL de 1 hora automaticamente e não precisam definir essa variável.
Documentação relacionada
- Referência do SDK TypeScript - Documentação completa da API
- Visão geral do SDK - Começando com o SDK
- Permissões do SDK - Gerenciando permissões de ferramentas