Zurück zum Blog

Erste SchritteAnleitung

Erster Request an CheapTokens in Python mit requests, ohne SDK

Ein 20-zeiliges Python-Skript nur mit requests: eine Chat-Completion, ein Timeout, HTTP-Fehlerbehandlung und die ausgegebene Antwort, finish_reason und Nutzung.

Von CheapTokens TeamVeröffentlicht am 4 Min. Lesezeit

Python-Skript, das den Chat-Completions-Endpunkt von CheapTokens mit requests aufruft
Auf dieser Seite
  1. Das ganze Skript
  2. Was jede Zeile tut
  3. Die Antwort lesen
  4. Wenn es nicht funktioniert
  5. Was ein Aufruf kostet
  6. Wie es weitergeht

Du brauchst das Paket openai nicht, um mit einer OpenAI-kompatiblen API zu sprechen. Ein requests.post-Aufruf, ein Bearer-Key und ein JSON-Body reichen aus, und du siehst genau, was über die Leitung geht. Diese Anleitung baut dieses Skript für CheapTokens (https://api.cheaptokens.dev/v1/chat/completions) und endet damit, dass es die Antwort, finish_reason und die Token-Nutzung ausgibt.

Es passt gut, wenn du auf einer abgeschotteten Maschine arbeitest, auf der nur requests installiert ist, wenn ein kleiner Cron-Job kein SDK mitziehen soll oder wenn du einfach verstehen willst, was das SDK für dich tut. Die Anleitung zum ersten Request behandelt SDK, curl und Node; hier geht es um reines Python.

Das ganze Skript#

Lege deinen Key zuerst in einer Umgebungsvariable ab (siehe wie man einen API-Key sicher speichert) und speichere dann dies als ask.py:

python
import os
import requests

url = "https://api.cheaptokens.dev/v1/chat/completions"
headers = {"Authorization": f"Bearer {os.environ['CHEAPTOKENS_API_KEY']}"}
payload = {
    "model": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "messages": [
        {"role": "user", "content": "Explain what a token is in two sentences."}
    ],
    "max_tokens": 200,
}

try:
    r = requests.post(url, headers=headers, json=payload, timeout=30)
    r.raise_for_status()
except requests.exceptions.Timeout:
    raise SystemExit("No reply within 30 seconds - try again or raise the timeout")
except requests.exceptions.HTTPError as e:
    raise SystemExit(f"HTTP {e.response.status_code}: {e.response.text}")

data = r.json()
choice = data["choices"][0]
print(choice["message"]["content"])
print("finish_reason:", choice["finish_reason"])
print("usage:", data["usage"])

Führe python ask.py aus. Die Modell-ID ist die vollständige Gateway-ID, deepseek-ai/DeepSeek-V4-Flash-0731; wenn du unsicher bist, was dort hingehört, liste die Modelle mit GET /v1/models. Um ein anderes Modell auszuprobieren, tausche zai-org/GLM-5.3-Flash ein und ändere sonst nichts: ein Guthaben deckt alle Modelle ab.

Der Weg eines Requests: Key, POST, raise_for_status, choices, usage
Ein Request von deinem Skript bis zur ausgegebenen Antwort

Was jede Zeile tut#

Hier sind die fünf Ideen, auf denen das Skript aufbaut. Der requests Quickstart (lebende Doku, geprüft am 2. November 2026) erklärt die meisten davon, und die Chat-Completions-Referenz von OpenAI definiert die Felder in der Antwort.

Lernkarten

Fünf Dinge im Skript

Der dritte Punkt ist der, den die Leute überspringen. Ein Skript, das in einem Cron-Job ewig hängt, ist viel schlimmer als eines, das nach 30 Sekunden laut scheitert.

Die Antwort lesen#

Eine erfolgreiche Antwort ist JSON. Die Teile, die dich interessieren, laut Chat-Completions-Referenz:

  • choices[0].message.content ist der Text. Er kann null sein, also rufe nicht blind String-Methoden darauf auf.
  • choices[0].finish_reason sagt, warum das Modell gestoppt hat: stop (es ist fertig), length (das Limit max_tokens hat es abgeschnitten), tool_calls, content_filter.
  • usage.prompt_tokens, usage.completion_tokens und usage.total_tokens sind das, wofür du bezahlst: Input, Output und deren Summe.

Die Antwort hat diese Form (die Zahlen sind Platzhalter):

json
{
  "choices": [
    {
      "message": {"role": "assistant", "content": "A token is a small piece of text..."},
      "finish_reason": "stop"
    }
  ],
  "usage": {"prompt_tokens": 18, "completion_tokens": 52, "total_tokens": 70}
}
Probier es selbstProbier es aus: setze max_tokens auf 5 und führe das Skript erneut aus. Was sagt finish_reason?Antwort anzeigen

Es sagt length: das Modell wurde durch dein Limit max_tokens gestoppt, die Antwort endet also mitten im Satz. Erhöhe das Limit und du bekommst wieder stop. Die ganze Geschichte steht in KI-Antwort abgeschnitten? finish_reason "length" beheben.

Wenn es nicht funktioniert#

Das Skript verwandelt die meisten Fehler in eine Zeile Ausgabe. Hier ist, was jede davon meist bedeutet:

Paare zuordnen

Ordne jede Meldung ihrer üblichen Ursache zu

  • HTTP 401Der Key fehlt, ist falsch geschrieben oder nicht der, den du senden wolltest
  • HTTP 404Der URL-Pfad oder die Modell-ID ist falsch
  • requests.exceptions.TimeoutInnerhalb des Timeouts sind keine Bytes angekommen
  • KeyError: 'CHEAPTOKENS_API_KEY'Die Umgebungsvariable ist in diesem Terminal nicht gesetzt

Für die tatsächlichen Fehler-Bodys und eine schrittweise Prüfung von Key, Basis-URL und Modell-ID nutze API 401- oder 404-Fehler: falscher Key, falsche Basis-URL oder Modell-ID. Zwei kleinere Stolperfallen: wenn du KeyError: 'choices' siehst, hast du einen Fehler-Body als Erfolg geparst, was bedeutet, dass raise_for_status() übersprungen wurde. Und wenn deine Maschine eine ~/.netrc-Datei hat, kann requests deren Credentials statt des von dir gesetzten Authorization-Headers verwenden.

Was ein Aufruf kostet#

Mit den Platzhalterzahlen aus der Antwort oben (etwa 18 Tokens rein, 52 raus) kostet ein Aufruf von DeepSeek-V4-Flash $0.0000055. Das ist eine Zahl, die man nicht spürt, also rechne es hoch. Sagen wir, dein Skript fasst 1.000 Support-Tickets pro Tag zusammen, jeweils etwa 800 Tokens rein und 300 raus:

Modell Pro Anfrage 1.000 Anfragen OpenRouter, 1.000 Anfragen
GLM-5.3-Flash $0.000028 $0.028 $0.0517
DeepSeek-V4-Flash $0.000042 $0.042 $0.098
MiniMax-M2.7 $0.000085 $0.085 $1.02

800 Input- und 300 Output-Tokens pro Anfrage. Die Preise pro 1 Mio. Tokens sind aktuell und ändern sich zusammen mit unseren Tarifen; die OpenRouter-Spalte zeigt Referenzpreise für dieselbe Arbeitslast.

Die Preise sind pro Modell fest, ohne Stoßzeiten, also kostet dasselbe Skript um 3 Uhr nachts dasselbe wie mittags. Die aktuellen Preise pro Modell stehen auf der Preisseite, und die Doku listet die Endpunkte auf.

Wie es weitergeht#

Sobald das funktioniert, sind die üblichen nächsten Schritte eine Schleife über viele Eingaben, ein Retry bei 429 (siehe 429 Too Many Requests: Retries mit Backoff) oder derselbe Aufruf mit Streaming. Wenn du HTTP lieber nicht selbst verwalten möchtest, ist der SDK-Weg nur eine base_url-Änderung entfernt.