API & SDKAnleitung
AI-Agent-Token-Kosten in Python verfolgen: usage, Budget, Stopp
Protokolliere das usage-Feld jeder Anfrage, summiere es pro Aufgabe und stoppe den Agenten bei einem Dollar-Budget. Funktionierendes Python-Beispiel für eine OpenAI-kompatible API.

Auf dieser Seite
Dein Agent lief zehn Minuten und die Rechnung ist größer als die Aufgabe. Um zu sehen, warum, lies das usage-Objekt in jeder API-Antwort, summiere es pro Aufgabe und multipliziere mit dem Preis des Modells pro 1M Token. Um es zu begrenzen, vergleiche diese laufende Summe nach jedem Schritt mit einem Budget und stoppe die Schleife, wenn es überschritten wird. Unten ist eine kleine Python-Klasse, die genau das tut.
Das Beispiel verwendet den OpenAI-kompatiblen Endpunkt https:/ und die Modell-ID deepseek- (380K Kontext, bis zu 32.768 Ausgabe-Token pro Antwort). Wenn du einen Lauf vor dem Start schätzen möchtest, ist das eine andere Aufgabe, und How to estimate the cost of an AI agent behandelt das. Dieser Artikel handelt vom Messen und Begrenzen während des Laufs.
Wo die Zahlen sind: das usage-Objekt#
Jede nicht-streamende Chat-Completion kommt mit einem usage-Objekt zurück. Die API-Referenz von DeepSeek (geprüft am 26. Oktober 2026) listet diese Felder auf:
prompt_tokens— alles, was du diesmal gesendet hast: System-Prompt, Verlauf, Tool-Ergebnisse.completion_— was das Modell zurückgeschrieben hat.tokens total_tokens— die beiden zusammenaddiert.
DeepSeek dokumentiert auch optionale Extras: prompt_ und prompt_ (sie summieren sich zu prompt_tokens) und completion_ für Thinking-Modelle. Die Seite zeigt kein Veröffentlichungsdatum, und diese Extras sind Erweiterungen des OpenAI-Formats, daher behandelt der Code unten sie als optional und verlässt sich nur auf die ersten beiden Felder.
Warum jeden Schritt protokollieren und nicht nur den letzten? Weil ein Agent seinen wachsenden Kontext jedes Mal erneut sendet. Schritt 1 könnte 2.000 Eingabe-Token senden, Schritt 30 könnte 9.000 senden, und die Rechnung ist die Summe aller. Der Grund wird in why a long chat costs more erklärt, und die Aufteilung Eingabe/Ausgabe in input vs output tokens.
Ein Messgerät, das den Agenten stoppt#
Hier ist das Ganze: ein Messgerät, das Token addiert, eine Zeile pro Schritt ausgibt und einen Fehler auslöst, wenn das Budget überschritten wird, plus eine nackte Agentenschleife darum. Installiere das SDK mit pip install openai und lege deinen Schlüssel in CHEAPTOKENS_ ab.
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
# example prices, USD per 1M tokens: use the current ones from the pricing table
PRICE_IN = 0.10
PRICE_OUT = 0.40
class BudgetExceeded(Exception):
pass
class TaskMeter:
def __init__(self, budget_usd):
self.budget = budget_usd
self.steps = 0
self.tokens_in = 0
self.tokens_out = 0
self.reasoning = 0
@property
def cost(self):
return (self.tokens_in * PRICE_IN + self.tokens_out * PRICE_OUT) / 1_000_000
def add(self, usage):
self.steps += 1
self.tokens_in += usage.prompt_tokens
self.tokens_out += usage.completion_tokens
details = getattr(usage, 'completion_tokens_details', None)
self.reasoning += getattr(details, 'reasoning_tokens', 0) or 0
print(f'step {self.steps}: in={usage.prompt_tokens} '
f'out={usage.completion_tokens} task=${self.cost:.4f}')
if self.cost > self.budget:
raise BudgetExceeded(
f'budget ${self.budget:.2f} crossed at step {self.steps}: '
f'${self.cost:.4f}')
def run_task(goal, budget_usd=0.50, max_steps=40):
meter = TaskMeter(budget_usd)
messages = [
{'role': 'system', 'content': 'Work step by step. Reply DONE when finished.'},
{'role': 'user', 'content': goal},
]
for _ in range(max_steps):
resp = client.chat.completions.create(
model=MODEL, messages=messages, max_tokens=1024)
meter.add(resp.usage) # log first, then decide
reply = resp.choices[0].message.content or ''
messages.append({'role': 'assistant', 'content': reply})
if 'DONE' in reply:
break
messages.append({'role': 'user', 'content': 'Continue.'})
return meter
try:
meter = run_task('Summarise the main risks of a database migration.')
print(f'finished: {meter.steps} steps, ${meter.cost:.4f}')
except BudgetExceeded as err:
print('stopped:', err)Drei Entscheidungen darin sind es wert, kopiert zu werden.
Protokolliere, bevor du entscheidest. meter.add zeichnet zuerst den Schritt auf und prüft erst dann das Budget, sodass ein gestoppter Lauf immer noch eine vollständige Spur hinterlässt. Die Prüfung erfolgt nach dem Aufruf, der die Grenze überschritten hat, sodass du um höchstens einen Schritt überschießen kannst. max_tokens=1024 begrenzt die Ausgabe dieses letzten Schritts.
Zwei harte Stopps, nicht einer. max_steps fängt einen Agenten ab, der schleift, ohne viel auszugeben; das Dollar-Budget fängt einen ab, der viel pro Schritt ausgibt. Du willst beides.
Preise leben an einem Ort. PRICE_IN und PRICE_OUT sind Platzhalterzahlen. Kopiere die aktuellen Werte für dein Modell von der pricing page; derzeit kostet DeepSeek-V4-Flash $0.015 pro 1M Eingabe-Token und $0.10 pro 1M Ausgabe-Token.
Was ein 40-Schritte-Lauf summiert#
Angenommen, dein Agent macht 40 Schritte, und weil der Kontext wächst, sendet ein durchschnittlicher Schritt 6.000 Eingabe-Token und bekommt 400 Token zurück. Das sind 40 × 6.000 = 240.000 Eingabe-Token und 40 × 400 = 16.000 Ausgabe-Token für die Aufgabe.

Auf DeepSeek-V4-Flash kostet das $0.0052. Die Tabelle führt dieselbe Arbeitslast auf den anderen Modellen aus und stellt OpenRouters Referenzpreis neben unseren:
| Modell | Input $/1M | Output $/1M | Kosten | OpenRouter |
|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.0054 | $0.0111 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.0052 | $0.0139 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.0144 | $0.0912 |
240.000 Input- und 16.000 Output-Tokens insgesamt. Die Preise pro 1 Mio. Tokens sind aktuell und ändern sich zusammen mit unseren Tarifen; die OpenRouter-Spalte zeigt Referenzpreise für dieselbe Arbeitslast.
Insgesamt, mit Eingabe und Ausgabe zusammen gezählt, kommt DeepSeek-V4-Flash für diese Aufgabe günstiger heraus als OpenRouter. Beachte auch, wo die Token sind: 240.000 der 256.000 sind Eingabe. Der Kontext, den dein Agent mitschleppt, ist die Rechnung, weshalb die in=-Zahl pro Schritt in deinem Protokoll diejenige ist, die du im Auge behalten solltest. Ein Budget von $0,50 pro Aufgabe im obigen Beispiel ist eine Obergrenze für einen Durchgeher, kein Ziel.
Modelle zu wechseln bedeutet nur, MODEL zu ändern. Wähle die ID aus den CheapTokens docs: Die Namen unterscheiden sich zwischen Anbietern, und eine kurze ID aus einem Preislabel funktioniert nicht in der API. Für lange Agentenschleifen hat DeepSeek-V4-Flash zu jeder Tageszeit einen Preis, sodass eine Aufgabe mittags und um 3 Uhr morgens gleich viel kostet. Siehe die DeepSeek page für seine Limits.
Wenn das Modell denkt#
Wenn eine Antwort in Token viel länger ist als der Text, den du siehst, schau dir reasoning_tokens an. Thinking-Token zählen als Ausgabe, sodass ein reasoning-schwerer Schritt weit mehr Ausgabe-Token produzieren kann, als der sichtbare Text vermuten lässt, und sie werden als Ausgabe abgerechnet. Das Messgerät oben sammelt sie in meter.reasoning, wenn die API das Feld zurückgibt, und lässt es bei 0, wenn nicht, sodass es nie an einem fehlenden Schlüssel abstürzt. Gib es neben out= aus, wenn du sehen willst, wie viel der Ausgabe Thinking war. Reasoning effort and thinking tokens erklärt warum.
Streaming: usage kommt zuletzt#
Wenn dein Agent streamt, gibt es kein usage in den normalen Chunks. Im OpenAI-Format fragst du es mit stream_ an. Die Referenz von DeepSeek (geprüft am 26. Oktober 2026) sagt, dass die Option nur zusammen mit stream=True funktioniert (andernfalls antwortet die API mit 400), dass usage in jedem Chunk außer einem null ist und dass der letzte Chunk vor data: [DONE] die Summen für die gesamte Anfrage trägt. Also rufe in einer Streaming-Schleife meter.add einmal auf, und zwar bei dem Chunk, bei dem usage nicht leer ist. Die nicht-streamende Schleife oben ist der einfachste Einstieg; streaming in Python enthält die Schleife selbst.
Wenn die Zahlen falsch aussehen#
usageist None. Du streamst ohneinclude_usage. Füge es hinzu oder wechsle zu einem nicht-streamenden Aufruf.- Die Summe ist niedriger als der Kontostand-Rückgang. Prüfe, dass jeder Aufruf durch das Messgerät geht: Wiederholungen, ein zusammenfassender Aufruf oder ein Tool-Auswahl-Aufruf außerhalb von
run_taskwerden leicht übersehen. Packeclient.in eine Funktion und leite alles durch sie.chat. completions. create - Die Kosten pro Schritt steigen weiter. Das ist normal für eine Schleife, die alles an
messagesanhängt. Kürze alte Tool-Ausgaben oder fasse den Verlauf zusammen; tool output out of context zeigt die Idee. BudgetExceededfeuert bei Schritt 2. Dein Budget ist kleiner als ein Schritt. Prüfe, dassPRICE_INpro 1M Token ist, nicht pro 1K.
Um die Zahlen zu speichern, schreibe meter.steps, meter.tokens_in, meter.tokens_out und meter.cost als eine JSON-Zeile pro Aufgabe. Eine Woche dieser Zeilen sagt dir die echten Token pro Schritt für deinen Agenten, was die Zahl ist, die du danach in jede Schätzung einsetzen solltest. Modelle, Preise und die erste Anfrage sind in den docs; Tool-Aufrufe werden in function calling in Python behandelt.



