テーマ
言語
·2 分で読めます

Responses API と Chat Completions の違いと使い分け

OpenAI互換APIにおける /v1/responses と /v1/chat/completions の実用上の違いを解説します。リクエスト形式、会話履歴、ツール、ストリーミングイベント、どちらを選ぶべきかを取り上げます。すべての例は GetVibe API で実際に実行しています。

Responses API と Chat Completions の違いと使い分け

OpenAI互換APIには現在、主に2つのリクエスト形式があります。従来からある /v1/chat/completions と、新しい /v1/responses です。GetVibe APIでは、1つのキーと1つのベースURL https://getvibeapi.com/v1 で両方を利用できます。ここでは、実際の違い、どちらを選ぶべきか、そして移行時に注意すべき1つの落とし穴について説明します。

簡単にまとめると

Chat CompletionsResponses
エンドポイントPOST /v1/chat/completionsPOST /v1/responses
入力messages 配列input:文字列またはアイテムの配列
システムプロンプトsystem ロールのメッセージinstructions フィールド
回答choices[0].messageoutput 配列:推論、メッセージ、関数呼び出し
出力上限max_tokensmax_output_tokens
利用者ほとんどのSDK、フレームワーク、チャットアプリCodex CLIと新しいエージェントSDK

形式によってモデル、価格、トークン数が変わることはありません。どちらを使っても、モデルの入力トークンと出力トークンに対して課金されます。

両方の形式で同じリクエストを送る

Chat Completions:

curl https://getvibeapi.com/v1/chat/completions \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "messages": [
      {"role": "system", "content": "1文で回答してください。"},
      {"role": "user", "content": "HTTP 429は何を意味しますか?"}
    ],
    "max_tokens": 300
  }'

Responses:

curl https://getvibeapi.com/v1/responses \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "instructions": "1文で回答してください。",
    "input": "HTTP 429は何を意味しますか?",
    "max_output_tokens": 300
  }'

Chat Completionsでは、テキストは choices[0].message.content に格納されます。Responsesでは output の中にあり、推論モデルの場合、最初のアイテムは reasoning アイテムで、回答はタイプが message のアイテムです。配列を自分でたどる必要はありません。Python SDKには output_text プロパティがあります。

import os
from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])

chat = client.chat.completions.create(
    model="gpt-6-luna",
    messages=[{"role": "system", "content": "1文で回答してください。"},
              {"role": "user", "content": "HTTP 429は何を意味しますか?"}],
)
print(chat.choices[0].message.content)

resp = client.responses.create(
    model="gpt-6-luna",
    instructions="1文で回答してください。",
    input="HTTP 429は何を意味しますか?",
)
print(resp.output_text)

ResponsesはOpenAIモデルに限定されません。公開前に、同じResponsesリクエストを gpt-6-luna、claude-sonnet-5.5、deepseek-v4.1-flash に送信したところ、3つとも回答しました。DeepSeekは、上記の説明どおり、message の前に reasoning アイテムを返しました。

会話履歴:自分で送信する

切り替える前に知っておくべきことはこれだけです。OpenAI独自のResponses APIでは、サーバー上で会話を保持できるため、次のリクエストで previous_response_id を使って前のレスポンスを指定できます。GetVibe APIは会話を保存しないため、previous_response_id はサポートされず、store は無視されます。実際に試したところ、リクエストは400エラーで拒否されました。

動作するパターンはChat Completionsの場合と同じです。履歴全体を input に含めて送信します。

history = [{"role": "user", "content": "私の名前はAnaです。覚えておいてください。"}]
first = client.responses.create(model="gpt-6-luna", input=history)

history.append({"role": "assistant", "content": first.output_text})
history.append({"role": "user", "content": "私の名前は何ですか?1語で答えてください。"})
second = client.responses.create(model="gpt-6-luna", input=history)
print(second.output_text)  # Ana

ツール:異なる形式

Function callingは両方の形式で利用できますが、ツール定義の形が異なります。Chat Completionsでは関数のフィールドが function オブジェクトの中にネストされます。一方、Responsesではツール上に直接配置されます。呼び出しは個別の function_call アイテムとして届き、同じ call_id を持つ function_call_output アイテムとして結果を返します。

import json

tools = [{
    "type": "function",
    "name": "get_weather",
    "description": "都市の現在の天気",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
        "additionalProperties": False,
    },
}]

items = [{"role": "user", "content": "デンバーの天気はどうですか?"}]
resp = client.responses.create(model="gpt-6-luna", input=items, tools=tools)

for item in resp.output:
    if item.type == "function_call":
        result = {"city": "Denver", "temp_f": 54, "sky": "overcast"}  # あなたの関数
        items.append({"type": "function_call", "call_id": item.call_id,
                      "name": item.name, "arguments": item.arguments})
        items.append({"type": "function_call_output", "call_id": item.call_id,
                      "output": json.dumps(result)})

final = client.responses.create(model="gpt-6-luna", input=items, tools=tools)
print(final.output_text)

今回の実行では、モデルは get_weather を {"city":"Denver"} とともに呼び出し、2回目のリクエストでは、デンバーは54°Fで曇りだと回答しました。同じループのChat Completions版については、function callingガイドをご覧ください。

ストリーミング

どちらの形式も "stream": true をサポートしていますが、イベントは異なります。Chat Completionsは均一な data: 行を送り、新しいテキストの各部分は choices[0].delta.content に含まれます。Responsesは名前付きイベントを送信します。最初に response.created、テキストの各部分とともに response.output_text.delta、最後に response.completed が送られます。SDKを使わずに自分でストリームを解析する場合は、形式ごとのパーサーが必要です。

どちらを選ぶべきか

  • Chat Completions:すでにこれを使ったコードがある場合、またはフレームワーク、チャットアプリ、ノーコードプラットフォームを使っている場合に適しています。ほぼすべてのツールが対応しているため、動作しているコードを形式変更のためだけに書き換える理由はありません。
  • Responses:ツールがResponsesを要求する場合に適しています。主な例はCodex CLIで、/v1/responses と通信します。セットアップ方法は Codex CLIのドキュメント と Codex CLIガイドで説明しています。

どちらを使っても、モデル一覧と価格は同じです。すべてのフィールドについては APIリファレンスを、最新の価格については モデルページをご覧ください。

Responses API と Chat Completions の比較OpenAI Responses API/v1/responsesChat Completions APIprevious_response_idCodex CLI Responses API

GetVibe APIを無料で試す

1つのOpenAI互換APIでGPT、Claude、Geminiなどを利用できます。カードまたは暗号資産で米ドル払いに対応しています。

関連記事

Responses API と Chat Completions の違いと使い分け | GetVibe API