对话补全

/v1/chat/completions 的每个字段我们怎么处理、流式要注意的四件事、工具调用与中途断开怎么计费。

查看 .md
http
POST https://api.scirouter.cn/v1/chat/completions

请求与响应都是 OpenAI Chat Completions 的形状。这一页只写我们怎么处理这些字段, 字段本身的语义以 OpenAI 的文档为准。

请求体

json
{
  "model": "bio/protein-72b",
  "messages": [
    { "role": "system", "content": "你是一名结构生物学助手。" },
    { "role": "user", "content": "帮我判断这段序列的二级结构倾向:MKTAYIAKQR…" }
  ],
  "max_tokens": 1024,
  "temperature": 0.3,
  "stream": false
}
字段必填我们怎么处理
model模型 id,见「模型列表」。不存在或已下线 404 model_not_found,白名单外 403 model_not_allowed
messages不能为空数组。原样转给上游
max_tokens必须是正整数;超过模型或套餐的单次上限直接 400details.limit 给出上限,不会替你悄悄截短。不填时取两者中较小的那个
max_completion_tokensmax_tokens 的新名字,两个都给时以 max_tokens 为准
temperature / top_p原样转给上游
stop字符串或字符串数组,其他类型 400
stream见下文「流式」
stream_options.include_usage流式时在末尾多发一个只带 usage 的分片
tools / tool_choice见下文「工具调用」
metadata / user你的归因标签,不转给上游,见「可观测性」
其他字段原样转给上游;厂商专有参数的写法见「多厂商差异」

请求体上限默认 4 MB,超过返回 413 payload_too_large

非流式响应

json
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1758585600,
  "model": "bio/protein-72b",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "这段序列……" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 42, "completion_tokens": 318, "total_tokens": 360 },
  "scirouter": { "request_id": "req_…", "attempts": 1, "…": "…" }
}

scirouter 字段与 X-SciRouter-* 响应头见「可观测性」。

finish_reasonlength 时,回答被 max_tokens 截断了。 它看起来可能很完整—— 一段结构数据、一段代码被截在中间时,解析不报错也不代表内容是全的。批处理请按它判断,而不是看内容长短。

流式

"stream": true,响应是 text/event-stream

text
: ping

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""}}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"这段序列"}}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":42,"completion_tokens":318,"total_tokens":360}}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"request_id":"req_…","attempts":1}}

data: [DONE]

读流时要处理好四件事:

  1. : 开头的行是注释,跳过。 排队或上游很久没吐字时,网关每隔一段时间发一行 : ping, 防止中间的代理把空闲连接掐掉。官方 SDK 会自动跳过。
  2. choices 可能是空数组。 末尾的用量分片(要了 include_usage 才有)和 scirouter 分片都是这样, 直接取 choices[0] 会越界。
  3. 收到 data: [DONE] 才算正常结束。 出错时流里会出现一个 {"error": {...}} 分片,之后直接断开、不发 [DONE]; 没收到 [DONE] 就结束的流一律按失败处理,形状见「错误码」。
  4. 错误分片可能出现在第一个内容分片之前。 心跳一旦发出,HTTP 状态码就已经是 200 了—— 这之后的任何错误(例如排队太久超时)都只能以错误分片出现。只看状态码会把它们全部当成成功。

故障转移只发生在第一个字节之前:上游一旦开始吐字,中途失败不会换线路重来(那会让你收到两段拼起来的回答), 而是按上一条给你一个错误分片。

工具调用

tools / tool_choice 按 OpenAI 的格式写,原样转给上游;模型返回的 tool_calls 也原样交还给你。

tools 的请求只会发往支持工具调用的线路。一个模型的所有线路都不支持时,返回 503 model_unavailabledetails.reason 说明原因——这种 503 重试不会好,请换模型。

中途断开与计费

  • 非流式请求失败不计费;
  • 流式请求在吐出一部分之后失败,按已经产生的用量计费(上游给了用量就按它,没给就按已转发的文本估算);
  • 你这边主动断开连接时,网关会同时取消上游,按断开前已产生的部分计费,结果不保存—— 所以带 Idempotency-Key 重试时会重新调用,见「缓存与幂等」。

相关

  • 所有错误码与哪些该重试:「错误码」
  • 重复请求直接命中、重试不重复扣费:「缓存与幂等」
  • 每次调用打给了谁、慢在哪:「可观测性」

请验证你的身份

为了保护你的账户,这个操作需要再验证一次。

验证码已发送到你绑定的手机号。5 分钟内的其他敏感操作不会再问。

Cookie 偏好

您可以随时回到这里修改。页脚有常驻入口。

必要

维持登录状态、记住主题与语言偏好。没有它们本站无法正常工作,因此无法关闭。

统计

了解哪些功能有人用、用户在哪一步流失。只收集维度(页面、操作类型、计数),不收集您输入的任何内容。

本站不加载任何第三方统计脚本,也不做会话录屏。完整说明