OpenAI /v1/responses

POST /v1/responses 是 cc-router 在 v2.3+ 加入的 OpenAI Responses 兼容入口。设计动机:让 Codex CLI 以及任何 OpenAI Responses 风格客户端也能通过 cc-router 复用所有上游订阅,无需再写一份适配代码。

适用版本:cc-router v3.0.0 及以上。

协议定位与翻译流程

客户端 (OpenAI Responses)                           cc-router                          上游
─────────────────────────                ─────────────────────────────────         ─────────────
POST /v1/responses ─────────────────────►│ handler::responses                  │
  body: OpenAI Responses 格式            │   ↓ request_to_anthropic            │
                                         │ Anthropic Messages 格式              │
                                         │   ↓ pipeline::dispatch              │──► 选订阅 / 改 model
                                         │ pipeline 返回 Anthropic SSE/JSON     │◄── 上游响应
                                         │   ↓ translate_*_to_responses        │
                                         │ OpenAI Responses 格式                │
◄──────────────────── HTTP 响应──────────│                                     │

调度 pipeline 零改动——所有上游 provider 路径(包括 codex / openai / gemini / kiro 这 4 个原本就做协议翻译的)全部复用。/v1/responses 只是在 pipeline 前后多挂了一层入口翻译


请求

POST /v1/responses
Content-Type: application/json
Header必需说明
Content-Type: application/json请求体必须是 JSON
x-api-keyAuthorization: Bearer ...视鉴权设置/v1/responses 不在白名单,开启鉴权后必填
其他 OpenAI SDK 自带头不消费,也不透传到上游(上游协议是 Anthropic)

鉴权差异:与 /v1/messages 相同的 token 校验,但 401 错误体仍是 Anthropic 风格(auth_layer 在 handler 之前生效);只有进入 responses handler 之后产生的 4xx/5xx 才走 OpenAI 风格。

请求体遵循 OpenAI Responses API 标准的子集。cc-router 消费并翻译以下字段:

字段类型必需行为
modelstring解析为虚拟模型;支持 gpt-5.5 / gpt-5.4 / gpt-5.4-mini 等别名,缺失返回 400
streamboolean否(默认 falsetrue 走 SSE 翻译,false 走 JSON 翻译
instructionsstring翻译为 Anthropic system;若 input 里也有 developer/system role 文本,追加合并
inputarray扁平 item 流(message / function_call / function_call_output / reasoning),翻译为 Anthropic messages
max_output_tokensinteger翻译为 Anthropic max_tokens(无则默认 4096,因为 Anthropic 协议必填)
reasoning.effortstring翻译为 Anthropic thinking { type: enabled, budget_tokens },阈值映射:minimal → 0 / low → 1024 / medium → 8192 / high → 16384
toolsarray翻译为 Anthropic tool schema
tool_choiceobject翻译为 Anthropic tool_choice

非流式请求示例

curl http://127.0.0.1:23456/v1/responses \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "max_output_tokens": 256,
    "instructions": "You are concise.",
    "input": [
      { "type": "message", "role": "user",
        "content": [{ "type": "input_text", "text": "用一句话说明 cc-router 是什么" }] }
    ]
  }' | jq

响应(非流式)

  • 200 OKContent-Type: application/json
  • 响应体是 OpenAI Responses 标准 response JSON
    • cc-router 把 pipeline 返回的 Anthropic message 翻译为 OpenAI Responses 形式
    • output[] 扁平化:text content_block → message item;tool_use → function_call item;thinking → reasoning item(encrypted_content 由 Anthropic signature 编解码而来)
    • usage.input_tokens / output_tokens 翻译为 OpenAI 字段
    • stop_reason 翻译为 status / incomplete_details(如 max_tokensincomplete_details.reason = max_output_tokens
{
  "id": "resp_xxx",
  "object": "response",
  "created_at": 1767225600,
  "status": "completed",
  "model": "gpt-5.5",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "output_text", "text": "..." }]
    }
  ],
  "usage": { "input_tokens": 42, "output_tokens": 128, "total_tokens": 170 }
}

响应(流式 SSE)

  • 200 OKContent-Type: text/event-stream设这一个头,不设 cache-control / transfer-encoding,让 axum 自动管 chunked 编码——避免在 HTTPS+rustls 路径上跟底层冲突触发 IncompleteMessage
  • 事件流是 OpenAI Responses SSE 协议,由内部转换器从上游 Anthropic SSE 实时翻译产生

事件映射

Anthropic 事件翻译为 OpenAI Responses 事件
message_startresponse.created + response.in_progress
content_block_start (text)response.output_item.added + response.content_part.added
content_block_delta (text_delta)response.output_text.delta
content_block_start (thinking)response.output_item.added(reasoning item)
content_block_delta (thinking_delta)response.reasoning_summary_text.delta
content_block_start (tool_use)response.output_item.added(function_call item)
content_block_delta (input_json_delta)response.function_call_arguments.delta
content_block_stopresponse.content_part.done + response.output_item.done
message_delta(旁路抽取 usage,不直接发帧)
message_stopresponse.completed
上游断流 / 上游漏发 message_stop兜底补一个 response.completed

关键差异(对比 Anthropic SSE):

  • 不发 data: [DONE]——OpenAI Responses 客户端按 response.completed 终止
  • 断流兜底:上游传输层中断或上游漏发 message_stop 时,cc-router 至少补一个 response.completed,让 OpenAI SDK 不会因等不到终结事件而 hang

流式请求示例

curl -N http://127.0.0.1:23456/v1/responses \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-5.4",
    "stream": true,
    "max_output_tokens": 256,
    "input": [
      { "type": "message", "role": "user",
        "content": [{ "type": "input_text", "text": "ping" }] }
    ]
  }'

返回流以 event: response.completed 终结(data: [DONE])。


调度逻辑

/v1/messages 完全相同——/v1/responses 把客户端 model 字段解析为虚拟模型,走相同的调度 + 重试逻辑。

这意味着:

  • gpt-5.5 / gpt-5.4 / gpt-5.4-minimodel-sonnet / claude-sonnet-4-6 等任意虚拟模型别名都可以从 /v1/responses
  • 上游可以是任意 9 家 Anthropic provider 或 codex / openai / gemini / kiro——客户端无感
  • /v1/responses 不能绑定 OAuth-only 的 codex provider 跑 fallback(同 /v1/messages 的约束)

完整虚拟模型映射表见 Anthropic /v1/messages → 虚拟模型映射


错误响应

/v1/responses 入口产生的错误用 OpenAI Responses 风格

{
  "error": {
    "message": "...",
    "type": "<kind>",
    "code": null
  }
}
Status场景来源
400request body 不是合法 JSONhandler::responses
400request body 缺 model 字段handler::responses
400OpenAI → Anthropic 请求翻译失败(如 input 结构非法)request_to_anthropic
401鉴权失败走 Anthropic 风格(auth_layer 在 handler 之前)
500pipeline 内部错误handler::responses
500读 pipeline JSON body 失败 / 上游响应解析失败translate_json_to_responses
上游 status 透传pipeline 返回的 Anthropic error 体自动翻译为 OpenAI 风格translate_json_to_responses

未实现的 OpenAI 接口

下列 OpenAI 官方接口在 cc-router 中未实现,属于设计选择:

  • POST /v1/chat/completions(Chat Completions API)——cc-router 的 OpenAI 兼容入口只做 Responses API
  • GET /v1/responses/{id}POST /v1/responses/{id}/cancel 等 Responses 状态接口——cc-router 是无状态代理,不缓存 response,客户端用 streaming response.completed 终止即可
  • OpenAI Assistants / Threads / Files API

cc-router 的预期客户端是 Codex CLI / Claude Code 这类无状态对话客户端,只依赖 POST /v1/responsesPOST /v1/messages + GET /v1/models