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

Hvordan feilsøke mislykkede AI-API-genereringer

CometAPI
AnnaJun 4, 2026
Hvordan feilsøke mislykkede AI-API-genereringer

AI-API-feil er annerledes enn vanlige API-feil. En 200-respons betyr ikke at genereringen lyktes. Et null-felt for content er ikke alltid en feil. Og den samme prompten som fungerte i går kan feile i dag fordi en leverandør oppdaterte innholdspolitikken sin.

Denne veiledningen forklarer hvordan du leser AI-API-feil, hva hver feiltyper faktisk betyr, og hvordan du bygger feilhåndtering som forteller deg hva som gikk i stykker i stedet for bare at noe gikk i stykker.

Note: Modellnavn som gpt-5.4 og gpt-5.4-mini brukt i denne artikkelen er CometAPI sine plattformidentifikatorer. De fungerer kun via https://api.cometapi.com/v1 — ikke direkte via OpenAI- eller Anthropics API-er. Se den fulle modelllisten.

Hvorfor feilsøking for AI-API-er er vanskeligere enn for vanlige API-er

Med et typisk REST-API betyr 200 suksess og 4xx betyr at du gjorde noe feil. AI-API-er legger til en tredje kategori: soft failures — responser som returnerer 200, men uten brukbart innhold.

Tre ting kan gå galt:

  1. Hard feil — HTTP-feil (4xx, 5xx). Forespørselen ble ikke fullført.
  2. Myk feil — HTTP 200, men finish_reason er content_filter eller length, eller content er null.
  3. Stille feil — HTTP 200, innholdet ser fint ut, men resultatet er feil på en måte du bare fanger på applikasjonslaget.

De fleste feilhåndteringer dekker bare punkt 1. Punkt 2 og 3 er der de fleste produksjonsfeil lever.

Forstå formatet på feilsvar

Text completions-endepunktet returnerer en konsistent feilstruktur:

{  "error": {    "message": "human-readable description (often includes request id)",    "type": "comet_api_error",    "param": "the_problematic_parameter_or_null",    "code": "error_code_or_null"  }}

Bilde- og videoendepunkter returnerer andre feilformater — parse alltid råresponsen i stedet for å anta en fast struktur på tvers av endepunkter.

Feltet message forteller vanligvis nøyaktig hva som er galt. Feltet param forteller hvilken parameter som forårsaket det. Logg alltid begge.

Kjenn betydningen av hver HTTP-statuskode

StatusBetydningVanlig årsakLøsning
400Bad requestManglende modell, feil parameter for modellenKontroller error.param i responsen
401UnauthorizedFeil eller manglende API-nøkkelVerifiser Authorization: Bearer -format
429Rate limitedFor mange forespørslerEksponentiell backoff (se Trinn 4)
500Server errorFeil hos leverandør, eller ugyldig request bodyPrøv igjen med backoff; kontroller forespørselformat
504Gateway timeoutLeverandøren brukte for lang tidPrøv igjen; vurder en raskere modell

Kilde**:* CometAPI chat completions-dokumentasjon

Distinksjonen mellom 400 og 500 er viktig for retry-logikk. En 400 betyr at forespørselen din er feil — å gjenta samme forespørsel hjelper ikke. En 500 eller 504 betyr at serveren hadde et problem — å prøve igjen gir mening.

Sjekk finish_reason — det mest oversette feltet

En 200-respons med finish_reason: "content_filter" betyr at genereringen ble blokkert. Feltet content vil være null eller tomt. Hvis du ikke sjekker dette, returnerer appen din stille ingenting.

finish_reasonBetydningHva du gjørLøsning
stopNormal fullføringIngenting — dette er suksessKontroller error.param i responsen
lengthTraff token-grensenØk max_tokens eller kort ned promptenVerifiser Authorization: Bearer -format
content_filterBlokkert av sikkerhetspolicyOmformuler prompten; unngå spesifikke navn/temaerEksponentiell backoff (se Trinn 4)
tool_callsModellen kalte et verktøy i stedet for tekstHåndter verktøykallet; innhold vil være nullPrøv igjen med backoff; kontroller forespørselformat
504Gateway timeoutLeverandøren brukte for lang tidPrøv igjen; vurder en raskere modell
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 is not set")​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:    """    Complete a chat request with full error and finish_reason handling.    Returns {"content": str, "finish_reason": str, "tool_calls": list | None}    Raises on API errors.    """    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 error 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"Network/timeout error: {e}")        raise​    choice = response.choices[0]    finish_reason = choice.finish_reason​    if finish_reason == "content_filter":        raise ValueError(            f"Generation blocked by content filter. "            f"Model: {model}. Rephrase the prompt."        )​    if finish_reason == "length":        used = response.usage.completion_tokens if response.usage else "unknown"        logging.warning(f"Output truncated at token limit. Used {used} tokens.")​    # Return structured result so callers can handle tool_calls explicitly    return {        "content": choice.message.content or "",        "finish_reason": finish_reason,        "tool_calls": choice.message.tool_calls,    }​# Usageresult = safe_complete(    messages=[{"role": "user", "content": "Summarize this article: [text]"}],    model="gpt-5.4-mini")​if result["finish_reason"] == "tool_calls":    # Handle tool call — content will be empty    print("Model wants to call a tool:", result["tool_calls"])else:    print(result["content"])

Oppdag stille feil på applikasjonslaget

Stille feil er de vanskeligste å fange. API-et returnerer 200, finish_reason er stop, men outputen er semantisk feil. Du kan bare fange disse på applikasjonslaget.

Vanlige mønstre:

def validate_completion(result: dict, task: str) -> str:    """    Application-layer validation for silent failures.    Raises ValueError if the output doesn't meet basic expectations.    """    content = result["content"].strip()​    # Empty output that isn't a tool call    if not content and result["finish_reason"] != "tool_calls":        raise ValueError(f"Empty output for task '{task}' with finish_reason='{result['finish_reason']}'")​    # Task-specific checks    if task == "classify":        valid_labels = {"positive", "negative", "neutral"}        if content.lower() not in valid_labels:            logging.warning(                f"Unexpected classification output: '{content}'. "                f"Expected one of {valid_labels}. "                f"Model may have returned explanation instead of label."            )​    if task == "json_extract":        import json        try:            json.loads(content)        except json.JSONDecodeError:            raise ValueError(                f"Expected JSON output but got: '{content[:100]}...'. "                f"Try adding 'respond with valid JSON only' to the prompt, "                f"or use response_format={{\"type\": \"json_object\"}}."            )​    if task == "summarize" and len(content.split()) < 10:        logging.warning(            f"Suspiciously short summary ({len(content.split())} words). "            f"Check if the input was too short or the model misunderstood the task."        )​    return content​​# Full flow with silent failure detectionresult = safe_complete(    messages=[{"role": "user", "content": "Classify as positive/negative/neutral: 'Great product!'"}],    model="claude-haiku-4-5")label = validate_completion(result, task="classify")

Stille feil kommer vanligvis fra ett av tre steder: prompten er tvetydig, modellen ignorerte formatinstruksene dine, eller inputen var for kort/for lang for oppgaven. Å logge hele outputen når validering feiler er den raskeste måten å diagnostisere hvilken.

Legg til eksponentiell backoff for rate limits

Rate limit-feil (429) er midlertidige. Riktig respons er å vente og prøve igjen med økende pauser — en standard praksis for alle API-er med rate limits:

import timeimport randomfrom openai import RateLimitError​def complete_with_retry(    messages: list,    model: str = "gpt-5.4-mini",    max_retries: int = 3,    **kwargs) -> dict:    """Retry on rate limits and server errors with exponential 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: don't retry, request is wrong            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 prevents thundering herd            logging.warning(f"Attempt {attempt + 1} failed. Waiting {wait:.1f}s before retry.")            time.sleep(wait)​    raise RuntimeError(f"All {max_retries} attempts failed") from last_error

Ikke prøv igjen på 400 eller 401 — det er klientfeil som ikke løser seg selv.

Feilsøk feil ved bildegenerering

Bildegenerering har egne feiltyper i tillegg til standard HTTP-feil:

import base64import requests​def generate_image_safe(prompt: str, model: str = "dall-e-3") -> dict:    """    Generate an image with full error handling.    Returns {"url": str | None, "bytes": bytes | None, "blocked": bool}    """    api_key = os.environ.get("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY is not set")​    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"Image generation HTTP error: {e.response.status_code} {e.response.text}")        raise    except requests.exceptions.Timeout:        logging.error("Image generation timed out after 60s")        raise​    data = response.json().get("data", [])​    if not data:        logging.warning("Image generation returned empty data — prompt may have been filtered.")        return {"url": None, "bytes": None, "blocked": True}​    item = data[0]​    if "revised_prompt" in item:        logging.info(f"Provider revised prompt to: {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    }

Bilde-spesifikke problemer å se etter:

SymptomÅrsakLøsning
Tom data-arrayPrompt filtrertSjekk revised_prompt; omformuler
response_format-feil på GPT Image 2Parameter ikke støttetBruk output_format i stedet
n > 1-feil på Qwen ImageModellbegrensningLøp flere forespørsler i loop
URL returnerer 403 senereURL utløptLast ned umiddelbart etter generering

Kilde**:* CometAPI image generation-dokumentasjon

Feilsøk feil ved videogenerering

Videogenerering feiler annerledes fordi den er asynkron. Initialiser statusvariabler før løkken slik at timeout-feilmeldingen alltid er velutformet:

def submit_and_poll_video(    prompt: str,    model: str = "veo3-fast",    max_wait: int = 600) -> str:    """Submit video task and poll to completion. Returns video URL."""    api_key = os.environ.get("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY is not set")​    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 submit failed: {e.response.status_code} {e.response.text}")        raise​    task_id = response.json()["id"]    logging.info(f"Video task submitted: {task_id}")​    poll_url = f"https://api.cometapi.com/v1/videos/{task_id}"    elapsed = 0    interval = 10    status = "unknown"   # initialize before loop    progress = 0         # initialize before loop​    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 failed: {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", "no error detail returned")            raise RuntimeError(f"Video task {task_id} failed: {error_detail}")​        time.sleep(interval)        elapsed += interval​    raise TimeoutError(        f"Video task {task_id} did not complete within {max_wait}s. "        f"Last status: {status}, progress: {progress}%"    )

Video-spesifikke problemer:

SymptomÅrsakLøsning
Oppgave fast i queued i 10+ minServerbelastningPrøv med en annen modell
failed uten feildetaljerPrompt filtrert eller modellfeilOmformuler prompt
Video-URL returnerer 403URL utløptLast ned umiddelbart
task_not_exist ved første Runway-pollOppgave initierer fortsatt (CometAPI-dokumentert atferd)Vent 5s og prøv igjen
Kling returnerer "succeed" ikke "succeeded"Klings API bruker en ikke-standard statusstrengHåndter begge i poll-logikken

Kilde**:* CometAPI video generation-dokumentasjon**, Kling Video-dokumentasjon

Node.js-versjon

import OpenAI from 'openai';​const apiKey = process.env.COMETAPI_KEY;if (!apiKey) throw new Error('COMETAPI_KEY is not set');​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 error ${err.status}: ${err.message}`);    } else {      console.error(`Server/network error: ${err.message}`);    }    throw err;  }​  const choice = response.choices[0];  const finishReason = choice.finish_reason;​  if (finishReason === 'content_filter') {    throw new Error(`Generation blocked by content filter. Model: ${model}`);  }​  if (finishReason === 'length') {    console.warn(`Output truncated. Used ${response.usage?.completion_tokens ?? 'unknown'} tokens.`);  }​  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) {      // Don't retry 4xx client errors      if (err.status && err.status < 500) throw err;​      lastError = err;      if (attempt < maxRetries - 1) {        const wait = (2 ** attempt + Math.random()) * 1000;        console.warn(`Attempt ${attempt + 1} failed. Retrying in ${(wait / 1000).toFixed(1)}s`);        await new Promise(r => setTimeout(r, wait));      }    }  }​  throw new Error(`All ${maxRetries} attempts failed: ${lastError?.message}`);}​// Usageconst result = await safeComplete(  [{ role: 'user', content: 'Classify as positive/negative/neutral: "Great product!"' }],  'claude-haiku-4-5');​if (result.finishReason === 'tool_calls') {  console.log('Tool call requested:', result.toolCalls);} else {  console.log(result.content);}

En sjekkliste for feilsøking

Når en generering feiler og du ikke vet hvor du skal begynne:

For tekstgenerering:

  • Er API-nøkkelen satt og i Authorization: Bearer <key>-format?
  • Er finish_reason noe annet enn stop?
  • Er content null? Sjekk om finish_reason er tool_calls
  • Ble outputen trunkert? Sjekk finish_reason: "length" og usage.completion_tokens
  • Er feilen en 4xx (fiks forespørselen) eller 5xx (prøv igjen)?
  • Består outputen valideringen på applikasjonslaget? (stille feil)

For bildegenerering:

  • Er data-arrayet tomt? (innholdsfilter)
  • Brukte du response_format på GPT Image 2? (ikke støttet — bruk output_format)
  • Satt du n > 1 på Qwen Image? (ikke støttet)
  • Lastet du ned bildet før URL-en utløp?

For videogenerering:

  • Er oppgaven fast i queued? (prøv en annen modell)
  • Sjekket du error-feltet i den feilede oppgaveresponsen?
  • Lastet du ned videoen før URL-en utløp?
  • Håndterer du både "succeed" (Kling) og "succeeded" (Veo, Runway)?

FAQ

Q: Forespørselen min returnerer 200, men det er ikke noe innhold. Hva skjedde?

Sjekk finish_reason. Hvis den er content_filter, ble genereringen blokkert — forespørselen lyktes, men outputen ble undertrykt. Hvis den er tool_calls, kalte modellen et verktøy i stedet for å returnere tekst, og content er null per design. Hvis finish_reason er stop men innholdet fortsatt er tomt, er det en stille feil — logg hele responsen og sjekk prompten din.

Q: Hvordan vet jeg om prompten min blir filtrert?

For tekst: sjekk finish_reason === "content_filter". For bilder: sjekk om data-arrayet er tomt. For video: sjekk om oppgaven når failed-status kort tid etter innsending uten feildetaljer. I alle tilfeller, prøv å omformulere prompten mer nøytralt.

Q: Når bør jeg prøve en feilet forespørsel på nytt?

Prøv igjen på 429 og 5xx med eksponentiell backoff. Ikke prøv igjen på 4xx — en dårlig forespørsel fikser ikke seg selv. Unntaket er 401 hvis du roterer API-nøkler.

Q: Hva er eksponentiell backoff og hvorfor betyr det noe?

I stedet for å prøve igjen umiddelbart venter du gradvis lenger: 1s, 2s, 4s. Å legge til tilfeldig jitter (+ random.random()) hindrer at flere klienter prøver igjen i takt. Dette er en standard praksis for alle API-er med rate limits — ikke spesifikt for CometAPI.

Q: Videooppgaven sitter fast i queued i 10 minutter. Er den feilet?

Ikke nødvendigvis — køer kan bygges opp under last. Vent opp til din max_wait-terskel, kast deretter en TimeoutError og prøv igjen med en annen modell. Logg oppgave-ID-en slik at du kan sjekke status manuelt ved behov.

Q: Hvordan fanger jeg stille feil?

Stille feil krever validering på applikasjonsnivå — API-et forteller deg ikke at outputen er semantisk feil. Sjekk at outputen samsvarer med forventet format (gyldig JSON, forventet etikett, minimumslengde). Logg hele outputen når validering feiler. De vanligste årsakene er tvetydige prompter, ignorerte formatinstrukser, eller input som er for kort eller for lang for oppgaven.

Klar til å redusere AI-utviklingskostnadene med 20 %?

Kom i gang gratis på minutter. Gratis prøvekreditter inkludert. Ingen kredittkort nødvendig.

Les mer