PT ▾

SDK Python OpenAI com base_url personalizado: configuração e correções

Um cabo foi movido de um soquete de servidor para outro, mostrando uma mudança de URL base para um SDK

Os SDKs da OpenAI permitem que você substitua o endpoint com um único argumento. Esta página mostra a configuração exata do SDK Python OpenAI com base_url personalizado para esta API, além da equivalente em Node, streaming e os erros que causam a maioria das primeiras chamadas falhas.

Última atualização

Resumo

  • Defina base_url para https://api.apicompatible.com/v1 e passe sua chave como api_key; nada mais no seu código precisa mudar.
  • O id do modelo é uncensored. Deixar um nome de modelo antigo no lugar é a causa mais comum de falha na primeira chamada.
  • O streaming funciona com stream=True, e cada requisição transmitida ocupa um dos seus slots concorrentes até que termine.
  • Variáveis de ambiente permitem que você altere endpoints sem tocar no código.

A resposta curta

Crie o cliente com dois argumentos, base_url e api_key, e continue usando os mesmos métodos que você já conhece. A URL base para esta API é https://api.apicompatible.com/v1, o id do modelo é uncensored, e a autenticação é um token bearer padrão que o SDK constrói a partir da sua chave.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.apicompatible.com/v1",
    api_key="YOUR_API_KEY",
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "Name three uses for a hash map."},
    ],
)

print(resp.choices[0].message.content)
print(resp.usage)

Essa é a alteração completa. O SDK anexa /chat/completions à URL base, então a requisição vai para POST /v1/chat/completions. Se você ainda não tem uma chave, a página da chave de API explica o cadastro e o crédito de teste.

Definindo a URL base com variáveis de ambiente

O SDK Python oficial lê OPENAI_API_KEY e OPENAI_BASE_URL do ambiente quando você não os passa no código. Isso é útil quando o mesmo aplicativo é executado contra diferentes endpoints em desenvolvimento e produção, ou quando uma ferramenta de terceiros constrói o cliente para você e não oferece lugar para editar argumentos do construtor.

export OPENAI_BASE_URL="https://api.apicompatible.com/v1"
export OPENAI_API_KEY="YOUR_API_KEY"

python - <<'EOF'
from openai import OpenAI

client = OpenAI()
r = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Say hello in five words."}],
)
print(r.choices[0].message.content)
EOF

Argumentos explícitos têm prioridade sobre variáveis de ambiente. Se uma chamada for para o host errado, verifique se outra parte do seu código cria um cliente com seu próprio base_url, e se um carregador de .env é executado antes do seu script ler as variáveis.

Mantenha a chave fora do controle de versão. Uma chave em uma variável de ambiente ou gerenciador de segredos é fácil de rotacionar; uma chave em um arquivo comitado não é.

A mesma alteração em Node

O pacote Node usa camel case para a mesma opção. Tudo o resto, incluindo os nomes dos métodos e a forma da resposta, corresponde ao que você escreveria contra qualquer endpoint no formato OpenAI.

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.apicompatible.com/v1",
  apiKey: process.env.API_KEY,
});

const completion = await client.chat.completions.create({
  model: "uncensored",
  messages: [{ role: "user", content: "Give me a one-line commit message for a typo fix." }],
});

console.log(completion.choices[0].message.content);

Para uma verificação HTTP bruta sem nenhum SDK, esta chamada curl envia a mesma requisição e é útil para separar problemas do SDK de problemas de chave:

curl https://api.apicompatible.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"uncensored","messages":[{"role":"user","content":"ping"}]}'

Streaming, assíncrono e retentativas

O streaming usa eventos enviados pelo servidor, e o SDK os transforma em um iterador. Passe stream=True e leia os deltas conforme chegam. Os números de uso chegam no final do streaming, então proteja-se contra chunks que não carregam texto.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.apicompatible.com/v1",
    api_key="YOUR_API_KEY",
)

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Explain idempotency in two sentences."}],
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
print()

O cliente assíncrono aceita os mesmos dois argumentos. Troque OpenAI por AsyncOpenAI, adicione await, e use async for em streams de streaming.

Dois limites importam quando você executa mais de uma requisição ao mesmo tempo. Uma chave completa permite 8 requisições concorrentes e 300 requisições por minuto, e uma chave de teste permite 2 e 60. Uma requisição transmitida mantém seu slot de concorrência até que o stream termine, então um consumidor travado que nunca drena o stream desperdiça um slot. Acima do limite você recebe HTTP 429 com o código de erro rate_limited ou concurrency. O SDK tenta novamente requisições falhas algumas vezes por padrão, e você pode mudar isso com max_retries no cliente. Um 429 com um cabeçalho Retry-After: 5 significa sobrecarga temporária, então esperar cinco segundos é a resposta correta.

Timeouts, reutilização de cliente e depuração do que foi enviado

Crie o cliente uma vez e reutilize-o. Cada cliente mantém seu próprio conjunto de conexões, então criar um novo para cada requisição desperdiça tempo e torna o código de streaming mais difícil de entender. Ambas as opções abaixo são definidas no construtor e se aplicam a cada chamada feita através desse cliente.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.apicompatible.com/v1",
    api_key="YOUR_API_KEY",
    timeout=60.0,
    max_retries=2,
)

Gerações longas podem demorar, então um tempo limite muito curto produz erros que parecem falhas de serviço. Escolha um tempo limite que se adapte à sua resposta mais longa esperada, e aumente-o para grandes saídas.

Quando você não consegue saber qual URL ou chave uma requisição usou, ative o log de depuração do SDK. Versões recentes do pacote Python leem uma variável de ambiente OPENAI_LOG, e defini-la como debug imprime a linha da requisição e o status da resposta. Verifique a documentação atual do SDK para o comportamento exato na sua versão, e remova a variável depois, já que os logs podem conter dados sensíveis. O host impresso deve ser api.apicompatible.com. Se mostrar algo diferente, uma instância de cliente diferente ou uma variável de ambiente está substituindo sua configuração.

Um último hábito que economiza tempo: mantenha a URL base, a chave e o id do modelo em um módulo de configuração. Quando os três vivem em um só lugar, alterar endpoints torna-se uma única edição e uma única revisão.

Erros que quebram a primeira chamada

A maioria das primeiras chamadas falhas vem de uma lista curta de causas. Verifique-a na ordem antes de suspeitar do serviço.

A URL base não contém /v1 ou possui um caminho estranho

O SDK adiciona apenas o nome do endpoint, então a URL base deve terminar em /v1. Usar https://api.apicompatible.com sem a parte da versão, ou colar o caminho completo /v1/chat/completions, geralmente produz um erro not-found porque a URL final acaba errada. Imprima client.base_url se não tiver certeza do que o SDK resolveu.

O id do modelo ainda é um nome de outro provedor

Esta API serve um único modelo e seu id é uncensored. Um nome de modelo restante de uma configuração anterior é uma causa frequente de erros, e é fácil de perder quando o nome está em um arquivo de configuração em vez do código. Pesquise seu projeto pela string antiga.

A chave vem do lugar errado

Uma chave de outro provedor não funcionará aqui, e o inverso também é verdadeiro. Se você definir tanto OPENAI_API_KEY quanto um api_key explícito, o valor explícito é usado. Verifique qual deles chegou ao cliente.

Você chama um endpoint que esta API não oferece

A API é apenas de texto. Ela expõe /v1/chat/completions, /v1/responses e /v1/models. Não há endpoints de imagem, áudio ou embeddings e nem ajuste fino, então caminhos de código que os usam têm que permanecer com o provedor original. A análise de custo e trade-off cobre quando essa divisão faz sentido.

A carga útil é muito grande

O corpo máximo da requisição é 8 MB. Contextos longos são válidos até 100.000 tokens no total para prompt mais geração, mas blobs base64 ou arquivos colados grandes podem atingir o limite do corpo primeiro.

Verificando a conexão e seu saldo

Antes de depurar o código do aplicativo, chame GET /v1/models. Uma lista limpa significa que a chave e a URL estão corretas. Toda resposta também carrega um cabeçalho X-Balance-USD, que permite monitorar o gasto sem uma chamada separada. Com o SDK Python, use with_raw_response para ler cabeçalhos:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.apicompatible.com/v1",
    api_key="YOUR_API_KEY",
)

raw = client.chat.completions.with_raw_response.create(
    model="uncensored",
    messages=[{"role": "user", "content": "ping"}],
)

print(raw.headers.get("X-Balance-USD"))
print(raw.headers.get("X-Request-Id"))
completion = raw.parse()
print(completion.choices[0].message.content)

Mantenha o valor X-Request-Id quando entrar em contato com o suporte, porque ele identifica a requisição exata. Requisições falhas ou recusadas não são cobradas, então uma chamada com erro custa nada. O preço é $0,15 por 1M tokens de entrada e $0,50 por 1M tokens de saída a partir de crédito pré-pago; a página de preços tem os detalhes e a documentação lista cada parâmetro.

Perguntas frequentes

Preciso de um SDK especial para usar um base_url personalizado?

Não. Os pacotes padrão da OpenAI para Python e Node aceitam uma opção de URL base. Você altera essa opção e a chave, mantendo suas chamadas existentes.

É base_url ou baseURL?

Python usa base_url e Node usa baseURL. Ambos usam o mesmo valor, https://api.apicompatible.com/v1.

Qual nome de modelo devo enviar?

Envie uncensored como o modelo. Esta API executa um único modelo, então não há nada mais para escolher.

Por que recebo HTTP 429 ao executar poucas requisições?

Uma chave de teste permite 2 requisições concorrentes, e streams abertos contam para esse número até que terminem. Feche ou finalize streams, ou migre para uma chave completa para 8 requisições concorrentes.

Obtenha sua chave em segundos

Cadastre-se, copie o token e atualize a URL do endpoint. Essa é toda a configuração necessária.

Abrir conta