跳到主要内容
版本:1.4.0

Responses API 代理

Responses API 是 OpenAI 面向使用输入/输出项格式而不是 Chat Completions 消息格式的应用提供的响应生成端点。AISIX AI 网关为 Responses API 客户端暴露该路由,同时将调用方认证、模型别名、上游凭证和网关策略保留在网关中。

当应用或工具已经使用 Responses API 时,请使用该路由。当模型的上游自身提供 Responses API 时,AISIX 会把请求转发过去;否则 AISIX 会通过服务提供方适配器转换请求,并向调用方返回 Responses API 结果。

准备工作​

请先准备以下内容:

  • 一个可以处理代理请求的 AISIX 网关。
  • 一个可以访问该模型别名的调用方 API Key。
  • 一个由原生提供 Responses API 或支持转换后请求形态的上游支撑的模型别名。

导出网关连接和请求值:

# AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径
# 本地快速入门使用 http://127.0.0.1:3000。
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="gpt-4o-prod"

发送 Responses 请求​

通过网关代理发送请求,并在请求体中使用 AISIX 模型别名:

curl -sS -X POST "${AISIX_PROXY}/v1/responses" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${AISIX_MODEL}"'",
"input": "Say hello from AISIX."
}'

AISIX 会解析模型别名,并为选中模型选择服务提供方路径。当服务提供方密钥选择原生 Responses 协议面时,AISIX 会直接转发请求,不转换请求体;否则会使用跨服务提供方桥接。

响应体会以 Responses API 格式返回:

{
"id": "resp_***",
"object": "response",
"model": "gpt-4o-prod",
"output": [
{
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Hello from AISIX."
}
]
}
],
"usage": {
"input_tokens": 12,
"output_tokens": 5,
"total_tokens": 17
}
}

在桥接路径上,具备推理能力的上游会在该 message item 之前先返回一个 reasoning item。参见桥接路径返回什么。

服务提供方行为​

AISIX 通过两种方式处理 Responses 请求:

上游行为
提供 Responses APIAISIX 将请求 model 改写为上游模型 ID,并将请求转发到上游 Responses API。当上游支持时,上游专属 Responses 能力会透传。
不提供AISIX 将受支持 Responses 字段转换为网关聊天格式,通过服务提供方适配器调度,并返回 Responses API 结果。

走哪一条按服务提供方密钥逐个决定。没有协议面声明时,AISIX 对 openai 服务提供方原生转发,对其它服务提供方一律转换。这个默认判断对某些端点在两个方向上都会出错:通过 openai 服务提供方 + 自定义 api_base 接入的 OpenAI 兼容端点可能根本没有 /v1/responses,而其它服务提供方的端点反而可能有。声明该密钥的 API 协议面即可说明属于哪一种,见声明 API 协议面。

桥接路径支持常见的文本、工具调用、工具结果、采样和流式字段,以及下文所述的消息 part、工具参数和结构化输出格式。它会把 reasoning.effort 带入规范化聊天请求的 reasoning_effort;支持推理力度控制的服务提供方适配器再将其转换为对应的线上字段。例如,Anthropic 收到的是 output_config.effort。你还可以通过推理力度映射按直连模型重写该值。聊天格式无法表达的 Responses 能力会被丢弃,而不是原样平铺到上游请求体上,这样请求仍能到达服务提供方而不会被其拒绝;属于这一类的字段见经过转换的请求会忽略哪些字段。

消息 part​

除文本 part 外,桥接路径还会把消息中的非文本 part 转换为对应的聊天内容块:

Responses part聊天内容块
input_imageimage_url,图片以 URL 或 data: URL 寻址;调用方给出 detail 时一并带上
input_filefile,携带调用方发送的 file_data、filename、file_id 中的相应字段
input_audioinput_audio,携带 data 和 format

只要某个消息槽产生了任意非文本块,其 content 就以数组形式发送;纯文本槽仍保持原有的裸字符串形态。

工具参数​

  • 只要有至少一个工具在转换后保留下来,parallel_tool_calls 就按调用方发送的值转发。
  • 每一种 tool_choice 形态都会归一化为服务提供方中立的聊天形态。auto、none、required 和 {"type": "function", "name": ...} 保持不变;{"type": "any"} 变为 required;{"type": "custom", "name": ...} 和 {"type": "tool", "name": ...} 变为同名函数;{"type": "allowed_tools", "mode": ...} 只保留其 mode,它列出的工具子集会被丢弃——聊天上游无法被限制为只能使用所给工具的某个子集。
  • custom(自由格式)工具会转换为只接受一个必填字符串参数的函数工具,该工具的语法规则折叠进这个参数的描述中——那是聊天上游唯一会读到它的地方。
  • 当工具结果的 output 是 JSON 对象、数字或布尔值时,它会被序列化为字符串后发给上游,因为聊天的 tool 消息只能携带字符串。null 和缺省的 output 仍为空字符串。

当转换后没有任何工具保留下来时(例如携带 "tools": [] 的上下文压缩请求,或只携带托管工具的请求),tool_choice 和 parallel_tool_calls 都会被丢弃,强制调用工具的形态同样如此。没有 tools 列表时上游会拒绝这两个字段,因此它们都不会被发出,该请求按普通的无工具请求继续处理。

结构化输出​

text.format 会转换为聊天的 response_format:json_schema 格式变为 {"type": "json_schema", "json_schema": {...}},携带调用方发送的 name、schema、strict、description 中的相应成员;json_object 直接对应;text 格式或完全没有 text 成员时不发送任何内容。

该字段由 OpenAI 兼容的聊天上游支持,Anthropic、Gemini 和 Bedrock 上游同样支持,它们各有自己的结构化输出字段。这几种映射在模型支持范围以及服务提供方接受的 schema 内容上各不相同:Anthropic 参见结构化输出,Gemini 参见 Gemini 上的结构化输出,Bedrock 参见结构化输出。

桥接路径返回什么​

桥接路径上有两类输出 item 并非来自会说 Responses 的上游,而是 AISIX 根据聊天响应构造出来的。

推理内容。 当聊天上游以 reasoning_content 上报其思维链时,AISIX 会把它作为一个 reasoning 输出 item 返回,位置在 message item 之前。非流式响应中,该 item 以 summary[{"type": "summary_text"}] 携带文本。流式响应中,它依次表现为 response.output_item.added、response.reasoning_summary_part.added、一个或多个 response.reasoning_summary_text.delta,以及相应的 done 事件;message item 在下一个 output_index 上开启。

自定义工具调用。 当模型调用经桥接转换的 custom 工具时,返回的是携带自由格式文本的 custom_tool_call item(字段为 input),而不是 function_call item:请求方向包裹它的那个字符串参数会被重新解开。流式响应中,该 item 只包含一个携带该输入的 response.custom_tool_call_input.delta,随后是 response.custom_tool_call_input.done。

经过转换的请求会忽略哪些字段​

  • reasoning 中除 effort 外的成员,例如 summary
  • text.verbosity
  • store
  • previous_response_id
  • metadata、service_tier 以及其它 OpenAI 专属控制项
  • web_search、file_search、code_interpreter、mcp、computer_use、image_generation 等托管工具

custom 工具已不在此列,它会按工具参数所述进行转换。

还有两项限制,原因是聊天格式没有对应表达:

  • 只以 file_id 寻址的 input_image 不会被转发。聊天的图片 part 只能以 URL 或 data: URL 寻址。
  • 工具结果内部的非文本 part 不会被转发。聊天的 tool 角色只支持文本,OpenAI 兼容上游会拒绝其中的图片。

策略与用量行为​

输入安全护栏可以在 AISIX 调用服务提供方之前检查请求文本。输出安全护栏可以在非流式响应到达调用方之前检查响应内容。

当客户端重放会话历史时,安全护栏可以把输入检查限制到最新一轮。AISIX 使用 Responses item 类型识别 assistant 轮次和当前轮次的工具结果。参见输入检查读取哪些消息。

在桥接路径上,模型生成的推理内容不在输出安全护栏的筛查和脱敏范围内,这与逐字转发路径一致。参见推理与思考内容。

如果输出安全护栏阻断响应,AISIX 会向调用方返回内容策略错误,并记录该阻断请求以便观测。

对于流式请求,AISIX 会保持 Responses SSE 形态。原生 Responses 目标可以直接透传上游 SSE;桥接目标则由 AISIX 把服务提供方流式分片编码为 Responses 事件。如果启用了输出安全护栏,AISIX 会先缓冲流内容进行策略检查,再决定返回或阻断。缓冲区中 AISIX 无法解析的帧会被丢弃,而不是未经扫描就放行;如果因此没有任何内容可返回,响应会被以 422 拒绝。参见 AISIX 无法扫描的帧。

对于成功响应,当上游响应包含 Token 用量时,网关会记录用量。流式用量会在 AISIX 从流中收到终止用量信息后发出。

当上游没有上报 Token 用量时,AISIX 会在本地估算计数,并把同一组数字返回给调用方:非流式响应放在 usage 中,流式响应放在 response.completed 事件的 usage 中。上游确实上报过的计数保持不变。响应中没有任何标识说明某个计数是估算出来的,用量记录上的 usage_estimated 字段才是判断依据。参见用量上报。

对于 Token 计数方式与 OpenAI 不同的桥接服务提供方,AISIX 会将计数转换为 Responses API 的形式:input_tokens 是完整输入,input_tokens_details.cached_tokens 是其中缓存读取的子集,input_tokens_details.cache_creation_tokens 是缓存写入的子集(仅在上游报告了写入时出现),total_tokens 等于 input_tokens + output_tokens。以 Anthropic 上游为例的完整说明,请参阅 Token 用量——那里用的是 Chat Completions 的字段名,与这里一一对应(prompt_tokens 对应 input_tokens,completion_tokens 对应 output_tokens,prompt_tokens_details 对应 input_tokens_details,completion_tokens_details 对应 output_tokens_details)。有一处形态差异:output_tokens_details.reasoning_tokens 在 Responses 响应中恒存在,包括值为 0 时;而 Chat Completions 会整块省略。

下一步​

你已经了解何时通过 AISIX 使用 Responses API,以及直接转发和桥接时的服务提供方处理差异。旧版 completions 路由请继续阅读文本补全;如果 Responses API 客户端依赖 SSE 行为,请继续阅读流式响应。