Responses API と Chat Completions のどちらを選ぶかは、どちらのエンドポイントが新しいかという問題ではなく、主に「会話の状態を誰が保持するか」という問題です。Chat Completions では、ターンごとにオーケストレーターが messages 配列全体を再送する必要があります。一方、Responses では、保存されたレスポンス ID から継続することが可能です。私たちは 2026年10月3日時点の TokenLab の公開 API ドキュメントおよびライブモデル API を確認しました。その結果、どちらを選択すべきかはモデルが受け入れるフォーマットにも依存することがわかりました。まずは決定表から始めましょう。
| エージェントの要件 | 選択 | 理由 |
|---|---|---|
| 既存の OpenAI 互換チャットクライアント、多くのモデルでポータブル | Chat Completions (/v1/chat/completions) |
API フォーマットガイド(2026年10月3日確認)に基づき、最も幅広いモデル互換性があるため |
| 保存されたサーバー側のレスポンスから会話を継続 | Responses (/v1/responses) |
previous_response_id と store は Responses のフィールドであるため |
| ターン間の任意の履歴編集、削除、またはメッセージマスキング | Chat Completions | messages 配列全体を自分で管理できるため |
| バックグラウンドレスポンスまたは Responses イベント | Responses | サポートするモデル向けにドキュメント化されているため |
| 継続可能な永続的 WebSocket 接続 | Responses | wss://api.tokenlab.sh/v1/responses を使用 |
| ポータブルな JSON オブジェクト出力 | Chat Completions | response_format: {"type": "json_object"} を使用 |
モデルが openai_responses をリストしていない |
Chat Completions、またはモデル固有のフォーマット | Responses はそれをリストしているモデル専用であるため |
| Claude の思考ブロック、Claude のツール使用、プロンプトキャッシュフィールド | Anthropic Messages (/v1/messages) |
Chat Completions はそれらのフィールドを保証しないため |
Gemini の contents、ファイル、キャッシュされたコンテンツ、Gemini ツール |
Gemini (/v1beta/models/:model:generateContent) |
Gemini 固有のフィールドは Gemini ルートで維持するため |
重要なポイント
- Chat Completions はクライアント管理型の状態です。Responses は
previous_response_idを通じてサーバー側で参照可能です。 - ツール呼び出しは、ネストされた
tool_callsとrole: "tool"メッセージから、型指定されたfunction_callおよびfunction_call_outputアイテムへと移行します。 - ストリーミングは
choices[0].deltaチャンクから名前付きイベントに変更されます。Responses クライアントはresponse.failedおよびresponse.incompleteも監視する必要があります。 - フォーマットのサポートはモデルごとに異なります。2026年10月3日時点で、例として挙げた3つのモデルのうち
gpt-5.6-terraのみがopenai_responsesを受け入れました。 - 1つの会話内でフォーマットを混在させないでください。次のリクエストの前に、保存された履歴を変換および検証してください。
Responses API vs Chat Completions:同じタスク、2つのリクエスト
「空が青い理由を2文で説明せよ」というシングルターンのタスクを例にします。API フォーマットガイド(2026年10月3日確認)のクライアント設定を使用した Chat Completions リクエストは以下の通りです:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain why the sky is blue in two sentences."},
],
max_tokens=1000,
)
print(response.choices[0].message.content)
同じタスクを Responses リクエストで行うと以下のようになります:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.responses.create(
model="gpt-5.6-terra",
instructions="You are a helpful assistant.",
input="Explain why the sky is blue in two sentences.",
max_output_tokens=1000,
)
print(response.output_text)
この単純なケースでは、フィールドは1対1で対応します。システムメッセージはトップレベルの instructions になり、messages は文字列またはアイテムの配列を受け入れる input になります。max_tokens は max_output_tokens になります。
レスポンスボディはより大きく異なります。Chat Completions は choices[0].message と finish_reason を返します。Responses は型指定されたアイテムの output 配列と status フィールドを返します。Create Response リファレンス(2026年10月3日確認)には queued、in_progress、completed、incomplete、failed、cancelled がリストされており、HTTP リクエストが成功した場合でも status を確認するよう指示されています。使用量キーも異なり、一方は prompt_tokens と completion_tokens、もう一方は input_tokens と output_tokens です。リファレンスの例ではそれぞれ 20/9/29 と 10/12/22 となっていますが、これらはサンプルペイロードであり、測定値ではありません。
会話の継続
サポートエージェントが1つの質問に答え、次に「注文 #4472 についてはどうですか?」と聞かれたとします。Chat Completions では、新しいユーザーメッセージを保存された配列に追加してすべて再送します。Responses では、前回のレスポンスの id を渡し、新しいターンのみを送信します:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": "What about order #4472?"
}
store はデフォルトで true なため、オフにしない限り、前回のレスポンスは後で取得できるように保持されます。アプリケーション側では、返された id をホップ間で永続的に保存する必要があります。カスタムの削除やメッセージマスキングが必要な場合は、ステートレスなフォーマットの方が直接的に適しています。
ステートレスな再送がエージェント規模で重要である理由は、概算でわかります。10,000トークンの履歴を20回の呼び出しごとに再送すると仮定すると、200,000入力トークンになります。gpt-5.6-terra の入力価格(100万トークンあたり0.60ドル)では、200,000 × 0.60 / 1,000,000 = 0.12ドルとなります(概算、トークン数は想定、キャッシュなし)。この価格は ライブモデル API(2026年10月3日確認、2026年10月2日更新)に基づいています。
2つの注意点があります。私たちが読んだドキュメントには、サーバー保持のコンテキストが入力トークンとして課金されるかどうかは記載されていないため、自身のトラフィックで usage を比較してください。また、272K 入力トークンを超えるリクエストは、リクエスト全体に対して入力2倍、出力1.5倍の価格(100万トークンあたり0.60ドルと3.60ドルではなく、1.20ドルと5.40ドル)が適用されます。長いステートレス履歴はこのラインを超える可能性があります。
ツール呼び出し:リクエストとレスポンスの形状
どちらのフォーマットも Structured Outputs & Tool Calling ガイド(2026年10月3日確認)のループに従います。ツールを送信し、呼び出しを読み取り、バックエンドで実行し、同じフォーマットで結果を返し、最終的な回答が得られるまで繰り返します。形状は異なります。
Chat Completions. ツールは {"type": "function", "function": {...}} として宣言されます。モデルは choices[0].message 上の tool_calls で回答し、finish_reason は tool_calls になります。継続するには、tool_calls を含むアシスタントメッセージと tool_call_id を持つ role: "tool" メッセージを含む配列全体を再送します。以下の値は例示です;lookup_customer はガイドで使用されているツール名です:
{
"model": "gpt-5.6-terra",
"messages": [
{"role": "user", "content": "Look up ana@example.com"},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_xyz789",
"type": "function",
"function": {"name": "lookup_customer", "arguments": "{\"email\": \"ana@example.com\"}"}
}
]
},
{"role": "tool", "tool_call_id": "call_xyz789", "content": "{\"status\": \"active\"}"}
]
}
Responses. モデルは output 内の function_call アイテムで回答し、それぞれが call_id、name、arguments を持ちます。結果を function_call_output 入力アイテムとして返し、前回のレスポンスを指し示します:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": [
{
"type": "function_call_output",
"call_id": "call_xyz789",
"output": "{\"status\": \"shipped\", \"tracking_number\": \"1Z999\"}"
}
]
}
中間のアシスタントツールメッセージを再構築する必要はありません。parallel_tool_calls は両方のフォーマットに存在します。Create Response リファレンスではデフォルトで true です。Chat リファレンスではデフォルトなしでリストされており、「選択したモデルがサポートしている場合」に適用されると記載されています。
1つギャップがありました。私たちが読んだページでは、Responses の tools と tool_choice については一般的な用語でしか説明されていません。ツールスキーマを移植する前に、Create Response リファレンスのツール定義の形状を読み、ターゲットモデルでテストしてください。また、ガイドの以下のルールを守ってください:
- TokenLab は組み込みツールをフォーマット間で変換しません。
- 副作用の前にツール引数を検証してください。
- クライアントの再試行によって同じ呼び出しが繰り返される可能性があるため、ツールの実行はべき等(idempotent)にしてください。
- 独自の権限チェックを適用してください。
ストリーミング:クライアントが処理すべきイベント
Chat Completions は SSE チャンクをストリーミングします。クライアントは choices[0].delta.content を読み取り、finish_reason を記録し、choices のないチャンクをスキップします。stream_options={"include_usage": True} を使用すると、使用量がそのようなチャンクで到着します。Streaming ガイド(2026年10月3日確認)は stop を完了、length をトークン制限、tool_calls をツール実行のリクエストとして扱います。
Responses は名前付きイベントをストリーミングします。ガイドのコンシューマーは以下を処理します:
- 追加するテキスト用の
response.output_text.delta - 成功マーカー用の
response.completed - 致命的な問題としての
response.failed、response.incomplete、およびerror
import os
from openai import OpenAI
with OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
) as client:
completed = False
with client.responses.create(
model="gpt-5.6-terra",
input="Write a short poem.",
stream=True,
) as stream:
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.completed":
completed = True
elif event.type in {"response.failed", "response.incomplete", "error"}:
raise RuntimeError(f"Stream ended with {event.type}")
if not completed:
raise RuntimeError("Stream closed before response.completed")
ガイドから以下の3つのクライアントルールが導かれます:
- 最初のイベントが到着した後、中断されたストリームは不完全であり、自動的に再開されません。役に立つ場合は部分的な出力を保持してもよいですが、完了としてマークしないでください。繰り返されたリクエストは異なり、再度コストが発生する可能性があります。
- ネットワークチャンクが必ずしも1つの完全なイベントとは限らないため、SDK を使用して SSE を解析してください。
- ユーザーが停止または切断した場合はアップストリームのストリームをキャンセルし、キーをサーバーに保持してください。
Responses は wss://api.tokenlab.sh/v1/responses で WebSocket も提供します。そこでのレスポンスは常にストリーミングされ、background と response.cancel はサポートされておらず、各接続は一度に1つのアクティブなレスポンスを実行し、接続は最大60分間持続します。イベントはレスポンススコープの sequence_number を持ちます。error という名前のストリームイベントはフラットなオブジェクトですが、接続およびプロトコルの失敗はネストされた error オブジェクトを使用するため、両方の形状を処理してください。
送信前にモデルが受け入れるフォーマットを確認する
Get a Model リファレンス(2026年10月3日確認)で説明されているように、モデルページまたは GET /v1/models/{model} から tokenlab.accepted_request_formats を読み取ります:
curl "https://api.tokenlab.sh/v1/models/gpt-5.6-terra"
レスポンスには、accepted_request_formats、pricing、制限、lifecycle を含む tokenlab オブジェクトが含まれます。値は エラーガイド で説明されているエンドポイントにマップされます:openai_chat_completions は /v1/chat/completions、openai_responses は /v1/responses、anthropic_messages は /v1/messages、gemini_generate_content は /v1beta/models/{model}:generateContent です。受け入れられたフォーマットはエンドポイントのみを確認します。個々のツールやフィールドはモデルによって異なる場合があります。
2026年10月3日時点で、この記事で参照されている3つのモデルをライブモデル API に対して確認しました:
| モデル | 受け入れフォーマット | 最大入力 / 出力トークン | 100万トークンあたりの価格 (USD) | ソース |
|---|---|---|---|---|
gpt-5.6-terra |
openai_chat_completions, openai_responses |
1,050,000 / 128,000 | 0.60 / 3.60 (入力272Kまで) | ライブ API |
claude-sonnet-5 |
anthropic_messages, openai_chat_completions |
1,000,000 / 128,000 | 0.90 / 4.50 | ライブ API |
gemini-3.5-flash |
gemini_generate_content, openai_chat_completions |
1,048,576 / 65,536 | 0.75 / 4.50 | ライブ API |
3つすべてがアクティブなライフサイクルステージにあり、代替モデルはなく、価格は 2026年10月2日T16:53:30.068Z に更新されました。したがって、今日 Responses リクエストを受け入れるのは gpt-5.6-terra のみです。他の2つは Chat Completions またはネイティブルートを通じて動作します。ライフサイクルや価格は変更される可能性があるため、出荷前に再確認してください。
ここでのエラーハンドリングも重要です。create 呼び出しでモデル名のスペルが間違っていると 400 model_not_found が返され、did_you_mean が含まれる場合があります。不明な ID について GET /v1/models/{model} を問い合わせると 404 model_not_found が返されます。retryable: false を伴う 503 all_channels_failed は、リクエストを繰り返しても無駄であることを意味します。製品に許可がない限り、自動的にモデルを切り替えないでください。
移行チェックリスト:Responses API vs Chat Completions
エージェントを Chat Completions から Responses に移行する際は、以下の順序に従ってください。
- モデルが
openai_responsesをリストしているか確認する。 リストしていない場合は、ここで停止してください。Chat Completions を維持するのがサポートされているパスです。 - 切り替え境界を選択する。 新しい会話は Responses で開始してください。フォーマットによって状態やツール呼び出しの表現が異なるため、ライブスレッドを途中で切り替えないでください。
- 保存された履歴を慎重に変換する。 古いスレッドを移行する必要がある場合は、次のリクエストの前にアプリケーション内で変換および検証してください。
- コアフィールドの名前を変更する。
messagesはinputに、システムまたは開発者メッセージはinstructionsに、max_tokensまたはmax_completion_tokensはmax_output_tokensになります。 - ツールループを書き直す。
choices[0].message.tool_callsの解析をfunction_callアイテムに置き換え、role: "tool"メッセージをcall_idでキー指定されたfunction_call_outputアイテムに置き換えます。 - レスポンス ID を永続化する。
previous_response_idを渡せるように各idを保存します。storeと保持期間を事前に決定し、TokenLab が保存されたレスポンスをどれくらいの期間保持するかを確認してください(読んだページには記載がありませんでした)。 - ストリームコンシューマーを書き直す。
response.output_text.delta、response.completed、response.failed、response.incomplete、およびerrorを処理します。response.completedなしでストリームが閉じた場合は失敗として扱ってください。 statusを確認する。 HTTP 成功であってもincompleteやfailedを含む場合があります。- 引き継がれない可能性のあるパラメータを監査する。 Create Response ページには
temperature、top_p、tools、parallel_tool_calls、reasoning、textがリストされています。n、logprobs、logit_bias、frequency_penalty、presence_penalty、seed、top_k、stop、user、stream_optionsはリストされていません。信頼する前に各モデルで確認してください。TokenLab は不明なフィールドをそのまま通過させる可能性がありますが、それはモデルがそれらを受け入れることを意味しません。 - JSON 出力をマップする。 Chat は
response_formatを使用します。Responses はtextオブジェクトを使用し、text.formatのサポートはモデルに依存します。 - 欠落しているエンドポイントを考慮して計画する。 Cancel、input-items、input-tokens エンドポイントは現在利用できません。保存されたレスポンスを削除しても生成はキャンセルされません。
- 再試行オフでリプレイテストを行う。
max_retries=0を維持し、再試行が安全かどうかを自身のコードで決定してください。タイムアウトした生成は自動的にリプレイされるべきではありません。
FAQ
Claude Sonnet 5 や Gemini 3.5 Flash に Responses リクエストを送信できますか?
2026年10月3日時点のライブモデル API によると、できません。claude-sonnet-5 は anthropic_messages と openai_chat_completions をリストしています。gemini-3.5-flash は gemini_generate_content と openai_chat_completions をリストしています。Chat Completions またはネイティブルートを使用し、出荷前に再度 accepted_request_formats を確認してください。
previous_response_id を使用すると、以前のターンの支払いは停止しますか?
読んだページには記載がありません。サーバーが保存されたレスポンスから継続できることは文書化されていますが、復元されたコンテキストがどのように課金されるかは記載されていません。マルチターンの呼び出しをいくつか実行し、ステートレスなベースラインに対して usage フィールドを比較してから節約を計画してください。
会話の途中でフォーマットを切り替えることはできますか?
いいえ。TokenLab のガイドでは、各フォーマットが状態とツール呼び出しを異なる方法で表現するため、会話ごとに1つのフォーマットを維持するように指示されています。保存された履歴を移行する必要がある場合は、次のリクエストを送信する前に、アプリケーション内で変換および検証してください。
実行中の Responses リクエストをキャンセルするにはどうすればよいですか?
キャンセルエンドポイントは現在利用できません。保存されたレスポンスを削除しても生成はキャンセルされず、WebSocket レスポンスは response.cancel をサポートしていません。ストリームの場合は、ユーザーが停止または切断したときにサーバーからアップストリームのストリームを閉じてください。
エンドポイントを変更する前に、TokenLab モデルカタログ を開き、エージェントが呼び出す正確なモデルの accepted_request_formats を確認してください。
出典
価格確認日 2026-10-03
- TokenLab Docs: API formats2026-10-03 時点で確認
- TokenLab Docs: Create Response2026-10-03 時点で確認
- TokenLab Docs: Create Chat Completion2026-10-03 時点で確認
- TokenLab Docs: Structured Outputs & Tool Calling2026-10-03 時点で確認
- TokenLab Docs: Streaming2026-10-03 時点で確認
- TokenLab Docs: Errors agents can act on2026-10-03 時点で確認
- TokenLab Docs: Migration Guides2026-10-03 時点で確認
- TokenLab Docs: Get a Model2026-10-03 時点で確認
