规范

Open Responses 是一个开源规范和生态系统,用于构建基于 OpenAI 响应 API 的多提供商、可互操作的 LLM 接口。它定义了一个共享模式客户端库工具层,使开发者能够以统一的方式调用语言模型、流式传输结果,并组合智能体工作流——与具体提供商无关。

本文档中,“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、“MAY” 和 “OPTIONAL” 等关键词在全大写时(如本处所示),应按照 BCP 14 [RFC2119] [RFC8174] 中所述进行解释。

动机与概览

现代 LLM 系统已趋同于相似的基本组件——消息、函数调用、工具使用和多模态输入——但每个提供商对它们的编码方式各不相同。Open Responses 对这些概念进行了标准化,从而实现:

  • 一规多供:只需描述一次输入/输出,即可在 OpenAI、Anthropic、Gemini 或本地模型上运行。
  • 可组合的智能体循环:统一的流式处理、工具调用和消息编排。
  • 更易评估与路由:通过共享模式比较提供商、路由请求并记录结果。
  • 提供者 API 的蓝图:希望以通用格式暴露其 API 的实验室或模型提供商可以轻松实现。

核心原则

智能体循环

所有模型在某种程度上都表现出代理性 —— 即感知输入、推理、通过工具采取行动,并反思结果的能力。

Open Responses 的核心正是为了向开发者揭示这种智能体循环的力量,支持允许模型执行多项任务并返回结果的请求,无论是由开发者托管的工具调用(控制权交还给用户),还是由提供商托管的工具调用(控制权保留在模型提供商手中,直到模型发出退出条件)。

Open Responses 定义了智能体循环中控制流的通用模式,一组由开发者控制的工具项目定义,以及一种定义提供商和路由器托管工具的模式。

项目 → 项目

项目是 Open Responses 中上下文的基本单位:它们代表模型输出、工具调用或推理状态的一个原子单元。项目具有双向性,既可作为模型的输入,也可作为模型的输出。

每种项目类型都有一个定义好的模式,绑定其用途并包含特定属性。

Open Responses 定义了一组被多数模型提供商支持的通用项目类型,并规定了如何定义特定于提供商的项目类型。

语义事件

流式传输被建模为一系列语义事件,而非原始文本或对象增量。

事件描述有意义的转换。它们要么是状态转换——response.in_progressresponse.completed——要么表示从先前状态的增量——response.output_item.addedresponse.output_text.delta

Open Responses 定义了一组被多数模型提供商支持的通用流式事件,并规定了如何定义特定于提供商的流式事件。

状态机

Open Responses 中的对象是状态机,即它们处于有限数量的状态之一,如 in_progresscompletedfailed。该规范定义了 API 中每个状态机的有效状态集合。

规范

HTTP 请求

所有消息必须遵循 HTTP 协议。

头信息

头字段描述是否必需
Authorization用于标识开发者的授权令牌
Content-Type告诉服务器 请求体中包含什么类型的数据 以及如何解析它。

HTTP 请求体

客户端必须将请求体编码为 application/json

HTTP 响应

头信息

头字段描述是否必需
Content-Type告诉客户端 响应体中包含什么类型的数据 以及如何解析它。

HTTP 响应体

非流式情况下,服务器必须仅以 application/json 格式返回数据。

流式 HTTP 响应

流式情况下,服务器必须返回头 Content-Type: text/event-stream,并将各个 data 对象作为 JSON 编码字符串返回。终止事件必须是字面量字符串 [DONE]

event 字段必须与事件体中的 type 匹配。服务器不应使用 id

event: response.output_text.delta
data: { "type":"response.output_text.delta","sequence_number":10,"item_id":"msg_07315d23576898080068e95daa2e34819685fb0a98a0503f78","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"Wd6S45xQ7SyQLT"}

项目

项目是 Open Responses 的核心上下文单位。Open Responses 定义了一些所有提供商共有的项目类型,如 messagefunction_call,并定义了如何定义额外的、特定于提供商的项目类型。所有项目都遵循一些通用原则:

项目是多态的

项目形态因用途而异。例如,message 项目的结构与 function_call 不同,依此类推。项目根据 type 字段进行区分。

示例:消息
{
"type": "message",
"id": "msg_01A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6",
"role": "assistant",
"status": "completed",
"content": [
{
"type": "output_text",
"text": "Hello! How can I assist you today?"
}
]
}
示例:函数调用
{
"type": "function_call",
"id": "fc_00123xyzabc9876def0gh1ij2klmno345",
"name": "sendEmail",
"call_id": "call_987zyx654wvu321",
"arguments": "{\"recipient\":\"jane.doe@example.com\",\"subject\":\"Meeting Reminder\",\"body\":\"Don't forget about our meeting tomorrow at 10am.\"}"
}

项目是状态机

在 Open Responses 中,所有项目都有生命周期。当模型正在生成当前项目的标记时,其状态为 in_progress;当模型在生成过程中耗尽其标记预算时,状态为 incomplete;当完全完成生成时,状态为 completed

需要注意的是,尽管项目遵循状态机模型——经历这些定义的状态——但这并不一定意味着它们在磁盘上持久化或长期存储。状态机描述的是项目在响应流程中的状态,而持久化是另一个独立的问题,且不由项目状态转换暗示。

所有项目类型应具有以下三种基本状态:

  • in_progress - 模型当前正在生成属于该项目的标记
  • incomplete - 模型在生成属于该项目的标记时耗尽了标记预算。这是一个终端状态。如果某项目以终端状态结束,它必须是最后生成的项目,且包含它的响应也必须处于 incomplete 状态。
  • completed - 模型已完成生成包含该项目的标记,或者工具调用已成功完成。这是一个终端状态,一旦项目进入此状态后,不得再对其进行任何更新。

项目是可流式的

当项目状态或值发生变化时,Open Responses 定义了如何在响应流中传达这些更新。

  1. 第一个事件必须始终是 response.output_item.added。项目将在负载中以当时可用的尽可能多的信息回显。对于 messages,这至少包括 role;对于 function_call,至少包括 name。所有未标记为可空的字段都必须有值。适用时使用零值。
示例
{
"type": "response.output_item.added",
"sequence_number": 11,
"output_index": 3,
"item": {
"id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"type": "message",
"status": "in_progress",
"content": [],
"role": "assistant"
}
}
  1. 某些项目具有 可流式内容。通常这是模型生成的文本,比如在 message 的情况下。此类内容必须由内容部分支持。此类情况下的第一个事件必须是 response.content_part.added,随后是表示内容部分增量的事件,例如 response.<content_type>.delta。增量事件可以重复多次,最终以 response.<content_type>.done 结束。内容部分然后通过 response.content_part.done 关闭。
示例
{
"type": "response.content_part.added",
"sequence_number": 12,
"item_id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"output_index": 3,
"content_index": 0,
"part": {
"type": "output_text",
"annotations": [],
"text": ""
}
}
{
"type": "response.output_text.delta",
"sequence_number": 13,
"item_id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"output_index": 3,
"content_index": 0,
"delta": "Here",
}
...
{
"type": "response.output_text.done",
"sequence_number": 25,
"item_id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"output_index": 3,
"content_index": 0,
"text": "Here\u2019s the current weather for San Francisco, CA (as of Wednesday, October 15, 2025):\n\n- Current conditions: Cloudy, 58\u00b0F (14\u00b0C).\n- Today\u2019s outlook: A shower in spots late this morning; oth
erwise a cloudy start with sunshine returning later. High near 67\u00b0F (19\u00b0C), low around 51\u00b0F (11\u00b0C).\n\nIf you\u2019d like wind speed, humidity, or hourly updates, I can pull those too. ",
}
{
"type": "response.content_part.done",
"sequence_number": 26,
"item_id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"output_index": 3,
"content_index": 0,
"part": {
"type": "output_text",
"annotations": [],
"text": "Here\u2019s the current weather for San Francisco, CA (as of Wednesday, October 15, 2025):\n\n- Current conditions: Cloudy, 58\u00b0F (14\u00b0C).\n- Today\u2019s outlook: A shower in spots late this mornin
g; otherwise a cloudy start with sunshine returning later. High near 67\u00b0F (19\u00b0C), low around 51\u00b0F (11\u00b0C).\n\nIf you\u2019d like wind speed, humidity, or hourly updates, I can pull those too. "
}
}
  1. 具有 content 的项目可能会发出多个内容部分,遵循上述模式。完成后,项目通过 response.output_item.done 关闭。
示例
{
"type": "response.output_item.done",
"sequence_number": 27,
"output_index": 3,
"item": {
"id": "msg_0f7983f1618f89d20068efe9b45d748191a5239d49c2971a65",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"text": "Here\u2019s the current weather for San Francisco, CA (as of Wednesday, October 15, 2025):\n\n- Current conditions: Cloudy, 58\u00b0F (14\u00b0C).\n- Today\u2019s outlook: A shower in spots late this mornin
g; otherwise a cloudy start with sunshine returning later. High near 67\u00b0F (19\u00b0C), low around 51\u00b0F (11\u00b0C).\n\nIf you\u2019d like wind speed, humidity, or hourly updates, I can pull those too. "
}
],
"role": "assistant"
}
}

项目是可扩展的

模型提供商可以发出不在 Open Responses 规范内的自定义项目类型。这些项目必须以前缀形式命名,使用规范的提供商缩写,例如:

{
"id": "ws_0df093a2d268cd7f0068efe79ac9408190b9833ec01e5d05ed",
"type": "openai:web_search_call",
"status": "completed",
"action": {
"type": "search",
"query": "weather: San Francisco, CA"
}
}

内容

在 Open Responses 中,“内容”代表用户与模型在每轮消息中交换的原始材料。它被有意设计为一个判别联合类型,而不是单一的多态类型,允许用户提供的输入和模型生成的输出采用不同的结构。

用户内容 vs 模型内容

存在两个顶级的内容联合类型:

  • UserContent:由用户或客户端应用程序提供的结构化数据。
  • ModelContent:由模型返回的结构化数据。

这一区别反映了对话轮次的不对称性。用户输入可以包含多种模态(例如文本、图像、音频、视频),而模型输出通常限制为文本,至少在基础协议中如此。将这两个联合类型分开,允许模型提供商独立演化其输出模式(例如未来添加 output_imageoutput_tool_call),而不必过度泛化用户端。

为何用户与助手内容形状不同

尽管两者都称为“内容”,但用户和助手的数据承载着非常不同的角色:

  • 用户内容捕捉的是 模型需要处理的内容。它可以包含一个或多个文本段落、图像或其他二进制数据,这些是模型推理步骤的重要输入。
  • 助手(模型)内容捕捉的是 模型产生的内容——其文本补全或推理输出。这些内容通常可序列化为 UTF-8 文本,可能带有 token logprobs 等元数据。

由于这种不对称性:

  • 用户内容必须支持多种数据类型(文本、base64 编码或 URL 获取的图像,以及其他未来的模态)。
  • 模型内容被有意地限定,以保持协议在各提供商之间简洁且可预测。

这种分离简化了验证、流式传输和日志记录。例如,客户端可以安全地假设每个模型消息都包含 output_text,而用户消息可能包含任意混合的文本和图像输入。

推理

推理项目以受控的、由提供商定义的方式暴露模型的内部思考过程。推理项目的有效载荷可能包含以下一个或多个字段:

  • content(原始推理内容):提供商可以选择直接通过 reasoning 项目的 content 字段公开模型的原始推理轨迹。此内容通常是可流式的,并遵循与其他类似文本内容部分相同的增量语义。暴露原始推理是可选的,可能出于安全、隐私或成本原因被禁用或截断。
  • encrypted_content(受保护的推理内容):提供商可以选择永远不向客户端暴露原始推理。相反,他们可以返回一个 encrypted_content 有效载荷,其格式和加密属性由提供商自定义。客户端应将其视为不透明且不可检查的字段;目的是让提供商在允许推理内容往返的同时加以保护。
  • summary(推理摘要):提供商可实现对推理轨迹的摘要视图(例如,对模型所采取关键步骤的简短自然语言解释),并通过 summary 字段公开。摘要设计为对终端用户安全,可用于透明度展示、调试或 UI 支持,而无需揭示完整原始轨迹。

这三个字段均为可选(可为空或零值),提供商可根据其安全策略、商业需求和实现细节自由支持其中任意组合。

示例
{
"type": "reasoning",
"status": "completed",
"summary": [
{
"type": "summary_text",
"text": "Determined that the user is asking for restaurant recommendations in a specific city, then filtered options by distance and rating before selecting three suggestions."
}
],
"content": [
{
"type": "output_text",
"text": "User asked: \"Where should I eat dinner in downtown Seattle tonight?\"↵↵1. Interpreted task as a search for nearby restaurants suitable for dinner.↵2. Prioritized places within a short walking radius of downtown.↵3. Filtered candidates by overall rating and number of reviews.↵4. Preferred options with vegetarian choices and moderate price range.↵5. Selected three restaurants that best match the inferred preferences."
}
],
"encrypted_content": null
}

错误

Open Responses 中的错误处理旨在为开发者和用户提供清晰、可操作的反馈,当请求失败或遇到问题时。

发生错误时,API 会返回一个结构化的错误对象,包含:

  • Type:错误类别,如 server_errormodel_errorinvalid_requestnot_found。这些通常(但不一定)对应于响应的状态码。
  • Code:可选的错误代码,提供更多关于具体问题的详细信息。所有常见错误代码都在规范中枚举。
  • Param:与错误相关的输入参数(如适用)。
  • Message:对问题的可读说明。

错误也会作为流式协议中的事件发出,允许客户端实时检测和响应流式响应中的问题。任何在流式过程中发生的错误之后都会跟随一个 response.failed 事件。

建议在客户端实现中检查错误响应并妥善处理。在可能的情况下显示友好的用户消息或触发适当的回退机制。

错误类型可以指示错误是否可恢复,使您的应用程序能够决定是否重试、提示用户或停止操作。错误的 code 提供额外细节,通常包括恢复指南或步骤,有助于开发者创建更健壮、响应更快的客户端。

{
"error": {
"message": "The requested model 'fake-model' does not exist.",
"type": "invalid_request_error",
"param": "model",
"code": "model_not_found"
}
}

错误类型

错误类型描述状态码
server_error服务器遇到意外情况,无法完成请求。这是内部故障,不由客户端引起。稍后重试可能成功。500
invalid_request请求格式错误或语义无效。一个或多个参数缺失、格式错误或不受支持。此错误可通过修复请求解决。400
not_found请求的资源不存在或在指定路径或标识符下不可访问。客户端应验证端点或资源 ID。404
model_error模型在处理一个原本有效的请求时失败。这表明模型或执行内部出错,无法由用户解决。500
too_many_requests客户端已超过允许的请求速率。请求正被临时限流。客户端应放慢速度并在延迟后重试。429

流式

Open Responses 定义了两种主要类型的流式事件,所有事件必须归入这两类。

增量事件

增量事件表示对象自上次更新以来的变化。该机制允许增量通信更新,使得流式响应成为可能且高效。

常见的增量事件示例包括:

  • 向列表中添加新项目(response.output_item.added)——例如,当生成新消息并追加到对话中时。
  • 向正在进行的输出追加更多文本(response.output_text.deltaresponse.function_call_arguments.delta)——例如,当语言模型逐字生成回复时。
  • 表示不再对内容部分进行更改(response.content_part.done)——例如,当模型完成生成句子或段落后。

所有可流式对象都必须遵循此增量事件模式。例如,输出项目的增量事件流可能从项目添加开始,接着是若干文本增量,最后以“完成”事件结束,表示完成。

simple-streaming.svg

状态机事件

状态机事件表示对象在其生命周期中状态的变化。例如,当响应状态从 in_progress 变为 completed 时,会触发 response.completed 事件。

其他示例包括:

  • Responsequeued 变为 in_progress 时,会发出 response.in_progress 事件。
  • 如果响应遇到错误并状态变为 failed,则会生成 response.failed 事件。

工具

工具使用是现代 LLM 智能体能力的核心。在 Open Responses 中,通常有两种类型的工具可以暴露:

外部托管工具

外部托管工具是指其实现位于模型提供商系统之外的工具。函数是一个很好的例子,其中 LLM 能够调用函数,但开发者必须运行该函数并将输出返回给 LLM 进行第二次请求。MCP 是另一个例子,其中外部服务器托管实现,尽管控制权不会首先交还给开发者。

内部托管工具

内部托管工具是指其实现位于模型提供商系统内部的工具。一个例子是 OpenAI 的文件搜索工具,其中模型能够调用文件搜索,且工具可以在不交还控制权给开发者的情况下执行并返回结果给 LLM。

previous_response_id

previous_response_id 字段允许客户端在无需重新发送整个对话历史的情况下继续或扩展现有响应。

当提供 previous_response_id 时,服务器必须加载与该先前响应相关联的输入和输出,并将其视为新请求上下文的一部分。

从概念上讲,模型在如下连接上进行采样:

previous_response.input + previous_response.output + input

其中:

  • previous_response.input 是发送给引用响应的完整结构化输入(包括任何消息、工具和对模型推理相关的配置)。
  • previous_response.output 是该响应中模型生成的内容(例如,消息、工具调用和其他输出项目)。
  • input 是与 previous_response_id 一同提供的新请求有效载荷,逻辑上追加在先前输入 + 输出之后。

服务器负责将此逻辑连接转换为内部表示(例如,消息、事件或标记)。提供商可以根据需要应用截断或压缩(受其截断策略约束),但必须保留以下顺序的语义:

previous_response.inputprevious_response.outputinput

从客户端的角度看,使用 previous_response_id 等价于要求模型从先前响应结束的位置“继续对话”,并在其之上叠加额外的指令或消息。

tool_choice

tool_choice 字段控制模型在响应期间是否以及如何调用工具。它适用于请求中暴露的所有工具(函数、托管工具等),并让客户端塑造模型的行为,从“从不调用工具”到“必须调用此特定工具”。

  • "auto"(默认):模型可自行决定调用工具或直接响应,基于其判断哪种方式最能满足请求。这是最灵活的模式,推荐用于大多数通用场景。
  • "required":模型必须至少调用一个工具,且在不调用工具的情况下不得直接响应。当工具调用是满足请求的唯一有效方式时(例如,“查找”或“执行”类操作,总是需要外部数据或副作用)使用此选项。
  • "none":模型不得调用任何工具。它必须仅依赖其内部知识和推理。这对“仅模型”补全、评估或当工具副作用不可取时很有用。

除了这些简单模式外,tool_choice 还接受一个结构化对象来强制使用特定工具:

{
"tool_choice": {
"type": "function",
"name": "fn_name"
}
}

在此形式中,模型必须调用指定的函数工具 fn_name。这在客户端已经确定哪个工具合适时非常有用(例如,在 UI 选择或路由决策之后),并希望跳过模型的工具选择步骤,同时仍允许模型构造参数并解释结果。

allowed_tools

allowed_tools 字段允许客户端限制模型实际可以调用的工具,而无需更改 tools 列表本身。所有工具仍会出现在模型的上下文中(保留共享系统提示和工具模式的缓存性),但模型必须将工具调用限制在 allowed_tools 中列出的子集中。

这主要是缓存保持的控制界面:与其修改 tools 字段(通常会无效化任何提示或模式缓存),客户端可以使用 allowed_tools 来动态缩小或扩大特定请求的有效工具菜单,同时重用相同的底层工具定义。

服务器必须将 allowed_tools 视为硬性约束:

  • 如果存在 allowed_tools,任何对未列出工具的调用都必须被服务器拒绝或抑制(例如,将其视为模型错误、转换为直接回复,或应用提供商特定的回退行为)。
  • 提供商也可以将 allowed_tools 用作训练或路由提示,但必须保证强制执行的完整性。

从概念上讲,tools 定义了模型可见的完整工具宇宙,而 allowed_tools 定义了此请求中可执行的子集。这种分离实现了细粒度的、按请求的工具治理——如租户级策略、用户角色或功能标志——而无需客户端重建或重新发送大型工具模式或系统提示。

示例
{
"model": "gpt-openresponses-1",
"input": [
{
"role": "user",
"content": [
{"type": "input_text", "text": "Summarize the latest sales data and then draft a follow-up email."}
]
}
],
"tools": [
{
"type": "function",
"name": "get_latest_sales_report",
"description": "Fetches the most recent sales report for the current quarter.",
"parameters": {
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "Geographic sales region identifier."
}
},
"required": ["region"]
}
},
{
"type": "function",
"name": "send_email",
"description": "Sends an email via the CRM.",
"parameters": {
"type": "object",
"properties": {
"to": { "type": "string" },
"subject": { "type": "string" },
"body": { "type": "string" }
},
"required": ["to", "subject", "body"]
}
}
],
"tool_choice": {
"type": "allowed_tools",
"tools": [
{ "type": "function", "name": "get_latest_sales_report" }
]
}
}
在此请求中,模型可以自由决定是否调用工具(tool_choice: "auto"),但如果调用,则只能调用 get_latest_sales_report,即使 send_email 在共享的 tools 列表中可见。

truncation

truncation 参数控制服务器在总输入(包括任何 previous_response 内容)超出模型上下文窗口时是否允许缩短有效上下文。

  • "auto":服务器可以截断较早的上下文部分(例如,旧消息或低优先级部分),以适应模型的上下文窗口。提供商应在执行时应用合理的启发式方法(例如,保留系统消息和近期对话),并可公开提供商特定的截断策略。
  • "disabled":服务器不得截断任何输入。如果合并后的上下文超出模型的最大上下文窗口,请求必须失败并报错,而不是无声丢弃内容。此模式适用于客户端更倾向于硬性失败而非任何上下文丢失的情况。

需要在大上下文工作负载下保持可预测行为的客户端可以使用 truncation 在优雅降级(auto)和严格正确性保证(disabled)之间进行选择。

service_tier

service_tier 字段是提供商关于请求处理的紧急程度和可靠性的提示。从概念上讲,它表达了“优先处理”响应:较高层级应获得更快的调度、更慷慨的资源分配或更严格的延迟目标,高于较低层级。

服务器可以暴露多个层级(例如,standardprioritybatch),并映射到不同的内部队列、SLA 或定价。实现方应文档化其支持的层级、每个层级所暗示的行为(例如,典型延迟、吞吐量或可靠性特征)以及与这些层级相关的任何约束或配额。

实现 Open Responses

在此示例中,客户端请求实现者公开的 custom_document_search 托管工具。实现者直接执行该工具,将结果返回给客户端,并抽象掉内部实现细节。

智能体循环

智能体循环是 Open Responses 能够与用户智能交互、推理任务并按需调用工具以完成复杂工作流的核心原则。在此循环中,语言模型分析用户的请求,判断其是否可以直接回答,还是需要使用工具,并按需发出工具调用。

当需要使用工具时,模型会发出工具调用事件,例如函数调用或托管工具调用,包含必要的参数。对于外部托管工具,执行发生在模型提供商之外,结果会在后续请求中返回。对于内部托管工具,模型提供商执行工具并立即流式返回结果。

这个推理、工具调用和响应生成的循环可以在会话内重复多次,使模型能够在生成最终答案之前收集信息、处理数据或通过工具采取行动。

sequenceDiagram
autonumber
participant User
participant API as API Server
participant LLM
participant Tool

User->>API: user request

loop agentic loop
API->>LLM: sample from model
LLM-->>API: Sampled message
alt tool called by model
API->>Tool: sampled tool call arguments
Tool-->>API: tool result
else
Note right of API: loop finished
end
end

API-->>User: output items

扩展 Open Responses

任何实现者都可以被认为拥有符合 Open Responses 规范的 API,只要其 API 直接实现该规范或为其适当超集。该规范承认,提供商希望构建不在规范内的功能。那些在前沿模型中广受欢迎的功能,应考虑由 TSC 进行标准化。

扩展工具

实现者可以通过在其 Open Responses 实现中直接提供新功能(如自定义搜索、检索或工作流编排),公开其自己的托管工具(不同于标准函数工具)。当用户或模型调用托管工具时,实现者在其自身环境中执行该工具,通常与模型提供商外部的服务或逻辑集成,并返回结果而不暴露实现细节。这使实现者能够在保持一致工具接口的同时增加自定义功能,面向用户和模型。

{
"model": "my-model",
"messages": [
{"role": "user", "content": "Find relevant documents about climate change."}
],
"tools": [
{
"type": "implementor_slug:custom_document_search",
"documents": [
{ "type": "external_file", "url": "https://arxiv.org/example.pdf" }
]
}
]
}

在此示例中,客户端请求实现者公开的 implementor_slug:custom_document_search 托管工具。实现者直接执行该工具,返回结果给客户端,并隐藏内部实现细节。

托管工具必须有对应的项目类型

在构建自定义工具时,该工具应具有自己的项目类型,为开发者提供工具调用执行期间发生情况的收据。该项目至少应包含模型调用工具的表示、工具调用的状态以及来自工具的结果。

在上述示例中,API 可能作为输出发出以下项目:

{
"type": "implementor_slug:custom_document_search",
"id": "cdc_759bd159770647a681a6ed186843fcca",
"query": ["climate change", "global warming"],
"status": "completed",
"results": [
{
"document_id": "result_6064c25dad6b4218b62e675234946de7",
"chunk": "Climate change threatens Cambodia’s crops, floods cities, heats temperatures, strains resources..."
}
...
]
}

该项目的模式应允许足够信息传递给开发者,以便可在后续请求中无损地重新填充。

扩展项目

实现者可以扩展 Item 联合类型,引入新的、非标准项目类型,以表示实现特定的行为或数据。然而,任何此类扩展项目类型及其轨迹——应被视为特定于该实现,不应假定在其他 Open Responses 服务器间可移植或互操作。

任何不属于此规范的新项目类型——必须以前缀形式命名,使用实现者缩写(例如,acme:search_result),如上所述。这种前缀约定有助于避免实现者之间的类型名冲突,并使扩展项目类型的归属和语义在日志、跟踪和轨迹中明确。

在发出或消费扩展项目类型时,实现者应记录其模式和预期行为,客户端应准备好遇到未知项目类型(例如,通过安全忽略或将其视为不透明记录)当与多个实现交互时。

必需的项目字段

Open Responses 轨迹中的每个 Item 必须包含以下顶层字段,无论其具体的 type 如何:

字段描述
id该项目在轨迹或会话中的唯一、不透明标识符。服务器可以选用任何稳定的标识符格式,但必须足够唯一,以便客户端能明确引用该项目(例如,通过 ItemReference 对象或日志)。
type识别具体项目模式的字符串。标准项目类型由本规范定义(例如,input_textoutput_texttool_call),而扩展类型必须以前缀形式命名(例如,acme:search_result)。
status描述项目当前状态的生命期指示器。典型值包括 "in_progress""completed""failed"。实现者可以定义附加状态,但应记录其语义,并在客户端侧保守处理未知状态值。

这些必需字段确保所有项目——标准和扩展类型——在日志、跟踪和流式响应中都是可寻址的(id)、可解释的(type)和可调试的(status)。

示例

{
"type": "acme:telemetry_chunk",
"id": "tc_123",
"status": "completed"
"request_id": "req_123",
"sequence": 4,
"latency_ms": 72,
"cache_hit": true,
"notes": "Model responded from warm cache."
}

在此示例中,一个实现者引入了自定义流式事件类型 acme:telemetry_chunk,用于在响应流中暴露延迟和缓存信息。理解此扩展的客户端可以利用它进行可观测性或 UX 决策,而其他客户端可以安全忽略它,仍然处理流中的标准标记和项目。

扩展流式事件

实现者可以引入新的、非标准的流式事件类型,以在响应流中暴露实现特定的元数据或行为。这些事件对于可观测性、调试、UI 适配或协调外部工作流非常有用,但必须不能改变核心 Open Responses 流的规范语义(例如,标记顺序或项目生命周期)。

与自定义项目类型一样,所有扩展流式事件必须以前缀形式命名,使用实现者缩写(例如,acme:trace_event),以避免冲突并使归属和语义明确。不理解给定扩展事件类型的客户端必须能够安全忽略它,而不影响重构标准响应的能力。

扩展流式事件的必需字段

扩展流式事件应遵循一致的结构,以使其易于跨实现消费。至少,每个事件必须包含:

  • type:事件模式的字符串标识符。非标准类型必须以前缀形式命名(例如,acme:trace_event)。
  • sequence_number:在流或会话内单调递增的数字,允许客户端对事件排序并检测间隙。

实现者可以添加特定用例的附加字段(例如,时间指标、缓存信息或工具调用跟踪),但应记录这些字段及其语义,以便客户端能够明智地使用它们。

示例

{
"type": "acme:trace_event",
"sequence_number": 1,
"phase": "tool_resolution",
"latency_ms": 34,
"related_item_id": "tc_789",
"details": "Resolved tool endpoint from local cache."
}

在此示例中,一个实现者引入了一个自定义流式追踪事件 acme:trace_event,用于暴露工具调用的内部时间和解析细节。识别此扩展的客户端可以增强其仪表板或实时调整 UX,而其他客户端可以安全忽略该事件,仍然处理流中的所有标准项目和标记。

扩展现有模式

除了定义全新的项目或事件类型外,实现者还可以通过添加额外的、实现特定的字段来扩展现有模式。这在不改变规范核心语义的前提下,有助于暴露更丰富的元数据(例如,可观测性细节、缓存提示或内部标识符)非常有用。

然而,此类扩展不可避免地降低了可移植性。依赖这些额外字段的客户端将更紧密地耦合到特定实现,依赖它们的轨迹或 OpenAPI 定义可能在其他 Open Responses 服务器上无法验证或表现一致。

为减轻此风险,对现有模式的扩展应遵循以下指导原则:

  • 保持所有标准字段完整且含义不变;扩展必须不改变核心行为。
  • 优先使用可选字段,以便可移植客户端能安全忽略它们。
  • 清晰记录扩展字段,包括其类型、允许值和失败模式。
  • 避免在非标准字段基础上构建跨厂商契约;相反,应通过 TSC 流程提议常用模式纳入核心规范。

实际上,这意味着扩展现有模式是演进实现的可接受方式,但实现者应将这些扩展视为特定于供应商,并避免假设其他兼容 Open Responses 的 API 会认识或尊重它们。