关于 open-responses
Open Responses 是一项开源规范,为多供应商 LLM 交互定义统一的 HTTP 协议,面向协议实现者和客户端开发者。它标准化消息、工具调用、流式事件及多模态输入,同时默认采用无状态设计。
主要功能
- 01统一多供应商请求与响应格式
- 02规范消息、工具调用和多模态内容
- 03定义 SSE 流式事件与状态转换
- 04通过 previous_response_id 串联对话
- 05支持供应商前缀扩展
适用场景
- 01实现兼容该协议的模型服务
- 02开发可连接不同供应商的客户端
- 03构建工具调用与多轮 Agent 流程
- 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 是一项开源规范,定义了用于多提供商大模型交互的统一 HTTP 协议。它标准化了客户端和服务端的通信方式——消息、工具调用、流式传输、多模态输入、推理——使针对某个提供商编写的代码也能与任何符合规范的提供商配合使用。
这是协议标准本身,而非任何特定 SDK。 Open Responses 不依赖于特定提供商。任何大模型提供商(OpenAI、Anthropic、Gemini、Databricks、Hugging Face、Ollama 等)都可以实现符合规范的 API。
默认无状态,需要时可有状态。 核心协议不要求服务端持久化会话。多轮对话可以通过
previous_response_id串联,该参数会指示服务端根据先前的响应重建上下文。不过,提供商可以通过扩展提供有状态功能(例如服务端存储、对话对象)。规范指出,条目状态“并不一定意味着它们会以持久化到磁盘或长期存储的方式保持有状态”。
设计原则
- 兼容多家提供商 — 一套架构,适用于任何提供商
- 无状态优先的协议 — 通过
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 | 自定义条目、自定义事件、架构扩展、治理流程 | 使用提供商特有功能扩展规范时 |
如需搜索特定主题的参考内容:grep 搜索 function_call、streaming、tool_choice、previous_response_id、vendor: 或其他关键词。
核心概念
端点和传输
所有请求都发送到 POST /v1/responses,并携带 Authorization: Bearer <token> 和 Content-Type: application/json。非流式响应以 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(在内容部分中的位置)。服务器 SHOULD NOT 使用 SSE id 字段。
流式事件
SSE 事件分为两类:
- 增量事件——增量内容:
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 根据执行位置定义了两类工具。
外部托管工具——其实现位于提供方系统之外。模型通过 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" | 模型必须至少调用一个工具 |
"none" | 不允许调用工具 |
{"type": "function", "name": "..."} | 强制使用特定工具 |
{"type": "allowed_tools", "tools": [...]} | 限制模型可以调用的工具 |
allowed_tools 形式嵌套在 tool_choice 中,而不是单独的顶层参数:
{
"tool_choice": {
"type": "allowed_tools",
"tools": [
{"type": "function", "name": "get_weather"}
]
}
}
模型 MUST 将工具调用限制在 allowed_tools 中列出的子集中。服务器 MUST 将此作为硬性约束执行。工具定义仍保留在模型的上下文中,从而保留提示缓存。
Agent 式循环模式
Agent 式循环是多步骤、工具增强工作流的核心模式。
流程
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 工具(同样由外部托管),执行时可以不先将控制权交还给开发者。
-
并行工具调用 — 模型可以在单个响应中发出多个
function_call项。执行所有这些调用,并在一次后续请求中返回所有结果。 -
循环终止 — 当响应中不再包含需要客户端处理的外部工具调用时,循环结束。最终响应可能不仅包含
message项,还包含reasoning项、内部托管的工具项以及其他非消息输出项。 -
由提供方处理内部工具 — 对于内部托管的工具,提供方会在同一请求中执行,并返回提供方特定的项类型。开发者无需执行循环。
示例:多工具 Agent
第 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 轮 — 模型发出两个并行的 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 支持四种扩展机制,均使用厂商前缀名称以避免冲突。完整详情和示例请加载 references/extensions.md。
| 机制 | 命名模式 | 必需字段 | 约束 |
|---|---|---|---|
| 自定义项 | vendor:type_name | id、type、status | 必须遵循项状态机,且必须支持往返传递 |
| 自定义事件 | vendor:event_name | type、sequence_number | 不得更改核心语义或令牌顺序 |
| Schema 扩展 | 带厂商前缀的字段 | 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 - 非流式 JSON 和流式 SSE 的
event/type保持一致 -
data: [DONE]终止标记 - 函数工具:
function_call项,以及function_call_output往返传递 - 使用
previous_response_id延续对话 - 错误对象包含
type、code、param、message,并使用正确的 HTTP 状态码 - 厂商前缀扩展(如适用)
客户端实现检查清单
- 发送
Authorization和Content-Type标头 - 根据
type字段解析多态项 - 跟踪项和响应状态机
- 处理 SSE:解析
event:+data:行,并处理[DONE] - 为外部托管的工具实现 Agentic 循环
- 静默忽略未知项类型和事件类型
- 支持使用
previous_response_id进行多轮对话 - 处理单个响应中的并行工具调用
快速参考
流式事件类型
| 事件 | 类别 |
|---|---|
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 结束,包含该项的响应也 MUST 为 incomplete。
错误类型
| 类型 | HTTP | 重试 |
|---|---|---|
invalid_request | 400 | 否 |
not_found | 404 | 否 |
too_many_requests | 429 | 是 |
server_error | 500 | 是 |
model_error | 500 | 可能 |