Wählen Sie Auto, TokenLab Verified oder Official für jede Anfrage, wobei die Preise vorab angezeigt werden.Neuigkeiten ansehen

Einen KI-Chatbot mit einem API-Key erstellen: Von Null zur Produktion in 30 Minuten

·19. September 2026·16 Min. Lesezeit·Aktualisiert 2. Oktober 2026·2792 Aufrufe
#Chatbot#Tutorial#Python#FastAPI#Streaming
Einen KI-Chatbot mit einem API-Key erstellen: Von Null zur Produktion in 30 Minuten

Sie können einen KI-Chatbot erstellen, der eine Antwort streamt, und das an einem Nachmittag. Die eigentliche Arbeit besteht darin, ihn nach dem ersten 429-Fehler am Laufen zu halten. Wir bauen einen kleinen FastAPI-Service mit SSE-Streaming, serverseitigem Konversationsgedächtnis und einer Modell-Allowlist – alles hinter einem einzigen TokenLab-Key. Das Ziel ist ein Backend, das Sie hinter einer echten Produktoberfläche platzieren können und bei dem Sie Modelle austauschen können, ohne die Integration neu schreiben zu müssen. Falls Sie den Austausch der Base-URL noch nicht durchgeführt haben, lesen Sie zuerst den Migrationsleitfaden. Wenn Ihr Hauptanliegen das Backoff unter Last ist, kombinieren Sie diesen Leitfaden mit dem Leitfaden zum Rate Limiting der AI API.

Wichtige Erkenntnisse

  • Ein produktionsreifer Chatbot benötigt sechs Komponenten: einen synchronen Endpunkt, einen Streaming-Endpunkt, serverseitigen Konversationsstatus, eine Modell-Allowlist, echte Fehlerbehandlung und einen Pfad für Speicher-Upgrades.
  • Laden Sie den Key aus TOKENLAB_API_KEY in jedem Prozess und bewahren Sie ihn auf dem Server auf. Die Authentifizierungs-Dokumentation (eingesehen am 03.10.2026) besagt, dass Keys niemals im clientseitigen Code offengelegt oder committet werden dürfen.
  • GET /v1/models ist öffentlich, daher beweist eine erfolgreiche Antwort nicht, dass Ihr Key funktioniert. Beweisen Sie es mit einer echten Chat-Anfrage (Quickstart, eingesehen am 03.10.2026).
  • SSE deckt die meisten Chat-Produkte ab. Behandeln Sie einen Stream, der nach der Ausgabe abbricht, als unvollständig und nicht als fertige Antwort.
  • Die Allowlist in diesem Leitfaden ordnet Tiers den Modellen deepseek-v4-flash, gpt-5.5, claude-sonnet-5 und gemini-3.5-flash zu. Jedes listet openai_chat_completions als akzeptiertes Format (eingesehen am 03.10.2026).
  • Basierend auf den unten stehenden Preisen kostet ein Turn mit 2.000 Eingabe- und 500 Ausgabetokens etwa 0,0006 $ bis 0,0075 $, je nach Modell.

KI-Chatbot erstellen: Setup und der Core-Service

Der fertige Service besteht aus sechs beweglichen Teilen:

  1. Ein synchroner /chat-Endpunkt für Smoke-Tests.
  2. Ein Streaming-/chat/stream-Endpunkt für die echte UI.
  3. Konversationsstatus, referenziert durch conversation_id.
  4. Eine Modell-Allowlist, damit das Frontend keine beliebigen IDs anfordern kann.
  5. Fehlerbehandlung, die nicht beim ersten 429-Fehler zusammenbricht.
  6. Ein Pfad vom In-Memory-Prototyp zu Redis oder PostgreSQL.

Das reicht für einen Support-Bot, einen internen Assistenten oder die erste Version eines eingebetteten Chat-Widgets. Jeder Codeblock unten wird an eine Datei, main.py, in der gezeigten Reihenfolge angehängt.

Schritt 1: Key festlegen und den Stack installieren

Erstellen Sie einen Key unter API Keys in Ihrem Workspace. Der vollständige Wert wird nur einmal angezeigt, und das Präfix in der Key-Liste kann keine Anfragen authentifizieren. Alle TokenLab-Keys beginnen mit sk-. Überprüfen Sie auch Ihr Guthaben unter Billing, da die erste Anfrage zum aktuellen Preis des Modells abgerechnet wird (Quickstart, eingesehen am 03.10.2026).

Speichern Sie den Key in einer Umgebungsvariablen, niemals im Quellcode. Der folgende Befehl hält ihn aus der Kommandozeile und dem Shell-Verlauf fern und gilt nur für das aktuelle Terminal und dessen Kindprozesse. Verwenden Sie für bereitgestellte Apps einen Secret Manager. Der Quickstart enthält auch eine PowerShell-Version.

printf 'TokenLab API key: '
read -r -s TOKENLAB_API_KEY
printf '\n'
export TOKENLAB_API_KEY
pip install fastapi uvicorn openai pydantic

Sie benötigen kein TokenLab-spezifisches SDK. Das offizielle OpenAI-SDK funktioniert, sobald Sie den Key und die Base-URL ändern (SDKs-Leitfaden, eingesehen am 03.10.2026).

Schritt 2: Schema, Allowlist und Memory definieren

Wir beginnen mit den gemeinsamen Teilen. Das Request-Schema verwendet tier anstelle eines rohen model-Strings, und jedes curl-Beispiel später in diesem Leitfaden sendet dieselben Felder.

Die erste Chatbot-Demo behält das Transkript normalerweise im Browser und sendet es bei jedem Turn erneut. Das funktioniert für einen Prototyp. Es wird jedoch unübersichtlich, sobald Sie Wiederholungsversuche (Retries), fortsetzbare Sitzungen oder serverseitige Tools benötigen. Daher besitzt der Server von Anfang an die Historie.

import json
import logging
import os
import time
import uuid
from collections import defaultdict

from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from openai import APIConnectionError, APIStatusError, OpenAI, RateLimitError
from pydantic import BaseModel, Field

log = logging.getLogger("chatbot")
app = FastAPI()

client = OpenAI(
    api_key=os.environ["TOKENLAB_API_KEY"],
    base_url="https://api.tokenlab.sh/v1",
    timeout=30.0,
    max_retries=0,
)

ALLOWED_MODELS = {
    "default": "deepseek-v4-flash",
    "flagship": "gpt-5.5",
    "balanced": "claude-sonnet-5",
    "budget": "gemini-3.5-flash",
}
SYSTEM_PROMPT = "You are a helpful assistant. Be concise and direct."
MAX_HISTORY = 20          # messages kept per conversation (your choice)
MAX_REPLY_TOKENS = 1000   # output cap per turn (your choice)

class ChatRequest(BaseModel):
    message: str = Field(min_length=1, max_length=4000)
    tier: str = "default"
    conversation_id: str | None = None

def resolve_model(tier: str) -> str:
    model = ALLOWED_MODELS.get(tier)
    if model is None:
        raise HTTPException(status_code=400, detail=f"unknown tier: {tier}")
    return model

conversations: dict[str, list[dict]] = defaultdict(list)

def build_messages(conv_id: str, user_msg: str) -> list[dict]:
    history = conversations[conv_id][-MAX_HISTORY:]
    return [
        {"role": "system", "content": SYSTEM_PROMPT},
        *history,
        {"role": "user", "content": user_msg},
    ]

def remember(conv_id: str, user_msg: str, reply: str) -> None:
    conversations[conv_id].append({"role": "user", "content": user_msg})
    conversations[conv_id].append({"role": "assistant", "content": reply})

Der Client setzt max_retries=0 und ein 30-Sekunden-Timeout, passend zum Quickstart. Wir entscheiden selbst über Wiederholungen, da ein blindes SDK-Retry bei einem gestreamten Turn eine Gebühr wiederholen könnte.

Schritt 3: Fehler zuordnen und den synchronen Endpunkt hinzufügen

Wir behalten eine kleine Funktion bei, die jede SDK-Ausnahme in einen Statuscode und eine benutzerfreundliche Nachricht umwandelt. Die Details gehen in Ihre Logs, nicht an den Benutzer.

def describe_error(exc: Exception) -> tuple[int, str]:
    if isinstance(exc, RateLimitError):  # check first: it subclasses APIStatusError
        return 429, "The assistant is busy. Please retry shortly."
    if isinstance(exc, APIConnectionError):
        return 502, "Connection problem. Please retry."
    if isinstance(exc, APIStatusError):
        log.error("upstream status=%s code=%s", exc.status_code, exc.code)
        if exc.status_code in (401, 402, 403):  # key, balance, or permission: operator problem
            return 503, "The assistant is unavailable right now."
        if exc.status_code in (400, 404):  # bad field or model ID: our bug
            return 500, "Something went wrong on our side."
        return 502, "The assistant is unavailable right now."
    return 500, "Something went wrong."

def retry_delay(exc: RateLimitError) -> float:
    try:
        return min(float(exc.response.headers.get("retry-after", "2")), 10.0)
    except ValueError:
        return 2.0

def create_with_one_retry(**kwargs):
    try:
        return client.chat.completions.create(**kwargs)
    except RateLimitError as exc:
        time.sleep(retry_delay(exc))
        return client.chat.completions.create(**kwargs)

@app.post("/chat")
def chat(req: ChatRequest):
    model = resolve_model(req.tier)
    conv_id = req.conversation_id or str(uuid.uuid4())
    messages = build_messages(conv_id, req.message)
    try:
        response = create_with_one_retry(
            model=model, messages=messages, max_tokens=MAX_REPLY_TOKENS
        )
    except (APIConnectionError, APIStatusError) as exc:
        status, message = describe_error(exc)
        raise HTTPException(status_code=status, detail=message)
    reply = response.choices[0].message.content or ""
    log.info("model=%s usage=%s", model, response.usage)
    remember(conv_id, req.message, reply)
    return {"conversation_id": conv_id, "reply": reply}

Führen Sie eine Anfrage aus, bevor Sie etwas anderes bauen. Wenn dies fehlschlägt, bauen Sie nicht darauf auf.

Antworten streamen und den KI-Chatbot reaktionsfähig halten

Die meisten Chatbot-Produkte fühlen sich langsam an, nicht weil das Modell langsam ist, sondern weil die UI leer bleibt, bis die vollständige Antwort eintrifft. Wir fügen SSE hinzu, da es die meisten Chat-Produkte abdeckt und weniger operativen Aufwand als WebSockets erfordert. Wenn Ihr Produkt bereits einen Browser-Client über einfaches HTTP betreibt, hält SSE die Architektur einfacher.

Schritt 4: Den Streaming-Endpunkt hinzufügen

Die Streaming-Dokumentation (Streaming-Leitfaden, eingesehen am 03.10.2026) hält Chat Completions-Streaming für Frameworks gültig, die bereits SSE-Chunks von /v1/chat/completions erwarten. Wir bleiben auf diesem Pfad, da alle vier Modelle auf der Allowlist dies akzeptieren. Wir kodieren jedes Ereignis als JSON, damit Zeilenumbrüche innerhalb einer Antwort das Framing nicht unterbrechen können.

def sse(payload: dict) -> str:
    return f"data: {json.dumps(payload)}\n\n"

@app.post("/chat/stream")
def chat_stream(req: ChatRequest):
    model = resolve_model(req.tier)
    conv_id = req.conversation_id or str(uuid.uuid4())
    messages = build_messages(conv_id, req.message)

    def generate():
        parts: list[str] = []
        finish_reason = None
        try:
            with client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=MAX_REPLY_TOKENS,
                stream=True,
                stream_options={"include_usage": True},
            ) as stream:
                for chunk in stream:
                    if chunk.usage:
                        log.info("model=%s usage=%s", model, chunk.usage)
                    if not chunk.choices:
                        continue
                    choice = chunk.choices[0]
                    if choice.delta.content:
                        parts.append(choice.delta.content)
                        yield sse({"delta": choice.delta.content})
                    if choice.finish_reason:
                        finish_reason = choice.finish_reason
        except (APIConnectionError, APIStatusError) as exc:
            _, message = describe_error(exc)
            yield sse({"error": message})
            return
        if finish_reason != "stop":
            yield sse({"error": f"Reply incomplete ({finish_reason})."})
            return
        remember(conv_id, req.message, "".join(parts))
        yield sse({"done": True, "conversation_id": conv_id})

    return StreamingResponse(generate(), media_type="text/event-stream")

Zwei Details sind hier wichtig. Erstens fügt include_usage: true die Token-Nutzung zu den Stream-Chunks hinzu, und der letzte Nutzungs-Chunk hat keine choices, daher überspringt die Schleife ihn. Zweitens speichern wir den Turn nur, wenn der finish_reason gleich stop ist. Ein length-Finish bedeutet, dass das Token-Limit die Antwort abgeschnitten hat, und die Dokumentation listet beides als normale Endbedingungen.

Da Fehler innerhalb des Generators auftreten, ist der HTTP-Status bereits 200, wenn ein Fehler auftritt. Der Client muss das error-Ereignis lesen. Der with-Block schließt den Upstream-Stream, wenn der Generator beendet wird. Die Dokumentation empfiehlt, den Upstream abzubrechen, wenn der Benutzer stoppt oder die Verbindung trennt. Testen Sie also, ob Ihr ASGI-Server den Generator bei einer Trennung tatsächlich stoppt.

Schritt 5: Den Stream im Browser lesen

Der Browser sollte Ihr eigenes authentifiziertes Backend aufrufen und niemals direkt TokenLab. Parsen Sie nach Ereignisgrenzen, da ein Netzwerk-Chunk nicht unbedingt ein vollständiges SSE-Ereignis ist.

async function sendMessage(payload, onDelta) {
  const response = await fetch('/chat/stream', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload), // { message, tier, conversation_id }
  });
  if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const events = buffer.split('\n\n');
    buffer = events.pop();
    for (const raw of events) {
      if (!raw.startsWith('data: ')) continue;
      const event = JSON.parse(raw.slice(6));
      if (event.error) throw new Error(event.error);
      if (event.delta) onDelta(event.delta);
    }
  }
}

Speicher auf Redis upgraden, wenn Sie es benötigen

Das In-Memory-Dictionary reicht für einen Prozess. Greifen Sie zu Redis, wenn Konversationen ein TTL, Wiederaufnehmbarkeit oder mehrere Instanzen benötigen. Greifen Sie zu PostgreSQL, wenn das Transkript Produktdaten ist, die Sie abfragen, prüfen oder darüber berichten müssen. Die Redis-Änderung ist Speicher-Plumbing, keine Logik. Führen Sie pip install redis aus und lassen Sie build_messages und remember über diese Helfer lesen und schreiben.

import redis

redis_client = redis.Redis(
    host=os.environ.get("REDIS_HOST", "127.0.0.1"), port=6379, decode_responses=True
)

def load_history(conv_id: str) -> list:
    raw = redis_client.get(f"chat:{conv_id}")
    return json.loads(raw) if raw else []

def save_history(conv_id: str, history: list) -> None:
    redis_client.setex(f"chat:{conv_id}", 60 * 60 * 24, json.dumps(history))

Fehler behandeln, wenn Sie einen KI-Chatbot für die Produktion bauen

Einem kundenorientierten Benutzer ist es egal, ob ein Fehler durch Rate Limiting, ein leeres Guthaben oder einen Upstream-Ausfall verursacht wurde. Sie interessieren sich dafür, ob die UI einfriert. Stellen Sie sich ein Support-Widget vor, dessen Stream nach vierzig Wörtern abbricht. Die TokenLab-Dokumentation besagt, dass ein Stream, der nach der Ausgabe unterbrochen wurde, keine vollständige Antwort ist und eine Wiederholung zu einer anderen Ausgabe und einer zweiten Gebühr führen kann (API-Fehler behandeln, eingesehen am 03.10.2026). Deshalb speichert Schritt 4 niemals einen unvollständigen Turn.

Schritt 6: Die Retry-Regeln anwenden

Behandeln Sie Fehler nach HTTP-Status und code, nicht nach der für Menschen lesbaren message, die sich ohne Vorankündigung ändern kann. Die Tabelle kombiniert die Dokumentation mit dem, was unser Service tut.

Status Bedeutung (laut Doku) Was dieser Service tut
400 Feld, Modell-ID oder Eingabe ist ungültig 500 zurückgeben, loggen, niemals wiederholen
401 Key fehlt, ungültig, abgelaufen oder widerrufen 503 zurückgeben, Operator alarmieren
402 Guthaben oder API-Key-Limit zu niedrig (insufficient_balance, quota_exceeded) 503 zurückgeben, Operator alarmieren
403 Key kann dieses Modell nicht verwenden 503 zurückgeben, Modellliste des Keys prüfen
404 Ressource oder Modell nicht gefunden 500 zurückgeben, ID gegen /v1/models prüfen
429 Anfragelimit erreicht Auf Retry-After warten, einmal wiederholen (nur synchron)
500–504 Service nicht verfügbar oder Netzwerkfehler Nur wiederholen, wenn retryable true ist; retry_after beachten

Zwei Warnungen aus der Dokumentation. Ein 503 all_channels_failed bedeutet nicht immer einen vorübergehenden Ausfall. Wenn retryable false ist, wiederholen Sie dieselbe Anfrage nicht und prüfen Sie GET /v1/models, bevor Sie ein anderes Modell wählen. Außerdem verwenden Chat Completions und Responses ein OpenAI-artiges error-Objekt, aber Anthropic Messages und Gemini behalten ihre eigenen Formate bei. Unser Service ruft Chat Completions auf jedem Modell der Allowlist auf, daher funktioniert ein Parser. Wenn Sie ein Tier auf ein natives Format umstellen, benötigen Sie einen zweiten Parser.

Speichern Sie die Request-ID aus den Antwort-Headern zusammen mit dem Endpunkt, dem Modell, der Zeit und Ihrer eigenen Benutzer- oder Job-ID. Die Dokumentation nennt den Header auf den von uns verwendeten Seiten nicht, also bestätigen Sie ihn anhand des Troubleshooting-Pfads, bevor Sie Ihre Logs verdrahten.

Der Rest der Produktions-Checkliste ist kurz:

  • Fügen Sie Ihre eigenen Request-IDs hinzu, damit Sie Frontend-Fehler mit Backend-Logs verbinden können.
  • Begrenzen Sie die Nebenläufigkeit pro Benutzer und die Anfragegröße. Das max_length=4000 bei message ist ein Ausgangspunkt, den Sie anpassen sollten.
  • Begrenzen Sie die Historie nach Nachrichtenanzahl, wie es MAX_HISTORY tut. Die Abrechnungsdokumentation besagt, dass sich die Tokenisierung je nach Modell, Sprache und Medieneingabe unterscheidet, daher ist eine Zeichenanzahl-Formel keine zuverlässige Abrechnungsschätzung.
  • Loggen Sie Modell, Latenz, Nutzung und Finish-Grund bei jedem Turn.
  • Halten Sie benutzerseitige Meldungen von internen Fehlerdetails getrennt.
  • Senden Sie einen Test-Turn an ein alternatives Tier, damit Sie wissen, dass das Fallback funktioniert, bevor der erste echte Ausfall auftritt.

Modelle auswählen und Kosten für Ihren KI-Chatbot schätzen

Lassen Sie das Frontend niemals einen beliebigen Modell-String an die API übergeben. Ein Freitextfeld lädt zu Tippfehlern, veralteten Modellen und Modellen ein, die Sie nie bereitstellen wollten. Die ALLOWED_MODELS-Map gibt Ihnen einen Ort, an dem Sie ein Modell austauschen können, wenn ein Anbieter eines veraltet, ohne Client-Update. Unbekannte Modell-IDs geben model_not_found zurück, und die Dokumentation verweist Sie auf /v1/models für eine aktuelle ID. Prüfen Sie das Modellverzeichnis, bevor Sie die Allowlist sperren.

Aktuelle Preise pro 1 Mio. Token

Dies sind TokenLab-Preise in USD aus dem Live-API-Eintrag jedes Modells, eingesehen am 03.10.2026. Die Preisgestaltung wurde zuletzt am 02.10.2026 um 16:53:30.068Z aktualisiert. Alle vier Modelle zeigten den Lebenszyklusstatus active.

Tier Modell-ID Eingabe / 1M Ausgabe / 1M Cache read / 1M Quelle
default deepseek-v4-flash (off-peak) 0,15 $ 0,60 $ 0,003 $ Modell-API
default deepseek-v4-flash (peak) 0,30 $ 1,20 $ 0,006 $ Modell-API
flagship gpt-5.5 1,50 $ 9,00 $ 0,15 $ Modell-API
balanced claude-sonnet-5 0,90 $ 4,50 $ 0,09 $ Modell-API
budget gemini-3.5-flash 0,75 $ 4,50 $ 0,075 $ Modell-API

Für deepseek-v4-flash listet der Eintrag Spitzenzeiten an Wochentagen, ausgenommen chinesische Feiertage. Off-Peak umfasst Wochenenden und diese Feiertage. claude-sonnet-5 listet auch einen Cache-Schreibpreis von 1,125 $ pro 1 Mio. Token.

Ein bearbeiteter Request

Nehmen wir einen Turn mit 2.000 Eingabe-Token und 500 Ausgabe-Token an. Diese Größe ist unsere Annahme, keine Messung. Für gpt-5.5:

  • Eingabe: 2.000 × 1,50 $ / 1.000.000 = 0,0030 $
  • Ausgabe: 500 × 9,00 $ / 1.000.000 = 0,0045 $
  • Gesamt: 0,0075 $ pro Turn (Schätzung, keine Cache-Treffer)

Mit derselben Arithmetik erhalten wir diese Schätzungen: deepseek-v4-flash kostet 0,0006 $ off-peak und 0,0012 $ zu Spitzenzeiten, claude-sonnet-5 kostet 0,00405 $ und gemini-3.5-flash kostet 0,00375 $. Über 1.000 solcher Turns sind das etwa 7,50 $ bei gpt-5.5 gegenüber 0,60 $ bis 1,20 $ bei deepseek-v4-flash. Echte Turns wachsen, wenn sich die Historie ansammelt, also lesen Sie usage aus der Antwort oder dem letzten Stream-Chunk, anstatt dieser Dimensionierung zu vertrauen.

In der Praxis leiten wir die meisten Konversationen an das Default-Tier weiter und reservieren gpt-5.5 oder claude-sonnet-5 für Turns, die sie benötigen. Die Abrechnungsdokumentation warnt davor, dass der niedrigste Preis pro Token nicht immer die niedrigsten Kosten pro abgeschlossener Aufgabe bedeutet. Führen Sie dieselben Prompts durch zwei Tiers und vergleichen Sie die Endkosten unter Usage.

Zwei Prüfungen, bevor Sie ausliefern. Die Abrechnungsdokumentation besagt, dass man keine kopierte Preistabelle hartcodieren sollte, also lesen Sie GET /v1/models/:model/pricing, wenn Ihre App Kosten anzeigt (Abrechnung und Preisgestaltung, eingesehen am 03.10.2026). Außerdem listet der deepseek-v4-flash-Eintrag json-mode, prompt-cache und tool-use, aber nicht vision. Wenn Ihr Chatbot Bilder akzeptiert, leiten Sie diese Turns an ein Tier weiter, dessen Eintrag vision auflistet.

Smoke-Test und Ihren KI-Chatbot ausliefern

Schritt 7: End-to-End ausführen

Starten Sie den Server in einem Terminal, in dem TOKENLAB_API_KEY exportiert ist. Die curl-Payloads verwenden dieselben message-, tier- und conversation_id-Felder wie ChatRequest.

uvicorn main:app --reload --port 8000
# 1. Synchroner Endpunkt: Erwarten Sie eine kurze Antwort und eine conversation_id
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Reply only with OK.", "tier": "default"}'

# 2. Streaming: Erwarten Sie data: {"delta": ...} Zeilen, dann {"done": true, ...}
curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "tier": "default"}'

# 3. Memory: Wiederverwenden einer conversation_id, die oben zurückgegeben wurde
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What did I just say?", "tier": "default", "conversation_id": "PASTE_ID_FROM_STEP_1"}'

# 4. Erzwungener Fehler: Erwarten Sie HTTP 400 und "unknown tier: nope"
curl -i -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello!", "tier": "nope"}'

Um einen Upstream-Fehler zu erzwingen, starten Sie den Server mit einem falschen TOKENLAB_API_KEY neu. Ihr Client sollte eine saubere 503-Meldung erhalten, und Ihre Logs sollten den Upstream-401 mit invalid_api_key zeigen. Öffnen Sie dann Requests, um das Modell, den Status und die Nutzung der erfolgreichen Aufrufe zu bestätigen. Wenn Sie einen Turn streamen, eine Konversation bewahren und bei einem erzwungenen Fehler einen sauberen Fehler zurückgeben können, haben Sie das richtige Fundament.

Danach sind die nächsten Upgrades eher langweilige Infrastruktur als mehr KI:

  • Auth, damit ein Benutzer nicht die Konversation eines anderen Benutzers lesen kann.
  • Persistenz, damit Sitzungen Deploys überleben.
  • Rate Limiting pro Benutzer, damit ein lauter Benutzer nicht Ihr Kontingent verbrennt.
  • Nutzungszuordnung, falls der Chatbot kundenorientiert ist.
  • Hintergrund-Zusammenfassung, falls Konversationen ein Langzeitgedächtnis benötigen.

Sobald die Base-URL-Migration hinter Ihnen liegt, ist eine Modelländerung eine Konfigurationsbearbeitung an ALLOWED_MODELS.

FAQ

Benötige ich WebSockets, um einen KI-Chatbot zu erstellen?

Nein. SSE, wie in Schritt 4 gezeigt, deckt die meisten Chat-Produkte ab. WebSockets bieten einen Mehrwert, wenn Sie bidirektionales Push außerhalb von Request und Response benötigen, wie z. B. Live-Zusammenarbeit oder serverinitiierte Ereignisse. Für eine Standard-Chat-UI ist SSE einfacher bereitzustellen und zu debuggen.

Welches Modell sollte mein Chatbot standardmäßig verwenden?

Beginnen Sie mit einem günstigen Tier wie deepseek-v4-flash und fügen Sie claude-sonnet-5 oder gpt-5.5 hinter der Allowlist für schwierigere Turns hinzu. Die oben genannten Preise, eingesehen am 03.10.2026, zeigen die Lücke. Testen Sie dann Ihre eigenen Prompts auf zwei Tiers und vergleichen Sie die Endkosten unter Usage. Prüfen Sie das Modellverzeichnis, bevor Sie sich festlegen, da sich die Aufstellungen ändern.

Warum gibt mein Chatbot 402 oder 429 zurück?

Ein 402 bedeutet, dass das Kontoguthaben oder das Nutzungslimit des Keys zu niedrig ist. Die Codes sind insufficient_balance und quota_exceeded, und eine Wiederholung der Anfrage hilft nicht. Ein 429 bedeutet, dass Sie ein Anfragelimit erreicht haben, warten Sie also auf Retry-After und versuchen Sie es dann erneut. Unser synchroner Endpunkt wiederholt den Vorgang einmal und der Streaming-Endpunkt meldet den Fehler an den Client.

Kann der Browser TokenLab direkt aufrufen?

Nicht sicher. Die Authentifizierungs-Dokumentation besagt, dass API-Keys niemals im clientseitigen Code offengelegt werden dürfen. Bewahren Sie den Key in der Serverumgebung auf und lassen Sie den Browser Ihr eigenes authentifiziertes Backend aufrufen, wie es das Frontend-Beispiel tut.


Erstellen Sie einen API-Key unter tokenlab.sh, fügen Sie Guthaben hinzu und führen Sie den oben genannten Smoke-Test aus.

Quellen

Preis geprüft am 2026-10-03

Verwandte Modelle

Kürzlich veröffentlichte Modelle

Mit den Modellen aus diesem Leitfaden bauen

Preise vergleichen, Routen testen und aus der Recherche einen laufenden API-Aufruf machen.