API та SDKПосібник
Тайм-аут і повторні спроби OpenAI Python SDK: налаштуйте їх для CheapTokens
Налаштуйте timeout, max_retries і max_tokens в OpenAI Python SDK, перехоплюйте правильні помилки та не дозволяйте завислому запиту виконуватися 10 хвилин.

На цій сторінці
Ваш скрипт викликав модель, нічого не повернулося, і через десять хвилин він усе ще чекає. Це стандартна поведінка OpenAI Python SDK: 10-хвилинний тайм-аут і 2 повторні спроби. Щоб це змінити, передайте timeout=30.0 і max_retries=2 у OpenAI(...), перевизначте їх для окремого виклику за допомогою client. і обмежте відповідь через max_tokens.
README SDK (перевірено 27 жовтня 2026 року) документує все це. Нижче це застосовано до ендпоінта CheapTokens, https:/, який підтримує формат OpenAI Chat Completions. Деталі цього налаштування наведено в Ваш перший API-запит із CheapTokens та в документації.
Що робить SDK, коли ви нічого не налаштовуєте#
Важливі два значення за замовчуванням. Тайм-аут становить 10 хвилин. Кількість повторних спроб — 2, з коротким експоненційним відступом, для помилок з'єднання та для відповідей 408, 409, 429 і 5xx, і лише коли тіло запиту можна безпечно надіслати повторно. Запит, який завершився тайм-аутом, також повторюється.
Отже, кожна спроба отримує власний тайм-аут, а найгірший випадок — це приблизно тайм-аут, помножений на кількість спроб, плюс паузи між ними:
- за замовчуванням: 600 × 3 = 1800 секунд, пів години
timeout=30.0,max_retries=2: 30 × 3 = 90 секунд
Скажімо, веб-ендпоінт має відповісти протягом 30 секунд. Зі стандартними налаштуваннями він може зависнути на пів години, перш ніж ваш код побачить помилку. Спробуйте на іншому налаштуванні, перш ніж читати далі.
Вгадайте число
Клієнт має timeout=45.0 і max_retries=3. Який найгірший час очікування в секундах до винятку, не враховуючи паузи між спробами?
Ваше припущення
0400
Показати відповідь
Відповідь: 180
45 × (3 повторні спроби + 1 перша спроба) = 180 секунд; паузи між спробами додають трохи зверху.
Налаштуйте timeout і max_retries на клієнті#
Найпростіше виправлення — встановити обидва значення один раз, під час створення клієнта:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.cheaptokens.dev/v1",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
timeout=30.0, # seconds per attempt
max_retries=2, # 0 turns retries off
)
resp = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": "Summarize this ticket in two sentences: ..."}],
max_tokens=800,
)
print(resp.choices[0].message.content)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)max_retries має бути невід'ємним цілим числом. timeout приймає float або об'єкт httpx Timeout, якщо ви хочете окремі ліміти для з'єднання та читання. README поточної гілки main імпортує httpx2 для цього, старіші версії використовували httpx, тому виконайте pip show openai і перевірте, який із них використовує ваша інсталяція. Звичайний float не потребує імпорту і працює в будь-якому разі.

Використовуйте повний ідентифікатор моделі з документації CheapTokens, тут deepseek-: ідентифікатори відрізняються між провайдерами. Ця модель приймає до 32 768 вихідних токенів на відповідь і має контекст 380K, саме тому рядок max_tokens вище стоїть навмисно. Детальніше про це нижче, а про модель — у cheap DeepSeek.
Перевизначте це для одного запиту#
Один клієнт, різні завдання. Відповідь у чаті має здатися швидко, нічний підсумок може зачекати. Замість створення другого клієнта, отримайте похідний для виклику:
quick = client.with_options(timeout=5.0, max_retries=0)
resp = quick.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": "Reply with one word: ok"}],
max_tokens=5,
)with_options повертає копію з новими значеннями і залишає client без змін. Встановлення max_retries=0 — правильний крок, коли ваш власний код уже виконує повторні спроби, наприклад, черга завдань, яка повторно ставить завдання в чергу. Інакше два шари множаться: 3 спроби SDK всередині 3 спроб черги — це 9 запитів для одного завдання.
Перехоплюйте помилки, які мають значення#
Після вичерпання повторних спроб SDK викликає виняток. Кожен клас помилки успадковується від openai.APIError, а невдалі запити містять request_id, який ви й логуєте:
import openai
def ask(prompt: str) -> str | None:
try:
r = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": prompt}],
max_tokens=800,
)
return r.choices[0].message.content
except openai.APITimeoutError:
print("timed out after retries")
except openai.RateLimitError as e:
print("429, slow down:", e.request_id)
except openai.APIConnectionError:
print("cannot reach the API")
except openai.APIStatusError as e:
print("HTTP", e.status_code, e.request_id)
return NoneПорядок — від вузького до широкого. APIStatusError охоплює будь-яку відповідь 4xx або 5xx, тож якби він стояв першим, він би поглинув RateLimitError. Те саме стосується тайм-ауту: він стоїть вище за загальну помилку з'єднання. У пакетному скрипті return None — це вся суть: залогувати запит, перейти до наступного і повторно запустити невдалі в кінці.
Коли спрацьовує тайм-аут і повторні спроби вичерпано, ось як виглядає виняток:

Детальніше про випадок 429, включно з очікуванням між спробами, дивіться в 429 Too Many Requests від AI API.
Обмежте max_tokens, щоб довга відповідь не вийшла з-під контролю#
Тайм-аут припиняє очікування. Він не змушує модель писати менше. Без max_tokens модель із лімітом відповіді 32 768 токенів може написати дуже довгу відповідь, а довга відповідь — повільна. Встановіть ліміт, який відповідає завданню: 800 для підсумку тікета, 5 для так/ні.
Ціна цього — відповідь може обірватися. Перевірте resp.: length означає, що ліміт спрацював до того, як модель завершила. Чому відповідь AI обривається на півслові? розповідає про це. Якщо ви натомість стрімите відповідь, перші слова з'являються рано, і очікування здається коротшим, дивіться Стрімінгові відповіді в Python.
Що повторні спроби роблять із рахунком#
Повторна спроба — це новий запит. Якщо спробу було оброблено, це окремий запит із власними токенами. Скажімо, підсумок тікета — це 1500 токенів на вході та 400 на виході: один запит коштує $0.000063 за сьогоднішніми цінами, а повна таблиця цін містить інші моделі. Ціни фіксовані для кожної моделі, без пікових годин, тож повторна спроба о 3 годині ночі коштує стільки ж, як і опівдні.
Пересуньте повзунки під власний пакет:
Калькулятор вартості
Пакет із 1000 підсумків тікетів
Вхідні токени на запит: 1 500 · Вихідні токени на запит: 400 · Запитів на день: 1 000
| Модель | За день | За місяць |
|---|---|---|
| GLM-5.3-Flash$0.02$0.04 | $0.046 | $1.38 |
| DeepSeek-V4-Flash$0.015$0.10 | $0.0625 | $1.88 |
| MiniMax-M2.7$0.05$0.15 | $0.135 | $4.05 |
Таблиця показує один прохід. Якщо десята частина пакета потребує другої спроби, додайте десяту частину. Повторні спроби — дешева страховка, коли збої рідкісні, і дорога звичка, коли ви встановлюєте max_retries=10 проти ендпоінта, який постійно збоїть.
Перед релізом#
Чек-лист
Тайм-аути та повторні спроби, готові до продакшену



