新規プロジェクトなら、基本線は Responses API です。既存の Chat Completions が単純なテキスト生成を安定して処理しているなら、移行は段階的で構いません。OpenAI の現行移行ガイドは、Responses を新規プロジェクトに推奨しつつ、Chat Completions は引き続きサポートされると明記しています。
違いは endpoint 名だけではありません。Chat Completions は Messages を入力し、choices 内の assistant message を返します。Responses は message、reasoning、function call、tool result を別々の型付き Item として扱います。このデータモデルの差が、出力解析、会話状態、ツール、streaming の実装に波及します。
最小コードが同じに見える理由
単発テキストでは移行は簡単に見えます。
jsconst completion = await client.chat.completions.create({ model: "gpt-5.6", messages: [{ role: "user", content: "問い合わせを分類して" }], }); const chatText = completion.choices[0].message.content; const response = await client.responses.create({ model: "gpt-5.6", input: "問い合わせを分類して", }); const responseText = response.output_text;
output_text は最終テキストを取り出す SDK の便利機能です。tool call、reasoning summary、引用、個別ステータスが必要なら、response.output の Item を型ごとに処理します。
| 実装上の契約 | Chat Completions | Responses API |
|---|---|---|
| endpoint | /v1/chat/completions | /v1/responses |
| 入力 | messages | input と任意の instructions |
| 出力 | choices[].message | 型付き output[] Items |
| 複数候補 | n で複数 choice | 1 response につき1 generation |
| 会話継続 | 履歴を再送 | previous_response_id、Conversations、手動 replay |
| Structured Outputs | response_format | text.format |
| streaming | chunk の choices[].delta | 型付きイベント |
単純な role/content 配列は Responses の input に再利用できます。しかし、これは最小入力の互換性であり、両 endpoint の request body や response body を混ぜてよいという意味ではありません。
会話状態は明示的に選ぶ
Chat Completions では、アプリが必要な履歴を保持し、次の messages に入れ直すのが一般的です。Responses では previous_response_id で前回とつなげられます。
jsconst first = await client.responses.create({ model: "gpt-5.6", instructions: "障害対応者として簡潔に答える。", input: "アラートを原因別にまとめて。", }); const next = await client.responses.create({ model: "gpt-5.6", previous_response_id: first.id, instructions: "障害対応者として簡潔に答える。", input: "最優先のグループだけ残して。", });
instructions を再指定しているのは意図的です。Responses API referenceによれば、previous_response_id を渡しても前回の instructions は自動継承されません。継続すべきポリシーはアプリ側で保持します。
また、会話をつなげやすいこととデータ保持は別問題です。OpenAI のデータ管理ドキュメントは、store、Zero Data Retention、background mode、prompt cache、hosted tools を別々に説明しています。現在、保存される Responses application state には少なくとも30日の保持が記載されていますが、組織設定や例外で挙動が変わります。実際の利用面を確認してください。
ツール呼び出しは往復形式が変わる
Chat Completions では、assistant message 内の tool_calls を読み、tool_call_id を持つ role: "tool" message を追加します。Responses では function_call Item を受け取り、同じ call_id を持つ function_call_output Item を返します。
jsconst outputs = response.output .filter((item) => item.type === "function_call") .map((call) => ({ type: "function_call_output", call_id: call.call_id, output: JSON.stringify(runTool(call.name, call.arguments)), }));
最初の call だけを処理してはいけません。並列 call、引数不正、timeout、tool error、結果後の再 call をテストします。現行の対応形式は OpenAI のfunction calling ガイドで確認できます。
Responses は web search、file search、code interpreter、remote MCP などの hosted tools も型付き Item として扱えるため、agentic workflow では有力です。ただし、実際の tool 対応はモデルごとに確認が必要です。
streaming は終了条件まで作り直す
Chat Completions の UI は choices[0].delta.content を順に足す実装が一般的です。Responses はテキスト delta、function arguments、Item 完了、response 完了などの型付きイベントを返します。公式 streaming ガイドに沿ってイベントを分岐してください。
HTTP 200 や最初の文字列到着だけを成功にすると、incomplete や途中失敗を見落とします。response ID、最終 status、Item type、usage、error または incomplete reason をログ対象にします。ユーザーキャンセルとネットワーク切断も別の終了状態です。
Structured Outputs も response_format から text.format へ設定位置が変わります。Structured Outputs ガイドを基に、JSON Schema だけでなく refusal、モデル対応、parse failure を確認します。

移行は adapter の後ろで証明する
Responses が向くのは、新規開発、reasoning context、hosted tools、複数段の function call、マルチモーダル入力、長い処理です。成熟した単発テキストサービスで利益が小さいなら、Chat Completions を維持する判断も成立します。Assistants API の終了予定を Chat Completions に適用してはいけません。

安全な移行では、まず choices[0] への直接依存を内部 adapter に閉じ込めます。同じ代表入力を両経路へ流し、文章の完全一致ではなく、構造化結果、refusal、切り詰め、tool intent、usage を比較します。その後、状態、全 tool call、streaming、データ管理を順番に切り替えます。
第三者 endpoint の「OpenAI compatible」は、多くの場合 Chat Completions 形式を指します。Responses の endpoint、Item、イベント、tool envelope、状態、error object は、その provider の最新ドキュメントで別途検証します。サンプルが一度返答したことではなく、会話が復元でき、call が欠落せず、schema が parse でき、stream が正しく閉じ、失敗原因が追えることを移行完了条件にしてください。



