AI API істен шығулары кәдімгі API істен шығуларынан өзгеше. 200 жауабы генерацияның сәтті өткенін білдірмейді. null content өрісі әрдайым қате емес. Кеше жұмыс істеген дәл сол prompt бүгін провайдердің контент саясаты жаңарғандықтан сәтсіз болуы мүмкін.
Бұл нұсқаулық AI API қателерін қалай оқу керегін, әрбір істен шығу режимінің нені білдіретінін және “бірдеңе бұзылды” деп қана айтпай, нақты қай жерде бұзылғанын көрсететін қате өңдеуді қалай құруды қамтиды.
Note: Бұл мақалада қолданылған gpt-5.4 және gpt-5.4-mini сияқты модель атаулары CometAPI платформасының идентификаторлары. Олар тек https://api.cometapi.com/v1 арқылы жұмыс істейді — OpenAI немесе Anthropic API-лары арқылы тікелей емес. Толық модель тізімін қараңыз.
Неліктен AI API диагностикасы кәдімгі API-ға қарағанда қиынырақ
Әдеттегі REST API-де 200 — сәтті, ал 4xx — сіздің қатеңіз. AI API-ларда үшінші санат бар: жұмсақ сәтсіздіктер — 200 қайтарады, бірақ қолдануға болатын мазмұн жоқ.
Үш нәрсе қате кетуі мүмкін:
- Қатаң сәтсіздік — HTTP қатесі (4xx, 5xx). Сұраныс аяқталмады.
- Жұмсақ сәтсіздік — HTTP 200, бірақ
finish_reasoncontent_filterнемесеlength, неcontentnull. - Үнсіз сәтсіздік — HTTP 200, контент қалыпты сияқты, бірақ нәтиже қолданба деңгейінде ғана байқалатын түрде қате.
Қате өңдеудің көпшілігі тек 1-жағдайды қамтиды. Нақты өндірістік ақаулардың көбі 2 және 3-жағдайларда болады.
Қате жауап форматын түсіну
Text completions endpoint-і тұрақты қате құрылымын қайтарады:
{ "error": { "message": "human-readable description (often includes request id)", "type": "comet_api_error", "param": "the_problematic_parameter_or_null", "code": "error_code_or_null" }}
Сурет және видео endpoint-тері басқа қате форматтарын қайтарады — endpoint-тер арасында тұрақты құрылымға сүйенбей, әрқашан бастапқы жауап денесін талдаңыз.
message өрісі әдетте нақты не қате екенін айтады. param өрісі қандай параметр себеп болғанын көрсетеді. Екеуін де әрқашан логтаңыз.
Әрбір HTTP мәртебе кодын нені білдіретінін біліңіз
| Status | Мағына | Жиі себеп | Шешім |
|---|---|---|---|
| 400 | Bad request | Модель жоқ, осы модельге тән емес параметр | Жауаптағы error.param-ды тексеріңіз |
| 401 | Unauthorized | API кілті қате немесе жоқ | Authorization: Bearer |
| 429 | Rate limited | Өте көп сұраныстар | Экспоненциалды backoff (4-қадамды қараңыз) |
| 500 | Server error | Провайдер жағындағы мәселе немесе қате дене | Backoff-пен қайталап көріңіз; форматты тексеріңіз |
| 504 | Gateway timeout | Провайдер тым ұзақ жауап берді | Қайта көріңіз; жылдамырақ модельді қарастырыңыз |
Source**: CometAPI chat completions docs
400 мен 500 айырмашылығы retry логикасы үшін маңызды. 400 — сіздің сұранысыңыз қате — дәл сол сұранысты қайталау көмектеспейді. 500 немесе 504 — сервер жағындағы мәселе — қайталап көру орынды.
Ең көп еленбейтін өріс — finish_reason-ды тексеріңіз
finish_reason: "content_filter" бар 200 жауабы генерацияның бұғатталғанын білдіреді. content өрісі null немесе бос болады. Мұны тексермесеңіз, қолданбаңыз үн-түнсіз ештеңе қайтаруы мүмкін.
| finish_reason | Мағына | Не істеу керек | Шешім |
|---|---|---|---|
| stop | Қалыпты аяқталу | Ештеңе — бұл сәтті аяқталу | Жауаптағы error.param-ды тексеріңіз |
| length | Токен шегіне жетті | max_tokens-ты ұлғайтыңыз немесе prompt-ты қысқартыңыз | Authorization: Bearer |
| content_filter | Қауіпсіздік саясаты бұғаттады | Prompt-ты қайта тұжырымдаңыз; нақты есім/тақырыптардан аулақ болыңыз | Экспоненциалды backoff (4-қадам) |
| tool_calls | Модель мәтін орнына құралды шақырды | Құрал шақыруын өңдеңіз; content null болады | Backoff-пен қайталап көріңіз; форматты тексеріңіз |
| 504 | Gateway timeout | Провайдер тым ұзақ жауап берді | Қайта көріңіз; жылдамырақ модельді қарастырыңыз |
Source**: CometAPI chat completions docs
import osimport loggingfrom openai import OpenAI, APIStatusError, APIConnectionError, APITimeoutErrorfrom dotenv import load_dotenvload_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"])
Үнсіз сәтсіздіктерді қолданба деңгейінде анықтаңыз
Үнсіз сәтсіздіктерді ұстау ең қиын. API 200 қайтарады, finish_reason — stop, бірақ нәтиже семантикалық тұрғыдан қате. Мұны тек қолданба деңгейінде ғана анықтауға болады.
Жиі үлгілер:
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")
Үнсіз сәтсіздіктер әдетте үш себептің бірінен болады: prompt екіұшты, модель формат нұсқауларын елемеді немесе енгізу тапсырма үшін тым қысқа/ұзын болды. Валидтеу сәтсіз болғанда толық output-ты логтау қай себеп екенін анықтаудың ең жылдам жолы.
Rate limit үшін экспоненциалды backoff қосыңыз
Rate limit қателері (429) уақытша. Дұрыс әрекет — кідірістерді біртіндеп ұзартып, қайта әрекет ету — rate limit бар кез келген API үшін стандартты тәжірибе:
import timeimport randomfrom openai import RateLimitErrordef 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
400 немесе 401 үшін қайталамаңыз — бұл клиент қателері, өздігінен шешілмейді.
Сурет генерациясы ақауларын түзету
Сурет генерациясында стандартты HTTP қателеріне қоса, өзінің сәтсіздік режимдері бар:
import base64import requestsdef 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 }
Суретке тән мәселелер:
| Белгі | Себеп | Шешім |
|---|---|---|
| Бос data массиві | Prompt сүзгіден өтті | revised_prompt-ты тексеріңіз; қайта жазыңыз |
| GPT Image 2-де response_format қатесі | Параметр қолдау таппайды | Оның орнына output_format қолданыңыз |
| Qwen Image-те n > 1 қатесі | Модель шектеуі | Циклмен жеке сұраныстар жіберіңіз |
| URL кейінірек 403 қайтарады | URL мерзімі өтті | Генерациядан кейін бірден жүктеңіз |
Source**: CometAPI image generation docs
Видео генерациясы ақауларын түзету
Видео генерациясы асинхронды болғандықтан, басқаша сәтсіздікке ұшырайды. Таймаут хабарламасы әрдайым дұрыс қалыптасуы үшін циклге дейін статус айнымалыларын инициализациялаңыз:
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}%" )
Видеге тән мәселелер:
| Белгі | Себеп | Шешім |
|---|---|---|
| Тапсырма 10+ минут бойы queued күйінде | Сервер жүктемесі | Басқа модельмен қайталап көріңіз |
| failed және error detail жоқ | Prompt сүзгіден өтті немесе модель қатесі | Prompt-ты қайта жазыңыз |
| Видео URL 403 қайтарады | URL мерзімі өтті | Дереу жүктеп алыңыз |
| Runway бірінші polling-де task_not_exist | Тапсырма әлі инициализацияда (CometAPI құжатталған) | 5с күтіп, қайталаңыз |
| Kling "succeed", ал басқалары "succeeded" | Kling API стандарттан тыс статус жолын қолданады | Polling логикасында екеуін де өңдеңіз |
Source**: CometAPI video generation docs**, Kling Video docs
Node.js нұсқасы
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);}
Ақауды түзетуге арналған чек-парақ
Генерация сәтсіз болып, неден бастарыңызды білмесеңіз:
Text generation үшін:
- API кілті орнатылған ба және
Authorization: Bearer <key>форматында ма? finish_reasonstopемес пе?contentnull ма?finish_reasontool_callsекенін тексеріңіз- Шығыс қысқарып қалды ма?
finish_reason: "length"жәнеusage.completion_tokens-ты тексеріңіз - Қате — 4xx (сұранысты түзету) әлде 5xx (қайта көру)?
- Нәтиже қолданба деңгейіндегі валидациядан өтті ме? (үнсіз сәтсіздік)
Image generation үшін:
dataмассиві бос па? (контент сүзгісі)- GPT Image 2-де
response_formatқолдандыңыз ба? (қолдау жоқ —output_formatқолданыңыз) - Qwen Image-те
n > 1қойдыңыз ба? (қолдау жоқ) - URL мерзімі өтпей тұрып суретті жүктеп алдыңыз ба?
Video generation үшін:
- Тапсырма
queuedкүйінде тұрып қалды ма? (басқа модельді көріңіз) - Сәтсіз тапсырма жауаптан
errorөрісін тексердіңіз бе? - URL мерзімі өтпей тұрып видеоны жүктеп алдыңыз ба?
"succeed"(Kling) және"succeeded"(Veo, Runway) екеуін де өңдеп жатырсыз ба?
Жиі қойылатын сұрақтар
Q: Сұраныс 200 қайтарады, бірақ контент жоқ. Не болды?
finish_reason-ды тексеріңіз. Егер content_filter болса, генерация бұғатталды — сұраныс сәтті өтті, бірақ шығыс басылды. Егер tool_calls болса, модель мәтін орнына құралды шақырды және content әдейі null. Егер finish_reason stop, бірақ контент әлі де бос болса — бұл үнсіз сәтсіздік — толық жауапты логтап, prompt-ты тексеріңіз.
Q: Prompt-ым сүзгіден өтіп жатқанын қалай білемін?
Мәтін үшін: finish_reason === "content_filter" екеніне қараңыз. Суреттер үшін: data массиві бос па, тексеріңіз. Видео үшін: жібергеннен көп ұзамай failed күйіне түсіп, error detail бермесе, ықтимал сүзгі. Барлық жағдайда prompt-ты бейтарап етіп қайта жазыңыз.
Q: Қашан сәтсіз сұранысты қайта көру керек?
429 және 5xx үшін экспоненциалды backoff-пен қайталаңыз. 4xx үшін қайталамаңыз — қате сұраныс өздігінен түзелмейді. Ерекше жағдай — 401, егер API кілттерін ауыстырып жатсаңыз.
Q: Экспоненциалды backoff деген не және неге маңызды?
Дереу қайталамай, кідірісті біртіндеп ұзартасыз: 1с, 2с, 4с. Кездейсоқ jitter (+ random.random()) бірнеше клиенттің бір сәтте қайталап жіберуін болдырмайды. Бұл кез келген rate limit бар API үшін стандартты тәжірибе — CometAPI-ға ғана тән емес.
Q: Видео тапсырма queued күйінде 10 минут тұр. Бұл сәтсіздік пе?
Әрқашан емес — жүктеме кезінде кезек ұзауы мүмкін. Өз max_wait шегіңізге дейін күтіңіз, содан кейін TimeoutError тастап, басқа модельмен қайталап көріңіз. Қолмен тексеру үшін task ID-ны логтаңыз.
Q: Үнсіз сәтсіздіктерді қалай ұстауға болады?
Үнсіз сәтсіздіктер үшін қолданба деңгейінде валидация қажет — API шығудың семантикалық тұрғыдан дұрыс еместігін айтпайды. Шығыс күтілетін форматқа сай ма (валид JSON, күтілетін белгі, минималды ұзындық) тексеріңіз. Валидация сәтсіз болса, толық шығуды логтаңыз. Ең жиі себептер: екіұшты prompt, формат нұсқауларын елемеу немесе тапсырмаға сай емес өте қысқа/ұзын енгізу.
