open-responses について
Open Responses は、複数プロバイダーの LLM を扱う統一 HTTP プロトコルのオープンソース仕様です。プロトコル実装者やクライアント開発者向けに、メッセージ、ツール呼び出し、ストリーミング、マルチモーダル入力を標準化し、ステートレスを基本としています。
主な機能
- 01プロバイダー間のリクエスト・応答形式を統一
- 02メッセージ・ツール呼び出し・マルチモーダル内容を規定
- 03SSE ストリーミングイベントと状態遷移を定義
- 04previous_response_id による会話の連結
- 05ベンダー接頭辞付き拡張に対応
活用シーン
- 01仕様に準拠したモデルサービスの実装
- 02複数プロバイダー向けクライアントの開発
- 03ツール利用と複数ターンのエージェント処理
- 04ストリーミングイベントと応答状態のデバッグ
MCP 対応
仕様では MCP ツールを外部ホスト型ツールに分類し、プロトコルのツール呼び出しにおける位置付けを説明しています。MCP サーバーや SDK ではなく、汎用プロトコルを定めるものです。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ openrouterteam/ skills --skill open-responsesインストール後、Claude Code で/open-responsesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonreferences/extensions.mdprotocol-and-items.mdstate-machines-and-streaming.md詳細
Open Responses
Open Responses は、複数プロバイダーとの LLM インタラクションを実現する、統一された HTTP プロトコルを定義するオープンソース仕様です。メッセージ、ツール呼び出し、ストリーミング、マルチモーダル入力、推論など、クライアントとサーバーの通信方法を標準化することで、あるプロバイダー向けに書かれたコードを、準拠するあらゆるプロバイダーで動作させます。
これはプロトコル標準そのものであり、特定の SDK ではありません。 Open Responses はプロバイダーに依存しません。あらゆる LLM プロバイダー(OpenAI、Anthropic、Gemini、Databricks、Hugging Face、Ollama など)が、準拠する API を実装できます。
デフォルトはステートレス、必要に応じてステートフルです。 コアプロトコルは、サーバー側でのセッション永続化を要求しません。複数ターンの会話は
previous_response_idを通じて連結でき、これによりサーバーは以前のレスポンスからコンテキストを再構築します。ただし、プロバイダーは拡張機能としてステートフルな機能(例:サーバー側ストレージ、会話オブジェクト)を提供する場合があります。仕様では、アイテムの状態は「ディスクに永続化されたり、長期的に保存されたりするという意味で、必ずしもステートフルであるとは限らない」と記されています。
設計原則
- 複数プロバイダーとの互換性 — 1 つのスキーマで、あらゆるプロバイダーに対応
- ステートレス優先のプロトコル —
previous_response_idを通じてコンテキストを再構築し、プロバイダーは任意で永続化を提供できます - ポリモーフィックなアイテム — すべてのモデル出力が、
typeで識別される共通のアイテム構造を共有します - セマンティックストリーミング — SSE イベントがステートマシンの遷移に直接対応します
- 断片化を招かない拡張性 — ベンダー接頭辞付きの拡張により、名前空間の衝突を防ぎます
仕様: https://www.openresponses.org/specification
参照ファイル
詳細なスキーマ、JSON の例、イベントの完全なカタログについては、適切な参照ファイルを読み込んでください。
| ファイル | 内容 | 読み込むタイミング |
|---|---|---|
references/protocol-and-items.md | HTTP プロトコル、アイテムの種類、コンテンツの種類、制御パラメーター、エラー処理 | リクエスト/レスポンス構造の実装またはデバッグ時 |
references/state-machines-and-streaming.md | ステートマシン図、ストリーミングイベントのカタログ、テキストとツール使用時の完全な SSE シーケンス | ストリーミングや状態遷移の実装またはデバッグ時 |
references/extensions.md | カスタムアイテム、カスタムイベント、スキーマ拡張、ガバナンスの手順 | プロバイダー固有の機能で仕様を拡張する時 |
特定のトピックを参照ファイル内で検索するには、function_call、streaming、tool_choice、previous_response_id、vendor: などのキーワードで grep してください。
コアコンセプト
エンドポイントとトランスポート
すべてのリクエストは、Authorization: Bearer <token> と Content-Type: application/json を指定して POST /v1/responses に送信します。ストリーミングしないレスポンスは JSON を返します。ストリーミングレスポンスでは SSE(text/event-stream)を使用し、data: [DONE] で終了します。
アイテム
アイテムは、type で識別されるポリモーフィックな原子的単位です。出力アイテム(レスポンス内でモデルが出力するアイテム)には、id、type、status フィールドが必要です。コア出力タイプは、message、function_call、reasoning です。プロバイダーは、ベンダー接頭辞付きのタイプ(例:acme:web_search_call)で拡張できます。
入力アイテム(リクエスト内でクライアントが送信するアイテム)に必要な項目は、タイプごとに異なります。input_text、input_image、input_file などのコンテンツタイプには、id や status は含まれません。function_call_output アイテムには call_id と output が必要ですが、id と status は任意です。
メッセージのロール: user、assistant、system、developer。system ロールは instructions パラメーターとは異なり、入力配列内のインラインメッセージアイテムです。developer ロールは独立したロールであり、プロバイダーによっては system とは異なる扱いをする場合があります。
ステートマシンとイベントの発行
レスポンスとアイテムのライフサイクルは、どちらも有限状態マシンです。各状態によって、発行できるイベントが制約されます。
レスポンスのライフサイクル — 状態ごとに発行されるイベント
stateDiagram-v2
[*] --> created : response.created
created --> queued : response.queued
queued --> in_progress : response.in_progress
state in_progress {
direction LR
note right of in_progress
Events emittable while in_progress:
─────────────────────────────────
response.output_item.added
response.content_part.added
response.output_text.delta
response.output_text.done
response.function_call_arguments.delta
response.function_call_arguments.done
response.reasoning_summary_text.delta
response.reasoning_summary_text.done
response.content_part.done
response.output_item.done
vendor:custom_event
All delta events carry: sequence_number,
output_index, item_id
Content-level events also carry: content_index
end note
}
in_progress --> completed : response.completed
in_progress --> incomplete : response.incomplete\n(item hit token budget)
in_progress --> failed : response.failed
completed --> [*]
incomplete --> [*]
failed --> [*]
注: アイテムが
incomplete状態で終了する場合、そのアイテムを含むレスポンスも必ずincompleteになります。
項目のライフサイクル — 状態ごとに発行されるイベント
stateDiagram-v2
[*] --> in_progress : response.output_item.added
state in_progress {
direction LR
note right of in_progress
Events emittable while item is in_progress:
──────────────────────────────────────────
Message items:
response.content_part.added
response.output_text.delta (repeated)
response.output_text.done
response.content_part.done
Function call items:
response.function_call_arguments.delta (repeated)
response.function_call_arguments.done
Reasoning items:
response.reasoning_summary_text.delta (repeated)
response.reasoning_summary_text.done
end note
}
in_progress --> completed : response.output_item.done
in_progress --> incomplete : response.output_item.done
completed --> [*]
incomplete --> [*]
note right of completed : Terminal — no further deltas
note right of incomplete : Terminal — token budget exhausted
イベントの有効性の概要
| レスポンスの状態 | 有効なイベント |
|---|---|
created | (一時的 — レスポンスオブジェクトが作成された直後) |
queued | (モデルが利用可能になるのを待機中) |
in_progress | すべての差分イベント、すべてのカスタムイベント、項目のライフサイクルイベント |
completed | (終端 — [DONE] 以外のイベントはこれ以上発生しない) |
incomplete | (終端 — [DONE] 以外のイベントはこれ以上発生しない) |
failed | (終端 — [DONE] 以外のイベントはこれ以上発生しない) |
| 項目の状態 | 有効なイベント |
|---|---|
in_progress | コンテンツの差分(.delta)、コンテンツの完了(.done)、パートのライフサイクル |
completed | (終端 — この項目について、これ以上差分は発生しない) |
incomplete | (終端 — この項目について、これ以上差分は発生しない) |
すべての差分イベントと項目イベントには、sequence_number(単調増加)、output_index(レスポンス出力配列内の位置)、item_id が含まれます。コンテンツレベルのイベント(テキスト、推論の要約)には、さらに content_index(コンテンツパート内の位置)が含まれます。サーバーは SSE の id フィールドを使用しないことが推奨されます。
ストリーミングイベント
SSE イベントには 2 つのカテゴリがあります。
- 差分イベント — 増分コンテンツ:
response.output_text.delta、response.function_call_arguments.delta、response.output_item.added、response.output_item.doneなど。 - ライフサイクルイベント — 状態遷移:
response.created、response.queued、response.in_progress、response.completed、response.incomplete、response.failed
ルール:SSE ヘッダーの event は、JSON 本文内の type フィールドと一致する必要があります。
ツール
Open Responses では、実行場所に基づいて 2 種類のツールを定義しています。
外部ホスト型ツール — 実装がプロバイダーのシステム外にあります。モデルは function_call 項目を通じて呼び出しを要求し、開発者は後続のリクエストで function_call_output 項目として結果を渡す必要があります。「外部ホスト型」が、必ずしも開発者がツールをローカルで実行することを意味するわけではありません。MCP ツールは外部ホスト型です(実装が外部サーバー上にあります)が、必ずしも先に制御が開発者へ戻るわけではありません。例:関数ツール、MCP サーバーのツール。
内部ホスト型ツール — 実装がプロバイダーのシステム内にあります。プロバイダーは制御を引き渡さずに実行し、同じレスポンス内でプロバイダー固有の項目タイプとして結果を返します。これらの項目は、後続のリクエストで損失なくラウンドトリップできる必要があります。例:ファイル検索、コードインタープリター、ウェブ検索。
ツールの定義
{
"type": "function",
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"},
"units": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["location"]
}
}
ツールの制御
tool_choice パラメーターは、モデルがツールを使用するかどうか、およびその使用方法を制御します。
tool_choice の値 | 目的 |
|---|---|
"auto" | ツールを呼び出すかどうかをモデルが決定します(デフォルト) |
"required" | モデルは少なくとも 1 つのツールを呼び出す必要があります |
"none" | ツール呼び出しは許可されません |
{"type": "function", "name": "..."} | 特定のツールを強制します |
{"type": "allowed_tools", "tools": [...]} | モデルが呼び出せるツールを制限します |
allowed_tools 形式は tool_choice の中にネストされており、独立したトップレベルのパラメーターではありません。
{
"tool_choice": {
"type": "allowed_tools",
"tools": [
{"type": "function", "name": "get_weather"}
]
}
}
モデルは、ツール呼び出しを allowed_tools で指定されたサブセットに限定しなければなりません(MUST)。サーバーはこれを厳格な制約として適用しなければなりません(MUST)。ツール定義はモデルのコンテキストに残るため、プロンプトキャッシュが維持されます。
エージェントループのパターン
エージェントループは、複数ステップでツールを活用するワークフローの中核となるパターンです。
フロー
Client Provider Model
| | |
|-- POST /v1/responses ---->| |
| |--- prompt to model ----->|
| |<-- output items ---------|
| | |
| [external tool calls needing |
| client-supplied results?] |
| | |
| YES |
|<-- response with --------| |
| function_call items | |
| | |
| [client satisfies | |
| tool calls] | |
| | |
|-- POST /v1/responses ---->| |
| previous_response_id + | |
| function_call_output |--- prompt + context ---->|
| items in input |<-- output items ---------|
| | |
| NO: no client-satisfied calls remain |
|<-- completed response ----| |
| (may contain message, | |
| reasoning, hosted-tool | |
| items, etc.) | |
主要原則
-
ステートレス優先の反復処理 — ループの各反復処理は、新しい HTTP リクエストです。サーバーは
previous_response_idからコンテキストを再構築します。プロバイダーは任意で状態を保持できますが、プロトコルではそれを必須としていません。 -
外部ツールの実行は開発者が制御 — 外部ホスト型の関数ツールでは、実行するタイミング、返す結果、処理を続けるかどうかを開発者が決定します。MCP ツール(こちらも外部ホスト型)の場合は、開発者に制御を渡すことなく実行されることがあります。
-
並列ツール呼び出し — モデルは、1 回のレスポンスで複数の
function_callアイテムを出力することがあります。それらをすべて実行し、後続の 1 回のリクエストですべての結果を返します。 -
ループの終了 — レスポンスに、クライアント側で処理する外部ツール呼び出しが残っていない場合、ループは終了します。最終レスポンスには
messageアイテムだけでなく、reasoningアイテム、内部ホスト型ツールアイテム、その他のメッセージ以外の出力アイテムが含まれることもあります。 -
内部ツールはプロバイダーが処理 — 内部ホスト型ツールでは、プロバイダーが同じリクエスト内で実行し、プロバイダー固有のアイテムタイプを返します。開発者側でループを実行する必要はありません。
例:複数ツールを使うエージェント
ターン 1 — ツールを含むリクエスト:
{
"model": "provider/model-name",
"input": [{"type": "message", "role": "user", "content": "Compare the weather in Paris and Tokyo."}],
"tools": [{"type": "function", "name": "get_weather", "description": "Get current weather for a city", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}]
}
ターン 1 — モデルが 2 つの並列 function_call アイテムを出力:
{
"id": "resp_100",
"status": "completed",
"output": [
{"id": "item_101", "type": "function_call", "name": "get_weather", "call_id": "call_paris", "arguments": "{\"location\":\"Paris\"}", "status": "completed"},
{"id": "item_102", "type": "function_call", "name": "get_weather", "call_id": "call_tokyo", "arguments": "{\"location\":\"Tokyo\"}", "status": "completed"}
]
}
ターン 2 — 開発者がツールの結果を返す:
{
"model": "provider/model-name",
"previous_response_id": "resp_100",
"input": [
{"type": "function_call_output", "call_id": "call_paris", "output": "{\"temperature\":18,\"condition\":\"partly cloudy\"}"},
{"type": "function_call_output", "call_id": "call_tokyo", "output": "{\"temperature\":24,\"condition\":\"sunny\"}"}
],
"tools": [...]
}
ターン 2 — モデルが最終回答を統合(function_call アイテムがないためループ終了):
{
"id": "resp_101",
"status": "completed",
"output": [
{"id": "item_200", "type": "message", "role": "assistant", "status": "completed", "content": [{"type": "output_text", "text": "Paris is currently 18°C and partly cloudy. Tokyo is warmer at 24°C with sunny skies."}]}
]
}
マルチターンの会話
マルチターンの会話では、previous_response_id を使ってコンテキストを連結します。サーバーはレスポンスチェーンをたどって会話全体を再構築します(プロバイダーは拡張機能としてサーバー側での永続化にも対応できます)。
Server loads: previous_response.input + previous_response.output + new_input
// Turn 1
{"model": "provider/model-name", "input": [{"type": "message", "role": "user", "content": "What is the population of France?"}]}
// Response: {"id": "resp_200", ...}
// Turn 2 — references Turn 1
{"model": "provider/model-name", "previous_response_id": "resp_200", "input": [{"type": "message", "role": "user", "content": "And what about Germany?"}]}
拡張機能
Open Responses は、名前の衝突を防ぐため、ベンダー接頭辞付きの名前を使う 4 つの拡張メカニズムをサポートしています。例を含む詳細については、references/extensions.md を読み込んでください。
| メカニズム | 命名パターン | 必須フィールド | 制約 |
|---|---|---|---|
| カスタムアイテム | vendor:type_name | id、type、status | アイテムのステートマシンに従い、往復可能であること |
| カスタムイベント | vendor:event_name | type、sequence_number | コアのセマンティクスやトークンの順序を変更しないこと |
| スキーマ拡張 | ベンダー接頭辞付きフィールド | N/A(任意フィールド) | 不明なフィールドを無視するクライアントを破損させないこと |
| ガバナンスパス | N/A | N/A | 幅広い採用 → TSC への提案 → コア仕様 |
クライアントは、不明なアイテムタイプとイベントタイプを無視しなければなりません。これは前方互換性を保証するための契約です。
準拠性
API が仕様を直接実装しているか、適切な上位互換仕様であれば、Open Responses に準拠しています。公開されている受け入れテストスイートは https://www.openresponses.org/ で利用できます。
コア準拠テスト
| テスト | 検証内容 |
|---|---|
| 基本的なテキストレスポンス | ResponseResource スキーマ、アイテム構造、使用量 |
| ストリーミングレスポンス | SSE イベント、正しい順序、最終構造 |
| システムプロンプト | instructions パラメーター、システムロールの処理 |
| ツール呼び出し | 関数ツールの定義、function_call 出力、往復処理 |
| 画像入力 | ユーザーコンテンツ内の画像 URL |
| マルチターンの会話 | メッセージ履歴、アシスタントとユーザーのターン |
サーバー実装チェックリスト
-
Authorizationヘッダーを使用するPOST /v1/responsesエンドポイント -
id、type、statusを含む有効な出力アイテム。入力アイテムはそれぞれの型の要件を満たすこと - アイテムの状態遷移:
in_progress->completed/incomplete - レスポンスの状態遷移:
created->queued->in_progress->completed/incomplete/failed - 6 つすべてのライフサイクルイベントを送信:
response.created、.queued、.in_progress、.completed、.incomplete、.failed - いずれかのアイテムが
incompleteで終了した場合、レスポンスもincomplete -
eventとtypeが一致する非ストリーミング JSON とストリーミング SSE - 終端マーカー
data: [DONE] - 関数ツール:
function_callアイテム、function_call_outputによるラウンドトリップ - 会話の継続に使用する
previous_response_id - 正しい HTTP ステータスコードを伴うエラーオブジェクト:
type、code、param、message - ベンダープレフィックス付き拡張(該当する場合)
クライアント実装チェックリスト
-
AuthorizationとContent-Typeヘッダーを送信 -
typeフィールドに基づいて多相アイテムを解析 - アイテムとレスポンスの状態遷移を追跡
- SSE を処理:
event:+data:行を解析し、[DONE]を処理 - 外部ホスト型ツール向けのエージェントループを実装
- 未知のアイテム型とイベント型を無視
- 複数ターンの会話で
previous_response_idをサポート - 1 つのレスポンス内での並列ツール呼び出しに対応
クイックリファレンス
ストリーミングイベントの種類
| イベント | カテゴリ |
|---|---|
response.created | ライフサイクル |
response.queued | ライフサイクル |
response.in_progress | ライフサイクル |
response.completed | ライフサイクル |
response.incomplete | ライフサイクル |
response.failed | ライフサイクル |
response.output_item.added / .done | デルタ |
response.content_part.added / .done | デルタ |
response.output_text.delta / .done | デルタ |
response.function_call_arguments.delta / .done | デルタ |
response.reasoning_summary_text.delta / .done | デルタ |
vendor:custom_event | カスタム |
アイテムの種類
| 種類 | カテゴリ |
|---|---|
message | コア |
function_call | コア |
function_call_output | コア |
reasoning | コア |
vendor:custom_type | 拡張 |
状態の概要
| オブジェクト | 状態 | 終端状態 |
|---|---|---|
| レスポンス | created -> queued -> in_progress -> completed / incomplete / failed | completed、incomplete、failed |
| アイテム | in_progress -> completed / incomplete | completed、incomplete |
いずれかのアイテムが incomplete で終了した場合、それを含むレスポンスも必ず incomplete でなければなりません。
エラーの種類
| 種類 | HTTP | 再試行 |
|---|---|---|
invalid_request | 400 | いいえ |
not_found | 404 | いいえ |
too_many_requests | 429 | はい |
server_error | 500 | はい |
model_error | 500 | 場合による |