Chat Completions 对话 API
OpenAI 兼容的 POST /v1/chat/completions:多模型、provider 路由、流式与工具调用。
无界模型云提供 OpenAI 兼容的对话补全接口 POST /v1/chat/completions,覆盖目录中的全部 LLM 模型族(Claude、GPT、Gemini、DeepSeek、通义千问、Kimi 等)。已有 OpenAI 兼容客户端只需切换 Base、Key 与 model 即可接入,无需改造业务代码。
私有化部署 API 完全一致,仅需替换 Base 域名 → 企业私有化部署。
概览
- 端点:
POST https://api.tos.run/v1/chat/completions - Base:
https://api.tos.run/v1(API 数据面;浏览器控制台是https://ai.tos.run,不要用作 API Base) - 协议:OpenAI Chat Completions 兼容,请求 / 响应字段与 OpenAI 一致
- 多模型:同一 Key、同一端点,通过
model+provider选择上游
鉴权
通过 HTTP 头 Authorization: Bearer <gk_...> 鉴权,API Key 以 gk_ 开头,在控制台创建。请求体为 application/json。
Authorization: Bearer gk_xxxxxxxxxxxxxxxx
Content-Type: application/json生产环境请把 Key 放在服务端,不要暴露到浏览器或客户端。
必须声明 provider
本网关采用严格路由:每次请求都必须明确指定上游 provider,没有隐式回退。可用三种方式声明(优先级从高到低):
- URL 查询参数
?provider=X(OpenRouter 必须用这种方式,因为它的body.provider字段被保留为上游路由对象) - 请求头
X-Provider: X(适合base_url无法追加查询串的客户端,如沙箱内的 CLI) - 请求体字段
body.provider
缺失或传入未知 provider 时,返回 400,错误体为 OpenAI 风格的 invalid_request_error:
{
"error": {
"message": "'provider' is required: pass it via ?provider=X or body.provider (valid: anthropic, deepseek, ...)",
"type": "invalid_request_error"
}
}没有默认 provider。即使 model 唯一对应某个上游,仍需显式声明 provider(否则 SaaS-only 模型会 400,强制客户端表达意图)。/v1/chat/completions 与 /v1/responses 同源;只有 /v1/messages 缺省默认 anthropic。
可路由的 LLM provider
对外公开的可路由 provider:
| provider | 说明 |
|---|---|
anthropic | Claude 系列(meganova / packy 等号源对外统一显示为 anthropic) |
openai | GPT 系列 |
dashscope | 通义千问(阿里云灵积) |
deepseek | DeepSeek |
gemini | Google Gemini |
kimi | Kimi(月之暗面) |
openrouter | OpenRouter 聚合路由 |
具体可用 provider 与模型以控制台 / 组织授权为准。
Gemini 模型
通过 provider=gemini 路由 Google Gemini。模型 ID 与 Google 官方保持一致,走 OpenAI 兼容协议,网关对请求 / 响应原样透传:
| model | 上下文窗口 | 视觉 | 说明 |
|---|---|---|---|
gemini-3.5-flash | 1,048,576 | ✅ | 高性价比 Flash,编码 / Agent 能力最强(2026-05 GA) |
gemini-3.1-pro-preview | 1,048,576 | ✅ | 旗舰多模态推理(text / image / video / audio / code) |
gemini-2.0-flash | 1,048,576 | ✅ | 上一代 Flash |
gemini-1.5-pro | 2,097,152 | ✅ | 超长上下文 Pro |
Gemini 3.x 为推理(thinking)模型,会先消耗一段思考 token 再产出回答。请将 max_tokens 设得足够大(建议 ≥ 1024);预算过小会让思考 token 耗尽全部额度,导致 message.content 返回 null 且 finish_reason 为 length。
基础调用
curl "https://api.tos.run/v1/chat/completions?provider=anthropic" \
-H "Authorization: Bearer $TOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-x",
"messages": [
{ "role": "system", "content": "你是一个简洁的中文助手。" },
{ "role": "user", "content": "用三句话介绍一下你自己。" }
]
}'import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.tos.run/v1",
api_key=os.environ["TOS_API_KEY"],
)
resp = client.chat.completions.create(
model="claude-sonnet-4-x",
messages=[
{"role": "system", "content": "你是一个简洁的中文助手。"},
{"role": "user", "content": "用三句话介绍一下你自己。"},
],
extra_query={"provider": "anthropic"},
)
print(resp.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.tos.run/v1",
apiKey: process.env.TOS_API_KEY,
});
const resp = await client.chat.completions.create(
{
model: "claude-sonnet-4-x",
messages: [
{ role: "system", content: "你是一个简洁的中文助手。" },
{ role: "user", content: "用三句话介绍一下你自己。" },
],
},
{ query: { provider: "anthropic" } },
);
console.log(resp.choices[0].message.content);官方 OpenAI SDK 没有顶层 provider 字段,推荐用 ?provider= 查询参数(Python extra_query / Node query)或在默认头里加 X-Provider。裸 fetch/curl 也可以把 provider 放进 JSON body。
参数
支持 OpenAI 标准字段:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 是 | 模型 ID,以控制台展示为准 |
messages | array | 是 | 对话消息数组,每项含 role 与 content |
max_tokens | integer | 否 | 单次响应最大输出 token 数 |
temperature | number | 否 | 采样温度,值越高输出越发散 |
top_p | number | 否 | 核采样阈值,与 temperature 二选一 |
stop | string / array | 否 | 停止序列,命中即停止生成 |
stream | boolean | 否 | 是否以 SSE 流式返回,默认 false |
tools | array | 否 | 工具(函数)定义列表 |
tool_choice | string / object | 否 | 工具选择策略,如 "auto" 或指定某个工具 |
不同 provider / 模型对参数支持不一致,网关会自动剔除该(provider, model)不支持的字段后再下发上游,避免上游 400。body.provider 是网关的路由键,对非 OpenRouter 的 provider 不会下发给上游;只有 OpenRouter 的 body.provider(上游路由对象,如 { "order": [...], "allow_fallbacks": true })会被原样转发。
流式
设置 stream: true 后,响应以 Server-Sent Events(SSE)逐块返回,每块是 OpenAI 标准的 chat.completion.chunk,增量文本在 choices[0].delta.content 中,以 data: [DONE] 结束。
curl "https://api.tos.run/v1/chat/completions?provider=anthropic" \
-H "Authorization: Bearer $TOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-x",
"stream": true,
"messages": [
{ "role": "user", "content": "写一首关于云的短诗。" }
]
}'流式请求时,网关会强制注入 stream_options.include_usage = true,以便上游在流尾发送一个 usage 块,用于计量与计费。该尾块的 choices 为空数组([]),标准 SDK(OpenAI / LangChain / LiteLLM / Vercel AI SDK 等)都会自动忽略;只有手写、无条件取 chunk.choices[0] 的 SSE 解析器需要做一处空数组判断。即使客户端显式传 include_usage:false,网关也会覆盖为 true(token 计量是网关的职责,不允许被绕过)。
流尾的 usage 块形如:
{
"id": "chatcmpl-xxx",
"object": "chat.completion.chunk",
"choices": [],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 38,
"total_tokens": 62
}
}工具调用
通过 tools 声明可调用的函数,模型在需要时返回 tool_calls。应用执行后,把结果以 role: "tool" 的消息回填到下一轮 messages,模型据此给出最终回答。
curl "https://api.tos.run/v1/chat/completions?provider=anthropic" \
-H "Authorization: Bearer $TOS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-x",
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名称" }
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto",
"messages": [
{ "role": "user", "content": "合肥今天天气怎么样?" }
]
}'响应与用量
非流式响应是 OpenAI 标准结构:
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"model": "claude-sonnet-4-x",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "你好,我是一个中文助手……" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 38,
"total_tokens": 62
}
}按 usage 中的输入 / 输出 token 计量计费,单位 1M token。具体单价、可用模型与折扣以控制台 / 组织价格为准;组织专属价格、合同折扣优先级更高。