API 文档

OpenAI 协议兼容层:三分钟接入、鉴权、端点、错误码、差异与缓存安全约定。

本页目录

QSTAR 对外暴露 OpenAI 协议兼容端点,任何遵守 OpenAI 协议的客户端都可以零改造对接;只需换 baseURL 与 api_key。

三分钟接入

bash
# 1) 取令牌
TOKEN=$(curl -s https://qstar.center/api/user/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"you","password":"***"}' \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["token"])')

# 2) 看模型
curl -s https://qstar.center/v1/models -H "Authorization: Bearer $TOKEN"

# 3) 发一句
curl -s https://qstar.center/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"只回复 OK 两个字"}]}'

鉴权

  • 令牌来源:POST /api/user/login,返回 { code: 0, data: { token, user_id, username } }。
  • 失败时走自有信封(HTTP 200 + code != 0),不是 401 —— 客户端必须按 code 判错。
  • 携带方式两种:Authorization: Bearer <token> 或 Authorization: <token>(裸 token,小写 bearer 亦可)。
  • 校验链路:JWT(HS256) 验签 → 过期时间 → Redis 会话键 users/<uid> 是否存在;登出即失效。
  • 防暴破:用户登录 10 次 / 15 分钟,后台登录 8 次 / 10 分钟,超限临时拒绝,请加退避重试。

端点

端点方法说明
/v1/modelsGET当前启用模型列表,id 即调用时的 model 值
/v1/chat/completionsPOST对话补全,支持 SSE 流式与非流式

请求字段

字段类型必填说明
modelstring是取自 /v1/models 的 id,不在列表内 → 404
messagesarray是[{ role: system|user|assistant, content }],空数组 → 400
streambool否true 走 SSE,默认 false
temperaturenumber否透传上游
max_tokensint否透传上游

非流式响应

json
{
  "id": "chatcmpl-xxxxxxxxxxxx",
  "object": "chat.completion",
  "created": 1760000000,
  "model": "gpt-4o-mini",
  "choices": [
    { "index": 0, "message": { "role": "assistant", "content": "OK" }, "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 }
}
usage 恒为 0(上游未回传 token 计数),不要用它做计费 / 限额判断。

SSE 流式

Content-Type 为 text/event-stream,响应头带 X-Accel-Buffering: no(禁止 nginx 缓冲)。

text
data: {"id":"chatcmpl-x","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"role":"assistant"}}]}

data: {"id":"chatcmpl-x","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"delta":{"content":"O"}}]}

data: {"id":"chatcmpl-x","object":"chat.completion.chunk","created":1760000000,"model":"gpt-4o-mini","choices":[{"index":0,"finish_reason":"stop"}]}

data: [DONE]

流式上游中途失败时,最后一个分片会追加提示文本(生成失败:<原因>),随后照常发 finish_reason 与 [DONE],并退还已预留算力 —— 客户端无需特判即可优雅收尾。

代码示例

python
from openai import OpenAI

client = OpenAI(base_url="https://qstar.center/v1", api_key=TOKEN)
r = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "只回复 OK 两个字"}],
)
print(r.choices[0].message.content)

# 流式
for chunk in client.chat.completions.create(
    model="gpt-4o-mini", messages=[{"role": "user", "content": "讲个笑话"}], stream=True
):
    print(chunk.choices[0].delta.content or "", end="", flush=True)
js
const res = await fetch("https://qstar.center/v1/chat/completions", {
  method: "POST",
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
  body: JSON.stringify({ model: "gpt-4o-mini", messages, stream: true }),
  signal,
});
const reader = res.body.getReader();
const dec = new TextDecoder();
let buf = "";
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buf += dec.decode(value, { stream: true });
  const lines = buf.split("\n");
  buf = lines.pop() ?? "";
  for (const l of lines) {
    const d = l.trim().startsWith("data:") ? l.trim().slice(5).trim() : null;
    if (!d) continue;
    if (d === "[DONE]") return;
    const delta = JSON.parse(d)?.choices?.[0]?.delta?.content;
    if (delta) render(delta);
  }
}

错误码

统一 OpenAI 信封:{ "error": { "message": "…", "type": "…", "code": "…" } }

HTTPtype触发场景客户端建议
400invalid_request_errorbody 解析失败 / messages 为空修请求体,不重试
401invalid_request_error缺令牌 / 签名无效 / 已过期 / 会话已登出重新登录取 token
402insufficient_quota算力余额不足提示充值,不重试
404model_not_foundmodel 不在 /v1/models 列表内先拉模型列表
502server_error上游模型服务异常(已退还算力)指数退避重试

与 OpenAI 官方协议的差异

能力状态
chat/completions 非流式 / 流式✅ 支持
models.list✅ 支持
role: system / user / assistant✅ 支持
temperature / max_tokens✅ 透传
n / top_p / presence_penalty / frequency_penalty❌ 忽略
stop / seed / logprobs / response_format / stream_options❌ 忽略(不报错)
tools / function_call❌ 未支持
视觉输入(image content part)❌ 未支持
usage 精确计数⚠️ 恒为 0
/v1/embeddings、/v1/images、/v1/audio 等❌ 未提供

缓存与安全约定

所有 /v1/* 响应强制带:Cache-Control: no-store, no-cache, must-revalidate, private, max-age=0;Pragma: no-cache;Expires: 0;Vary: Authorization。

响应随 Authorization 变化。任何中间层若按「仅 URL」缓存,会把已登录用户的响应回给未登录请求,造成越权读取。接入方不要在自有网关对 /v1/* 做响应缓存;若必须缓存,缓存键须包含 Authorization。

外网回归必测三步:① 未登录 GET /v1/models → 401;② 带令牌 → 200;③ 再次未登录 → 401(若为 200 说明缓存投毒复发)。

故障排查速查

现象原因 / 排查
未登录却返回 200缓存投毒;加随机 query 串复测,若结果变回正确即按键缓存命中
流式一次性返回nginx proxy_buffering 未关,或 curl 少了 -N
401 但令牌没过期会话键 users/<uid> 已删(登出 / 被踢),重新登录
404 但模型名看着对用 /v1/models 的 id,不是展示名 name
部署后仍是旧行为边缘未刷新,需回源刷新(EO purge)
本地 curl 403/520/000沙箱 / 代理假故障;节点内改用 curl -sLk --noproxy '*'
502上游异常,已退还算力,退避重试
这篇文档是否有帮助?

完整帮助中心(含全部在应用主题)请登录后访问 /help。