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 URL | http://127.0.0.1:23456/v1(有的工具要求不带 /v1,按工具提示调整) |
| API Key | cc-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 | 必填且不能为空,翻译规则见下节 |
stream | true 走 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_choice | auto / none / required(→ any)/ 指定函数(→ tool) |
parallel_tool_calls | false 时翻译为 disable_parallel_tool_use: true |
user | 翻译为 metadata.user_id,同时作为会话亲和的会话标识 |
reasoning_effort 映射
reasoning_effort | thinking.budget_tokens |
|---|---|
minimal | 1024 |
low | 2048 |
medium | 8192 |
high / xhigh / max | 16384 |
| 其他值 | 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_url | image 块;支持 data:image/...;base64,... 与 http(s) URL |
role: assistant,content | text 块 |
role: assistant,tool_calls | tool_use 块(arguments 必须是合法 JSON) |
role: assistant,reasoning_content | 丢弃。客户端拿不到合法签名,回传给上游会被拒 |
role: tool | tool_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-abcmodel回显客户端请求时的模型名(不是虚拟模型名,也不是真实模型名)- 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_reason | finish_reason |
|---|---|
end_turn / stop_sequence | stop |
max_tokens | length |
tool_use | tool_calls |
refusal | content_filter |
只要响应里有工具调用,finish_reason 就是 tool_calls(max_tokens / refusal 除外),即使上游或中转站报的是 end_turn。客户端可以放心按 finish_reason == "tool_calls" 判断是否执行工具。
usage 映射
| Chat 字段 | 计算方式 |
|---|---|
prompt_tokens | input_tokens + cache_creation_input_tokens + cache_read_input_tokens |
completion_tokens | output_tokens |
total_tokens | 两者之和 |
prompt_tokens_details.cached_tokens | cache_read_input_tokens |
响应(流式 SSE)
200 OK,Content-Type: text/event-stream- 每帧都是
data: {chat.completion.chunk},没有event:行,以data: [DONE]结束
帧序列:
| 顺序 | 内容 | 来源 Anthropic 事件 |
|---|---|---|
| 1 | delta: {"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 |
| 倒数第 3 | delta: {} + finish_reason | message_delta |
| 倒数第 2 | choices: [] + usage | message_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 按以下优先级识别会话,同一会话固定用同一家订阅:
- 请求体
user字段(Open WebUI 等会按用户填写) - 请求头
x-session-id - 首条
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_error | invalid_request_error |
rate_limit_error / overloaded_error | rate_limit_error |
| 其他 | server_error |
| Status | 场景 |
|---|---|
400 | 请求体不是合法 JSON、缺少 model、messages 为空,或翻译失败(旧版 functions、不支持的 content part、tool_calls 的 arguments 不是合法 JSON 等) |
401 | 鉴权失败。注意此时是 Anthropic 风格错误体,因为鉴权发生在入口 handler 之前 |
500 | cc-router 内部错误,或读取 / 解析上游响应失败 |
503 | 该虚拟模型未绑定订阅,或所有订阅暂时不可用 |
| 上游 status | 所有订阅都失败时,透传最后一家上游的状态码,错误体翻译为 OpenAI 风格 |