Kimi K2.7 Code is now on CometAPI — Kimi's most intelligent coding model to date, reliably follows instructions in long contexts and completes programming tasks with a higher success rate. Try it now

So debuggen Sie fehlgeschlagene KI-API-Generierungen

CometAPI
AnnaJun 4, 2026
 So debuggen Sie fehlgeschlagene KI-API-Generierungen

Fehler bei KI-APIs unterscheiden sich von regulären API-Fehlern. Eine 200-Antwort bedeutet nicht, dass Ihre Generierung erfolgreich war. Ein Feld content mit null ist nicht immer ein Fehler. Und derselbe Prompt, der gestern noch funktioniert hat, kann heute scheitern, weil ein Anbieter seine Inhaltsrichtlinie aktualisiert hat.

Dieser Leitfaden erklärt, wie man KI-API-Fehler liest, was die einzelnen Fehlermodi tatsächlich bedeuten und wie man ein Fehlermanagement aufbaut, das Ihnen sagt, was kaputtging — statt nur, dass etwas kaputtging.

Hinweis: Modellnamen wie gpt-5.4 und gpt-5.4-mini sind Plattformbezeichner von CometAPI. Sie funktionieren nur über https://api.cometapi.com/v1 — nicht direkt über die APIs von OpenAI oder Anthropic. Siehe die vollständige Modellliste.

Warum Debugging von KI-APIs schwieriger ist als bei regulären APIs

Bei einer typischen REST-API bedeutet 200 Erfolg und 4xx, dass Sie etwas falsch gemacht haben. KI-APIs fügen eine dritte Kategorie hinzu: Soft-Fails — Antworten, die 200 zurückgeben, aber keinen nutzbaren Inhalt enthalten.

Drei Dinge können schiefgehen:

  1. Harte Fehler — HTTP-Fehler (4xx, 5xx). Die Anfrage wurde nicht abgeschlossen.
  2. Soft-Fehler — HTTP 200, aber finish_reason ist content_filter oder length, oder content ist null.
  3. Stiller Fehler — HTTP 200, der Inhalt sieht gut aus, aber die Ausgabe ist auf eine Weise falsch, die Sie erst in der Anwendungsschicht erkennen.

Die meisten Fehlerbehandlungen decken nur Fall 1 ab. Fälle 2 und 3 sind die Ursache der meisten Produktionsbugs.

Das Fehlerrückgabeformat verstehen

Der Text-Completions-Endpunkt gibt eine konsistente Fehlerstruktur zurück:

{  "error": {    "message": "menschenlesbare Beschreibung (enthält oft die Request-ID)",    "type": "comet_api_error",    "param": "der problematische Parameter oder null",    "code": "Fehlercode oder null"  }}

Bild- und Video-Endpunkte liefern andere Fehlerformate — parsen Sie immer den Roh-Response-Body, anstatt eine feste Struktur über alle Endpunkte hinweg anzunehmen.

Das Feld message sagt Ihnen normalerweise genau, was falsch ist. Das Feld param sagt Ihnen, welcher Parameter es verursacht hat. Loggen Sie immer beide.

Die Bedeutung der einzelnen HTTP-Statuscodes kennen

StatusBedeutungHäufige UrsacheMaßnahme
400Bad RequestModell fehlt, falscher Parameter für dieses ModellPrüfen Sie error.param in der Antwort
401UnauthorizedFalscher oder fehlender API-SchlüsselFormat Authorization: Bearer <key> prüfen
429Rate LimitedZu viele AnfragenExponentielles Backoff (siehe Schritt 4)
500ServerfehlerAnbieterproblem oder fehlerhafter Request-BodyMit Backoff erneut versuchen; Request-Format prüfen
504Gateway TimeoutAnbieter brauchte zu langeErneut versuchen; schnelleres Modell erwägen

Quelle**:* CometAPI chat completions docs

Die Unterscheidung 400 vs. 500 ist wichtig für die Retry-Logik. Ein 400 bedeutet, Ihre Anfrage ist falsch — erneutes Senden derselben Anfrage hilft nicht. 500 oder 504 bedeutet ein Serverproblem — erneute Versuche sind sinnvoll.

finish_reason prüfen — das am häufigsten übersehene Feld

Eine 200-Antwort mit finish_reason: "content_filter" bedeutet, dass Ihre Generierung blockiert wurde. Das Feld content ist null oder leer. Wenn Sie das nicht prüfen, gibt Ihre App stillschweigend nichts zurück.

finish_reasonBedeutungVorgehenMaßnahme
stopNormale BeendigungNichts — das ist ErfolgPrüfen Sie error.param in der Antwort
lengthTokenlimit erreichtmax_tokens erhöhen oder Prompt kürzenFormat Authorization: Bearer <key> prüfen
content_filterDurch Sicherheitsrichtlinie blockiertPrompt umformulieren; bestimmte Namen/Themen meidenExponentielles Backoff (siehe Schritt 4)
tool_callsModell hat ein Tool aufgerufen statt Text zu liefernTool-Aufruf behandeln; content ist nullMit Backoff erneut versuchen; Request-Format prüfen
504Gateway-ZeitüberschreitungAnbieter brauchte zu langeErneut versuchen; schnelleres Modell erwägen

Quelle**:* CometAPI chat completions docs

import osimport loggingfrom openai import OpenAI, APIStatusError, APIConnectionError, APITimeoutErrorfrom dotenv import load_dotenv​load_dotenv()​api_key = os.environ.get("COMETAPI_KEY")if not api_key:    raise ValueError("COMETAPI_KEY ist nicht gesetzt")​client = OpenAI(    base_url="https://api.cometapi.com/v1",    api_key=api_key,)​def safe_complete(messages: list, model: str = "gpt-5.4-mini", **kwargs) -> dict:    """    Führt eine Chat-Anfrage mit vollständiger Fehler- und finish_reason-Behandlung aus.    Gibt {"content": str, "finish_reason": str, "tool_calls": list | None} zurück    Löst bei API-Fehlern Ausnahmen aus.    """    try:        response = client.chat.completions.create(            model=model,            messages=messages,            **kwargs        )    except APIStatusError as e:        error_body = {}        try:            error_body = e.response.json().get("error", {})        except Exception:            pass        logging.error(            f"API-Fehler status={e.status_code} "            f"message={error_body.get('message')} "            f"param={error_body.get('param')}"        )        raise    except (APIConnectionError, APITimeoutError) as e:        logging.error(f"Netzwerk-/Timeout-Fehler: {e}")        raise​    choice = response.choices[0]    finish_reason = choice.finish_reason​    if finish_reason == "content_filter":        raise ValueError(            f"Generierung durch Inhaltsfilter blockiert. "            f"Modell: {model}. Prompt umformulieren."        )​    if finish_reason == "length":        used = response.usage.completion_tokens if response.usage else "unknown"        logging.warning(f"Ausgabe am Tokenlimit abgeschnitten. Verwendet {used} Token.")​    # Strukturierte Rückgabe, damit Aufrufer tool_calls explizit behandeln können    return {        "content": choice.message.content or "",        "finish_reason": finish_reason,        "tool_calls": choice.message.tool_calls,    }​# Verwendungresult = safe_complete(    messages=[{"role": "user", "content": "Fassen Sie diesen Artikel zusammen: [Text]"}],    model="gpt-5.4-mini")​if result["finish_reason"] == "tool_calls":    # Tool-Aufruf behandeln — content ist leer    print("Modell möchte ein Tool aufrufen:", result["tool_calls"])else:    print(result["content"])

Stille Fehler auf der Anwendungsebene erkennen

Stille Fehler sind am schwersten zu finden. Die API liefert 200, finish_reason ist stop, aber die Ausgabe ist semantisch falsch. Sie können sie nur auf der Anwendungsebene erkennen.

Häufige Muster:

def validate_completion(result: dict, task: str) -> str:    """    Validierung auf Anwendungsebene für stille Fehler.    Löst ValueError aus, wenn die Ausgabe grundlegenden Erwartungen nicht entspricht.    """    content = result["content"].strip()​    # Leere Ausgabe, die kein Tool-Aufruf ist    if not content and result["finish_reason"] != "tool_calls":        raise ValueError(f"Leere Ausgabe für Aufgabe '{task}' mit finish_reason='{result['finish_reason']}'")​    # Aufgabenspezifische Prüfungen    if task == "classify":        valid_labels = {"positive", "negative", "neutral"}        if content.lower() not in valid_labels:            logging.warning(                f"Unerwartete Klassifikationsausgabe: '{content}'. "                f"Erwartet eine aus {valid_labels}. "                f"Das Modell hat möglicherweise eine Erklärung statt eines Labels zurückgegeben."            )​    if task == "json_extract":        import json        try:            json.loads(content)        except json.JSONDecodeError:            raise ValueError(                f"JSON-Ausgabe erwartet, erhalten: '{content[:100]}...'. "                f"Versuchen Sie, 'Antwort nur als gültiges JSON' zum Prompt hinzuzufügen, "                f"oder verwenden Sie response_format={{\"type\": \"json_object\"}}."            )​    if task == "summarize" and len(content.split()) < 10:        logging.warning(            f"Auffällig kurze Zusammenfassung ({len(content.split())} Wörter). "            f"Prüfen Sie, ob der Input zu kurz war oder das Modell die Aufgabe missverstanden hat."        )​    return content​​# Gesamtablauf mit Erkennung stiller Fehlerresult = safe_complete(    messages=[{"role": "user", "content": "Als positiv/negativ/neutral klassifizieren: 'Great product!'"}],    model="claude-haiku-4-5")label = validate_completion(result, task="classify")

Stille Fehler entstehen meist aus drei Ursachen: Der Prompt ist mehrdeutig, das Modell ignoriert Ihre Formatvorgaben oder der Input war für die Aufgabe zu kurz/zu lang. Das vollständige Loggen der Ausgabe bei Validierungsfehlern ist der schnellste Weg, herauszufinden, welche Ursache vorliegt.

Exponentielles Backoff für Ratenbegrenzungen hinzufügen

Rate-Limit-Fehler (429) sind temporär. Die richtige Reaktion ist, mit zunehmenden Verzögerungen zu warten und erneut zu versuchen — eine Standardpraxis für jede API mit Ratenbegrenzungen:

import timeimport randomfrom openai import RateLimitError​def complete_with_retry(    messages: list,    model: str = "gpt-5.4-mini",    max_retries: int = 3,    **kwargs) -> dict:    """Erneut versuchen bei Rate-Limits und Serverfehlern mit exponentiellem Backoff."""    last_error = None​    for attempt in range(max_retries):        try:            return safe_complete(messages, model=model, **kwargs)​        except APIStatusError as e:            if e.status_code < 500:                raise  # 4xx: nicht erneut versuchen, Anfrage ist falsch            last_error = e​        except RateLimitError as e:            last_error = e​        except (APIConnectionError, APITimeoutError) as e:            last_error = e​        if attempt < max_retries - 1:            wait = (2 ** attempt) + random.random()  # Jitter verhindert Gleichlauf beim Retry            logging.warning(f"Versuch {attempt + 1} fehlgeschlagen. Warte {wait:.1f}s vor erneutem Versuch.")            time.sleep(wait)​    raise RuntimeError(f"Alle {max_retries} Versuche fehlgeschlagen") from last_error

Versuchen Sie es nicht erneut bei 400 oder 401 — das sind Client-Fehler, die sich nicht von selbst lösen.

Fehler bei der Bildgenerierung debuggen

Die Bildgenerierung hat eigene Fehlermodi zusätzlich zu den Standard-HTTP-Fehlern:

import base64import requests​def generate_image_safe(prompt: str, model: str = "dall-e-3") -> dict:    """    Generiert ein Bild mit vollständiger Fehlerbehandlung.    Gibt {"url": str | None, "bytes": bytes | None, "blocked": bool} zurück    """    api_key = os.environ.get("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY ist nicht gesetzt")​    BASE64_MODELS = {"gpt-image-2", "qwen-image"}​    headers = {        "Authorization": f"Bearer {api_key}",        "Content-Type": "application/json"    }​    payload = {"model": model, "prompt": prompt, "size": "1024x1024"}    if model in BASE64_MODELS:        payload["output_format"] = "png"    else:        payload["response_format"] = "url"​    try:        response = requests.post(            "https://api.cometapi.com/v1/images/generations",            json=payload,            headers=headers,            timeout=60        )        response.raise_for_status()    except requests.exceptions.HTTPError as e:        logging.error(f"HTTP-Fehler bei der Bildgenerierung: {e.response.status_code} {e.response.text}")        raise    except requests.exceptions.Timeout:        logging.error("Bildgenerierung nach 60s zeitüberschritten")        raise​    data = response.json().get("data", [])​    if not data:        logging.warning("Bildgenerierung lieferte leere Daten — Prompt wurde ggf. gefiltert.")        return {"url": None, "bytes": None, "blocked": True}​    item = data[0]​    if "revised_prompt" in item:        logging.info(f"Anbieter hat Prompt überarbeitet zu: {item['revised_prompt']}")​    if "url" in item:        return {"url": item["url"], "bytes": None, "blocked": False}​    return {        "url": None,        "bytes": base64.b64decode(item["b64_json"]),        "blocked": False    }

Bildspezifische Punkte, auf die Sie achten sollten:

SymptomUrsacheMaßnahme
Leeres Daten-ArrayPrompt gefiltertrevised_prompt prüfen; umformulieren
response_format-Fehler bei GPT Image 2Parameter nicht unterstütztStattdessen output_format verwenden
n > 1 Fehler bei Qwen ImageModellbeschränkungAnfragen in einer Schleife ausführen
URL liefert später 403URL abgelaufenSofort nach Generierung herunterladen

Quelle**:* CometAPI image generation docs

Fehler bei der Videogenerierung debuggen

Videogenerierung schlägt anders fehl, weil sie asynchron ist. Initialisieren Sie Statusvariablen vor der Schleife, damit die Timeout-Fehlermeldung immer korrekt formatiert ist:

def submit_and_poll_video(    prompt: str,    model: str = "veo3-fast",    max_wait: int = 600) -> str:    """Video-Aufgabe einreichen und bis zum Abschluss pollen. Gibt Video-URL zurück."""    api_key = os.environ.get("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY ist nicht gesetzt")​    headers = {"Authorization": f"Bearer {api_key}"}​    try:        response = requests.post(            "https://api.cometapi.com/v1/videos",            headers=headers,            files={                "prompt": (None, prompt),                "model": (None, model),                "size": (None, "16x9")            },            timeout=30        )        response.raise_for_status()    except requests.exceptions.HTTPError as e:        logging.error(f"Video-Einreichung fehlgeschlagen: {e.response.status_code} {e.response.text}")        raise​    task_id = response.json()["id"]    logging.info(f"Video-Task eingereicht: {task_id}")​    poll_url = f"https://api.cometapi.com/v1/videos/{task_id}"    elapsed = 0    interval = 10    status = "unknown"   # vor der Schleife initialisieren    progress = 0         # vor der Schleife initialisieren​    while elapsed < max_wait:        try:            poll_response = requests.get(poll_url, headers=headers, timeout=30)            poll_response.raise_for_status()        except requests.exceptions.HTTPError as e:            logging.error(f"Poll-Request fehlgeschlagen: {e.response.status_code}")            raise​        result = poll_response.json()        status = result.get("status", "unknown")        progress = result.get("progress", 0)​        logging.info(f"Task {task_id}: status={status} progress={progress}%")​        if status == "succeeded":            return result["output"][0]        elif status in ("failed", "cancelled"):            error_detail = result.get("error", "keine Fehlerdetails zurückgegeben")            raise RuntimeError(f"Video-Task {task_id} fehlgeschlagen: {error_detail}")​        time.sleep(interval)        elapsed += interval​    raise TimeoutError(        f"Video-Task {task_id} wurde nicht innerhalb von {max_wait}s abgeschlossen. "        f"Letzter Status: {status}, Fortschritt: {progress}%"    )

Videospezifische Probleme:

SymptomUrsacheMaßnahme
Aufgabe 10+ Min in queuedServerauslastungMit anderem Modell versuchen
failed ohne FehlerdetailPrompt gefiltert oder ModellfehlerPrompt umformulieren
Video-URL liefert 403URL abgelaufenSofort herunterladen
task_not_exist beim ersten Runway-PollAufgabe initialisiert noch (CometAPI-dokumentiertes Verhalten)5s warten und erneut versuchen
Kling liefert "succeed" statt "succeeded"Die Kling-API nutzt einen nicht standardisierten Status-StringBeide im Polling behandeln

Quelle**:* CometAPI video generation docs**, Kling Video docs

Node.js-Version

import OpenAI from 'openai';​const apiKey = process.env.COMETAPI_KEY;if (!apiKey) throw new Error('COMETAPI_KEY ist nicht gesetzt');​const client = new OpenAI({  baseURL: 'https://api.cometapi.com/v1',  apiKey,});​async function safeComplete(messages, model = 'gpt-5.4-mini', options = {}) {  let response;​  try {    response = await client.chat.completions.create({ model, messages, ...options });  } catch (err) {    if (err.status && err.status < 500) {      console.error(`Client-Fehler ${err.status}: ${err.message}`);    } else {      console.error(`Server-/Netzwerkfehler: ${err.message}`);    }    throw err;  }​  const choice = response.choices[0];  const finishReason = choice.finish_reason;​  if (finishReason === 'content_filter') {    throw new Error(`Generierung durch Inhaltsfilter blockiert. Modell: ${model}`);  }​  if (finishReason === 'length') {    console.warn(`Ausgabe abgeschnitten. Verwendet ${response.usage?.completion_tokens ?? 'unknown'} Token.`);  }​  return {    content: choice.message.content ?? '',    finishReason,    toolCalls: choice.message.tool_calls ?? null,  };}​async function completeWithRetry(messages, model = 'gpt-5.4-mini', maxRetries = 3) {  let lastError;​  for (let attempt = 0; attempt < maxRetries; attempt++) {    try {      return await safeComplete(messages, model);    } catch (err) {      // 4xx-Clientfehler nicht erneut versuchen      if (err.status && err.status < 500) throw err;​      lastError = err;      if (attempt < maxRetries - 1) {        const wait = (2 ** attempt + Math.random()) * 1000;        console.warn(`Versuch ${attempt + 1} fehlgeschlagen. Neuer Versuch in ${(wait / 1000).toFixed(1)}s`);        await new Promise(r => setTimeout(r, wait));      }    }  }​  throw new Error(`Alle ${maxRetries} Versuche fehlgeschlagen: ${lastError?.message}`);}​// Verwendungconst result = await safeComplete(  [{ role: 'user', content: 'Als positiv/negativ/neutral klassifizieren: "Great product!"' }],  'claude-haiku-4-5');​if (result.finishReason === 'tool_calls') {  console.log('Tool-Aufruf angefordert:', result.toolCalls);} else {  console.log(result.content);}

Eine Debugging-Checkliste

Wenn eine Generierung fehlschlägt und Sie nicht wissen, wo Sie anfangen sollen:

Für Textgenerierung:

  • Ist der API-Schlüssel gesetzt und im Format Authorization: Bearer <key>?
  • Ist finish_reason etwas anderes als stop?
  • Ist content null? Prüfen Sie, ob finish_reason tool_calls ist.
  • Wurde die Ausgabe abgeschnitten? Prüfen Sie finish_reason: "length" und usage.completion_tokens.
  • Handelt es sich um einen 4xx-Fehler (Request korrigieren) oder 5xx (erneut versuchen)?
  • Besteht die Ausgabe Ihre Validierung auf Anwendungsebene? (stiller Fehler)

Für Bildgenerierung:

  • Ist das Array data leer? (Inhaltsfilter)
  • Haben Sie response_format bei GPT Image 2 verwendet? (nicht unterstützt — verwenden Sie output_format)
  • Haben Sie n > 1 bei Qwen Image gesetzt? (nicht unterstützt)
  • Haben Sie das Bild heruntergeladen, bevor die URL abgelaufen ist?

Für Videogenerierung:

  • Steckt die Aufgabe in queued fest? (anderes Modell versuchen)
  • Haben Sie das Feld error in der fehlgeschlagenen Task-Antwort geprüft?
  • Haben Sie das Video heruntergeladen, bevor die URL abgelaufen ist?
  • Behandeln Sie sowohl "succeed" (Kling) als auch "succeeded" (Veo, Runway)?

FAQ

F: Meine Anfrage gibt 200 zurück, aber es gibt keinen Inhalt. Was ist passiert?

Prüfen Sie finish_reason. Wenn es content_filter ist, wurde die Generierung blockiert — die Anfrage war erfolgreich, aber die Ausgabe wurde unterdrückt. Wenn es tool_calls ist, hat das Modell ein Tool aufgerufen statt Text zurückzugeben, und content ist absichtlich null. Wenn finish_reason stop ist, der Inhalt aber trotzdem leer ist, ist das ein stiller Fehler — loggen Sie die vollständige Antwort und prüfen Sie Ihren Prompt.

F: Woher weiß ich, ob mein Prompt gefiltert wird?

Für Text: Prüfen Sie finish_reason === "content_filter". Für Bilder: Prüfen Sie, ob das Array data leer ist. Für Videos: Prüfen Sie, ob die Aufgabe kurz nach dem Absenden den Status failed erreicht, ohne Fehlerdetails. In allen Fällen versuchen Sie, den Prompt neutraler zu formulieren.

F: Wann sollte ich eine fehlgeschlagene Anfrage erneut versuchen?

Bei 429 und 5xx mit exponentiellem Backoff erneut versuchen. Nicht bei 4xx — eine fehlerhafte Anfrage behebt sich nicht von selbst. Die Ausnahme ist 401, wenn Sie API-Schlüssel rotieren.

F: Was ist exponentielles Backoff und warum ist das wichtig?

Anstatt sofort erneut zu versuchen, warten Sie zunehmend länger: 1s, 2s, 4s. Das Hinzufügen von Jitter (+ random.random()) verhindert, dass mehrere Clients synchron erneut versuchen. Das ist eine Standardpraxis für jede API mit Ratenbegrenzungen — nicht spezifisch für CometAPI.

F: Die Videoaufgabe steckt seit 10 Minuten in queued. Ist sie fehlgeschlagen?

Nicht unbedingt — unter Last können sich Warteschlangen aufbauen. Warten Sie bis zu Ihrer max_wait-Schwelle, dann lösen Sie einen TimeoutError aus und versuchen es mit einem anderen Modell erneut. Loggen Sie die Task-ID, damit Sie den Status bei Bedarf manuell prüfen können.

F: Wie fange ich stille Fehler ab?

Stille Fehler erfordern Validierung auf Anwendungsebene — die API sagt Ihnen nicht, dass die Ausgabe semantisch falsch ist. Prüfen Sie, dass die Ausgabe dem erwarteten Format entspricht (gültiges JSON, erwartetes Label, Mindestlänge). Loggen Sie die vollständige Ausgabe, wenn die Validierung fehlschlägt. Die häufigsten Ursachen sind mehrdeutige Prompts, ignorierte Formatvorgaben oder Inputs, die für die Aufgabe zu kurz oder zu lang sind.

Bereit, die KI-Entwicklungskosten um 20 % zu senken?

In wenigen Minuten kostenlos starten. Inklusive kostenlosem Testguthaben. Keine Kreditkarte erforderlich.

Mehr lesen