Was this page helpful?
El Claude Agent SDK proporciona información detallada sobre el uso de tokens para cada interacción con Claude. Esta guía explica cómo realizar un seguimiento adecuado de los costos y comprender los informes de uso, especialmente cuando se trata de usos de herramientas paralelas y conversaciones de múltiples pasos.
Para la documentación completa de la API, consulta la referencia del SDK de TypeScript.
Cuando Claude procesa solicitudes, informa sobre el uso de tokens a nivel de mensaje. Estos datos de uso son esenciales para realizar un seguimiento de los costos y facturar a los usuarios de manera apropiada.
Cuando Claude ejecuta herramientas, los informes de uso difieren según si las herramientas se ejecutan secuencialmente o en paralelo:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Ejemplo: Seguimiento de uso en una conversación
const result = await query({
prompt: "Analyze this codebase and run tests",
options: {
onMessage: (message) => {
if (message.type === 'assistant' && message.usage) {
console.log(`Message ID: ${message.id}`);
console.log(`Usage:`, message.usage);
}
}
}
});Así es como se informan los mensajes y el uso en una conversación típica de múltiples pasos:
<!-- Paso 1: Solicitud inicial con usos de herramientas paralelas -->
assistant (text) { id: "msg_1", usage: { output_tokens: 100, ... } }
assistant (tool_use) { id: "msg_1", usage: { output_tokens: 100, ... } }
assistant (tool_use) { id: "msg_1", usage: { output_tokens: 100, ... } }
assistant (tool_use) { id: "msg_1", usage: { output_tokens: 100, ... } }
user (tool_result)
user (tool_result)
user (tool_result)
<!-- Paso 2: Respuesta de seguimiento -->
assistant (text) { id: "msg_2", usage: { output_tokens: 98, ... } }Todos los mensajes con el mismo campo id reportan uso idéntico. Cuando Claude envía múltiples mensajes en el mismo turno (por ejemplo, texto + usos de herramientas), comparten el mismo ID de mensaje y datos de uso.
// Todos estos mensajes tienen el mismo ID y uso
const messages = [
{ type: 'assistant', id: 'msg_123', usage: { output_tokens: 100 } },
{ type: 'assistant', id: 'msg_123', usage: { output_tokens: 100 } },
{ type: 'assistant', id: 'msg_123', usage: { output_tokens: 100 } }
];
// Cobra solo una vez por ID de mensaje único
const uniqueUsage = messages[0].usage; // Igual para todos los mensajes con este IDSolo debes cobrar a los usuarios una vez por paso, no por cada mensaje individual. Cuando veas múltiples mensajes del asistente con el mismo ID, usa el uso de cualquiera de ellos.
El mensaje final result contiene el uso acumulativo total de todos los pasos en la conversación:
// El resultado final incluye el uso total
const result = await query({
prompt: "Multi-step task",
options: { /* ... */ }
});
console.log("Total usage:", result.usage);
console.log("Total cost:", result.usage.total_cost_usd);El mensaje de resultado también incluye modelUsage, que proporciona datos de uso por modelo autorizados. Como total_cost_usd, este campo es preciso y adecuado para propósitos de facturación. Esto es especialmente útil cuando se usan múltiples modelos (por ejemplo, Haiku para suagentes, Opus para el agente principal).
// modelUsage proporciona desglose por modelo
type ModelUsage = {
inputTokens: number
outputTokens: number
cacheReadInputTokens: number
cacheCreationInputTokens: number
webSearchRequests: number
costUSD: number
contextWindow: number
}
// Acceso desde el mensaje de resultado
const result = await query({ prompt: "..." });
// result.modelUsage es un mapa de nombre de modelo a ModelUsage
for (const [modelName, usage] of Object.entries(result.modelUsage)) {
console.log(`${modelName}: $${usage.costUSD.toFixed(4)}`);
console.log(` Input tokens: ${usage.inputTokens}`);
console.log(` Output tokens: ${usage.outputTokens}`);
}Para las definiciones de tipo completas, consulta la referencia del SDK de TypeScript.
Aquí hay un ejemplo completo de implementación de un sistema de seguimiento de costos:
En casos raros, podrías observar diferentes valores de output_tokens para mensajes con el mismo ID. Cuando esto ocurra:
total_cost_usd en el mensaje de resultado es autoritarioCuando uses almacenamiento en caché de solicitudes, realiza un seguimiento de estos tipos de tokens por separado:
interface CacheUsage {
cache_creation_input_tokens: number;
cache_read_input_tokens: number;
cache_creation: {
ephemeral_5m_input_tokens: number;
ephemeral_1h_input_tokens: number;
};
}Cada objeto de uso contiene:
input_tokens: Tokens de entrada base procesadosoutput_tokens: Tokens generados en la respuestacache_creation_input_tokens: Tokens utilizados para crear entradas de cachécache_read_input_tokens: Tokens leídos del cachéservice_tier: El nivel de servicio utilizado (por ejemplo, "standard")total_cost_usd: Costo total en USD (solo en mensaje de resultado)Aquí se muestra cómo agregar datos de uso para un panel de facturación:
class BillingAggregator {
private userUsage = new Map<string, {
totalTokens: number;
totalCost: number;
conversations: number;
}>();
async processUserRequest(userId: string, prompt: string) {
const tracker = new CostTracker();
const { result, stepUsages, totalCost } = await tracker.trackConversation(prompt);
// Actualiza totales del usuario
const current = this.userUsage.get(userId) || {
totalTokens: 0,
totalCost: 0,
conversations: 0
};
const totalTokens = stepUsages.reduce((sum, step) =>
sum + step.usage.input_tokens + step.usage.output_tokens, 0
);
this.userUsage.set(userId, {
totalTokens: current.totalTokens + totalTokens,
totalCost: current.totalCost + totalCost,
conversations: current.conversations + 1
});
return result;
}
getUserBilling(userId: string) {
return this.userUsage.get(userId) || {
totalTokens: 0,
totalCost: 0,
conversations: 0
};
}
}import { query } from "@anthropic-ai/claude-agent-sdk";
class CostTracker {
private processedMessageIds = new Set<string>();
private stepUsages: Array<any> = [];
async trackConversation(prompt: string) {
const result = await query({
prompt,
options: {
onMessage: (message) => {
this.processMessage(message);
}
}
});
return {
result,
stepUsages: this.stepUsages,
totalCost: result.usage?.total_cost_usd || 0
};
}
private processMessage(message: any) {
// Solo procesa mensajes del asistente con uso
if (message.type !== 'assistant' || !message.usage) {
return;
}
// Omite si ya hemos procesado este ID de mensaje
if (this.processedMessageIds.has(message.id)) {
return;
}
// Marca como procesado y registra el uso
this.processedMessageIds.add(message.id);
this.stepUsages.push({
messageId: message.id,
timestamp: new Date().toISOString(),
usage: message.usage,
costUSD: this.calculateCost(message.usage)
});
}
private calculateCost(usage: any): number {
// Implementa tu cálculo de precios aquí
// Este es un ejemplo simplificado
const inputCost = usage.input_tokens * 0.00003;
const outputCost = usage.output_tokens * 0.00015;
const cacheReadCost = (usage.cache_read_input_tokens || 0) * 0.0000075;
return inputCost + outputCost + cacheReadCost;
}
}
// Uso
const tracker = new CostTracker();
const { result, stepUsages, totalCost } = await tracker.trackConversation(
"Analyze and refactor this code"
);
console.log(`Steps processed: ${stepUsages.length}`);
console.log(`Total cost: $${totalCost.toFixed(4)}`);