Was this page helpful?
Claude Agent SDK는 Claude와의 각 상호작용에 대한 상세한 토큰 사용량 정보를 제공합니다. 이 가이드에서는 비용을 올바르게 추적하고 사용량 보고를 이해하는 방법을 설명하며, 특히 병렬 도구 사용 및 다단계 대화를 다룰 때 유용합니다.
전체 API 문서는 TypeScript SDK 레퍼런스를 참조하세요.
Claude가 요청을 처리할 때, 메시지 수준에서 토큰 사용량을 보고합니다. 이 사용량 데이터는 비용을 추적하고 사용자에게 적절하게 청구하는 데 필수적입니다.
Claude가 도구를 실행할 때, 도구가 순차적으로 실행되는지 병렬로 실행되는지에 따라 사용량 보고가 달라집니다:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Example: Tracking usage in a conversation
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);
}
}
}
});다음은 일반적인 다단계 대화에서 메시지와 사용량이 보고되는 방식입니다:
<!-- Step 1: Initial request with parallel tool uses -->
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)
<!-- Step 2: Follow-up response -->
assistant (text) { id: "msg_2", usage: { output_tokens: 98, ... } }동일한 id 필드를 가진 모든 메시지는 동일한 사용량을 보고합니다. Claude가 같은 턴에서 여러 메시지를 보낼 때(예: 텍스트 + 도구 사용), 동일한 메시지 ID와 사용량 데이터를 공유합니다.
// All these messages have the same ID and usage
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 } }
];
// Charge only once per unique message ID
const uniqueUsage = messages[0].usage; // Same for all messages with this ID사용자에게는 단계당 한 번만 청구해야 합니다, 개별 메시지마다 청구하면 안 됩니다. 동일한 ID를 가진 여러 어시스턴트 메시지가 보이면, 그 중 하나의 사용량을 사용하세요.
최종 result 메시지에는 대화의 모든 단계에서 발생한 총 누적 사용량이 포함됩니다:
// Final result includes total usage
const result = await query({
prompt: "Multi-step task",
options: { /* ... */ }
});
console.log("Total usage:", result.usage);
console.log("Total cost:", result.usage.total_cost_usd);결과 메시지에는 모델별 사용량 데이터를 제공하는 modelUsage도 포함됩니다. total_cost_usd와 마찬가지로, 이 필드는 정확하며 청구 목적에 적합합니다. 이는 여러 모델을 사용할 때(예: 서브에이전트에 Haiku, 메인 에이전트에 Opus) 특히 유용합니다.
// modelUsage provides per-model breakdown
type ModelUsage = {
inputTokens: number
outputTokens: number
cacheReadInputTokens: number
cacheCreationInputTokens: number
webSearchRequests: number
costUSD: number
contextWindow: number
}
// Access from result message
const result = await query({ prompt: "..." });
// result.modelUsage is a map of model name to 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}`);
}전체 타입 정의는 TypeScript SDK 레퍼런스를 참조하세요.
다음은 비용 추적 시스템을 구현하는 완전한 예시입니다:
드문 경우, 동일한 ID를 가진 메시지에서 서로 다른 output_tokens 값을 관찰할 수 있습니다. 이 경우:
total_cost_usd가 권위 있는 값입니다프롬프트 캐싱을 사용할 때, 다음 토큰 유형을 별도로 추적하세요:
interface CacheUsage {
cache_creation_input_tokens: number;
cache_read_input_tokens: number;
cache_creation: {
ephemeral_5m_input_tokens: number;
ephemeral_1h_input_tokens: number;
};
}각 사용량 객체에는 다음이 포함됩니다:
input_tokens: 처리된 기본 입력 토큰output_tokens: 응답에서 생성된 토큰cache_creation_input_tokens: 캐시 항목 생성에 사용된 토큰cache_read_input_tokens: 캐시에서 읽은 토큰service_tier: 사용된 서비스 티어 (예: "standard")total_cost_usd: USD 기준 총 비용 (결과 메시지에만 포함)다음은 청구 대시보드를 위해 사용량 데이터를 집계하는 방법입니다:
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);
// Update user totals
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) {
// Only process assistant messages with usage
if (message.type !== 'assistant' || !message.usage) {
return;
}
// Skip if we've already processed this message ID
if (this.processedMessageIds.has(message.id)) {
return;
}
// Mark as processed and record usage
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 {
// Implement your pricing calculation here
// This is a simplified example
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;
}
}
// Usage
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)}`);