EntrarContatoComeçar grátis
Base URL and SDK Migration27 de julho de 2026Flatkey Team

Migração do cliente OpenAI: preserve RPM, TPM e comportamento de retry

Migre um cliente no estilo OpenAI para um gateway unificado sem tempestades de retry, revisando RPM, TPM, timeouts, streaming, backoff, canaries e rollback.

Migração do cliente OpenAI: preserve RPM, TPM e comportamento de retry

Uma migração do cliente OpenAI pode parecer concluída após duas mudanças de configuração: substituir a chave de API e apontar o SDK para uma nova URL base. A primeira solicitação é bem-sucedida, a forma da resposta parece familiar e o pull request aparenta estar pronto para merge.

Isso prova compatibilidade de interface. Não prova comportamento em produção.

A parte mais difícil de uma migração do cliente OpenAI é preservar o que acontece quando o tráfego se torna irregular: as solicitações chegam em rajadas, os prompts crescem, os streams duram mais do que o esperado, um provedor retorna 429 ou uma resposta expira após o trabalho já ter começado. Se o SDK, sua aplicação e uma fila de jobs fizerem retry de forma independente, uma chamada com falha pode se transformar em várias tentativas quase simultâneas.

Este tutorial mostra como migrar uma integração existente em Python ou TypeScript no estilo OpenAI para um gateway unificado, tornando explícito o comportamento de rate limit e retry. Os exemplos usam a URL base compatível com OpenAI da Flatkey, mas o método de revisão se aplica a qualquer migração de gateway.

Resposta rápida: o que deve mudar?

Para uma migração do cliente OpenAI segura, revise estas configurações em conjunto, em vez de tratar a URL base como se fosse a mudança inteira.

Superfície da migração O que revisar Decisão inicial segura
Endpoint da API URL base e autenticação Alterar por meio de variáveis de ambiente, não por literais espalhados
Seleção de modelo Identificadores exatos de modelo e parâmetros suportados Fixar um modelo conhecido para o canary
Retries do SDK Número de retries automáticos e códigos de status com retry Escolher se o SDK ou sua aplicação será o responsável pelos retries
Retries da aplicação Backoff, jitter, limite de tentativas e orçamento de retries Manter um único responsável pelos retries e registrar cada tentativa
Controle de RPM Taxa de chegada de solicitações e tamanho dos bursts Adicionar um limite de concorrência ou fila antes do cutover
Controle de TPM Prompt mais tokens de saída esperados Testar prompts grandes realistas, não apenas um smoke test de uma linha
Timeouts Duração total da solicitação, conexão e leitura Definir valores explícitos para chamadas síncronas e em streaming
Observabilidade IDs de solicitação, tentativas, tokens, latência e resultado final Comparar logs do cliente com logs de uso do gateway

Se você precisa primeiro da explicação no nível das siglas, leia Limites de taxa de LLM explicados: RPM, TPM e retries. Este guia começa onde essa explicação termina: no diff da migração e no plano de testes em produção.

Por que trocar apenas a URL base é necessário, mas insuficiente

O quickstart da Flatkey documenta a mudança mínima no cliente: manter o padrão de requisição do SDK OpenAI e definir a URL base para https://router.flatkey.ai/v1. Ele também recomenda verificar os Usage Logs após a solicitação para que você possa confirmar o modelo, as contagens de tokens, a latência e o custo.

Esse é o smoke test correto. Uma migração do cliente OpenAI em produção precisa de quatro perguntas adicionais:

  1. O SDK faz retry automaticamente em 429, timeout ou erros de servidor?
  2. Outra camada também faz retry da mesma operação com falha?
  3. A concorrência é limitada pela taxa de requisições, taxa de tokens ou ambas?
  4. Você consegue distinguir uma operação lógica de suas tentativas individuais?

A documentação oficial dos SDKs OpenAI para Python e Node atualmente diz que falhas selecionadas são reexecutadas duas vezes por padrão, incluindo respostas 429, erros de conexão, timeouts e alguns erros de servidor. Ambos os SDKs expõem configuração de retry e timeout. Esse padrão é conveniente para uma integração direta, mas pode se tornar uma amplificação invisível quando seu próprio código já implementa backoff.

O objetivo da migração não é “desativar todo retry”. O objetivo é “saber qual camada é dona do retry”.

Etapa 1: inventarie cada camada de retry antes de mudar o código

Comece desenhando o caminho real da chamada.

ação do usuário ou job
  -> wrapper de retry da aplicação
  -> retry de entrega da fila
  -> retry do SDK OpenAI
  -> gateway
  -> provedor

Para cada camada, registre:

  • Quais erros disparam outra tentativa.
  • O número máximo de tentativas.
  • Se o atraso usa sleep fixo, backoff exponencial ou jitter.
  • Se um valor Retry-After fornecido pelo servidor é respeitado.
  • Se o mesmo identificador da operação é preservado entre as tentativas.
  • Se uma requisição com timeout é considerada falha antes de qualquer trabalho ocorrer.

A última suposição é arriscada. Um timeout no cliente apenas informa que o cliente parou de esperar. O sistema upstream ainda pode ter aceitado ou concluído a requisição. Para conteúdo gerado, um retry pode, portanto, criar outro resultado e outra requisição faturável, mesmo quando sua aplicação observou apenas uma tarefa lógica.

Estime a amplificação no pior caso

Suponha que uma fila possa entregar um job três vezes, o wrapper da aplicação permita três tentativas e o SDK faça a chamada inicial mais dois retries. No pior caso, um job lógico pode disparar:

3 entregas da fila × 3 tentativas da aplicação × 3 tentativas do SDK = 27 tentativas HTTP

Você talvez nunca atinja esse número completo, mas a multiplicação explica por que um 429 breve pode virar uma tempestade de retries. Escreva esse número na revisão da migração. Isso torna padrões ocultos visíveis.

Etapa 2: mova as configurações de endpoint para configuração

Mantenha o diff da migração reversível. Não substitua strings de endpoint em todo o codebase.

Python antes e depois

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LLM_API_KEY"],
    base_url=os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1"),
    max_retries=0,
    timeout=45.0,
)

Para o canário Flatkey, configure:

export LLM_API_KEY="$FLATKEY_API_KEY"
export LLM_BASE_URL="https://router.flatkey.ai/v1"

TypeScript antes e depois

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: process.env.LLM_BASE_URL ?? "https://api.openai.com/v1",
  maxRetries: 0,
  timeout: 45_000,
});

Esses exemplos definem as retries do SDK como zero porque a próxima seção atribui explicitamente à aplicação a responsabilidade pelas retries. Se sua aplicação não tiver uma camada de retry, você pode, em vez disso, manter retries limitadas no SDK. Não mantenha ambas por engano.

Para a checklist mais ampla de compatibilidade, veja OpenAI Compatible API Gateway: Migration Checklist for Minimal Code Changes.

Step 3: dê a uma única camada a responsabilidade explícita pelas retries

Uma política de retry útil tem cinco partes:

  1. Uma pequena lista de falhas passíveis de retry.
  2. Um limite estrito de tentativas.
  3. Um tempo total máximo de retry.
  4. Exponential backoff com jitter.
  5. Logs estruturados para cada tentativa.

Aqui está um pequeno wrapper em Python para uma chamada síncrona de chat:

import random
import time
from openai import APITimeoutError, APIConnectionError, APIStatusError, RateLimitError

RETRYABLE_STATUS_CODES = {408, 409, 429, 500, 502, 503, 504}


def create_chat_with_retry(client, *, model, messages, max_attempts=4):
    started_at = time.monotonic()

    for attempt in range(1, max_attempts + 1):
        try:
            return client.chat.completions.create(
                model=model,
                messages=messages,
            )
        except (RateLimitError, APITimeoutError, APIConnectionError) as error:
            retryable = True
            caught_error = error
        except APIStatusError as error:
            retryable = error.status_code in RETRYABLE_STATUS_CODES
            caught_error = error

        if not retryable or attempt == max_attempts:
            raise caught_error

        exponential_delay = min(2 ** (attempt - 1), 16)
        jitter = random.uniform(0, 0.5 * exponential_delay)
        sleep_seconds = exponential_delay + jitter

        print({
            "event": "llm_retry",
            "attempt": attempt,
            "next_delay_seconds": round(sleep_seconds, 2),
            "elapsed_seconds": round(time.monotonic() - started_at, 2),
            "error_type": type(caught_error).__name__,
        })
        time.sleep(sleep_seconds)

    raise RuntimeError("unreachable")

Trate isto como um ponto de partida revisável, não como uma política universal. Em produção, faça o parse e respeite um cabeçalho de resposta Retry-After válido antes de cair de volta para um atraso calculado localmente. Adicione um orçamento de tempo total decorrido para que as retries não excedam a latência que seu produto pode tolerar.

Não faça retry de todo erro

Failure Default action Why
400 invalid request Do not retry unchanged The payload must change
401 authentication Do not retry unchanged The key or header must change
404 model not found Do not retry unchanged The model identifier or access must change
429 rate limit Retry with delay and jitter Capacity may become available
500 or 503 Retry within a small budget The failure may be temporary
Client timeout Retry cautiously The upstream request may already have executed

O quickstart da Flatkey dá a mesma orientação de alto nível para 429: tente novamente com backoff exponencial e jitter. A adição específica da migração é garantir que apenas uma camada aplique essa política.

Passo 4: dimensione a concorrência para RPM e TPM

Uma migração do cliente OpenAI pode preservar a sintaxe das requisições enquanto altera a capacidade disponível. RPM e TPM restringem cargas de trabalho diferentes:

  • RPM torna-se o gargalo quando você envia muitas requisições pequenas.
  • TPM torna-se o gargalo quando prompts, saídas ou avaliações paralelas são grandes.

Use o tráfego observado em vez de uma única média. Colete pelo menos:

  • Requisições por minuto na mediana e no pico.
  • Tokens de entrada no p50, p95 e máximo.
  • Tokens de saída no p50 e p95.
  • Duração mediana e p95 da requisição.
  • Número de streams concorrentes.

Um teto aproximado de concorrência pode ser estimado a partir de cada limite:

Concorrência baseada em RPM ≈ (RPM / 60) × segundos médios por requisição

Concorrência baseada em TPM ≈ (TPM / tokens médios por requisição / 60)
                        × segundos médios por requisição

Use o menor resultado como teto inicial e depois deixe margem para picos e retries.

Exemplo: suponha que uma rota permita 600 RPM e 300.000 TPM, que a requisição média use 1.500 tokens no total e que a duração média seja de 3 segundos.

Teto por RPM: (600 / 60) × 3 = 30 requisições concorrentes
Teto por TPM: (300,000 / 1,500 / 60) × 3 = 10 requisições concorrentes

TPM é a restrição mais apertada neste exemplo. Começar com 30 requisições concorrentes porque o RPM parecia generoso criaria respostas 429 evitáveis.

Este cálculo é direcional, não uma garantia do provedor. Os provedores podem usar janelas deslizantes, token buckets, limites separados para tokens de entrada e saída, pools específicos por modelo ou controles de aceleração. O plano de testes deve verificar o comportamento real para o modelo e a conta selecionados.

Passo 5: teste separadamente o comportamento de streaming e timeout

Não trate uma chamada bem-sucedida sem streaming como prova de que o streaming é seguro.

Para requisições em streaming, teste:

  • Tempo até o primeiro token.
  • Intervalo máximo de silêncio entre chunks.
  • Timeout de leitura do cliente.
  • Comportamento quando o consumidor se desconecta.
  • Se o seu wrapper de retry pode iniciar acidentalmente um segundo stream.
  • Se a saída parcial é retida, descartada ou exibida ao usuário.

Um stream que falha após saída parcial não é equivalente a uma requisição que falhou antes de qualquer saída. Tentar novamente automaticamente pode mostrar texto duplicado ou produzir uma continuação diferente. Decida se o produto deve tentar novamente, perguntar ao usuário ou exibir o resultado parcial.

Lembre-se também de que timeouts do SDK e timeouts da infraestrutura podem ser diferentes. Um proxy reverso, uma plataforma serverless, um worker de jobs ou uma conexão do navegador podem encerrar antes que a biblioteca cliente atinja seu próprio timeout. Durante a migração do cliente OpenAI, registre o menor timeout no caminho completo da requisição.

Passo 6: execute uma matriz de canary antes do tráfego amplo

Use um único modelo fixado e uma pequena porcentagem do tráfego. O primeiro canary deve responder se a nova rota preserva o comportamento, e não se todos os modelos funcionam.

Caso de teste Entrada Evidência esperada
Autenticação Chaves válidas e inválidas Sucesso mais um 401 sem retry
Validação de modelo IDs de modelo válidos e com erro de digitação Sucesso mais um erro de modelo sem retry
Rajada pequena de requisições Muitos prompts curtos Enfileiramento controlado sem um pico de retries
Rajada de prompts grandes Menos prompts com alto volume de tokens A pressão de TPM fica visível e limitada
429 forçado Exceda temporariamente o limite do canary Um único responsável pelo retry, atrasos com jitter, tentativas limitadas
Timeout forçado Defina um timeout de cliente intencionalmente curto Timeout registrado sem replay ilimitado
Interrupção de streaming Desconectar durante um stream Comportamento explícito de saída parcial
Erro de servidor Injetar ou simular 503 Retries limitados e relatório final de erro
Rollback Restaurar a base URL anterior Rollback apenas de configuração funciona

Para cada operação lógica, registre:

operation_id
attempt_number
base_url_name
model_requested
http_status
input_tokens
output_tokens
latency_ms
retry_delay_ms
final_outcome

Depois compare os logs da aplicação com os Flatkey Usage Logs. As contagens devem fazer sentido em conjunto. Se uma operação da aplicação mapear para várias requisições do gateway, sua instrumentação de retry deve explicar o motivo.

Etapa 7: defina limites de rollout e rollback

Uma migração do cliente OpenAI deve ter condições numéricas de parada antes do início do primeiro canary.

Exemplos de limites:

  • Faça rollback se a taxa final de erro aumentar mais do que um ponto percentual acordado.
  • Pare se as tentativas por operação excederem o orçamento esperado de retries.
  • Pare se a latência p95 exceder o orçamento de timeout do produto.
  • Pare se o uso de tokens por operação bem-sucedida mudar inesperadamente.
  • Expanda o tráfego somente depois que os caminhos com e sem streaming passarem nos testes.

Evite comparar apenas contagens brutas de 429. Uma boa fila pode reduzir erros finais enquanto aumenta temporariamente requisições adiadas. Acompanhe tanto os resultados no nível de tentativa quanto no nível de operação.

Checklist do pull request de migração

Copie esta checklist para o PR de implementação.

  • A base URL e a chave vêm de variáveis de ambiente.
  • O canary usa um identificador de modelo exato e verificado.
  • Uma camada é a dona dos retries.
  • Os padrões de retry do SDK estão documentados no PR.
  • O comportamento de 429, timeout e 5xx tem tentativas limitadas.
  • O backoff inclui jitter e respeita Retry-After quando presente.
  • Os limites de RPM e TPM são estimados com base no tráfego observado.
  • O streaming tem um teste de falha separado.
  • Cada tentativa compartilha um único operation_id lógico.
  • Os logs de uso e os logs da aplicação são comparados.
  • Os limites de rollout e rollback são definidos antes do lançamento.
  • O endpoint anterior pode ser restaurado sem outra mudança de código.

Erros comuns de migração

Manter retries do SDK e retries da aplicação sem calcular o total

Esta é a descoberta de revisão mais importante. Os padrões continuam sendo comportamento, mesmo quando não estão visíveis na função local.

Testar apenas um prompt minúsculo

Uma solicitação de uma linha comprova credenciais e compatibilidade de resposta. Ela diz quase nada sobre pressão de TPM, limites de saída, streams longos ou latência p95.

Tentar novamente erros de autenticação e validação

Backoff não consegue corrigir uma chave inválida, um parâmetro sem suporte ou um modelo digitado incorretamente. Repetir payloads inalterados desperdiça capacidade e esconde o defeito real.

Tratar um timeout como prova de que nenhuma requisição foi executada

O cliente pode parar de esperar depois que o upstream aceitou a chamada. Projete retries e contabilização com essa ambiguidade em mente.

Alterar endpoint, modelos, prompts e política de retry em uma única release

Isso torna difícil atribuir as falhas. Migre primeiro uma forma de requisição já conhecida e, depois, amplie a escolha de modelo quando a rota estiver observável.

Uma definição mais segura de “compatível com OpenAI”

Para o planejamento de migração, “compatível com OpenAI” deve significar que o padrão de interação é suficientemente familiar para reduzir mudanças de código. Não deve ser interpretado como uma promessa de que todo provedor compartilha cotas idênticas, contagem de tokens, semântica de erro, latência, comportamento de streaming ou suporte a parâmetros.

Essa distinção torna uma migração do cliente OpenAI mais fácil de revisar. Mantenha a interface estável onde isso ajudar, mas teste o contrato operacional onde provedores e rotas podem diferir.

A Flatkey centraliza acesso e cobrança atrás de uma única URL base compatível com OpenAI, o que pode simplificar o diff do cliente e a expansão futura de modelos. O trabalho de engenharia ainda é tornar retries, throughput e observabilidade explícitos antes que o tráfego de produção seja movido.

Esse é o padrão que uma migração do cliente OpenAI em produção deve atender: uma pequena mudança de interface sustentada por evidência operacional explícita.

Revise a página de preços da Flatkey ao selecionar os modelos para o seu canary e, então, aprove a migração somente depois que a checklist passar na revisão de código e o comportamento da rota estiver visível nos logs.

Perguntas frequentes

Devo desativar os retries do SDK da OpenAI durante a migração?

Desative-os se sua aplicação ou fila já for responsável pelos retries. Se nenhuma outra camada tentar novamente, retries limitados do SDK podem ser razoáveis. A regra importante é evitar múltiplos responsáveis independentes por retry.

Qual é a diferença entre RPM e TPM durante uma migração?

RPM limita a frequência de requisições, enquanto TPM limita o throughput de tokens. Chamadas pequenas e de alta frequência podem atingir primeiro o RPM; menos prompts ou saídas grandes podem atingir primeiro o TPM. Teste ambos os formatos de carga.

Um 429 deve sempre ser tentado novamente?

Somente dentro de um orçamento limitado de retries e de latência. Respeite Retry-After quando disponível; caso contrário, use backoff exponencial com jitter. Pare se a operação não puder mais cumprir o objetivo de latência do produto.

Posso repetir com segurança uma geração que expirou por timeout?

Não com certeza. A requisição upstream pode ter sido executada mesmo que o cliente tenha expirado por timeout. Trate o retry como uma possível requisição duplicada e registre a relação entre as tentativas.

Qual é o canary mínimo seguro?

Use um único modelo fixado, uma única forma de solicitação, propriedade explícita das tentativas de retry, um limite de concorrência e testes para 429, timeout, interrupção de streaming e rollback. Compare as tentativas no lado do cliente com os logs de uso do gateway antes de expandir o tráfego.

Sources