JA ▾

OpenAI Python SDK カスタム base_url:設定と修正

あるサーバーソケットから別のサーバーソケットにケーブルが移動し、SDK の base URL 切替を示す

OpenAI SDKを使用すると、引数1つでエンドポイントを上書きできます。このページでは、このAPI用のOpenAI Python SDKにおけるカスタムbase_urlの設定方法と、Node版、ストリーミング、そして最初の呼び出しで最も失敗の原因となるミスについて解説します。

最終更新日

まとめ

  • base_url を https://api.apicompatible.com/v1 に設定し、キーを api_key として渡します。コードの他の部分は変更する必要はありません。
  • モデル ID は uncensored です。古いモデル名をそのままにしておくと、最初の呼び出しが失敗する最も一般的な原因となります。
  • ストリーミングはstream=Trueで動作し、ストリーミング中のリクエストは終了まで並行スロットの1つを占有します。
  • 環境変数を使用すると、コードを修正せずにエンドポイントを切り替えることができます。

短い答え

2 つの引数 base_url と api_key でクライアントを作成し、既知のメソッドを引き続き使用します。この API の base URL は https://api.apicompatible.com/v1、モデル ID は uncensored です。認証は、SDK がキーから構築する標準的なベアートークンです。

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)

これが全ての変更点です。SDKはbase URLの末尾に/chat/completionsを付加するため、リクエストはPOST /v1/chat/completionsに到達します。まだキーをお持ちでない場合は、APIキーページでサインアップと試用クレジットについて説明しています。

環境変数による base URL の設定

公式 Python SDK は、コードで引数を渡さない場合、環境変数から OPENAI_API_KEY と OPENAI_BASE_URL を読み取ります。これは、同じアプリケーションが開発環境と本番環境で異なるエンドポイントに対して実行される場合や、サードパーティツールがクライアントを構築してコンストラクタ引数を編集する場所を提供しない場合に便利です。

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

明示的な引数は環境変数よりも優先されます。呼び出しが誤ったホストに送信される場合は、コードの他の部分が独自の base_url でクライアントを構築していないか、またスクリプトが変数を読み取る前に .env ローダーが実行されていないか確認してください。

キーをソース管理から除外してください。環境変数やシークレットマネージャー内のキーは回転(ローテーション)が容易ですが、コミットされたファイル内のキーは容易ではありません。

Node での同じ変更

Node パッケージは、同じオプションにキャメルケースを使用します。メソッド名やレスポンスの形状など、他のすべては 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);

SDK を使用しない生の HTTP 確認には、この curl コマンドが同じリクエストを送信し、SDK の問題とキーの問題を分離するのに役立ちます:

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"}]}'

ストリーミング、非同期、リトライ

ストリーミングはサーバー送信イベント(SSE)を使用し、SDKはそれらをイテレータに変換します。stream=Trueを渡して、到着するデルタを読み取ります。使用量はストリームの末尾に届くため、テキストを含まないチャンクには注意してください。

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()

非同期クライアントは同じ 2 つの引数を受け取ります。OpenAI を AsyncOpenAI に置き換え、await を追加し、ストリームに async for を使用します。

複数のリクエストを同時に実行する際、2つの制限が重要になります。フルキーでは同時リクエスト8件と1分あたり300リクエストが可能で、トライアルキーではそれぞれ2と60です。ストリーミングリクエストはストリーミングが完了するまで並行スロットを保持するため、ストリームを消費しないストールしたコンシューマーはスロットを無駄にします。制限を超えると、エラーコードがrate_limitedまたはconcurrencyのHTTP 429が返されます。SDKはデフォルトで失敗したリクエストを数回再試行しますが、クライアント側でmax_retriesを変更できます。Retry-After: 5ヘッダー付きの429は一時過負荷を示すため、5秒待つのが正しい対応です。

タイムアウト、クライアントの再利用、送信内容のデバッグ

クライアントは1回作成して再利用してください。各クライアントは独自の接続プールを保持するため、リクエストごとに新しいクライアントを作成すると時間とリソースの無駄になり、ストリーミングコードの推論が難しくなります。以下の2つのオプションはコンストラクタで設定され、そのクライアントを通じて行われるすべての呼び出しに適用されます。

from openai import OpenAI

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

長時間の生成には時間がかかるため、非常に短いタイムアウトはサービス障害のように見えるエラーを引き起こします。最も長い予想される回答に合ったタイムアウトを選択し、大きな出力に対してはそれを引き上げてください。

リクエストに使用されたURLやキーが不明な場合は、SDKのデバッグログを有効にしてください。Pythonパッケージの最近のバージョンはOPENAI_LOG環境変数を読み取り、これをdebugに設定すると、リクエスト行とレスポンスステータスが出力されます。現在のSDKドキュメントでバージョンごとの正確な動作を確認し、ログには機密データが含まれる可能性があるため、後で変数を削除してください。出力されるホストはapi.apicompatible.comであるはずです。それ以外が表示される場合は、別のクライアントインスタンスまたは環境変数が設定を上書きしています。

時間を節約する最後の習慣:base URL、キー、モデル ID を 1 つの構成モジュールに保持してください。これら 3 つが 1 か所にあれば、エンドポイントの切替は 1 つの編集と 1 つのレビューで完了します。

最初の呼び出しを失敗させるミス

最初の呼び出しの失敗のほとんどは、限られた数の原因によるものです。サービスを疑う前に、順番に確認してください。

base URL に /v1 が不足しているか、不要なパスが含まれている

SDKはエンドポイント名のみを追加するため、base URLは/v1で終わる必要があります。バージョンセグメントなしでhttps://api.apicompatible.comを使用するか、完全な/v1/chat/completionsパスを貼り付けると、最終的なURLが正しくならないため、通常はnot-foundエラーが発生します。SDKが解決したURLが不明な場合は、client.base_urlを出力してください。

モデル ID がまだ別のプロバイダの名前になっている

この API は 1 つのモデルのみを提供し、その ID は uncensored です。以前のセットアップの名残のモデル名はエラーの頻発する原因であり、コードではなく構成ファイルにある場合、見落としやすくなります。プロジェクト内で古い文字列を検索してください。

キーが誤った場所から来ている

別のプロバイダのキーはここでは機能せず、その逆もまた同様です。OPENAI_API_KEY と明示的な api_key の両方を設定した場合、明示的な値が使用されます。どちらがクライアントに届いたか確認してください。

この API が提供していないエンドポイントを呼び出している

APIはテキストのみです。/v1/chat/completions、/v1/responses、/v1/modelsが公開されています。画像、音声、埋め込み用のエンドポイントはなく、ファインチューニングもサポートしていないため、それらを使用するコードパスは元のプロバイダに依存し続ける必要があります。コストとトレードオフの分析では、この分割が意味をなす場合について解説しています。

ペイロードが大きすぎる

最大リクエストボディサイズは 8 MB です。長いコンテキストは、プロンプトと completion を合わせて合計 100,000 トークンまで問題ありませんが、base64 ブロブや巨大な貼り付けファイルは、まずボディ制限に達する可能性があります。

接続と残高の確認

コードデバッグ前にGET /v1/modelsを呼び出します。正常なリストはキーとURLが正しいことを意味します。レスポンスにはX-Balance-USDヘッダーが含まれ、別の呼び出しなしで支出を確認できます。Python SDKではwith_raw_responseを使用してヘッダーを読み取ります:

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)

サポートに連絡する際はX-Request-Idの値を保持してください。これは特定のリクエストを識別するためです。失敗または拒否されたリクエストには課金されないため、失敗した呼び出しにはコストがかかりません。料金は前払いクレジットから、入力トークン100万トークンあたり$0.15、出力トークン100万トークンあたり$0.50です。詳細は料金ページ、すべてのパラメータはドキュメントに記載されています。

よくある質問

カスタム base_url を使用するには特別な SDK が必要ですか?

いいえ。標準的な OpenAI Python および Node パッケージは base URL オプションを受け付けます。そのオプションとキーを変更し、既存の呼び出しを維持してください。

base_urlかbaseURLか?

Pythonではbase_url、Node.jsではbaseURLを使用します。どちらも同じ値https://api.apicompatible.com/v1.を取ります。

どのモデル名を送信すべきですか?

モデルにはuncensoredを指定してください。このAPIは1つのモデルのみで動作するため、選択肢はありません。

数件のリクエストしか実行していないのにHTTP 429が返されるのはなぜですか?

トライアルキーでは同時実行リクエスト数が2に制限され、オープン中のストリームもその数に含まれます。ストリームを閉じるか終了させるか、または同時実行リクエスト数が8のフルキーに移行してください。

数秒でキーを取得

サインアップしてトークンをコピーし、エンドポイントURLを更新します。これだけですべての設定が完了します。

アカウントを開く