Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Claude Agent SDK 为每次与 Claude 的交互提供详细的 token 用量信息。本指南说明如何正确跟踪成本和理解用量报告,特别是在处理并行工具使用和多步骤对话时。
有关完整的 API 文档,请参阅 TypeScript SDK 参考。
当 Claude 处理请求时,它会在消息级别报告 token 用量。这些用量数据对于跟踪成本和适当地向用户计费至关重要。
当 Claude 执行工具时,用量报告会根据工具是顺序执行还是并行执行而有所不同:
import { query } from "@anthropic-ai/claude-agent-sdk";
// 示例:在对话中跟踪用量
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);
}
}
}
});以下是在典型多步骤对话中消息和用量的报告方式:
<!-- 步骤 1:包含并行工具使用的初始请求 -->
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)
<!-- 步骤 2:后续响应 -->
assistant (text) { id: "msg_2", usage: { output_tokens: 98, ... } }所有具有相同 id 字段的消息报告相同的用量。当 Claude 在同一轮中发送多条消息(例如,文本 + 工具使用)时,它们共享相同的消息 ID 和用量数据。
// 所有这些消息具有相同的 ID 和用量
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 } }
];
// 每个唯一消息 ID 只收费一次
const uniqueUsage = messages[0].usage; // 具有此 ID 的所有消息相同您应该每步只向用户收费一次,而不是为每条单独的消息收费。当您看到多条具有相同 ID 的助手消息时,使用其中任何一条的用量即可。
最终的 result 消息包含对话中所有步骤的总累计用量:
// 最终结果包含总用量
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 提供按模型的明细
type ModelUsage = {
inputTokens: number
outputTokens: number
cacheReadInputTokens: number
cacheCreationInputTokens: number
webSearchRequests: number
costUSD: number
contextWindow: number
}
// 从结果消息中访问
const result = await query({ prompt: "..." });
// result.modelUsage 是模型名称到 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 参考。
以下是实现成本跟踪系统的完整示例:
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) {
// 仅处理带有用量的助手消息
if (message.type !== 'assistant' || !message.usage) {
return;
}
// 如果已处理此消息 ID 则跳过
if (this.processedMessageIds.has(message.id)) {
return;
}
// 标记为已处理并记录用量
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 {
// 在此实现您的定价计算
// 这是一个简化示例
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;
}
}
// 使用方式
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)}`);在极少数情况下,您可能会观察到具有相同 ID 的消息具有不同的 output_tokens 值。当这种情况发生时:
total_cost_usd 是权威的使用提示缓存时,请分别跟踪这些 token 类型:
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:处理的基础输入 token 数output_tokens:响应中生成的 token 数cache_creation_input_tokens:用于创建缓存条目的 token 数cache_read_input_tokens:从缓存读取的 token 数service_tier:使用的服务层级(例如,"standard")total_cost_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);
// 更新用户总计
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
};
}
}Was this page helpful?