本文へスキップ

導入ガイド

クライアントはそのまま。変えるのは Base URL と model 値だけ。

ここのテキストモデルは、あなたの SDK がすでに話しているプロトコルを話します。Chat Completions、ステートレスな Responses サブセット、Anthropic Messages、Google generateContent。面白いのは、対象モデルが宣言していないパラメータがどうなるかです。

解決する課題

互換レイヤーはたいてい黙って嘘をつく

典型的な失敗は 500 ではありません。ゲートウェイが受け取り、捨て、何も言わなかったパラメータです。結果としてモデルはあなたの temperature も、ツール定義も、レスポンス形式もなしに走り、出力は「壊れている」ではなく「少し残念」に見えます。

01

未宣言のパラメータは捨てられず拒否されます

messages、tools、tool_choice、response_format、max_tokens、temperature、top_p はモデルの宣言済みフィールドに対応します。それ以外はモデルのスキーマへ転送され、宣言がなければ 400 です。沈黙が答えになることはありません。

02

エラー形状は呼んだプロトコルに従います

/v1 では本文が OpenAI や Anthropic のエラーオブジェクトで、/api/v1 の {code, msg, data, request_id} 封筒ではありません。両方の面を使うなら両方を扱ってください。

03

ストリーミングと精算は別の話です

stream: true は data: [DONE] で終わる chat.completion.chunk を返します。課金は実測使用量に従うため、途中で中断したストリームも無料にはなりません。

実装方針

エンドポイントを差し替え、評価を回し直す

base_url と api_key を変え、model 文字列を GET /v1/models の値に置き換え、すでにあるテストを走らせます。あるパラメータで 400 が返るなら、選んだモデルはそれを最初から備えていなかったということです。黙って捨てる実装では得られない情報です。

OpenAI 互換クライアントならどれでも動きます。変えるのは Base URL と model 値だけです。

POST /v1/chat/completions

from openai import OpenAI

client = OpenAI(
    base_url="https://api.spicyapi.ai/v1",
    api_key=os.environ["SPICY_API_KEY"],
)

stream = client.chat.completions.create(
    model="<publisher>/<model>/chat",          # exact value from GET /v1/models
    messages=[{"role": "user", "content": "Summarise these notes in three bullets."}],
    temperature=0.7,
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

text/event-stream

data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"- "}}]}
data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"Ships"}}]}
data: [DONE]

契約

先に押さえておく項目

OpenAI 互換 LLM API:Base URL を差し替えるだけ — 先に押さえておく項目
フィールド / ヘッダー値・上限
POST /v1/chat/completionschat.completion · SSE with stream: true
GET /v1/modelsevery callable model value
Authorization: Bearer · x-api-key · x-goog-api-keyaccepted on /v1
undeclared parameter400 · never silently dropped

横にスワイプして全項目を確認できます。

導入

最初の呼び出しから本番まで

  1. 01キーを作り、GET /v1/models で今この瞬間呼べる識別子を取得します。
  2. 02クライアントを Base URL に向け、まず非ストリーミングで一度送ります。返るのは標準の chat.completion オブジェクトです。
  3. 03ストリーミングを有効にし、読み取り側が chat.completion.chunk と [DONE] を処理できるか確認します。
  4. 04コンソールでキーごとの使用量を見ながら、本番トラフィックを流す前に日次上限を設定します。

向き不向き

この方法が向いている場面

こんなときに選ぶ

  • 動いている OpenAI・Anthropic・Google のクライアントコードがあり、その後ろのモデルだけ替えたい。
  • 画像、動画、テキストをひとつのキー、ひとつの残高、ひとつの消費上限でまとめたい。

こんなときは別の方法へ

  • サーバー側の状態を持つスレッドやアシスタントに依存している場合。ここで扱うのはステートレスな Responses サブセットです。
  • メディア出力が必要な場合。それは createTask か、すでにその形を話すクライアント向けの Videos 投影を使います。

裏付け

自分で確認できること

四つのプロトコル面、ひとつのキー

/v1/chat/completions、/v1/responses、/v1/messages、/v1beta/models/{model}:generateContent はすべて同じキーで認証します。Authorization: Bearer、x-api-key、x-goog-api-key は、それぞれの SDK が期待する場所で受け付けられます。

モデル一覧が契約です

GET /v1/models は、/v1 と /api/v1 のすべての操作が受け付ける識別子をそのまま返し、提供元は owned_by に入ります。価格はアカウント固有のため /api/v1/models 側にあり、公開されません。

検証、制限、保留は共通です

互換レイヤーはネイティブ面と同じ認証、レート制限、入力検証、価格計算、資金保留を使います。違うのは封筒だけです。

公開前に

確認しておくプラットフォームの挙動

  • キーはサーバー側に置きます。URL のクエリ文字列に入れた資格情報は受け付けられません。
  • 問い合わせに備えて、各呼び出しでプロトコル自身のレスポンス id を記録します。
  • 非対応パラメータの 400 を利用者にどう見せるか、公開前に決めます。
  • 残高だけに頼らず、キーごとの日次・月次・累計の上限を設定します。

よくある質問

このページでよく聞かれること

Base URL と model 文字列を設定できるクライアントならどれでも動きます。OpenAI 形状は /v1/chat/completions と /v1/responses、Anthropic は /v1/messages、Google GenAI は generateContent 系のパスを使います。

次に

テキストモデルにクライアントを向ける

既存の OpenAI・Anthropic・Google クライアントをそのまま向ける。何がそのまま通り、何を意図的に拒否し、テキストはどう課金されるか。

関連ガイド