Zum Hauptinhalt springen
Lektion 12 von 20 · Produktion, Evaluierung und Optimierung

Token-Zählung und Budgetierung

Lektion 12 von 20 Aktualisiert am 28. Juli 2026 Fortgeschritten
Auf dieser Seite
  1. Token verstehen
  2. Zählen mit tiktoken
  3. Budgetierung vor dem Aufruf
  4. Kosten vor dem Ausgeben schätzen
  5. Kernaussagen

Token verstehen

Tokens sind die grundlegende Maßeinheit für große Sprachmodelle (LLMs). Jede API-Anzahlung wird in Tokens berechnet, und jedes Modell lehnt Anfragen ab, die sein Kontextfenster überschreiten. Das Beherrschen der Token-Zählung ermöglicht Ihnen drei Dinge, die eine Näherung nicht leisten kann: Sie können Kosten vorhersagen, bevor Sie sie anfallen lassen, Ihre Prompts basierend auf harten Zahlen statt auf Bauchgefühl optimieren und Kontextgrenzen einhalten, ohne erst dann auf einen Überlauf zu stoßen, wenn die API einen Fehler wirft.

Zählen mit tiktoken

Die Bibliothek tiktoken wendet die exakt gleiche Tokenisierung an wie das Modell. Sie instanzen einen Encoder für das Zielmodell und zählen dann die Länge der codierten Sequenz.

import tiktoken

# Encoder für GPT-Modelle
encoder = tiktoken.encoding_for_model("gpt-5.6-terra")

def count_tokens(text: str) -> int:
    """Zählt die Anzahl der Tokens in einem Text."""
    return len(encoder.encode(text))

# Beispiele
print(count_tokens("Hallo"))           # ~1-2 Tokens
print(count_tokens("Hallo Welt"))      # ~3-4 Tokens
print(count_tokens("Entwicklung"))      # ~2-3 Tokens (Akzente kosten mehr)

Das dritte Beispiel verdient einen Moment der Aufmerksamkeit. „Entwicklung” kostet mehr als seine Zeichenlänge vermuten lässt, da akzentuierte Zeichen weniger effizient tokenisiert werden. In der Praxis verbraucht ein französischer Korpus mehr Tokens als ein äquivalenter englischer: Wenn Sie Ihr Budget unter Verwendung englischer Prompts geschätzt und dann in Französisch eingesetzt haben, wird Ihre tatsächliche Rechnung Ihre Prognose überschreiten.

Eine API-Anfrage enthält mehr als nur rohen Text: Jede Nachricht beinhaltet eine Rolle, manchmal einen Namen, und die API fügt strukturelle Tokens hinzu. Die folgende Funktion berücksichtigt diesen Overhead, um eine realistische Gesamtsumme zu liefern.

def count_conversation_tokens(messages: list[dict]) -> int:
    """Zählt Tokens in einem Gespräch (Nachrichten + Overhead)."""
    total = 0
    for message in messages:
        total += 4  # Overhead pro Nachricht (Rolle, etc.)
        total += count_tokens(message["content"])
        if message.get("name"):
            total += count_tokens(message["name"])
    total += 2  # End-Tokens
    return total

conversation = [
    {"role": "system", "content": "Sie sind eine technische Assistentin."},
    {"role": "user", "content": "Erklären Sie Microservices."},
    {"role": "assistant", "content": "Microservices sind eine Architektur..."},
]

print(f"Gesamte Tokens: {count_conversation_tokens(conversation)}")

Bei einem Gespräch mit drei Nachrichten ist der Overhead vernachlässigbar. Bei einer Historie von zweihundert kurzen Nachrichten – typisch für einen Support-Chat – summieren sich diese zu fast tausend Tokens, die Sie nicht berücksichtigt haben.

Budgetierung vor dem Aufruf

Das Kontextfenster ist kein Eingangs-Budget: Es ist ein geteiltes Budget zwischen dem, was Sie senden, und dem, was das Modell generiert. Wenn Sie das Fenster mit Ihrem Prompt bis zum Rand füllen, wird die Antwort abgeschnitten. Die Struktur BudgetTokens macht diese Zuweisung explizit, indem sie einen Teil für die Ausgabe vorab reserviert.

from dataclasses import dataclass

@dataclass
class BudgetTokens:
    """Verwaltet das Token-Budget für einen Aufruf."""
    context_limit: int       # Modellfenster
    system_tokens: int = 0   # System-Prompt
    history_tokens: int = 0  # Gesprächshistorie
    user_tokens: int = 0     # Aktuelle Nachricht
    output_reserve: int = 2000 # Für die Antwort reserviert

    @property
    def available_tokens(self) -> int:
        used = (
            self.system_tokens
            + self.history_tokens
            + self.user_tokens
        )
        return self.context_limit - used - self.output_reserve

    @property
    def is_over(self) -> bool:
        return self.available_tokens < 0

    def report(self) -> str:
        return (
            f"Kontext: {self.context_limit} | "
            f"System: {self.system_tokens} | "
            f"Historie: {self.history_tokens} | "
            f"Nutzer: {self.user_tokens} | "
            f"Output-Reserve: {self.output_reserve} | "
            f"Verfügbar: {self.available_tokens}"
        )

# Beispiel mit einem Kontextfenster von 128K Tokens
budget = BudgetTokens(
    context_limit=128_000,
    system_tokens=count_tokens(system_prompt),
    history_tokens=count_conversation_tokens(history),
    user_tokens=count_tokens(user_message),
)

if budget.is_over:
    print("Budget überschritten — Komprimierung erforderlich")

Die Methode report unterstützt mehr als nur das Debugging. Protokollieren Sie sie an einer Stichprobe von Produktionsanfragen, und Sie werden sofort sehen, welcher Komponente Ihren Kontext verbraucht. In den meisten Anwendungen kommt die Überraschung von der Historie, selten vom System-Prompt, den alle überwachen.

Als Nächstes müssen Sie handeln, wenn das Budget überschritten ist. Die Funktion prepare_context wendet die einfachste und robusteste Regel an: Behalten Sie die neuesten Nachrichten und werfen Sie die ältesten weg, sobald das Budget erschöpft ist. Die Iteration läuft rückwärts ab, um am Kopf einzufügen und die chronologische Reihenfolge wiederherzustellen.

def prepare_context(
    system_prompt: str,
    history: list[dict],
    message: str,
    model_limit: int = 128_000,
    output_reserve: int = 4_000,
) -> list[dict]:
    """Vorbereitet den Kontext unter Einhaltung des Token-Budgets."""

    system_tokens = count_tokens(system_prompt)
    message_tokens = count_tokens(message)
    history_budget = (
        model_limit - system_tokens - message_tokens - output_reserve
    )

    # Behalten Sie die neuesten Nachrichten innerhalb des Budgets
    kept_messages = []
    used_tokens = 0

    for msg in reversed(history):
        msg_tokens = count_tokens(msg["content"]) + 4
        if used_tokens + msg_tokens > history_budget:
            break
        kept_messages.insert(0, msg)
        used_tokens += msg_tokens

    return (
        [{"role": "system", "content": system_prompt}]
        + kept_messages
        + [{"role": "user", "content": message}]
    )

Dieser Abbruch ist brutal: Alles, was außerhalb des Budgets liegt, geht verloren. Wenn älterer Kontext wirklich wichtig ist – z. B. eine Kundendatei, die über mehrere Wochen verfolgt wurde – ersetzen Sie die reine Löschung durch die Komprimierungsstrategie, die in der vorherigen Lektion behandelt wurde.

Kosten vor dem Ausgeben schätzen

Die teuersten Abrechnungsfehler entstehen durch Batch-Verarbeitung: Sie führen einen Durchlauf auf 10.000 Dokumenten durch und entdecken den Betrag erst am nächsten Tag. Eine Schätzung zuerst, in wenigen Millisekunden lokaler Berechnung, vermeidet dieses Szenario.

def estimate_cost(
    input_tokens: int,
    estimated_output_tokens: int,
    model: str = "gpt-5.6-terra",
) -> dict:
    """Schätzt die Kosten eines Aufrufs, bevor dieser ausgeführt wird."""
    # Raten pro Million Tokens (Juli 2026 — offizielles Preisgitter prüfen)
    rates = {
        "gpt-5.6-luna": {"input": 0.20, "output": 1.20},
        "gpt-5.6-terra": {"input": 2.00, "output": 12.00},
        "gpt-5.6-sol": {"input": 5.00, "output": 30.00},
    }

    rate = rates.get(model, rates["gpt-5.6-terra"])
    input_cost = (input_tokens / 1_000_000) * rate["input"]
    output_cost = (estimated_output_tokens / 1_000_000) * rate["output"]

    return {
        "model": model,
        "input_tokens": input_tokens,
        "estimated_output_tokens": estimated_output_tokens,
        "input_cost": f"${input_cost:.6f}",
        "output_cost": f"${output_cost:.6f}",
        "total_cost": f"${input_cost + output_cost:.6f}",
    }

# Bevor ein großer Prompt gesendet wird
schätzung = estimate_cost(
    input_tokens=50_000,
    estimated_output_tokens=2_000,
    model="gpt-5.6-sol",
)
print(schätzung)

Die Tarif-Tabelle ist in diesem Beispiel hartcodiert, mit dem Datum in einem Kommentar. Behandeln Sie sie als Konfigurationsdaten, die regelmäßig gegen das offizielle Preisgitter zu überprüfen sind: Eine Schätzung, die auf veralteten Preisen basiert, ist gefährlicher als keine Schätzung überhaupt, weil sie falsches Vertrauen weckt.

Schließlich kennen Sie die Grenzen jedes Modells, um Ihr Budget zu planen. Kontextfenster variieren von Modell zu Modell innerhalb der GPT-5.6-Familie – konsultieren Sie die offizielle Seite OpenAI Models für aktuelle Werte und konfigurieren Sie context_limit aus Ihren Einstellungen statt es im aufrufenden Code hart zu codieren.

Kernaussagen

  • Verwenden Sie tiktoken, um Tokens vor jedem Aufruf zu zählen, einschließlich des Overheads pro Nachricht.
  • Französisch verbraucht mehr Tokens als Englisch für denselben Inhalt: Passen Sie Ihre Schätzungen an.
  • Reservieren Sie immer ein Budget für Output-Tokens innerhalb des Kontextfensters.
  • Verwalten Sie den Kontext automatisch, indem Sie die ältesten Nachrichten löschen.
  • Schätzen Sie Kosten, bevor Sie teure Anfragen senden, unter Verwendung verifizierter Raten.