API e SDKGuia
Timeout e tentativas do SDK Python da OpenAI: defina-os para a CheapTokens
Defina timeout, max_retries e max_tokens no SDK Python da OpenAI, capture os erros certos e evite que uma requisição travada rode por 10 minutos.

Nesta página
Seu script chamou o modelo, nada voltou e, dez minutos depois, ele ainda está esperando. Esse é o padrão do SDK Python da OpenAI: um timeout de 10 minutos e 2 tentativas. Para mudar isso, passe timeout=30.0 e max_retries=2 para OpenAI(...), sobrescreva-os por chamada com client. e limite a resposta com max_tokens.
O README do SDK (verificado em 27 de outubro de 2026) documenta tudo isso. Abaixo, ele é aplicado ao endpoint da CheapTokens, https:/, que fala o formato OpenAI Chat Completions. Os detalhes dessa configuração estão em Sua primeira requisição de API com a CheapTokens e na documentação.
O que o SDK faz quando você não define nada#
Dois padrões importam. O timeout é de 10 minutos. As tentativas são 2, com um breve backoff exponencial, para erros de conexão e para respostas 408, 409, 429 e 5xx, e apenas quando o corpo da requisição pode ser reenviado com segurança. Uma requisição que atinge o timeout também é repetida.
Assim, cada tentativa tem seu próprio timeout, e o pior caso é aproximadamente o timeout multiplicado pelo número de tentativas, mais as pausas entre elas:
- padrão: 600 × 3 = 1800 segundos, meia hora
timeout=30.0,max_retries=2: 30 × 3 = 90 segundos
Digamos que um endpoint web precise responder em 30 segundos. Com os padrões, ele pode travar por meia hora antes que seu código veja um erro. Teste em outra configuração antes de continuar a leitura.
Adivinhar o número
Um cliente tem timeout=45.0 e max_retries=3. Qual é a espera no pior caso, em segundos, antes da exceção, sem contar as pausas entre tentativas?
O seu palpite
0400
Mostrar resposta
Resposta: 180
45 × (3 tentativas + 1 primeira tentativa) = 180 segundos; as pausas entre tentativas adicionam um pouco a mais.
Defina timeout e max_retries no cliente#
A correção mais simples é definir ambos de uma vez, ao criar o cliente:
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 deve ser um inteiro não negativo. timeout aceita um float, ou um objeto httpx Timeout se você quiser limites separados para conexão e leitura. O README do branch main atual importa httpx2 para isso, versões mais antigas usavam httpx, então execute pip show openai e verifique qual deles sua instalação usa. Um float simples não precisa de import e funciona de qualquer forma.

Use o id completo do modelo da documentação da CheapTokens, deepseek- aqui: os ids diferem entre provedores. Este modelo aceita até 32.768 tokens de saída por resposta e tem um contexto de 380K, e é por isso que a linha max_tokens acima está lá de propósito. Mais sobre isso abaixo, e sobre o modelo em DeepSeek barato.
Sobrescreva para uma requisição#
Um cliente, trabalhos diferentes. Uma resposta de chat deve desistir rápido, um resumo noturno pode esperar. Em vez de criar um segundo cliente, derive um para a chamada:
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 retorna uma cópia com os novos valores e deixa client intacto. Definir max_retries=0 é a escolha certa quando seu próprio código já repete tentativas, por exemplo uma fila de tarefas que reenfileira a tarefa. Caso contrário, as duas camadas se multiplicam: 3 tentativas do SDK dentro de 3 tentativas da fila são 9 requisições para uma tarefa.
Capture os erros que importam#
Depois que as tentativas se esgotam, o SDK lança uma exceção. Toda classe de erro herda de openai.APIError, e requisições com falha carregam request_id, que é o que você registra:
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 NoneA ordem vai do mais específico ao mais amplo. APIStatusError cobre qualquer resposta 4xx ou 5xx, então, se viesse primeiro, engoliria RateLimitError. A mesma ideia vale para o timeout: ele fica acima do erro de conexão geral. Em um script em lote, return None é o ponto central: registre o prompt, passe para o próximo e reexecute as falhas no final.
Quando o timeout dispara e as tentativas se esgotam, é assim que a exceção se parece:

Para o caso 429 em detalhe, incluindo a espera entre tentativas, veja 429 Too Many Requests de uma API de IA.
Limite max_tokens para que uma resposta longa não fuja#
Um timeout para de esperar. Ele não faz o modelo escrever menos. Sem max_tokens, um modelo com limite de 32.768 tokens de resposta fica livre para escrever uma resposta muito longa, e uma resposta longa é lenta. Defina um limite que caiba no trabalho: 800 para um resumo de ticket, 5 para um sim/não.
O custo é que uma resposta pode ser cortada. Verifique resp.: length significa que o limite foi atingido antes de o modelo terminar. Por que uma resposta de IA para no meio da frase? cobre isso. Se você transmitir a resposta em vez disso, as primeiras palavras chegam cedo e a espera parece mais curta, veja Respostas em streaming em Python.
O que as tentativas fazem com a conta#
Uma nova tentativa é uma nova requisição. Se uma tentativa foi processada, é uma requisição separada com seus próprios tokens. Digamos que um resumo de ticket tenha 1.500 tokens de entrada e 400 de saída: uma requisição custa $0.000063 nos preços de hoje, e a tabela de preços completa tem os outros modelos. Os preços são fixos por modelo, sem horário de pico, então uma nova tentativa às 3 da manhã custa o mesmo que uma ao meio-dia.
Mova os controles para o seu próprio lote:
Calculadora de custos
Um lote de 1.000 resumos de tickets
Tokens de entrada por solicitação: 1.500 · Tokens de saída por solicitação: 400 · Solicitações por dia: 1.000
| Modelo | Por dia | Por mês |
|---|---|---|
| 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 |
A tabela mostra uma passada. Se um décimo do lote precisar de uma segunda tentativa, adicione um décimo. As tentativas são um seguro barato quando as falhas são raras, e um hábito caro quando você define max_retries=10 contra um endpoint que continua falhando.
Antes de publicar#
Lista de verificação
Timeouts e tentativas, prontos para produção



