SDK-Kostenverfolgung

Das Claude Code SDK bietet detaillierte Token-Nutzungsinformationen für jede Interaktion mit Claude. Dieser Leitfaden erklärt, wie Sie Kosten ordnungsgemäß verfolgen und die Nutzungsberichterstattung verstehen, insbesondere beim Umgang mit parallelen Tool-Verwendungen und mehrstufigen Gesprächen. Für die vollständige API-Dokumentation siehe die TypeScript SDK-Referenz.

Token-Nutzung verstehen

Wenn Claude Anfragen verarbeitet, meldet es die Token-Nutzung auf Nachrichtenebene. Diese Nutzungsdaten sind wesentlich für die Kostenverfolgung und die angemessene Abrechnung von Benutzern.

Schlüsselkonzepte

  1. Schritte: Ein Schritt ist ein einzelnes Anfrage/Antwort-Paar zwischen Ihrer Anwendung und Claude
  2. Nachrichten: Einzelne Nachrichten innerhalb eines Schritts (Text, Tool-Verwendungen, Tool-Ergebnisse)
  3. Nutzung: Token-Verbrauchsdaten, die an Assistenten-Nachrichten angehängt sind

Struktur der Nutzungsberichterstattung

Einzelne vs. parallele Tool-Verwendung

Wenn Claude Tools ausführt, unterscheidet sich die Nutzungsberichterstattung je nachdem, ob Tools sequenziell oder parallel ausgeführt werden:
import { query } from "@anthropic-ai/claude-code";

// Beispiel: Nutzung in einem Gespräch verfolgen
const result = await query({
  prompt: "Analysiere diese Codebasis und führe Tests aus",
  options: {
    onMessage: (message) => {
      if (message.type === 'assistant' && message.usage) {
        console.log(`Nachrichten-ID: ${message.id}`);
        console.log(`Nutzung:`, message.usage);
      }
    }
  }
});

Beispiel für Nachrichtenfluss

So werden Nachrichten und Nutzung in einem typischen mehrstufigen Gespräch gemeldet:
<!-- Schritt 1: Erste Anfrage mit parallelen Tool-Verwendungen -->
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)

<!-- Schritt 2: Nachfolgende Antwort -->
assistant (text)      { id: "msg_2", usage: { output_tokens: 98, ... } }

Wichtige Nutzungsregeln

1. Gleiche ID = Gleiche Nutzung

Alle Nachrichten mit demselben id-Feld melden identische Nutzung. Wenn Claude mehrere Nachrichten im selben Zug sendet (z.B. Text + Tool-Verwendungen), teilen sie dieselbe Nachrichten-ID und Nutzungsdaten.
// Alle diese Nachrichten haben dieselbe ID und Nutzung
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 } }
];

// Nur einmal pro eindeutiger Nachrichten-ID berechnen
const uniqueUsage = messages[0].usage; // Gleich für alle Nachrichten mit dieser ID

2. Einmal pro Schritt berechnen

Sie sollten Benutzer nur einmal pro Schritt berechnen, nicht für jede einzelne Nachricht. Wenn Sie mehrere Assistenten-Nachrichten mit derselben ID sehen, verwenden Sie die Nutzung von einer beliebigen davon.

3. Ergebnisnachricht enthält kumulative Nutzung

Die finale result-Nachricht enthält die gesamte kumulative Nutzung aller Schritte im Gespräch:
// Finales Ergebnis enthält Gesamtnutzung
const result = await query({
  prompt: "Mehrstufige Aufgabe",
  options: { /* ... */ }
});

console.log("Gesamtnutzung:", result.usage);
console.log("Gesamtkosten:", result.usage.total_cost_usd);

Implementierung: Kostenverfolgungssystem

Hier ist ein vollständiges Beispiel für die Implementierung eines Kostenverfolgungssystems:
import { query } from "@anthropic-ai/claude-code";

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) {
    // Nur Assistenten-Nachrichten mit Nutzung verarbeiten
    if (message.type !== 'assistant' || !message.usage) {
      return;
    }
    
    // Überspringen, wenn wir diese Nachrichten-ID bereits verarbeitet haben
    if (this.processedMessageIds.has(message.id)) {
      return;
    }
    
    // Als verarbeitet markieren und Nutzung aufzeichnen
    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 {
    // Implementieren Sie hier Ihre Preisberechnung
    // Dies ist ein vereinfachtes Beispiel
    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;
  }
}

// Verwendung
const tracker = new CostTracker();
const { result, stepUsages, totalCost } = await tracker.trackConversation(
  "Analysiere und refaktoriere diesen Code"
);

console.log(`Verarbeitete Schritte: ${stepUsages.length}`);
console.log(`Gesamtkosten: $${totalCost.toFixed(4)}`);

Umgang mit Grenzfällen

Diskrepanzen bei Output-Token

In seltenen Fällen könnten Sie unterschiedliche output_tokens-Werte für Nachrichten mit derselben ID beobachten. Wenn dies auftritt:
  1. Verwenden Sie den höchsten Wert - Die letzte Nachricht in einer Gruppe enthält typischerweise die genaue Gesamtsumme
  2. Überprüfen Sie gegen Gesamtkosten - Die total_cost_usd in der Ergebnisnachricht ist maßgebend
  3. Melden Sie Inkonsistenzen - Reichen Sie Probleme im Claude Code GitHub-Repository ein

Cache-Token-Verfolgung

Bei Verwendung von Prompt-Caching verfolgen Sie diese Token-Typen separat:
interface CacheUsage {
  cache_creation_input_tokens: number;
  cache_read_input_tokens: number;
  cache_creation: {
    ephemeral_5m_input_tokens: number;
    ephemeral_1h_input_tokens: number;
  };
}

Best Practices

  1. Verwenden Sie Nachrichten-IDs für Deduplizierung: Verfolgen Sie immer verarbeitete Nachrichten-IDs, um Doppelberechnungen zu vermeiden
  2. Überwachen Sie die Ergebnisnachricht: Das finale Ergebnis enthält maßgebende kumulative Nutzung
  3. Implementieren Sie Protokollierung: Protokollieren Sie alle Nutzungsdaten für Auditing und Debugging
  4. Behandeln Sie Fehler elegant: Verfolgen Sie partielle Nutzung auch wenn ein Gespräch fehlschlägt
  5. Berücksichtigen Sie Streaming: Für Streaming-Antworten akkumulieren Sie Nutzung während Nachrichten eintreffen

Referenz für Nutzungsfelder

Jedes Nutzungsobjekt enthält:
  • input_tokens: Verarbeitete Basis-Input-Token
  • output_tokens: In der Antwort generierte Token
  • cache_creation_input_tokens: Token, die zur Erstellung von Cache-Einträgen verwendet wurden
  • cache_read_input_tokens: Aus dem Cache gelesene Token
  • service_tier: Die verwendete Service-Stufe (z.B. “standard”)
  • total_cost_usd: Gesamtkosten in USD (nur in Ergebnisnachricht)

Beispiel: Aufbau eines Abrechnungs-Dashboards

So aggregieren Sie Nutzungsdaten für ein Abrechnungs-Dashboard:
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);
    
    // Benutzersummen aktualisieren
    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
    };
  }
}

Verwandte Dokumentation