OpenAI /v1/chat/completions

POST /v1/chat/completions 是 cc-router 的 OpenAI Chat Completions 兼容入口。Open WebUI、Cherry Studio、Cline、LobeChat 这类只支持「OpenAI 兼容」接口的工具,把 Base URL 指向 cc-router 即可使用你聚合的全部订阅。

适用版本:cc-router v5.0.0 及以上。三个入口的对比见 接口总览。

快速接入

配置项填写
Base URLhttp://127.0.0.1:23456/v1(有的工具要求不带 /v1,按工具提示调整)
API Keycc-router 设置页的 token;关闭鉴权时随便填一个非空值
模型名model-fable / model-opus / model-sonnet / model-haiku,或 gpt-5.6 / gpt-5.5 / gpt-5.4 / gpt-5.4-mini 等别名

大多数工具会通过 GET /v1/models 自动拉取模型列表,从里面选一个即可。

Open WebUI:管理员面板 → 设置 → 外部连接 → OpenAI API 旁的 + → URL 填 http://127.0.0.1:23456/v1,密钥填 token。Open WebUI 跑在 Docker 里时,把 127.0.0.1 换成 host.docker.internal,并把 cc-router 的监听地址切到「局域网」。

Cherry Studio:设置 → 模型服务 → 添加 → 提供商类型选 OpenAI → API 地址填 http://127.0.0.1:23456,密钥填 token → 管理 → 拉取模型列表。

OpenAI Python SDK:

from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:23456/v1", api_key="<cc-router token>")
resp = client.chat.completions.create(
    model="model-sonnet",
    messages=[{"role": "user", "content": "用一句话说明 cc-router 是什么"}],
)
print(resp.choices[0].message.content)

协议定位与翻译流程

客户端 (Chat Completions)                     cc-router                              上游
────────────────────────        ──────────────────────────────────────         ─────────────
POST /v1/chat/completions ─────►│ Chat → Anthropic Messages 请求翻译    │
                                │   ↓                                  │
                                │ 调度 pipeline(与 /v1/messages 相同)  │──► 选订阅 / 改 model
                                │   ↓                                  │◄── 上游响应
                                │ Anthropic JSON / SSE → Chat 格式翻译   │
◄────────────── HTTP 响应 ───────│                                      │

调度 pipeline 与 /v1/messages 完全共用,订阅、虚拟模型、限额、会话亲和、失败自动切换全部生效。上游可以是任意类型的出口(Anthropic / OpenAI / Gemini / OAuth),客户端无感。请求日志详情里「入口接口」显示 /v1/chat/completions。


请求

POST /v1/chat/completions
Content-Type: application/json
Header必需说明
Content-Type: application/json是请求体必须是 JSON
Authorization: Bearer <token> 或 x-api-key视鉴权设置开启鉴权后必填
x-session-id否会话亲和的会话标识,见下文

请求字段

字段行为
model必填。按 虚拟模型别名规则 解析,缺失返回 400
messages必填且不能为空,翻译规则见下节
streamtrue 走 SSE,默认 false
max_completion_tokens / max_tokens翻译为 Anthropic max_tokens,前者优先;都没给时默认 4096
reasoning_effort翻译为 Anthropic thinking.budget_tokens,见下表;none 表示不开启 thinking
temperature / top_p透传;开启 thinking 时不透传(Anthropic 要求 thinking 时 temperature 为 1,交给上游默认)
stop字符串或数组,翻译为 stop_sequences
tools只接受 type: "function",翻译为 Anthropic tool schema(parameters → input_schema)
tool_choiceauto / none / required(→ any)/ 指定函数(→ tool)
parallel_tool_callsfalse 时翻译为 disable_parallel_tool_use: true
user翻译为 metadata.user_id,同时作为会话亲和的会话标识

reasoning_effort 映射

reasoning_effortthinking.budget_tokens
minimal1024
low2048
medium8192
high / xhigh / max16384
其他值8192

开启 thinking 且 max_tokens 不大于预算时,cc-router 会自动把 max_tokens 抬高到「预算 + 4096」,满足上游「max_tokens 必须大于 budget_tokens」的要求。

强制工具调用优先于 reasoning_effort:tool_choice 为 required 或指定函数时,cc-router 保留工具选择、丢弃 thinking。强制工具调用是功能需求,思考强度只是偏好,两者冲突时以前者为准。

messages 翻译规则

Chat 消息翻译为 Anthropic
role: system / developer按顺序合并进顶层 system
role: user,文本text 块
role: user,image_urlimage 块;支持 data:image/...;base64,... 与 http(s) URL
role: assistant,contenttext 块
role: assistant,tool_callstool_use 块(arguments 必须是合法 JSON)
role: assistant,reasoning_content丢弃。客户端拿不到合法签名,回传给上游会被拒
role: tooltool_result 块(必须有 tool_call_id);连续多条合并进同一条 user 消息

相邻的同角色消息会自动合并,满足 Anthropic 的角色交替要求。

不支持或忽略的字段

字段处理
旧版 functions / function_call返回 400,请改用 tools / tool_choice
音频、文件类 content part返回 400
n > 1、logprobs、logit_bias、seed、presence_penalty、frequency_penalty忽略
response_format(含 JSON Schema 强制)忽略,不报错
stream_options忽略;流式响应总会在末尾带一帧 usage

非流式请求示例

curl http://127.0.0.1:23456/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
    "model": "model-sonnet",
    "messages": [
      { "role": "system", "content": "You are concise." },
      { "role": "user", "content": "用一句话说明 cc-router 是什么" }
    ]
  }' | jq

响应(非流式)

  • 200 OK,Content-Type: application/json,标准 chat.completion 对象
  • id 由上游消息 id 转换而来:msg_abc → chatcmpl-abc
  • model 回显客户端请求时的模型名(不是虚拟模型名,也不是真实模型名)
  • thinking 内容放在 message.reasoning_content,与 DeepSeek 的惯例一致,主流客户端都能折叠显示
{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1790000000,
  "model": "model-sonnet",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "...",
        "reasoning_content": "..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 128,
    "total_tokens": 170,
    "prompt_tokens_details": { "cached_tokens": 0 }
  }
}

finish_reason 映射

Anthropic stop_reasonfinish_reason
end_turn / stop_sequencestop
max_tokenslength
tool_usetool_calls
refusalcontent_filter

只要响应里有工具调用,finish_reason 就是 tool_calls(max_tokens / refusal 除外),即使上游或中转站报的是 end_turn。客户端可以放心按 finish_reason == "tool_calls" 判断是否执行工具。

usage 映射

Chat 字段计算方式
prompt_tokensinput_tokens + cache_creation_input_tokens + cache_read_input_tokens
completion_tokensoutput_tokens
total_tokens两者之和
prompt_tokens_details.cached_tokenscache_read_input_tokens

响应(流式 SSE)

  • 200 OK,Content-Type: text/event-stream
  • 每帧都是 data: {chat.completion.chunk},没有 event: 行,以 data: [DONE] 结束

帧序列:

顺序内容来源 Anthropic 事件
1delta: {"role": "assistant", "content": ""}message_start
…delta: {"content": "..."}text_delta
…delta: {"reasoning_content": "..."}thinking_delta
…delta: {"tool_calls": [{index, id, type, function: {name, arguments: ""}}]}tool_use 块开始
…delta: {"tool_calls": [{index, function: {arguments: "..."}}]}input_json_delta
倒数第 3delta: {} + finish_reasonmessage_delta
倒数第 2choices: [] + usagemessage_stop
最后data: [DONE]

流式请求示例

curl -N http://127.0.0.1:23456/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
    "model": "model-sonnet",
    "stream": true,
    "messages": [{ "role": "user", "content": "ping" }]
  }'

首帧错误自动重试:与 /v1/messages 相同,上游返回 200 但首个事件就是错误时(比如配额耗尽伪装成成功),cc-router 会直接切换下一家订阅重试,客户端无感。

中途出错与断流兜底:流中途收到上游错误时,cc-router 发出一帧错误体 + data: [DONE];上游连接意外中断时,补发 finish_reason、usage 与 data: [DONE],客户端不会一直挂起等待。


会话亲和

调度模式为「会话亲和」时,cc-router 按以下优先级识别会话,同一会话固定用同一家订阅:

  1. 请求体 user 字段(Open WebUI 等会按用户填写)
  2. 请求头 x-session-id
  3. 首条 user 消息内容的哈希

自己写客户端时,给每个对话传一个稳定的 user 或 x-session-id,能明显提高上游 prompt cache 的命中率。


错误响应

/v1/chat/completions 产生的错误使用 OpenAI 风格:

{
  "error": {
    "message": "...",
    "type": "invalid_request_error",
    "code": "invalid_request_error",
    "param": null
  }
}

type 按 OpenAI 惯例归类,code 保留 Anthropic 原始错误类型,方便排查:

Anthropic 错误类型(code)OpenAI type
invalid_request_error / authentication_error / permission_errorinvalid_request_error
rate_limit_error / overloaded_errorrate_limit_error
其他server_error
Status场景
400请求体不是合法 JSON、缺少 model、messages 为空,或翻译失败(旧版 functions、不支持的 content part、tool_calls 的 arguments 不是合法 JSON 等)
401鉴权失败。注意此时是 Anthropic 风格错误体,因为鉴权发生在入口 handler 之前
500cc-router 内部错误,或读取 / 解析上游响应失败
503该虚拟模型未绑定订阅,或所有订阅暂时不可用
上游 status所有订阅都失败时,透传最后一家上游的状态码,错误体翻译为 OpenAI 风格