短い答え
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です。詳細は料金ページ、すべてのパラメータはドキュメントに記載されています。
