Skip to main content
互換モードを呼び出すと、OpenAI、Claude、Gemini、Grok、Qwen、GLM など、すべてのモデルが同じ OpenAI スキーマを返します。パースロジックのほとんどは共通であり、以下のパターンに従えば、モデルを切り替えてもコード変更は不要です。 このページでは、レスポンス処理を最初から正しく行えるようにします。まず共通点を示し、その後、許容すべきわずかな違いを1つの表にまとめます(いずれも統合を妨げるものではありません)。
リクエスト側(base_url、auth、モデルの切り替え)については、互換モードの呼び出しで説明しています。このページは純粋にレスポンス側、つまり返ってきた内容をどうパースするかに焦点を当てています。

2つのモード、1つのエンドポイント

同じ/v1/chat/completionsエンドポイントです。streamフラグだけで形が変わります:

非ストリーミング応答

安定した構造 — choices[0].message.content を読むだけです:
非ストリーミング出力は主要なすべてのモデルで非常に一貫しています — choices[0].message.content はどこでも動作します。一部のモデル(例: OpenAI ファミリー)では、message 上で annotationsrefusal も追加されます。必要であれば読んでください。不要なら無視して構いません。

ストリーミングレスポンス (SSE)

ストリーミングでは、チャンクを Server-Sent Events として 1 行ごとに data: {...} で送信し、data: [DONE] で終了します:
公式 SDK では、そのまま反復するだけです。要点は delta.content を蓄積すること です:

統合メモ: いくつかの違いを、共通の方法で処理します

ストリーミングの詳細はモデルごとに少し異なりますが、以下のルールに従えば、1つのコードパスでそれらすべてをカバーできます
最終チャンクのchoicesは空の配列になることがあります。 usageを含む最後のチャンクは、いくつかのモデル(gpt-4.1-mini, grok, qwen, glm)では"choices":[]です。そこでchoices[0]をインデックス参照すると例外になります。読み取る前に、choicesが空でないことを確認してください。

堅牢な参考パーサー

raw SSE を自前で処理する場合(SDK を使わない場合)、これで上記のすべての違いをカバーできます:
推論モデル(grok、qwen、glm など)は、まず delta.reasoning_content(思考の連鎖)をストリーミングし、次に delta.content(回答)をストリーミングします。上のパーサーは content だけを読み取るため、思考は自動的にスキップされます。思考を表示するには、推論モデルの出力 を参照してください。

使用方法と課金

  • usage は非ストリーミング応答ではインラインで返り、ストリーミングでは最後のチャンクで届きます(場所は上の表どおりです — 「存在する場合は必ず記録」)。
  • 項目の内訳は異なります。OpenAI 系では completion_tokens_details が追加され、Gemini/Claude では input_tokens/output_tokens が追加され、推論モデルでは reasoning_tokens が追加されます。3 つの標準項目、つまり prompt_tokens / completion_tokens / total_tokens を参照してください。
ストリーミングされた total_tokens を信用しないでください。 テストでは、一部のモデル(例: gpt-5.4-mini)が、total ≠ prompt + completion となっている末尾フレームを出力することがありますが、同じモデルは非ストリーミングでは正しくなります。そのフレームではなく、アカウント明細を基に課金してください。

関連リンク