Claude Code agent_summary: Tokenverbrauch messen und senken

Miss die Modellanfragen hinter den Fortschrittsanzeigen der Hintergrundagenten in Claude Code. Vergleiche die geschätzten 16.4% eines Teams mit den vom Team von Claude Code gemeldeten 2% insgesamt und 6% im Terminal. Ermittle deinen Anteil mit einem lokalen OpenTelemetry-Empfänger und prüfe die Cache-Korrektur in 2.1.311+, die Agentensteuerung und Community-Patches.

Inhalt
Claude Code agent_summary: Tokenverbrauch messen und senken

Aktualisiere Claude Code auf 2.1.311 oder neuer und miss agent_summary mit OpenTelemetry, bevor du Agentenfunktionen deaktivierst. Diese Anfragen für Fortschrittszusammenfassungen können zusätzliche Kosten verursachen, während Hintergrundagenten arbeiten. Die häufig genannte Zahl 16.4% ist der geschätzte Kostenanteil eines Teams, kein allgemeiner Aufschlag auf den Tokenverbrauch.

Was agent_summary macht

agent_summary erstellt Fortschrittstexte durch separate Modellanfragen. Im Bericht zu Claude Code 2.1.312 beschreibt dblumenau diesen Ablauf. Jede Anfrage schickte den Gesprächsverlauf eines arbeitenden Hintergrundagenten an dessen eigenes Modell. Das Modell sollte einen Text mit drei bis fünf Wörtern liefern. Das Beispiel verwendete Haiku; der Mechanismus ist also nicht auf Opus beschränkt.

Arbeitende Hintergrundagenten können solche Anfragen ungefähr alle 30 Sekunden auslösen. Bei unverändertem Gesprächsverlauf können einzelne Aufrufe entfallen, wie das offizielle Änderungsprotokoll dokumentiert. Zähle deshalb tatsächliche Anfragen, statt die verstrichenen Minuten mit zwei zu multiplizieren.

Die Länge des Kontexts kann daher mehr ausmachen als die Länge des angezeigten Textes. Prüfe bei der Kostenanalyse das gemeldete Modell und die Cache-Nutzung.

Die konfigurierbare Statuszeile deines Terminals funktioniert anders. Die Dokumentation zur eigenen Statuszeile beschreibt ein lokales Skript, das keine API-Tokens verbraucht. Wenn du dieses Skript entfernst, bleiben die separaten Modellanfragen für Zusammenfassungen davon unberührt.

Was 16.4%, 2% und 6% tatsächlich messen

Die drei Kostenanteile beziehen sich auf unterschiedliche Gruppen. Stand 2026-11-01 liegen diese Berichte vor:

BerichtGruppe und ZeitraumGemeldeter Kostenanteil der ZusammenfassungenBerechnungsgrundlage
Flamerix AIEine gemessene Woche eines Teams16.4%Claude Codes Schätzungen in cost_usd je Anfrage
edwinarbus vom Team von Claude CodeNutzer, die Telemetrie senden; Woche vor der Antwort vom 29. OktoberEtwa 2%Kosten zu API-Listenpreisen
Dieselbe Teamantwort, Teilgruppe TerminalTerminalnutzung innerhalb dieser TelemetriestichprobeEtwa 6%Kosten zu API-Listenpreisen

Flamerix berichtete außerdem, dass Zusammenfassungen 19.7% der API-Anfragen ausmachten. Anfrageanteil und Kostenanteil haben unterschiedliche Bezugsgrößen. Keiner der beiden Werte zeigt, welchen Anteil deines Abonnementkontingents die Zusammenfassungen verbrauchen.

Nutze diese Berichte als Anlass, deinen eigenen Einsatz zu messen. Ein Team, das viele lange Aufgaben delegiert, kann deutlich andere Werte erreichen als jemand, der überwiegend im Hauptdialog arbeitet.

Zuerst aktualisieren, ohne feste Einsparungen anzunehmen

Version 2.1.311+ behebt laut der Antwort des Teams von Claude Code teure Zusammenfassungsanfragen, bei denen der Prompt-Cache nicht greift. Die Korrektur entfernt die Zusammenfassungsanfragen nicht. Eine bestimmte Ersparnis für deine Sitzungen lässt sich daraus nicht ableiten.

Bei einer nativen Installation führe diese Befehle in Bash aus:

claude --version
claude update
claude --version

Starte Claude Code danach neu. Verwaltet ein Paketmanager die Installation, nutze dessen Aktualisierungsbefehl aus der offiziellen Installationsanleitung. Prüfe anschließend die installierte Version. Der Update-Kanal oder Organisationsrichtlinien können die verfügbare Version begrenzen.

Dieselbe Teamantwort beschreibt die Arbeit an einem günstigeren Modus mit kurzen Notizen und einem kleineren Modell. Ein Veröffentlichungstermin wird nicht genannt. Stand 2026-11-01 ist keine öffentliche Einstellung dokumentiert, mit der sich dieser Modus aktivieren lässt. Plane diese Einsparung noch nicht in dein Budget ein.

Deine Sitzung mit OpenTelemetry messen

Sammle die Log-Ereignisse claude_code.api_request und gruppiere sie nach query_source. Die Monitoring-Referenz beschreibt dieses Attribut, das gemeldete model und die geschätzten Kosten in cost_usd.

Wenn deine Organisation diese Ereignisse bereits sammelt, nutze ihr Monitoring-System. Filtere eine Sitzung oder einen festgelegten Zeitraum. Zähle die Ereignisse zu API-Anfragen und summiere cost_usd je Quelle. Für Modellvergleiche gruppiere zusätzlich nach model.

Für das lokale Beispiel brauchst du Bash, Python 3 und Claude Code mit bereits eingerichteter Authentifizierung. Verwende einen Rechner, auf dem du das Telemetrieziel selbst festlegen kannst. Der Empfänger hält aggregierte Werte im Arbeitsspeicher und gibt Metadaten aus. Dafür musst du keine vollständigen Prompts oder Antworten aufzeichnen.

Lokalen Empfänger starten

Führe den folgenden Block im ersten Terminal aus. Der Empfänger nimmt OTLP HTTP JSON über die lokale Loopback-Schnittstelle entgegen und zeigt fortlaufend die Gesamtsummen je Quelle:

python3 -u - <<'PY'
import gzip, json, math
from collections import defaultdict
from http.server import BaseHTTPRequestHandler, HTTPServer

rows = defaultdict(lambda: [0, 0.0, 0])
models = defaultdict(set)
seen = set()

def scalar(value):
    return next((value[k] for k in ("stringValue", "doubleValue", "intValue", "boolValue")
                 if k in value), None)

def report():
    count = sum(row[0] for row in rows.values())
    cost = sum(row[1] for row in rows.values())
    missing = sum(row[2] for row in rows.values())
    print("\nquery_source\trequests\trequest_%\tknown_USD\tcost_%\tmissing_cost\tmodels")
    for source, (n, usd, absent) in sorted(rows.items()):
        share = f"{100 * usd / cost:.2f}" if cost > 0 and not missing else "n/a"
        names = ",".join(sorted(models[source]))
        print(f"{source}\t{n}\t{100 * n / count:.2f}\t{usd:.6f}\t{share}\t{absent}\t{names}")
    print(f"Total API records: {count}; missing costs: {missing}", flush=True)

class Receiver(BaseHTTPRequestHandler):
    def log_message(self, *args):
        pass

    def do_POST(self):
        if self.path != "/v1/logs":
            self.send_error(404)
            return
        raw = self.rfile.read(int(self.headers.get("Content-Length", "0")))
        try:
            if self.headers.get("Content-Encoding") == "gzip":
                raw = gzip.decompress(raw)
            data = json.loads(raw)
        except (ValueError, OSError):
            self.send_error(400)
            return
        for resource in data.get("resourceLogs", []):
            for scope in resource.get("scopeLogs", []):
                for record in scope.get("logRecords", []):
                    a = {item["key"]: scalar(item["value"])
                         for item in record.get("attributes", [])}
                    event = a.get("event.name") or scalar(record.get("body", {}))
                    if event in ("user_prompt", "claude_code.user_prompt"):
                        print("Received user_prompt event.", flush=True)
                    if event not in ("api_request", "claude_code.api_request"):
                        continue
                    identity = a.get("request_id") or json.dumps(record, sort_keys=True)
                    if identity in seen:
                        continue
                    seen.add(identity)
                    source = str(a.get("query_source") or "(missing)")
                    models[source].add(str(a.get("model") or "(missing)"))
                    row = rows[source]
                    row[0] += 1
                    try:
                        usd = (float(a["cost_usd"]) if a.get("cost_usd") is not None
                               else float(a["cost_usd_micros"]) / 1_000_000)
                        if not math.isfinite(usd) or usd < 0:
                            raise ValueError()
                        row[1] += usd
                    except (KeyError, ValueError, TypeError):
                        row[2] += 1
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(b"{}")
        report()

server = HTTPServer(("127.0.0.1", 4318), Receiver)
print("Listening on 127.0.0.1:4318. Stop after Claude exits with Ctrl+C.", flush=True)
try:
    server.serve_forever()
except KeyboardInterrupt:
    pass
finally:
    server.server_close()
    report()
PY

Sitzung für die Messung starten

Führe diesen Block im zweiten Terminal aus. Die Subshell begrenzt die Änderungen der Umgebungsvariablen auf diesen Start von Claude Code:

(
  export CLAUDE_CODE_ENABLE_TELEMETRY=1
  export OTEL_LOGS_EXPORTER=otlp
  export OTEL_METRICS_EXPORTER=none
  export OTEL_TRACES_EXPORTER=none
  export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/json
  export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://127.0.0.1:4318/v1/logs
  export OTEL_LOGS_EXPORT_INTERVAL=1000
  claude
)

Nutze eine normale Aufgabe, für die Hintergrundarbeit sinnvoll ist. Bitte etwa einen Hintergrundagenten, Authentifizierungstests zu prüfen, ohne Dateien zu ändern. Arbeite im Hauptdialog weiter und vergewissere dich, dass der Hintergrundagent tatsächlich startet.

Bleibe in einer interaktiven Sitzung und leite Claudes Ausgabe nicht durch eine Pipe. claude -p ändert den Ausführungsmodus und kann damit auch das Verhalten der Zusammenfassungen ändern.

Im ersten Terminal sollte nach deinem Prompt zuerst Received user_prompt event. erscheinen. Danach sollten Zeilen für API-Anfragen folgen. Lass die Aufgabe abschließen und beende Claude regulär. Warte auf den letzten Telemetrieexport, bevor du den Empfänger mit Ctrl+C stoppst. Kopiere die abschließende Tabelle aus dem Ausgabeverlauf des Terminals.

Ergebnisse auswerten und fehlende Daten prüfen

Lies die Zeile agent_summary für deinen Messzeitraum. Der Nenner von request_% ist die Zahl aller erfassten Ereignisse zu API-Anfragen. Für cost_% ist es die Summe der geschätzten Kosten aller erfassten API-Anfragen:

summary cost share = 100 × summary estimated USD / all captured estimated USD

Die Spalte models listet die gemeldeten Modelle je Quelle auf. Wenn du den Cache in einem bestehenden Monitoring-System untersuchst, prüfe auch input_tokens, cache_read_tokens, cache_creation_tokens und output_tokens.

Anfragen ohne Quellenangabe bleiben als (missing) im Nenner enthalten. Fehlt bei einer erfassten Anfrage ein gültiger Kostenwert, zeigt der Empfänger für Kostenanteile n/a. Kläre fehlende Felder, bevor du die Aufschlüsselung als vollständig behandelst.

Fehlt die Zeile agent_summary, wurden in diesem Zeitfenster keine solchen Anfragen beobachtet. Das belegt nicht, dass die Funktion deaktiviert ist. Prüfe zuerst, ob Prompt-Ereignisse, Ereignisse zu API-Anfragen und tatsächliche Hintergrundarbeit vorhanden waren.

Wenn nichts ankommt, prüfe den laufenden Empfänger, http/json als Protokoll und einen Endpunkt mit /v1/logs am Ende. Ein von deiner Organisation verwaltetes Ziel kann lokale Einstellungen übersteuern. Starte für weitere Diagnosen claude --debug-file ./otel-debug.log in derselben Subshell. Suche anhand der Monitoring-Anleitung nach Exporterfehlern mit dem Präfix [3P telemetry].

Warum Gesprächsverlauf, /usage und Rechnung abweichen können

Eine fehlende Zeile im Gesprächsverlauf kann die Zuordnung zu einer Quelle verbergen, obwohl die Gesamtsumme der Sitzung stimmt. In Issue #104358 berichtet rabitlord1324 von fehlenden Einträgen für Hintergrundanfragen, bezeichnet den internen Kostenabgleich von Claude Code aber als korrekt.

Die aktuelle Dokumentation zu /usage erklärt Sitzungssummen und den Verbrauch nach Modell. Die hier nötige Aufschlüsselung nach query_source beschreibt sie nicht. Wenn ein Parser Zusammenfassungen im Gesprächsverlauf übersieht, belegt das also nicht, dass sie auch in /usage fehlen.

cost_usd bleibt eine Schätzung. Claude Code rechnet normalerweise mit Listenpreisen. Eine verwaltete modelPricing-Tabelle kann jedoch andere Preise für die Berichte festlegen. Verbrauchtes Abonnementkontingent und API-Gebühren sind unterschiedliche Größen. Gleiche bei nutzungsabhängiger Abrechnung die Ergebnisse mit den tatsächlichen Nutzungsdaten deines Anbieters ab.

Wenn du BetterToken nutzt, lautet die dokumentierte Basis-URL für Claude Code https://bettertoken.ai. Der Katalog führt claude-opus-5-5 mit Stand 2026-11-01. Gleiche deinen Messzeitraum mit Modell, Tokenverbrauch und Gebühren in der Konsole ab.

Kosten senken und nützliche Arbeit erhalten

Wenn die gemessenen Zusatzkosten ins Gewicht fallen, beginne mit enger gefassten Aufgaben oder weniger Hintergrundagenten. Stand 2026-11-01 dokumentieren weder die Referenz zu Umgebungsvariablen noch die Subagentenreferenz einen Schalter, der nur Zusammenfassungen deaktiviert.

OptionWas sich ändertAbwägung
Weniger oder kürzere HintergrundaufgabenVerringert die Gelegenheiten für wiederholte Zusammenfassungen des GesprächsverlaufsKann nützliche Parallelität kosten; vergleiche die Ausführungszeit
Ein kleineres Modell für einen Subagenten mit klar begrenzter AufgabeÄndert das Modell, das die delegierte Arbeit ausführtPrüfe die Ergebnisqualität und das tatsächlich in der Telemetrie gemeldete Modell
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 claudeDeaktiviert die Hintergrundausführung über die betroffenen Werkzeuge weitgehendClaude setzt die Arbeit erst fort, wenn die Subagenten fertig sind
CLAUDE_CODE_FORK_SUBAGENT=0 claudeVerhindert, dass Claude selbstständig Gesprächsverzweigungen startetHintergrundsubagenten bleiben möglich; ausbleibende Zusammenfassungen sind nicht garantiert
Community-Patch über Bun preloadVersucht, den Timer für Zusammenfassungen abzufangenFührt fremden Code in Claude Code aus und kann nach einem Update nicht mehr funktionieren

Die Variable für Hintergrundaufgaben entfernt den Parameter run_in_background und verhindert die automatische Hintergrundausführung über die betroffenen Werkzeuge. Für MCP-Aufgaben, das Werkzeug Monitor und separate Hintergrundsitzungen gelten Ausnahmen oder eigene Einstellungen. Die Variable schaltet nicht jede Hintergrundaktivität ab.

Die Steuerung des Fork-Modus, also der Gesprächsverzweigungen, ist dokumentiert. Dass dadurch auch Zusammenfassungen ausbleiben, ist jedoch nicht garantiert. Unter 2.1.312 berichtete chrisvaillancourt von ausbleibenden Zusammenfassungen auf macOS. dblumenau beobachtete auf Linux weiterhin solche Anfragen. Die Berichte unterscheiden sich bei Konfiguration und Ausführungsmodus.

Setze die Variable vor dem Start einer neuen Sitzung. Prüfe widersprüchliche env-Einträge in ~/.claude/settings.json und den Projekteinstellungen. Sie können Werte ersetzen, die aus der Shell übernommen wurden.

Betrachte den Flamerix-Preload-Patch als experimentelle Community-Lösung. Prüfe zunächst den Code einer festgelegten Revision. Kontrolliere nach jedem Clientupdate die Zahl der Anfragen. Ein eingefrorener Fortschrittstext allein zeigt nicht, dass keine Anfragen mehr gesendet werden.

Nutze für klar begrenzte Rechercheaufgaben die Anleitung zur Modellprüfung bei Subagenten mit rein lesendem Zugriff. Vergrößern umfangreiche Werkzeugdefinitionen den Kontext, prüfe mit dem Kostenvergleich für MCP-Kontext den Nutzen eines kleineren Werkzeugumfangs.

Ändere jeweils nur eine Variable. Vergleiche dieselbe Aufgabe, dasselbe Modell, die Kontextbedingungen, das akzeptierte Ergebnis und die Laufzeit zusammen mit den Kosten je Quelle. Aktiviere die Hintergrundarbeit wieder, wenn der Verlust sinnvoller Parallelität mehr kostet als die gemessene Einsparung.

Bereit, Ihren LLM-Workflow zu optimieren?

Verbinden Sie Modelle über eine API, verwalten Sie Schlüssel und behalten Sie KI-Kosten im Blick.

Kostenlos starten