# SciRouter 接口文档(完整版) > SciRouter 是科研领域下的垂域大模型服务平台,面向科研人员与科研团队。本文档讲其中的模型 API:兼容 OpenAI Chat Completions、OpenAI Responses 与 Anthropic Messages 三种格式,接入多家厂商的科研模型,统一鉴权、计费与调度。 本文件把 https://www.scirouter.cn/docs 下的 23 页接口文档合成一份,供 AI 编程助手读完后实现接入。内容最后更新于 2026-10-25;每一页前面标了它的来源地址与更新日期。 ## 接入要点 - base URL:`https://api.scirouter.cn/v1`。兼容 OpenAI 格式,另支持 Anthropic Messages 与 OpenAI Responses 格式。共十个接口:`GET /models`、`GET /models/{model_id}`、`POST /chat/completions`、`POST /embeddings`;OpenAI Images 格式的 `POST /images/generations`、`POST /images/edits`(multipart)、`POST /images/variations`,只能调用生图模型(`/models` 中 `scirouter.kind` 为 `image` 的模型);OpenAI Responses 格式的 `POST /responses`,无状态:`store` 只接受 false,不支持 `previous_response_id` / `background`;Anthropic 格式的 `POST /messages`、`POST /messages/count_tokens`(Anthropic SDK 自行拼接 `/v1`,其 base URL 只写到域名)。旧的 `/completions`、Assistants、语音、按 id 操作已保存响应等接口不存在,返回 404。`model` 必须是具体的模型 id(或平台为其配置的别名),不提供 `auto` 这类虚拟模型。 - 认证:`Authorization: Bearer ` 或 `x-api-key: `,同时携带时须为同一个 Key;不接受其他写法(Cookie、查询参数、`api-key` 请求头)。Key 格式为 `sk-sr-` 加 40 位字母数字,三种格式均只接受该 Key;OpenAI、Anthropic 等厂商的 Key 返回 401(平台自行鉴权、计费,以平台的凭据调用厂商)。Key 从环境变量(如 `SCIROUTER_API_KEY`)读取,不写入代码,不放入浏览器、App 等前端。 - 模型 id:格式为 `厂商/模型名`,从 `GET /models` 获取,原样填入 `model`。列表已按该 Key 的权限过滤(Key 与项目的白名单、套餐、受限模型的授权),列出的模型均有调用权限;唯一例外是维护中的模型(503 `model_unavailable`)。 - 错误:OpenAI 格式为 `{"error": {"message", "type", "code", "scirouter_code", "param", "request_id", "details"}}`。按小写的 `error.code` 分支,不按 `message` 判断。三个上游语义错误(400 `context_window_exceeded` / `unsupported_param` / `content_filtered`)的 `error.code` 为原厂兼容值(`context_length_exceeded` / `unsupported_parameter` / `content_filter`),平台码在 `error.scirouter_code`。403 的 `details.scope`(`key` / `project` / `plan`)指明拦截请求的白名单层级。`/messages` 两个接口使用 Anthropic 格式 `{"type": "error", "error": {"type", "message", "code", "details"}, "request_id"}`,状态码与 `error.code` 同上。 - 应重试(指数退避,遵守 `Retry-After`,设重试上限):429 `rate_limited`、429 `upstream_saturated`、502 `upstream_error`、503 `model_unavailable`(仅限带 `Retry-After` 时;不带时属于 `details.reason` 为 `tools_unsupported` 一类,重试无效)、504 `upstream_timeout`、409 `idempotency_conflict`(同一个键的请求仍在处理中;同一个键对应不同请求体也返回该码,有限次重试后仍为 409 时停止)。套餐日上限触发的 `rate_limited`,`Retry-After` 指向次日零点。 - 不应重试:其余 4xx。包括 400 `context_window_exceeded`(缩短输入或调小 `max_tokens`)、400 `unsupported_param`(`error.param` 指出无法传递的参数;请求中有只能原样转发的内容而没有可用线路时,`details.reason` 为 `unsupported_content`)、402 `insufficient_quota`(预扣不足)、429 `key_quota_exceeded`(Key 的月度上限,创建后不能修改,次月恢复或更换 Key)、429 `project_budget_exceeded`(项目月预算,`Retry-After` 指向次月 1 日,可在控制台调高)。 - 流式:跳过以 `:` 开头的注释行(心跳 `: ping`);`choices` 可能为空数组;出错时发送一个 `{"error": …}` 分片后断开。**未收到 `data: [DONE]` 的流一律按失败处理**,即使 HTTP 状态为 200。`/messages` 的流按 Anthropic 的事件格式发送(带 `event:` 行),以 `message_stop` 结束,没有 `[DONE]`;出错时为 `event: error`,未收到 `message_stop` 同样按失败处理。非流式请求最长等待约 270 秒(超时返回 504 `upstream_timeout`,不计费),回答耗时可能超过该时长时使用流式。 - 思考过程:`/chat/completions` 中,推理模型的思考过程同时出现在 `reasoning_content` 与 `reasoning` 两个字段(内容相同),非流式在 `message` 中,流式在 `delta` 中;`/messages` 中为 Anthropic 格式的 `thinking` 块。 - 参数:每个参数到线路上只有四种处理结果,即原样传递、翻译、平台模拟、明确告知。提示类参数(采样、思考强度、缓存提示)无法传递时被去掉,并在响应头 `X-SciRouter-Param-Actions` 留痕(如 `dropped=seed,top_k; translated=reasoning`),不报错;契约类参数(结构化输出、工具、`n`、`logprobs`)依次尝试翻译、模拟、换线路,均不可行时返回 400 `unsupported_param`。请求头 `X-SciRouter-Unsupported-Params: strict` 使提示类参数也返回 400,`lenient` 使契约类参数也被去掉。`GET /models` 的 `scirouter.supported_params` / `emulated_params` 为模型的能力自述。 - 截断与预扣:`finish_reason` 为 `length` 表示回答被 `max_tokens` 截断。`/chat/completions` 的 `max_tokens` 超过模型或套餐上限时返回 400(`details.limit` 给出上限),不自动截短;`/messages` 超过上限时按上限发出,响应头 `X-SciRouter-Max-Tokens-Clamped` 写明请求值与实际值。预扣按输入估算加输出上限冻结配额(账户充值余额大于 0 时输出只按输出上限与平台设定值中的较小者估算),结束后按实际用量结算,实际超出的部分照扣。 - 幂等:非流式的 `/chat/completions`、`/messages`、`/responses` 与 `/embeddings` 请求可带 `Idempotency-Key` 请求头(不超过 128 字节,作用域为该 Key,保留 24 小时,重试时请求体须逐字节相同)。服务端已处理完成、仅响应在传输中丢失时,同键重试直接重放结果,不再扣费;请求由调用方先断开时,服务端取消且不保存结果,重试会重新计费。图片接口也接受该请求头,`b64_json` 与流式的结果不保存,同键再请求返回 409 `idempotency_conflict`。 - 报障:记录响应头 `X-Request-Id`(错误体中也有 `request_id`)。 --- # 快速开始 > 创建 API Key、选择模型并发送第一个请求,确认接入成功。 来源:https://www.scirouter.cn/docs/quickstart · 更新于 2026-10-24 SciRouter 的接口兼容 OpenAI Chat Completions、OpenAI Responses 与 Anthropic Messages 三种格式。已调用 OpenAI 接口的代码,将 `base_url` 设为 `https://api.scirouter.cn/v1`、Key 换成 SciRouter 的 API Key、`model` 换成平台的模型 id 即可调用。 | 格式 | 客户端 | 接入说明 | |---|---|---| | OpenAI Chat Completions | 已调用 OpenAI 接口的代码 | 本页 | | Anthropic Messages | Anthropic SDK、Claude Code | [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages) | | OpenAI Responses | OpenAI SDK 的 `responses.*`、Codex CLI | [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses) | Claude Code、Codex、Cursor 等编程工具的配置见[编程工具概览](https://www.scirouter.cn/docs/coding-tools)。 三种格式均使用 SciRouter 控制台创建的 API Key(以 `sk-sr-` 开头)。鉴权、计费与线路选择由平台完成,调用厂商时使用平台自己的凭据;请求中不需要、也不能携带 OpenAI、Anthropic 等厂商的 Key。 ## 1. 创建 API Key 在控制台的 [API Keys 页面](https://www.scirouter.cn/console/keys)新建 Key。在团队工作区新建时须选择一个团队项目,调用扣除团队的配额。 Key 的明文只在创建时显示一次,关闭创建窗口后无法再次查看(见[认证与 API Key](https://www.scirouter.cn/docs/authentication))。创建后立即复制,存入环境变量或密钥管理工具: ```bash export SCIROUTER_API_KEY="YOUR_API_KEY" ``` ## 2. 选择模型 在[模型中心](https://www.scirouter.cn/models)选择模型,复制其模型 id(格式为 `厂商/模型名`)。示例中的 `YOUR_MODEL_ID` 为占位,使用时替换为所选模型的 id。程序中列出该 Key 可调用的模型,使用 [`GET /models`](https://www.scirouter.cn/docs/models)。 ## 3. 发送第一个请求 ```bash curl https://api.scirouter.cn/v1/chat/completions \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_MODEL_ID", "messages": [{"role": "user", "content": "用一句话解释什么是蛋白质二级结构"}] }' ``` Python(`pip install openai`): ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1", ) response = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "用一句话解释什么是蛋白质二级结构"}], ) print(response.choices[0].message.content) ``` 响应状态为 200 且 `choices[0].message.content` 非空,表示接入成功。返回 401、403 或 404 时,按[错误码](https://www.scirouter.cn/docs/errors)排查。 ## Playground [Playground](https://www.scirouter.cn/playground) 中可直接调整参数、查看用量,并将当前调用复制为可运行的代码。 Playground 需要登录,不需要 API Key:请求使用登录会话,Key 不出现在网页中。每次运行按实际用量扣除配额。 ## 相关文档 - LangChain、LlamaIndex、Vercel AI SDK 与 Node.js:[SDK 与框架](https://www.scirouter.cn/docs/sdks) - 流式、工具调用、思考过程与 `max_tokens` 超限的处理:[对话补全](https://www.scirouter.cn/docs/chat-completions) - 错误处理:[错误码](https://www.scirouter.cn/docs/errors) - 单次调用路由到的线路与扣费:[可观测性](https://www.scirouter.cn/docs/observability) - 整份文档的一键复制,供 AI 编程助手生成接入代码:[给 AI 助手](https://www.scirouter.cn/docs/llms) --- # 认证与 API Key > API Key 的携带方式、可设置的限制、调用前的检查顺序与预扣规则,以及泄露后的吊销。 来源:https://www.scirouter.cn/docs/authentication · 更新于 2026-10-24 所有 `/v1` 接口使用 API Key 认证,Key 放在 `Authorization` 请求头中: ```http Authorization: Bearer YOUR_API_KEY ``` ## 请求头 | 请求头 | 取值 | 说明 | |---|---|---| | `Authorization` | `Bearer ` | 对所有 `/v1` 接口有效。`Bearer` 后为空时视为未携带该请求头 | | `x-api-key` | API Key | Anthropic SDK 的默认写法(见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages)),对所有 `/v1` 接口有效 | - 两个请求头同时携带时须为同一个 Key,否则返回 401 `unauthenticated`。 - 只接受以上两种方式。Cookie、查询参数与 `api-key` 请求头均不作为凭据。 - 网关收到 `/v1` 请求时丢弃 `Cookie` 请求头。浏览器中的 SciRouter 登录会话不作为调用凭据,其他网页无法借用登录会话调用模型、消耗配额。 ## Key 格式 Key 的明文以 `sk-sr-` 开头,后接 40 位字母数字,共 46 位。格式错误或 Key 不存在时返回 401 `unauthenticated`。格式错误最常见的原因是填入了 OpenAI、Anthropic 等厂商的 Key,此时 `message` 提示改用 SciRouter 的 Key。 ## 平台 Key 与厂商 Key 对话补全、Messages(Anthropic 格式)与 Responses(OpenAI Responses 格式)三种格式只接受 SciRouter 控制台创建的 Key。 每次调用由平台使用该 Key 鉴权、检查白名单与配额、按平台的价格计费并选择线路;调用厂商时使用平台在该厂商的账号与凭据。请求携带 OpenAI、Anthropic 等厂商的 Key 时返回 401。SciRouter 的 Key 不会发送给任何厂商。 文档中的「原样转发」指请求体的格式与字段原样到达厂商,鉴权与计费仍由平台完成。 各 SDK 与工具读取的环境变量名由其自身定义(`OPENAI_API_KEY`、`ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`、Codex 的 `env_key`),取值均填 SciRouter 的 Key。本机已设置厂商官方 Key 的,替换为 SciRouter 的 Key,或确认指向 SciRouter 的工具读取的是另一个变量。 ## Key 的设置 在控制台的 [API Keys 页面](https://www.scirouter.cn/console/keys)新建 Key。以下设置均只约束该 Key: | 设置 | 作用 | 超出限制时 | |---|---|---| | 名称 | 用于识别 | — | | 限定模型 | 模型白名单,留空表示不限。控制台一次选择一个模型 | 403 `model_not_allowed`,`details.scope` 为 `key`;`GET /models` 只列出白名单内的模型 | | 月度配额上限 | 该 Key 每个自然月(北京时间)可消耗的配额。不填表示不限,填 0 表示不能产生任何消费 | 429 `key_quota_exceeded`,次月恢复 | | 有效期 | 到期后自动失效,不设置表示不过期 | 401 `key_expired` | | 归属项目 | 将 Key 归入一个项目:项目有独立的模型白名单与月预算,用量按项目归账。个人工作区可选;团队工作区必须选择一个团队项目,调用扣除团队的配额 | 项目白名单外:403 `model_not_allowed`,`details.scope` 为 `project`;超出预算:429 `project_budget_exceeded`,`Retry-After` 到次月 1 日;项目已归档:422 `project_archived` | - 除归属项目外,其他设置创建后不能修改;需要变更时新建 Key 并吊销旧 Key。 - 归属项目可以修改,只能在同一工作区内移动。 - 每个账户最多保留 50 个有效的 Key。 - 明文只在创建时显示一次,平台只保存其哈希,关闭创建窗口后无法再次获取。创建后立即复制,存入密钥管理工具或环境变量。 ## 环境变量 Key 存入环境变量,不写入代码: ```bash export SCIROUTER_API_KEY="YOUR_API_KEY" ``` 官方 OpenAI SDK(Python 与 Node)读取 `OPENAI_API_KEY` 与 `OPENAI_BASE_URL` 两个环境变量。不修改现有代码时,将这两个变量指向 SciRouter(`model` 仍需换成平台的模型 id): ```bash export OPENAI_API_KEY="$SCIROUTER_API_KEY" export OPENAI_BASE_URL="https://api.scirouter.cn/v1" ``` ## 浏览器端调用 `/v1` 的 CORS 对所有来源开放(不带凭证),浏览器可以直接调用。直接调用会将 Key 暴露给每个打开网页的用户,任何人都可从开发者工具中获取。浏览器、App 与小程序中的调用经调用方自己的后端转发。 [Playground](https://www.scirouter.cn/playground) 与站内 Chat 使用登录会话,不经过 API Key 明文。 ## 按用途划分 Key 按服务、环境或实验分别创建 Key: - 泄露时只需吊销对应的 Key,其他服务不受影响; - 用量与日志按 Key 分开统计; - 白名单与月度配额上限可按用途设置。例如为批量评测所用的 Key 设置月度上限,失控时消耗不超过该上限。 同一个 Key 下需要进一步区分(如十个实验共用一个 Key)时,在请求体的 `metadata` 中添加标签,见[可观测性](https://www.scirouter.cn/docs/observability)。 ## 泄露与吊销 Key 泄露时,在控制台吊销该 Key,然后新建 Key 替换。吊销立即生效(极少数情况下最迟 1 分钟),不可撤销;此后使用该 Key 的请求返回 401 `key_revoked`。 Key 不支持暂停,只能吊销。 | 情况 | 结果 | |---|---| | 成员被移出团队 | 该成员在团队项目下创建的 Key 一并吊销 | | 团队被停用 | 团队项目下的 Key 调用返回 403 `team_suspended` | ## 调用前的检查 每次调用按以下顺序检查,任一步未通过即返回错误,不调用上游: | 顺序 | 检查项 | 未通过时 | |---|---|---| | 1 | 认证:Key 格式正确、存在、未吊销、未过期,账户未停用 | 401 `unauthenticated` / `key_revoked` / `key_expired` / `account_suspended` | | 2 | 请求与模型:模型存在;模型不在维护或停用状态;`max_tokens` 不超过模型与套餐的单次上限 | 404 `model_not_found`;503 `model_unavailable`;400,`details.limit` 为上限 | | 3 | 授权:模型在 Key 的白名单、Key 所属项目的白名单与套餐内;受限模型还要求调用所在的团队已获授权 | 403 `model_not_allowed`,`details.scope` 指明未通过的一层;403 `model_restricted` | | 4 | 配额:依次检查 Key 的月度上限、项目的月预算、套餐的日上限,本次花费按输入估算加输出上限全额估计 | 429 `key_quota_exceeded`;429 `project_budget_exceeded`;429 `rate_limited`,`Retry-After` 到次日零点 | | 5 | 限频:每分钟请求数、每分钟 token 数(按估算)与并发请求数,Key 与账户各计一份。账户指个人账户;团队项目下的 Key 计入团队 | 429 `rate_limited`,`details.scope` 为 `key` / `personal` / `team`;模型的全站并发已满时返回 503 `model_unavailable`,`details.reason` 为 `model_busy`,带 `Retry-After` | | 6 | 预扣:按估算成本冻结一笔配额(有下限),调用结束后按实际用量结算,多退少补 | 402 `insufficient_quota`,见[预扣](#预扣) | - 第 4 步比较的是「已用量 + 本次全额估算」,接近上限时估算值大的请求先被拒绝。充值余额大于 0 的账户,第 6 步的预扣只按输出预留估,两者不是同一个数。 - 每分钟请求数在第 4 步之前先预检一次,命中响应缓存的请求也计入。因此限频的 429 可能先于配额的 429 出现。 ## 预扣 估算值 = 输入估算 + 输出上限。输出上限即 `max_tokens`,未传时为平台为该请求确定的上限(模型与套餐上限中较小的值,见[对话补全](https://www.scirouter.cn/docs/chat-completions)「max_tokens」)。 账户的充值余额大于 0 时,对话请求的输出只按输出预留估算:输出预留是输出上限与平台设定值中的较小者,因此 `max_tokens` 写得大不会多冻结配额。充值余额为 0 或为负(只有赠送额度、或已透支)的账户按输出上限全额估算。 调用结束后按实际用量结算:实际花费超过预扣的部分照扣,配额可能因此变为负数,之后的请求返回 402 `insufficient_quota`,充值后恢复。余额不足以冻结估算值时返回 402:`details.required_quota` 为本次需冻结的配额,团队账户另带 `details.account_kind: "team"`。 Key 月度上限、项目月预算与套餐每日上限仍按输入估算加输出上限全额判断。 命中响应缓存的请求只计一次请求数,不检查配额、不预扣、不扣费,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 ## 余量查询 - 限频余量在响应头 `x-ratelimit-{limit,remaining,reset}-{requests,tokens}` 中,取 Key 与账户两份中更紧的一份。套餐不限的项不返回,并发数没有对应的响应头。 - 配额与预算在控制台查看,见[可观测性](https://www.scirouter.cn/docs/observability)。 --- # SDK 与框架 > OpenAI 与 Anthropic SDK、常用框架及图形客户端的接入方式,接口清单与重试、超时策略。 来源:https://www.scirouter.cn/docs/sdks · 更新于 2026-10-24 接口与 OpenAI 兼容,可修改 base URL 的 OpenAI 客户端均可直接使用,只需修改两项配置: | 配置项 | 取值 | |---|---| | base URL | `https://api.scirouter.cn/v1` | | API Key | 在 SciRouter 控制台创建的 Key(以 `sk-sr-` 开头,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)),不能使用 OpenAI 的 Key | 示例中的 `YOUR_MODEL_ID` 为占位,替换为在[模型中心](https://www.scirouter.cn/models)选定的模型 id。Anthropic SDK 的接入见 [Anthropic SDK 与 Claude Code](#anthropic-sdk-与-claude-code);Claude Code、Codex、Cursor 等编程工具的配置见[编程工具概览](https://www.scirouter.cn/docs/coding-tools)。 ## Python(openai) ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1", ) # 非流式 resp = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "这段序列的二级结构倾向?"}], ) print(resp.choices[0].message.content) # 流式 stream = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "这段序列的二级结构倾向?"}], stream=True, ) for chunk in stream: # 末尾的 scirouter 扩展分片与 include_usage 的用量分片 choices 为空,取值前先判断 if chunk.choices and chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True) ``` 读取响应头 `X-Request-Id`(用于报障)与 `scirouter` 扩展字段: ```python raw = client.chat.completions.with_raw_response.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "…"}], ) print(raw.headers.get("X-Request-Id")) resp = raw.parse() print(resp.model_dump().get("scirouter")) ``` ## Node.js / TypeScript(openai) ```bash npm install openai ``` ```typescript import OpenAI from 'openai' const client = new OpenAI({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn/v1', }) // 非流式,同时读取响应头 const { data, response } = await client.chat.completions .create({ model: 'YOUR_MODEL_ID', messages: [{ role: 'user', content: '这段序列的二级结构倾向?' }], }) .withResponse() console.log(data.choices[0].message.content, response.headers.get('x-request-id')) // 流式 const stream = await client.chat.completions.create({ model: 'YOUR_MODEL_ID', messages: [{ role: 'user', content: '这段序列的二级结构倾向?' }], stream: true, }) for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '') } ``` > 注意:不要在浏览器中使用上述代码,否则 Key 会暴露给所有访问者。前端页面应通过调用方自己的后端转发请求。 ## LangChain(Python) ```bash pip install langchain-openai ``` ```python import os from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="YOUR_MODEL_ID", base_url="https://api.scirouter.cn/v1", api_key=os.environ["SCIROUTER_API_KEY"], ) print(llm.invoke("这段序列的二级结构倾向?").content) ``` - `with_structured_output()` 默认发送 `json_schema` 并带 `strict: true`。模型支持原生结构化输出时原样传递;不支持时由平台模拟(强制工具或提示),响应头 `X-SciRouter-Param-Actions` 中出现 `emulated=response_format`,见[参数如何被处理](https://www.scirouter.cn/docs/params)。 - `ChatAnthropic`(接 `/v1/messages`,base URL 不带 `/v1`)获取结构化输出时默认使用强制工具。模型不支持强制工具时,平台降为 `auto` 并在提示中要求调用工具,结果尽力而为。 - LangChain 默认不发送 `stream_options.include_usage`,不影响用量统计:平台向上游始终请求用量,流式响应末尾仍返回 `usage`。 ## LlamaIndex ```bash pip install llama-index-llms-openai-like ``` ```python import os from llama_index.llms.openai_like import OpenAILike llm = OpenAILike( model="YOUR_MODEL_ID", api_base="https://api.scirouter.cn/v1", api_key=os.environ["SCIROUTER_API_KEY"], is_chat_model=True, ) print(llm.complete("这段序列的二级结构倾向?")) ``` `is_chat_model=True` 不能省略。省略时 LlamaIndex 调用旧的 `/completions` 接口,平台不提供该接口。 ## Vercel AI SDK ```bash npm install ai @ai-sdk/openai-compatible ``` ```typescript import { createOpenAICompatible } from '@ai-sdk/openai-compatible' import { generateText } from 'ai' const scirouter = createOpenAICompatible({ name: 'scirouter', baseURL: 'https://api.scirouter.cn/v1', apiKey: process.env.SCIROUTER_API_KEY, }) const { text } = await generateText({ model: scirouter('YOUR_MODEL_ID'), prompt: '这段序列的二级结构倾向?', }) ``` AI SDK 会重试流中无法识别的错误码,因此平台流内错误帧的 `code` 只使用原厂可识别的值(`rate_limit_exceeded`、`server_error` 等),平台码放在 `scirouter_code`,见[错误码](https://www.scirouter.cn/docs/errors)「流式响应中的错误」。 ## Anthropic SDK 与 Claude Code `/v1/messages` 为 Anthropic Messages 格式,Anthropic SDK(Python 的 `anthropic`、TypeScript 的 `@anthropic-ai/sdk`)与 Claude Code 可直接使用。这些客户端会自行拼接 `/v1`,**base URL 为 `https://api.scirouter.cn`,不带 `/v1`**。SDK 的完整写法见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages),Claude Code 的配置见 [Claude Code](https://www.scirouter.cn/docs/claude-code)。 ## OpenAI Responses 与 Codex CLI `/v1/responses` 为 OpenAI Responses 格式。新版 OpenAI SDK 的 `client.responses.create` / `stream` / `parse` 与 Codex CLI(`wire_api = "responses"`)可直接使用,base URL 与对话补全相同(带 `/v1`)。 平台不保存状态:`store` 只接受 `false`,不支持 `previous_response_id`。完整写法见 [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses),Codex 的 `config.toml` 见 [Codex](https://www.scirouter.cn/docs/codex)。 ## 图形客户端与 IDE 插件 Claude Code、Codex、OpenCode、Kilo CLI、Kilo Code、Cursor 与 CC Switch 各有一页配置说明,见[编程工具概览](https://www.scirouter.cn/docs/coding-tools)。其他桌面聊天客户端与 IDE 插件按服务商类型填写: | 服务商类型 | API 地址 | Key | |---|---|---| | 「OpenAI 兼容」类 | `https://api.scirouter.cn/v1` | SciRouter 的 Key | | 「Anthropic」类 | `https://api.scirouter.cn`(不带 `/v1`) | SciRouter 的 Key | 两类服务商均填写 SciRouter 的 Key,不填写厂商的 Key。部分客户端要求地址填到 `/v1` 为止,部分客户端会自动补上 `/v1`;填错时返回 404,改用另一种写法。 | 客户端 | 配置 | |---|---| | Cline、Continue | 选择 OpenAI 兼容的服务商,base URL 填 `https://api.scirouter.cn/v1`,模型填平台的模型 id | | Dify | 选择「OpenAI-API-compatible」供应商,填写同样两项 | Cursor、Cline、Continue 按 `error.code` 的原厂值识别错误(上下文超长为 `context_length_exceeded`,参数不支持为 `unsupported_parameter`),平台的错误体使用相同的值,见[错误码](https://www.scirouter.cn/docs/errors)「上游语义错误」。 Cursor、Cline、Continue、Dify 均不读取 `error.param` 自动调整参数。参数能否传到线路上由网关统一处理:提示类参数去掉并留痕,契约类参数翻译或模拟,见[参数如何被处理](https://www.scirouter.cn/docs/params)。 ## 直接调用 HTTP 没有 SDK 的语言直接发送 HTTP 请求,与[快速开始](https://www.scirouter.cn/docs/quickstart)中的 curl 相同:`POST https://api.scirouter.cn/v1/chat/completions`,请求头 `Authorization: Bearer `,JSON 请求体。流式响应按 SSE 读取,要点见[对话补全](https://www.scirouter.cn/docs/chat-completions)。 ## 接口清单 `/v1` 下提供以下接口: | 接口 | 文档 | |---|---| | `GET /models`、`GET /models/{id}` | [模型列表](https://www.scirouter.cn/docs/models) | | `POST /chat/completions` | [对话补全](https://www.scirouter.cn/docs/chat-completions) | | `POST /embeddings` | [向量](https://www.scirouter.cn/docs/embeddings) | | `POST /images/generations`、`POST /images/edits`、`POST /images/variations` | [图片](https://www.scirouter.cn/docs/images) | | `POST /responses` | [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses) | | `POST /messages`、`POST /messages/count_tokens` | [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages) | - 平台不提供旧的 `/completions`、语音、Assistants,以及 Responses 中按 id 读取、删除、取消已保存响应的接口(平台不保存响应),调用返回 404。 - `model` 必须是具体的模型 id,平台不提供 `auto` 这类虚拟模型。 - `/v1` 之外另有 MCP 端点 `https://api.scirouter.cn/mcp`(使用同一个 Key),供调用方的 agent 使用平台的检索与读库工具,见 [MCP 与托管工具](https://www.scirouter.cn/docs/mcp)。 ## 重试与超时 官方 SDK 默认对连接错误、408、409、429 与 5xx 自动重试两次,并参考 `Retry-After`。SDK 不读取 `error.code`,因此以下错误也会被重试: - `key_quota_exceeded`、`project_budget_exceeded` 等重试无效的 429; - 不带 `Retry-After` 的 503(`details.reason` 为 `tools_unsupported` 等)。 这些请求在预扣之前被拒绝,不扣费,只增加几秒等待。需要精确控制时,将 `max_retries` 设为 0,按[错误码](https://www.scirouter.cn/docs/errors)自行分支。 **非流式请求最长等待约 270 秒,回答耗时可能超过该时长时使用流式。** 非流式请求在生成完成前连接上没有任何数据;平台最多等待整个响应约 270 秒,超时返回 504 `upstream_timeout`(`details.timeout` 为 `response`),不计费。该时长短于接入层(CDN)等待源站应答的 300 秒,因此客户端收到的是 JSON 错误体,不是 CDN 的 524。推理类模型单次回答可能需要数分钟,此类请求使用流式;流式响应带 `: ping` 心跳,不受该限制。 客户端超时应长于模型的正常耗时;非流式请求的超时设为 300 秒以上无效。 三个上游语义错误(上下文超长、参数不支持、内容审核)返回 400,SDK 不重试。它们的 `error.code` 为原厂兼容值(`context_length_exceeded` 等),平台码在 `error.scirouter_code`。各错误是否值得重试见[错误码](https://www.scirouter.cn/docs/errors)。 --- # 编程工具概览 > 编程工具接入平台的通用步骤:各工具的接口格式与地址写法、模型 id、上下文窗口、计费与常见错误。 来源:https://www.scirouter.cn/docs/coding-tools · 更新于 2026-10-24 编程工具通过 SciRouter 的接口调用平台上的模型。在工具中填写三项:平台的地址、SciRouter 的 API Key、平台的模型 id。各工具使用的接口格式不同,地址的写法随之不同。 ## 准备 1. 在控制台 [API Keys 页面](https://www.scirouter.cn/console/keys)创建 Key(以 `sk-sr-` 开头)。为编程工具单独创建一个 Key,按需设置模型白名单与月度上限,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)。 2. 在[模型中心](https://www.scirouter.cn/models)选择模型,复制模型 id(格式为 `厂商/模型名`)。该 Key 可调用的模型以 `GET /models` 的返回为准。 3. 将 Key 存入环境变量 `SCIROUTER_API_KEY`,各工具页的配置从这里读取: ```bash echo 'export SCIROUTER_API_KEY="YOUR_API_KEY"' >> ~/.zshrc # bash 写入 ~/.bashrc source ~/.zshrc ``` Windows 在 PowerShell 中执行 `setx SCIROUTER_API_KEY "YOUR_API_KEY"`,重新打开终端后生效。 ## 接口格式与地址 | 工具 | 接口格式 | 地址 | 接入说明 | |---|---|---|---| | Claude Code | Anthropic Messages | `https://api.scirouter.cn` | [Claude Code](https://www.scirouter.cn/docs/claude-code) | | Codex | OpenAI Responses | `https://api.scirouter.cn/v1` | [Codex](https://www.scirouter.cn/docs/codex) | | OpenCode | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | [OpenCode](https://www.scirouter.cn/docs/opencode) | | Kilo CLI | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | [Kilo CLI](https://www.scirouter.cn/docs/kilo-cli) | | Kilo Code | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | [Kilo Code](https://www.scirouter.cn/docs/kilo-code) | | Cursor | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | [Cursor](https://www.scirouter.cn/docs/cursor) | | CC Switch | 随所配置的工具 | 随所配置的工具 | [CC Switch](https://www.scirouter.cn/docs/cc-switch) | | Cline、Continue 等 | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | [SDK 与框架](https://www.scirouter.cn/docs/sdks)「图形客户端与 IDE 插件」 | Anthropic 格式的工具在地址后自行拼接 `/v1/messages`,**地址不带 `/v1`**;其余工具的地址带 `/v1`。多写或少写 `/v1` 时返回 404。 三种格式都能调用平台上的全部对话模型。模型的线路不支持工具所用的格式时,平台转换请求,见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages)「请求的转发方式」与 [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses)「请求的转发方式」。 ## 模型 id - 填写平台的模型 id(`厂商/模型名`,含 `/`),区分大小写。 - 工具内置的模型名(如 Claude Code 的 `sonnet`、`opus`)不会自动对应到平台的模型,按各工具页的写法映射到平台的模型 id。 - 同一个工具可配置多个模型 id,在工具内切换。 ## 上下文窗口与输出上限 工具不识别平台的模型 id 时,按自身的默认值估算上下文窗口与输出上限,与模型的实际值可能不同。在工具中写明所选模型的上下文窗口与输出上限(见[模型中心](https://www.scirouter.cn/models)的详情页),工具才能在窗口用满前压缩对话。各工具的写法见各页。 输入超出窗口时,平台在发出前返回 400 `context_window_exceeded`(`error.code` 为 `context_length_exceeded`)。Claude Code 与 Codex 据此压缩对话后重发,见各自的页面。 ## 计费与用量 编程工具的调用与直接调用接口相同,按所用模型的价格与实际 token 计费。工具执行一个任务会连续发出多次请求,每次都带上完整的对话历史,输入 token 随对话变长而增加;上游提示词缓存命中的部分按命中价计,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 用量在控制台[用量页面](https://www.scirouter.cn/console/usage)查看。单次请求在[调用日志](https://www.scirouter.cn/console/logs)中按 `request_id` 查询,可按调用格式(OpenAI / Anthropic)筛选。 ## 常见错误 | 现象 | 原因 | 处理方式 | |---|---|---| | 返回 404,模型 id 无误 | 地址多写或少写 `/v1` | 按[接口格式与地址](#接口格式与地址)改正 | | 401 `unauthenticated` | 工具读到的不是 SciRouter 的 Key:填入了厂商的 Key,或环境变量没有生效 | 检查工具读取的变量,值应以 `sk-sr-` 开头;修改环境变量后重新打开终端 | | 404 `model_not_found` | 模型 id 写错,或填了工具内置的模型名 | 以[模型中心](https://www.scirouter.cn/models)或 `GET /models` 返回的 id 为准 | | 403 `model_not_allowed` | 模型不在 Key、项目或套餐的白名单中 | 修改白名单,或更换模型 | | 402 `insufficient_quota` | 余额不足以预扣 | 充值,见[认证与 API Key](https://www.scirouter.cn/docs/authentication) | | 400 `context_window_exceeded` | 对话超出模型的上下文窗口 | 在工具中写明窗口大小,或压缩对话、换用窗口更大的模型 | 其余错误见[错误码](https://www.scirouter.cn/docs/errors)。报障时提供响应头 `X-Request-Id` 的值。 --- # Claude Code > 在 Claude Code 中使用平台的模型:安装、settings.json 配置、模型映射、上下文窗口与常见报错的处理。 来源:https://www.scirouter.cn/docs/claude-code · 更新于 2026-10-24 Claude Code 通过 Anthropic Messages 格式(`POST /v1/messages`)调用平台的模型,平台上的对话模型均可使用。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的三步。 ## 安装 ```bash npm install -g @anthropic-ai/claude-code claude --version ``` 输出版本号表示安装成功。Windows 需先安装 WSL 或 Git for Windows。 ## 配置 Claude Code 从 `settings.json` 的 `env` 字段读取环境变量,写在这里对所有终端生效: | 系统 | 文件路径 | |---|---| | macOS / Linux | `~/.claude/settings.json` | | Windows | `C:\Users\<用户名>\.claude\settings.json` | 文件不存在时新建。写入以下内容,将 `YOUR_API_KEY` 换成 SciRouter 的 Key、`YOUR_MODEL_ID` 换成平台的模型 id: ```json { "env": { "ANTHROPIC_BASE_URL": "https://api.scirouter.cn", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "YOUR_MODEL_ID" } } ``` 文件中已有其他设置时,只合并 `env` 中的这几项。**`ANTHROPIC_BASE_URL` 不带 `/v1`**:Claude Code 在其后拼接 `/v1/messages`。 也可只在当前终端设置,不写入文件: ```bash export ANTHROPIC_BASE_URL="https://api.scirouter.cn" export ANTHROPIC_AUTH_TOKEN="$SCIROUTER_API_KEY" export ANTHROPIC_MODEL="YOUR_MODEL_ID" export ANTHROPIC_DEFAULT_HAIKU_MODEL="YOUR_MODEL_ID" claude ``` ### 环境变量 | 环境变量 | 取值 | 说明 | |---|---|---| | `ANTHROPIC_BASE_URL` | `https://api.scirouter.cn` | 不带 `/v1` | | `ANTHROPIC_AUTH_TOKEN` 或 `ANTHROPIC_API_KEY` | SciRouter 的 API Key | 设置其一。前者以 `Authorization: Bearer` 发送,后者以 `x-api-key` 发送 | | `ANTHROPIC_MODEL` | 平台的模型 id | 启动时使用的模型 | | `ANTHROPIC_DEFAULT_HAIKU_MODEL` | 平台的模型 id | `haiku` 别名对应的模型;Claude Code 执行后台小任务时也使用它 | | `ANTHROPIC_DEFAULT_SONNET_MODEL`、`ANTHROPIC_DEFAULT_OPUS_MODEL` | 平台的模型 id | `sonnet`、`opus` 别名对应的模型,见[多个模型](#多个模型) | | `CLAUDE_CODE_SUBAGENT_MODEL` | 平台的模型 id | 子代理未另行指定模型时使用的模型,见[多个模型](#多个模型) | | `CLAUDE_CODE_MAX_OUTPUT_TOKENS` | 所选模型的输出上限 | 见[输出上限](#输出上限) | | `CLAUDE_CODE_MAX_CONTEXT_TOKENS` | 所选模型的上下文窗口 | 见[上下文窗口](#上下文窗口) | | `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` | `1` | 见[模型发现](#模型发现) | | `CLAUDE_CODE_ATTRIBUTION_HEADER` | `0` | 不发送归因块,见[归因块](#归因块) | | `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` | `1` | 见[上游为其他厂商的兼容接口](#上游为其他厂商的兼容接口) | `ANTHROPIC_AUTH_TOKEN` 与 `ANTHROPIC_API_KEY` 的变量名由 Claude Code 定义,取值为 SciRouter 控制台创建的 API Key(以 `sk-sr-` 开头),不能使用 Anthropic 官方的 Key。两者都设置且不是同一个 Key 时,请求返回 401;其中一个为空串时(发出空的 `Authorization: Bearer`)按未携带处理。shell 中已设置 `ANTHROPIC_API_KEY` 为官方 Key 的,删除该变量或改为 SciRouter 的 Key。 ## 启动 ```bash cd my-project claude ``` 首次进入目录时选择信任该目录。发送一条消息,收到回答即接入成功;该请求出现在控制台[调用日志](https://www.scirouter.cn/console/logs)中,调用格式为 Anthropic。 首次启动仍出现登录引导时,在 `~/.claude.json`(Windows 为 `C:\Users\<用户名>\.claude.json`)中加入以下一项后重新启动。文件已存在时只加这一项,不覆盖其他内容: ```json { "hasCompletedOnboarding": true } ``` ## 多个模型 `haiku`、`sonnet`、`opus` 三个别名可分别映射到平台的不同模型,在会话中输入 `/model` 切换: ```json { "env": { "ANTHROPIC_BASE_URL": "https://api.scirouter.cn", "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY", "ANTHROPIC_MODEL": "YOUR_MODEL_ID", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "YOUR_MODEL_ID", "ANTHROPIC_DEFAULT_SONNET_MODEL": "YOUR_MODEL_ID", "ANTHROPIC_DEFAULT_OPUS_MODEL": "YOUR_MODEL_ID", "CLAUDE_CODE_SUBAGENT_MODEL": "YOUR_MODEL_ID" } } ``` - `haiku` 用于后台小任务(生成标题、摘要等),宜映射到响应快、单价低的模型。 - Claude Code 在检索代码、规划任务时会启动内置的子代理(如 Explore、Plan)。子代理所用的模型没有映射到平台的模型 id 时,请求可能返回 404 `model_not_found`;设置 `CLAUDE_CODE_SUBAGENT_MODEL` 后,未另行指定模型的子代理改用它。 - 切换到未映射的别名时,Claude Code 请求 Anthropic 的模型名;平台没有为该名称配置别名时返回 404 `model_not_found`。 ## VS Code 与 JetBrains Claude Code 的 IDE 插件使用同一份 `settings.json`,完成上文配置后在 IDE 的插件市场搜索 Claude Code 安装即可。 ## 输出上限 Claude Code 不识别平台的模型 id 时,默认每次请求 32000 个输出 token。超过模型或套餐的单次上限时,平台按上限发出,不返回错误,处理方式见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages)「max_tokens」。回答达到上限时 `stop_reason` 为 `max_tokens`,与厂商截断时相同。 将 `CLAUDE_CODE_MAX_OUTPUT_TOKENS` 设为模型的输出上限后,Claude Code 按真实上限规划。上限见[模型中心](https://www.scirouter.cn/models)的详情页。 ## 上下文窗口 Claude Code 对不识别的模型 id 一律按 20 万 token 计算压缩对话的时机。所选模型的窗口更小时,用 `CLAUDE_CODE_MAX_CONTEXT_TOKENS` 写明真实窗口(见[模型中心](https://www.scirouter.cn/models)的详情页),Claude Code 才会按时压缩。 未设置时由平台兜底:输入、或输入加 `max_tokens` 放不进窗口的请求,平台在发出前返回 400 `context_window_exceeded`,Claude Code 根据 `message` 处理后重发。 | 情况 | `message` 包含 | Claude Code 的处理 | |---|---|---| | 输入超过窗口 | `prompt is too long: N tokens > M maximum` | 按两个数字压缩历史后重发 | | 输入未超过窗口,加上 `max_tokens` 后超过 | ``input length and `max_tokens` exceed context limit`` | 调小 `max_tokens` 后重发 | 兜底方式每次多一个往返,建议设置 `CLAUDE_CODE_MAX_CONTEXT_TOKENS`。 ## 模型发现 设置 `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1` 后,Claude Code 启动时读取一次平台的模型列表并放入 `/model`,只保留 id 中含 `claude` 或 `anthropic` 的模型。其他模型通过 `ANTHROPIC_MODEL` 与别名映射直接填写平台的模型 id。 ## 归因块 Claude Code 在 `system` 开头带一块归因信息(客户端版本与提示指纹)。使用非 Anthropic 的模型时,可设置 `CLAUDE_CODE_ATTRIBUTION_HEADER=0` 不发送。未设置时,平台走其他入口转换时去掉该块,响应头 `X-SciRouter-Param-Actions` 中记 `reshaped=…`。 ## 厂商服务端工具 WebSearch 是厂商的服务端工具,平台不支持,请求返回 400,`details.reason` 为 `server_tool_unsupported`。Claude Code 自身的 WebSearch / WebFetch 不受影响。 ## 上游为其他厂商的兼容接口 Claude Code 发送 Claude 官方接口支持的全部字段:`thinking` 的 `adaptive`、对话中途的 `system` 消息、`context_management`、`output_config`。线路背后是其他厂商的 Anthropic 兼容接口时,请求原样转发,厂商不支持这些字段时返回 400: - 前几项由 Claude Code 自行去掉后重试。 - `context_management` 等提示类参数:厂商的报错中能识别出参数名时,平台去掉该参数,在同一条线路重发一次,`X-SciRouter-Param-Actions` 中记 `healed=context_management`;识别不出时仍返回 400。 - 400 `context_management: Extra inputs are not permitted` 一类报错反复出现时,设置 `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`。 转换方式(线路没有 Anthropic 入口)不受影响:`context_management` 中的 `clear_tool_uses_*` 由平台补实现,其余编辑去掉并留痕。 平台拒绝请求时的两种标记(`capability_rejected`、`policy_blocked`)及 Claude Code 的处理见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages)「错误」。 --- # Codex > 在 Codex 中使用平台的模型:安装、config.toml 配置、环境变量、启动,以及平台对 Codex 请求的处理。 来源:https://www.scirouter.cn/docs/codex · 更新于 2026-10-24 Codex(命令行与 IDE 插件)通过 OpenAI Responses 格式(`POST /v1/responses`)调用平台的模型,平台上的对话模型均可使用。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的三步。 ## 安装 ```bash npm install -g @openai/codex codex --version ``` 输出版本号表示安装成功。 ## 配置 Codex 的配置文件: | 系统 | 文件路径 | |---|---| | macOS / Linux | `~/.codex/config.toml` | | Windows | `C:\Users\<用户名>\.codex\config.toml` | 文件不存在时新建。写入以下内容,将 `YOUR_MODEL_ID` 换成平台的模型 id: ```toml model = "YOUR_MODEL_ID" model_provider = "scirouter" [model_providers.scirouter] name = "SciRouter" base_url = "https://api.scirouter.cn/v1" env_key = "SCIROUTER_API_KEY" wire_api = "responses" ``` `model` 与 `model_provider` 两行须写在所有 `[...]` 段之前;文件中已有这两项时,改为上面的值。 | 配置项 | 取值 | 说明 | |---|---|---| | `model` | 平台的模型 id | 默认使用的模型 | | `model_provider` | `scirouter` | 与 `[model_providers.scirouter]` 中的名称一致 | | `name` | `SciRouter` | 界面上显示的服务商名称 | | `base_url` | `https://api.scirouter.cn/v1` | 带 `/v1` | | `env_key` | `SCIROUTER_API_KEY` | Codex 从该环境变量读取 Key,Key 不写入配置文件 | | `wire_api` | `responses` | 使用 Responses 格式 | ## 启动 确认环境变量 `SCIROUTER_API_KEY` 已设置(见[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」),然后启动: ```bash cd my-project codex ``` 发送一条消息,收到回答即接入成功。临时使用其他模型时,在启动命令中指定: ```bash codex --model YOUR_MODEL_ID ``` IDE 插件读取同一份 `config.toml`。 ## 平台对 Codex 请求的处理 | 项 | 平台的处理 | |---|---| | 对话历史 | Codex 每轮将完整对话(含其带回的推理项)放入 `input`,`store` 为 `false`,与平台的无状态约束一致,见 [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses)「不支持的字段」 | | `shell` / `apply_patch` 工具 | 函数工具,所有模型均可使用 | | MCP 工具 | 按 `namespace` 发送,平台展开为 `{namespace}__{name}` 的函数工具(展开后重名时返回 400),所有模型均可使用 | | 推理项续接 | 只有线路标为「原生 Responses」的模型原样续接厂商的加密推理项。其他模型走转换,平台生成的 `rs_` 推理项带 `encrypted_content`(可验证思考块的序列化),Codex 下一轮原样带回即可续接,见 [Responses(OpenAI Responses 格式)](https://www.scirouter.cn/docs/responses)「转换」 | | 上下文超长 | 平台发送 `event: response.failed`,`response.error.code` 为 `context_length_exceeded`。Codex 只在收到该事件时自动压缩对话,因此流式请求即使在开流前判定超长,也返回 HTTP 200 加该事件,不返回 400 | | 退避 | Codex 只读取 `Retry-After`(不读取 `retry-after-ms`),平台的 429 均带该响应头 | Codex 中接入平台的 MCP 工具见 [MCP 与托管工具](https://www.scirouter.cn/docs/mcp)。 --- # OpenCode > 在 OpenCode 中使用平台的模型:安装、opencode.json 中的服务商配置、上下文窗口与模型选择。 来源:https://www.scirouter.cn/docs/opencode · 更新于 2026-10-24 OpenCode 通过 OpenAI Chat Completions 格式(`POST /v1/chat/completions`)调用平台的模型。命令行与桌面客户端读取同一份配置。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的三步。 ## 安装 ```bash npm install -g opencode-ai opencode --version ``` 输出版本号表示安装成功。 ## 配置 在配置文件中添加 SciRouter 作为服务商: | 范围 | 文件路径 | |---|---| | 全局(macOS / Linux) | `~/.config/opencode/opencode.json` | | 全局(Windows) | `C:\Users\<用户名>\.config\opencode\opencode.json` | | 单个项目 | 项目根目录的 `opencode.json`,与全局配置合并,同名项以它为准 | 文件不存在时新建。写入以下内容,将 `YOUR_MODEL_ID` 换成平台的模型 id,`limit` 按该模型的上下文窗口与输出上限填写(见[模型中心](https://www.scirouter.cn/models)的详情页): ```json { "provider": { "scirouter": { "npm": "@ai-sdk/openai-compatible", "name": "SciRouter", "options": { "baseURL": "https://api.scirouter.cn/v1", "apiKey": "{env:SCIROUTER_API_KEY}" }, "models": { "YOUR_MODEL_ID": { "name": "YOUR_MODEL_ID", "limit": { "context": 128000, "output": 16384 } } } } } } ``` `limit` 中的数值为示例。 | 字段 | 取值 | 说明 | |---|---|---| | `provider` 下的键 | `scirouter` | 服务商 id,可自定义;`/models` 中按它分组 | | `npm` | `@ai-sdk/openai-compatible` | 使用 Chat Completions 格式 | | `name` | `SciRouter` | 界面上显示的服务商名称 | | `options.baseURL` | `https://api.scirouter.cn/v1` | 带 `/v1` | | `options.apiKey` | `{env:SCIROUTER_API_KEY}` | 从环境变量读取 Key。直接写 Key 时,配置文件随项目提交会泄露 Key | | `models` 下的键 | 平台的模型 id | 每个要用的模型一项,可写多项 | | `models.*.name` | 任意 | 模型列表中显示的名称 | | `models.*.limit.context` / `limit.output` | 整数 | 上下文窗口与输出上限。OpenCode 据此判断剩余上下文;不写时 OpenCode 不知道模型的窗口 | ## 使用 ```bash cd my-project opencode ``` 输入 `/models`,在 SciRouter 分组下选择模型,发送一条消息,收到回答即接入成功。修改配置文件后重新启动 OpenCode。 桌面客户端使用同一份全局配置,在模型列表中选择 SciRouter 下的模型即可。 --- # Kilo CLI > 在 Kilo CLI 中使用平台的模型:安装、kilo.json 中的服务商配置、上下文窗口与模型选择。 来源:https://www.scirouter.cn/docs/kilo-cli · 更新于 2026-10-24 Kilo CLI 是 Kilo Code 的命令行版本,通过 OpenAI Chat Completions 格式(`POST /v1/chat/completions`)调用平台的模型。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的三步。 ## 安装 ```bash npm install -g @kilocode/cli kilo --version ``` 输出版本号表示安装成功。 ## 配置 在配置文件中添加 SciRouter 作为服务商: | 范围 | 文件路径 | |---|---| | 全局(macOS / Linux) | `~/.config/kilo/kilo.json`(也可命名为 `kilo.jsonc`) | | 全局(Windows) | `C:\Users\<用户名>\.config\kilo\kilo.json` | | 单个项目 | 项目根目录的 `kilo.json` | 文件不存在时新建。写入以下内容,将 `YOUR_MODEL_ID` 换成平台的模型 id,`limit` 按该模型的上下文窗口与输出上限填写(见[模型中心](https://www.scirouter.cn/models)的详情页): ```json { "provider": { "scirouter": { "npm": "@ai-sdk/openai-compatible", "name": "SciRouter", "env": ["SCIROUTER_API_KEY"], "options": { "baseURL": "https://api.scirouter.cn/v1" }, "models": { "YOUR_MODEL_ID": { "name": "YOUR_MODEL_ID", "limit": { "context": 128000, "output": 16384 } } } } } } ``` `limit` 中的数值为示例。 | 字段 | 取值 | 说明 | |---|---|---| | `provider` 下的键 | `scirouter` | 服务商 id,可自定义;`/models` 中按它分组 | | `npm` | `@ai-sdk/openai-compatible` | 使用 Chat Completions 格式 | | `env` | `["SCIROUTER_API_KEY"]` | 从该环境变量读取 Key,Key 不写入配置文件 | | `options.baseURL` | `https://api.scirouter.cn/v1` | 带 `/v1` | | `models` 下的键 | 平台的模型 id | 每个要用的模型一项,可写多项 | | `models.*.limit.context` / `limit.output` | 整数 | 上下文窗口与输出上限。**不写时按 0 处理**,Kilo 无法管理上下文 | ## 使用 ```bash cd my-project kilo ``` 输入 `/models`,在 SciRouter 分组下选择模型,发送一条消息,收到回答即接入成功。修改配置文件后重新启动 Kilo CLI。 --- # Kilo Code > 在 Kilo Code 插件中使用平台的模型:添加自定义服务商、选择模型、写明上下文窗口。 来源:https://www.scirouter.cn/docs/kilo-code · 更新于 2026-10-24 Kilo Code 是 VS Code 与 JetBrains IDE 的编程插件,通过 OpenAI Chat Completions 格式(`POST /v1/chat/completions`)调用平台的模型。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的前两步。 ## 安装 在 IDE 的插件市场搜索 Kilo Code 并安装。 ## 添加服务商 1. 打开 Kilo Code 的设置(齿轮图标),进入「Providers」标签页。 2. 滚动到底部,点击「Custom provider」。 3. 按下表填写,点击「Submit」保存。 | 字段 | 填写 | |---|---| | 「Provider ID」 | `scirouter`(自定义,不与其他服务商重复) | | 「Display name」 | `SciRouter` | | 「Provider API」 | 选择「OpenAI Compatible」 | | 「Base URL」 | `https://api.scirouter.cn/v1`(带 `/v1`) | | 「API key」 | SciRouter 的 API Key | | 「Models」 | 从自动列出的模型中选择,或手动填写平台的模型 id | | 「Headers」 | 留空 | 填好地址与 Key 后,Kilo Code 读取平台的 `GET /models`,列出该 Key 可调用的模型。列表为空时检查地址与 Key,再点击「Fetch models」重新读取。 ## 使用 在对话框的模型选择中选择 SciRouter 下的模型,发送一条消息,收到回答即接入成功。 需要写明模型的上下文窗口与输出上限时,编辑 Kilo 的配置文件 `kilo.json`,在该服务商的模型下加 `limit`,写法见 [Kilo CLI](https://www.scirouter.cn/docs/kilo-cli)「配置」。插件与 Kilo CLI 使用同一份配置。 --- # Cursor > 在 Cursor 中使用平台的模型:填写 Key 与地址、添加模型,以及请求经 Cursor 服务器转发带来的限制。 来源:https://www.scirouter.cn/docs/cursor · 更新于 2026-10-24 Cursor 通过 OpenAI Chat Completions 格式(`POST /v1/chat/completions`)调用平台的模型,用于聊天与 Agent。Tab 补全仍使用 Cursor 内置的模型。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的前两步。 ## 配置 1. 打开「Cursor Settings」,进入「Models」。 2. 在「OpenAI API Key」中填入 SciRouter 的 API Key。 3. 打开「Override OpenAI Base URL」,填入 `https://api.scirouter.cn/v1`(带 `/v1`)。 4. 点击「Add Custom Model」,填入平台的模型 id,并启用该模型。 ## 使用 在聊天面板的模型选择中选择上一步添加的模型,发送一条消息,收到回答即接入成功。 ## 限制 - Cursor 的请求先发到 Cursor 的服务器,由其拼装提示后转发到平台;API Key 随每次请求发送到 Cursor 的服务器。 - 平台地址须能从公网访问。私有部署只在内网可达时,Cursor 无法使用;改用 Claude Code、Codex、OpenCode 等在本机直接发出请求的工具。 - 对话超出所选模型的上下文窗口时,平台返回 400 `context_window_exceeded`;新开对话,或换用窗口更大的模型。 --- # CC Switch > 在 CC Switch 中添加 SciRouter 供应商,为 Claude Code、Codex、OpenCode 等工具切换到平台的模型。 来源:https://www.scirouter.cn/docs/cc-switch · 更新于 2026-10-24 CC Switch 是管理多个编程工具配置的桌面应用。在其中添加 SciRouter 作为供应商后,可为 Claude Code、Codex、OpenCode 等工具一键切换到平台的模型。直连模式下,CC Switch 只改写各工具的配置文件,请求由工具直接发往平台。配置前先完成[编程工具概览](https://www.scirouter.cn/docs/coding-tools)「准备」中的前两步。 ## 添加供应商 1. 在 CC Switch 侧栏选中要配置的工具。 2. 点击右上角「+」,在预设中选择「自定义」。 3. 按下表填写,保存。 | 字段 | 填写 | |---|---| | 供应商名称 | `SciRouter` | | API Key | SciRouter 的 API Key | | API 格式与请求地址 | 按工具填写,见下表 | | 模型 | 手动填写平台的模型 id,见下表 | | 工具 | API 格式 | 请求地址 | 模型 | |---|---|---|---| | Claude Code | Anthropic Messages | `https://api.scirouter.cn`(不带 `/v1`) | 在「模型映射」中把默认模型与 Haiku、Sonnet、Opus 都填成平台的模型 id | | Codex | OpenAI Responses | `https://api.scirouter.cn/v1` | 默认模型填平台的模型 id | | OpenCode 等其他工具 | OpenAI Chat Completions | `https://api.scirouter.cn/v1` | 在模型列表中添加平台的模型 id | 各工具使用的格式与平台对它的处理见对应页面:[Claude Code](https://www.scirouter.cn/docs/claude-code)、[Codex](https://www.scirouter.cn/docs/codex)、[OpenCode](https://www.scirouter.cn/docs/opencode)。 ## 切换与生效 1. 在主界面选中 SciRouter,点击「启用」(OpenCode 等可同时添加多个供应商的工具为「添加」)。也可在系统托盘菜单中直接点击供应商名称。 2. Claude Code 切换后无需重启;Codex 等其他工具需重启终端或对应的工具。 3. 在工具中发送一条消息,收到回答即接入成功。 CC Switch 顶部的「路由」模式由 CC Switch 在本机转换请求格式。接入平台使用「直连」即可:平台本身支持 Anthropic Messages、OpenAI Responses 与 Chat Completions 三种格式。 --- # 对话补全 > POST /v1/chat/completions 的字段处理、流式响应、思考过程、工具调用、超时与中途断开的计费。 来源:https://www.scirouter.cn/docs/chat-completions · 更新于 2026-10-24 ```http POST https://api.scirouter.cn/v1/chat/completions ``` 请求与响应格式与 OpenAI Chat Completions 一致。字段语义以 OpenAI 文档为准,下文只列平台的处理方式。 ## 请求 ```json { "model": "YOUR_MODEL_ID", "messages": [ { "role": "system", "content": "你是一名结构生物学助手。" }, { "role": "user", "content": "帮我判断这段序列的二级结构倾向:MKTAYIAKQR…" } ], "max_tokens": 1024, "temperature": 0.3, "stream": false } ``` | 字段 | 必填 | 平台的处理 | |---|---|---| | `model` | 是 | 模型 id,见[模型列表](https://www.scirouter.cn/docs/models)。模型不可调用时的错误见[错误](#错误) | | `messages` | 是 | 不能为空数组,原样转给上游。助手消息上可带上一轮响应中的 `thinking_blocks`,平台原样接收,见[带签名的思考块](#带签名的思考块) | | `max_tokens` | 否 | 正整数。超限、未填写与上下文窗口的处理见 [max_tokens](#maxtokens) | | `max_completion_tokens` | 否 | `max_tokens` 的新名称。两者都提供时,平台的校验与预扣以 `max_tokens` 为准,两个字段均原样转给上游;超限报错时 `param` 为 `max_tokens` | | `temperature` / `top_p` | 否 | 按模型的请求规则处理:超出范围的值夹到范围内,模型不接受采样参数时去掉,均在响应头 `X-SciRouter-Param-Actions` 中留痕;其他情况原样转给上游 | | `stop` | 否 | 字符串或字符串数组,其他类型返回 400 | | `stream` | 否 | 见[流式响应](#流式响应) | | `stream_options.include_usage` | 否 | 流式时末尾多一个带 `usage` 的分片(`choices` 通常为空)。未设置或为 `false` 时平台去掉该分片 | | `tools` / `tool_choice` | 否 | 见[工具调用](#工具调用)。`type: "mcp"`、`server_label: "scirouter"` 的项是平台托管工具,由平台执行,见 [MCP 与托管工具](https://www.scirouter.cn/docs/mcp) | | `metadata` / `user` | 否 | 调用方的归因标签,不转给上游,见[可观测性](https://www.scirouter.cn/docs/observability) | | `scirouter` | 否 | 顶层扩展字段,只接受 `max_tool_rounds`(托管工具的轮数,1–30),其他键返回 400。不转给上游 | | 其他字段 | 否 | 按[参数如何被处理](https://www.scirouter.cn/docs/params)的登记表分类处理 | 其他字段的处理: | 类别 | 示例 | 处理 | |---|---|---| | 提示类 | `seed`、惩罚项、`reasoning_effort` 等 | 无法带到线路上时去掉并留痕 | | 契约类 | `response_format`、`n`、`logprobs` 等 | 依次尝试翻译、模拟、换线路,均不可行时返回 400 `unsupported_param` | | 计价类 | `web_search_options` | 返回 400 | | 不在登记表中的专有参数 | — | 走 OpenAI 兼容入口时原样带上,走其他入口时去掉并留痕,见[多厂商差异](https://www.scirouter.cn/docs/vendors) | 请求体上限默认为 4 MB,超过时返回 413 `payload_too_large`。 ### max_tokens | 情况 | 平台的处理 | |---|---| | 超过模型或套餐的单次上限 | 返回 400,`details.limit` 为上限。平台不自动截短 | | 未填写,套餐有单次上限 | 平台填入模型与套餐上限中较小的值,发给上游 | | 未填写,套餐无单次上限 | 使用上游的默认值 | | 输入估算本身超过套餐的每分钟 token 数 | 400 `validation_failed`,`details.reason` 为 `plan_tpm_exceeded`,`message` 写明输入估算与套餐每分钟上限,见[错误码](https://www.scirouter.cn/docs/errors)。`max_tokens` 不参与这一判定:每分钟 token 数只按输出预留计入,见[错误码](https://www.scirouter.cn/docs/errors)「HTTP 429 的来源」 | | 输入加 `max_tokens` 超过模型的上下文窗口 | 400 `context_window_exceeded`,带 `details.limit` / `details.estimated`,见[参数如何被处理](https://www.scirouter.cn/docs/params)「上下文窗口」 | 预扣按「输入估算 + 输出上限」计算,未填写时按上表确定的上限;账户的充值余额大于 0 时,输出只按输出上限与平台设定值中的较小者估算。结束后按实际用量结算,实际超出的部分照扣,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)「预扣」。 ## 非流式响应 ```json { "id": "chatcmpl-…", "object": "chat.completion", "created": 1758585600, "model": "YOUR_MODEL_ID", "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, "cost_quota": 18240, "…": "…" } } ``` 数值为示例。 - `scirouter` 字段与 `X-SciRouter-*` 响应头见[可观测性](https://www.scirouter.cn/docs/observability)。 - 单次调用扣除的配额以 `scirouter.cost_quota` 为准,不根据 `usage` 自行计算。 - `finish_reason` 为 `length` 表示回答被 `max_tokens` 截断。结构化数据或代码被截断时解析可能不报错,内容仍不完整;批处理按 `finish_reason` 判断,不按内容长度判断。 ## 流式响应 请求带 `"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,"cost_quota":18240}} data: [DONE] ``` 读取流时处理以下四点: 1. 以 `:` 开头的行是注释,跳过。排队或上游长时间无输出时,网关约每 10 秒发送一行 `: ping` 心跳。官方 SDK 自动跳过。 2. `choices` 可能为空数组。末尾的用量分片(`include_usage` 为 `true` 时才有)、`scirouter` 扩展分片与托管工具的进度分片均如此,直接读取 `choices[0]` 会越界。 3. **收到 `data: [DONE]` 才表示正常结束。** 出错时流中出现一个 `{"error": {...}}` 分片,随后断开,不发送 `[DONE]`。未收到 `[DONE]` 即结束的流按失败处理,错误分片的格式见[错误码](https://www.scirouter.cn/docs/errors)。 4. 错误分片可能出现在第一个内容分片之前。心跳发出后 HTTP 状态码已是 200,此后的错误(如排队超时)只能以错误分片返回。只检查状态码会将这些错误当作成功。 故障转移只发生在第一个字节之前。上游开始输出后,中途失败不换线路重试,返回错误分片。 ## 思考过程 推理模型的思考过程同时写在 `reasoning_content` 与 `reasoning` 两个字段中,内容相同,读取任一字段即可:非流式在 `choices[].message` 上,流式在 `choices[].delta` 上。 思考消耗的 token 在 `usage.completion_tokens_details.reasoning_tokens` 中(上游返回时才有),已包含在 `completion_tokens` 内。 ### 带签名的思考块 部分模型对思考过程签名。多轮工具调用时,须将上一轮的思考块连同签名一起带回,模型才能接续;只带回 `reasoning_content` 的文本会丢失签名。 这类模型的助手消息上另有扩展字段 `thinking_blocks`:非流式在 `choices[].message` 上,流式在 `choices[].delta` 上,签名在最后一个分片中。数组中每项为以下两种之一: ```json [ { "type": "thinking", "thinking": "…", "signature": "…" }, { "type": "redacted_thinking", "data": "…" } ] ``` - 下一轮将助手消息原样放回 `messages`,包括 `thinking_blocks`,内容不做修改。平台原样接收,并优先将请求发回签发该签名的线路。 - 不签名的模型没有该字段。 - 字段名为上述 `thinking` / `signature` 与 `redacted_thinking` / `data`,已按此格式实现的客户端无需修改。 ### 签名被拒时的重试 请求落到其他线路时,签名可能无效并被厂商拒绝。线路走 Anthropic Messages 入口时,平台不返回该 400,在同一条线路上重试一次: | 情况 | 重试方式 | 响应扩展块 `param_actions` 的 `reshaped` | |---|---|---| | 厂商判定这些思考块属于其他对话(此前的历史有改动),且该线路支持 | 请厂商只丢掉对不上的块及其后的思考块,其余照常使用。此后发往该线路的请求均如此发送 | 厂商给出的原因,如 `thinking(prefix_binding_mismatch)` | | 其他情况 | 去掉请求历史中的思考块后重试 | `thinking(signature_rejected)` | - 第一种方式重试后仍因签名被拒,或线路不支持该选项时,按第二种方式再重试一次;线路不支持的,此后不再按第一种方式发送。 - 第二种方式下,平台记录该线路拒绝过的思考块。此后发往该线路的请求,去掉历史中最后一条带有被拒块的消息及其之前的思考块,之后新增的思考块照常带上。 - 重试仍失败时按普通失败处理。 线路走其他入口时,厂商的 400 照旧原样交回。Anthropic 格式(`/v1/messages`)的调用不做上述重试:签名被拒的 400 照旧原样交回,由客户端去掉思考块后重发,见 [Messages](https://www.scirouter.cn/docs/messages)。 ## 工具调用 `tools` 与 `tool_choice` 按 OpenAI 格式编写,模型返回的 `tool_calls` 原样交给调用方。需要平台代为执行工具(如搜索网页、读取文献)时,使用托管工具,见 [MCP 与托管工具](https://www.scirouter.cn/docs/mcp)。 模型未声明工具调用能力(`GET /models` 的 `features`)时,带 `tools` 的请求在选择线路前返回 400 `unsupported_param`,`details.cause` 为 `feature_missing`。 ### 线路筛选 选择线路时按以下条件过滤: | 请求条件 | 跳过的线路 | |---|---| | 带 `tools`(模型已声明工具调用能力) | 不支持工具调用的线路 | | 流式 | 不支持流式的线路 | | 预计 token 数(输入 + `max_tokens`)超过线路的单次上限 | 该线路 | 没有满足条件的线路时返回 503 `model_unavailable`,`details.reason` 指明缺少的条件: | `details.reason` | 含义 | |---|---| | `tools_unsupported` | 没有支持工具调用的线路 | | `streaming_unsupported` | 没有支持流式的线路 | | `input_too_large` | 预计 token 数超过线路的单次上限,常见于 `max_tokens` 过大,先调小 | | `no_capable_endpoint` | 同时缺少以上多项 | 以上几种不带 `Retry-After`,原样重试无效,去掉对应参数或更换模型。带 `Retry-After` 的 503(`endpoints_busy` / `model_busy`)表示暂时繁忙。见[错误码](https://www.scirouter.cn/docs/errors)「HTTP 503 的 details.reason」。 ## 超时 | 情况 | 结果 | |---|---| | 流式:上游开始响应后连续约 60 秒无任何数据(各线路可单独配置) | 504 `upstream_timeout`,`details.timeout` 为 `idle`。发生在第一个内容分片之前时换线路重试,之后返回错误分片 | | 连接超时(默认约 10 秒,按线路) | 504 `upstream_timeout`,`details.timeout` 为 `connect` | | 总时长上限(默认约 10 分钟,按线路) | 504 `upstream_timeout`,`details.timeout` 为 `total` | | 上游自身报告超时 | 504,`details.timeout` 为 `upstream` | | 上游的流未正常结束即断开 | 502 `upstream_error`,`details.provider_error.code` 为 `stream_interrupted` | | 非流式:整个响应超过约 270 秒 | 504 `upstream_timeout`,`details.timeout` 为 `response`,不计费 | **非流式请求最长等待约 270 秒。** 非流式请求须等完整生成后才有第一个字节,平台不按开始响应的时间判定,最多等待整个响应约 270 秒。该时长短于接入层(CDN)等待源站应答的 300 秒,超时时返回 JSON 错误体,不出现 CDN 的 524。 回答可能超过数分钟(推理模型、长输出)时使用流式。流式约每 10 秒发送一行心跳,不受 270 秒限制,受上表的空闲超时与总时长上限约束。 ## 中途断开与计费 | 情况 | 计费 | |---|---| | 非流式请求失败 | 不计费 | | 流式请求输出一部分后失败 | 按已产生的用量计费:上游返回用量时按上游用量,未返回时估算(输入按估算,输出按已收到的正文、思考过程与工具调用参数) | | 调用方主动断开,流式 | 网关同时取消上游,结果不保存;按断开前已产生的部分计费,口径同上 | | 调用方主动断开,非流式 | 网关同时取消上游,结果不保存;无法获得用量,不计费 | **调用方主动断开后结果不保存,带 `Idempotency-Key` 重试时会重新调用并照常计费**,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 ## 错误 | 状态码 | code | 触发条件 | |---|---|---| | 404 | `model_not_found` | 模型不存在 | | 503 | `model_unavailable` | 模型维护中、已停用或尚未定价;无满足条件的线路见[线路筛选](#线路筛选) | | 403 | `model_not_allowed` | 模型不在 Key、项目或套餐的白名单内,`details.scope` 为 `key` / `project` / `plan` | | 403 | `model_restricted` | 模型只对获授权的团队开放 | | 400 | `context_window_exceeded` | 输入加 `max_tokens` 超过模型的上下文窗口 | | 400 | `unsupported_param` | 契约类参数无法处理,或模型未声明工具调用能力时带 `tools` | | 413 | `payload_too_large` | 请求体超过上限(默认 4 MB) | 所有错误码与重试策略见[错误码](https://www.scirouter.cn/docs/errors)。 ## 相关文档 - 错误码与可重试的错误:[错误码](https://www.scirouter.cn/docs/errors) - 重复请求命中缓存、重试不重复扣费:[缓存与幂等](https://www.scirouter.cn/docs/caching) - 单次调用路由到的线路与耗时:[可观测性](https://www.scirouter.cn/docs/observability) --- # Messages(Anthropic 格式) > POST /v1/messages 与 count_tokens 的接入、请求转发方式、流式事件、计费与错误格式。 来源:https://www.scirouter.cn/docs/messages · 更新于 2026-10-25 ```http POST https://api.scirouter.cn/v1/messages POST https://api.scirouter.cn/v1/messages/count_tokens ``` 请求与响应格式与 Anthropic Messages API 一致。Anthropic SDK、Claude Code 等按 Anthropic 格式发送请求的客户端,替换 base URL 与 Key 即可调用。平台上的所有对话模型均可通过此接口调用;模型的线路没有 Anthropic 入口时,网关转换请求并尽量保留内容,见[请求的转发方式](#请求的转发方式)。 ## 接入 Anthropic SDK 与 Claude Code 会在 base URL 后拼接 `/v1/messages`,因此 **base URL 为 `https://api.scirouter.cn`,不带 `/v1`**。Key 为控制台创建的 API Key,携带方式见[认证与 API Key](https://www.scirouter.cn/docs/authentication)。 Python: ```python import os import anthropic client = anthropic.Anthropic( api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn", # SDK 自己会拼 /v1/messages ) msg = client.messages.create( model="YOUR_MODEL_ID", max_tokens=1024, messages=[{"role": "user", "content": "这段序列的二级结构倾向?"}], ) print(msg.content) ``` TypeScript: ```typescript import Anthropic from '@anthropic-ai/sdk' const client = new Anthropic({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn', }) const msg = await client.messages.create({ model: 'YOUR_MODEL_ID', max_tokens: 1024, messages: [{ role: 'user', content: '这段序列的二级结构倾向?' }], }) ``` curl: ```bash curl https://api.scirouter.cn/v1/messages \ -H "x-api-key: $SCIROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_MODEL_ID", "max_tokens": 1024, "messages": [{"role": "user", "content": "这段序列的二级结构倾向?"}] }' ``` `anthropic-version` 可省略,默认值见[请求头](#请求头)。 ## Claude Code Claude Code 的安装、`settings.json` 写法、环境变量与使用要点见 [Claude Code](https://www.scirouter.cn/docs/claude-code)。 ## 请求 | 字段 | 必填 | 说明 | |---|---|---| | `model` | 是 | 平台的模型 id,也可填写平台为该模型配置的别名(如厂商官方的模型名)。名称末尾带 `-YYYYMMDD` 日期时,去掉日期后查找。响应中的 `model` 为解析后的平台模型 id | | `max_tokens` | 是 | 非负整数,处理方式见 [max_tokens](#maxtokens) | | `messages` | 是 | 不能为空。`role` 可为 `user`、`assistant`,以及对话中途的 `system`(Claude Code 每个请求都带一条) | | `stream` | 否 | `true` 时为流式,见[流式响应](#流式响应) | | `tools` | 否 | 见[工具](#工具) | | `metadata` | 否 | 不转给上游 | | 其他字段 | 否 | 按线路处理,见[请求的转发方式](#请求的转发方式);各参数无法带到线路上时的处理见[参数如何被处理](https://www.scirouter.cn/docs/params) | 请求体上限为 32 MB(对话补全为 4 MB),超过时返回 413 `payload_too_large`。 ### max_tokens | 情况 | 平台的处理 | |---|---| | 超过模型或套餐的单次输出上限 | 按上限发出,在响应头 `X-SciRouter-Max-Tokens-Clamped` 与 `scirouter.max_tokens_clamped` 中写明请求值、实际发出的值与生效的上限,不静默截短。此时 `thinking.budget_tokens` 若不小于发出的值,一并降为该值减 1(厂商要求思考预算小于 `max_tokens`) | | 输入估算本身超过套餐的每分钟 token 数 | 返回 400 `invalid_request_error`(`error.code` 为 `validation_failed`,`details.reason` 为 `plan_tpm_exceeded`)。`message` 以 `prompt is too long: N tokens > M maximum` 开头(N 为输入估算,M 为套餐每分钟上限),末尾带 `capability_rejected: prompt_too_long`,Claude Code 据此尝试自动压缩对话后重发(压缩请求本身也超过上限时压缩失败,需 `/clear` 或升级套餐),见[错误码](https://www.scirouter.cn/docs/errors)。`max_tokens` 写多大都不因每分钟 token 数被拒:它只按输出预留计入,结束后按实际用量结算 | | 值为 `0` | 只预热厂商的提示词缓存,不生成。只走 Anthropic 入口,模型的线路都没有 Anthropic 入口时返回 400,见[无法转发的内容](#无法转发的内容) | | 输入加 `max_tokens` 超过模型的上下文窗口 | 400 `context_window_exceeded`,见[参数如何被处理](https://www.scirouter.cn/docs/params)「上下文窗口」 | 对话补全接口的 `max_tokens` 超限返回 400,与本接口不同。 ### 工具 | 工具 | 处理 | |---|---| | 自定义工具 | 照常使用 | | advisor 工具(`advisor_*`) | 只走 Anthropic 入口。其 `model` 须为平台上有定价的模型(正式 id 或别名),否则返回 400 `validation_failed`,`details.reason` 为 `sub_model_unpriced`;调用方须有该模型的调用权限,否则与直接调用一样返回 403。子推理按该模型的价格另行计费,见[计费](#计费) | | 厂商的服务端工具(`web_search_*`、`web_fetch_*`、`code_execution_*`、`tool_search_tool_*`、`mcp_toolset`)与 `mcp_servers`、`container` | 不支持,返回 400 `validation_failed`,`details.reason` 为 `server_tool_unsupported` | ## 请求的转发方式 模型背后的每条线路对应同一个上游账号,可接入多种协议,每种协议是线路的一个入口(见[多厂商差异](https://www.scirouter.cn/docs/vendors)「字段生效规则」)。Anthropic 格式的调用在一条线路上按以下顺序处理,前一级无法处理时进入下一级: | 级别 | 条件 | 处理 | |---|---|---| | 1. 原样转发 | 线路有 Anthropic 入口 | 请求原样转发,只修改少数几处 | | 2. 转换 | 线路没有 Anthropic 入口 | 转为主入口的协议后调用,扩展字段能携带的内容均带上 | | 3. 降级 | OpenAI 格式中没有对应概念的块 | 改写为等价的文字或普通工具,内容不丢失 | | 4. 返回 400 | 无法用文字表达的内容 | 见[无法转发的内容](#无法转发的内容) | 每一级去掉或改写的内容记录在响应头 `X-SciRouter-Param-Actions` 与扩展块 `param_actions` 中(`dropped` / `reshaped`)。 ### 原样转发 线路有 Anthropic 入口时,请求原样转发,只修改以下几处: - `model` 换成上游的模型名; - 去掉 `metadata`; - `max_tokens` 写入生效值; - 按平台的[提示词缓存](https://www.scirouter.cn/docs/caching)策略处理 `cache_control` 断点; - 去掉签名为空的思考块。这类块来自其他模型的思考过程,厂商会因签名无效拒绝整个请求。 厂商自定义参数、思考块与签名、文档块、`anthropic-beta` 均到达上游,响应原样返回。「原样」指请求的格式与字段:鉴权、计费、限额与线路选择仍由平台完成,发给厂商的 `x-api-key` 是平台在该厂商的凭据,调用方的 SciRouter Key 不会到达厂商。 ### 转换 线路没有 Anthropic 入口时,网关将请求转为主入口的协议后调用,再将结果转回 Anthropic 格式。只保留能对应的字段: | 内容 | 转换方式 | |---|---| | 内容块 | 可转换 `text`、`image`、`document`(PDF、纯文本)、`tool_use`、`tool_result`、`thinking`、`redacted_thinking` | | 工具结果中的图片 | 移入紧随其后的用户消息,并标注来自哪个工具调用 | | 对话中途的 `system` 消息 | 在原位置成为一条 system 消息 | | `system` 第一块为 Claude Code 的归因块(`x-anthropic-billing-header: …`) | 去掉(Anthropic 的接口同样去掉该块) | | `cache_control` 断点 | 上游支持内容块上的 `cache_control` 时带上断点 | | 思考块的签名 | 按线路配置,以上游支持的扩展写法连同签名带上 | | `anthropic-beta` | 按线路配置转发 | | `thinking` | 按模型的思考控制翻译为该线路的写法;模型没有思考能力时去掉并留痕 | | `top_k` | 带给支持它的线路 | | `speed` 等计价参数 | 不带 | | `context_management` | `clear_tool_uses_*` 由平台在转换后的历史上补实现(保留最近几次工具调用,更早的工具结果换成占位);`compact_*` 等其余编辑去掉并留痕 | | `document` 块 | 转为该线路的文件内容段 | | `output_format` / `output_config.format` 的 JSON Schema | 转为 `response_format`;模型没有原生结构化输出时由平台模拟 | | 输出上限 | 按该线路支持的字段名写入 | `cache_control` 断点、思考块的签名与 `anthropic-beta`,线路未配置的不带并留痕。字段对照见[多厂商差异](https://www.scirouter.cn/docs/vendors)与[参数如何被处理](https://www.scirouter.cn/docs/params)。 转回的响应与原生响应的差异: | 项 | 差异 | |---|---| | 流式的 `message_start.usage` | 为 0,真实用量在 `message_delta.usage` 中 | | 工具调用 | 在流的末尾整块发出,参数完整 | | 命中停止序列 | `stop_reason` 为 `end_turn`,`stop_sequence` 为 null(OpenAI 格式不报告命中的是哪一条) | | 上游给出 Anthropic 没有的结束原因 | 原样写入 `stop_reason`(如 `insufficient_system_resource`),不视为正常结束 | | 思考签名 | 上游经扩展字段返回的思考签名,还原为带签名的 `thinking` 块 | 多轮工具调用时,将上一轮的思考块原样带回。平台优先将请求发回签发该签名的线路;落到其他线路时签名可能无效,厂商返回 400,平台原样交回该错误。 ### 降级 OpenAI 格式中没有对应概念的块,改写为等价的文字或普通工具。内容完整保留,只缺少厂商对这些块的专门处理: | 原内容 | 改写为 | |---|---| | `search_result` | 带来源与标题的文本块 | | 文档块的 `citations` / `context` | 文字说明 | | Anthropic 定义的客户端工具(`bash_*` / `text_editor_*` / `computer_*`) | 同名的普通函数工具 | | 非文本的 `system` 块 | 并入第一条用户消息 | | 历史中的服务端工具结果(`web_search_tool_result` / `web_fetch_tool_result`) | 带标题与来源的文本;`server_tool_use` 去掉 | 每条改写在 `param_actions` 中记为 `reshaped`。带这些内容的请求,模型有带 Anthropic 入口的线路时一定走该线路(优先于权重与粘性),没有时才降级。 ### 无法转发的内容 以下内容无法用文字表达: - Files API 来源的文件与图片(文件在厂商侧,平台无法获取); - 按需压缩 `compaction`; - `max_tokens: 0`; - 非 JSON Schema 的输出格式; - 没有可提取文字的块与工具(代码执行结果、`memory_*` 等)。 模型没有带 Anthropic 入口的线路时,返回 400 `unsupported_param`,`details.reason` 为 `unsupported_content`,`details.unsupported_content` 列出相应内容(如 `["document:file", "param:compaction"]`)。平台不会丢弃这些内容后作答。该错误由请求内容引起,重试无效。 ## 响应 非流式: ```json { "id": "msg_…", "type": "message", "role": "assistant", "model": "YOUR_MODEL_ID", "content": [{ "type": "text", "text": "…" }], "stop_reason": "end_turn", "usage": { "input_tokens": 42, "output_tokens": 318 }, "scirouter": { "request_id": "req_…", "attempts": 1, "cost_quota": 18240, "…": "…" } } ``` 数值为示例。 顶层的 `scirouter` 是平台的扩展块,内容与[对话补全](https://www.scirouter.cn/docs/chat-completions)相同,SDK 忽略该字段。单次调用扣除的配额见 `scirouter.cost_quota`。 ## 流式响应 请求带 `"stream": true` 时按 Anthropic 的事件格式发送:每条事件带 `event:` 行,事件类型与 Anthropic 相同(`message_start`、`content_block_delta`……`message_stop`)。与对话补全的流式响应的差异: - 没有 `data: [DONE]`,流以 `message_stop` 结束。平台在结算后才发送 `message_stop`,其中多一个 `scirouter` 字段(含本次的 `cost_quota`)。 - 开始输出后出错时,发送一个 `event: error` 事件(内容为[错误](#错误)中的错误体),随后断开。**未收到 `message_stop` 即结束的流按失败处理。** - 流中有以 `:` 开头的心跳注释行,SDK 自动忽略。 非流式请求最长等待约 270 秒,超时返回 504 `upstream_timeout`(`details.timeout` 为 `response`),不计费;回答可能很长时使用流式,见 [SDK 与框架](https://www.scirouter.cn/docs/sdks)「重试与超时」。 ## 计费 按厂商返回的 `usage` 结算,口径与厂商一致:`input_tokens`、`cache_read_input_tokens`、`cache_creation_input_tokens`(含 5 分钟与 1 小时两档写入)分别按各自的单价计费;思考 token 包含在 `output_tokens` 中,按输出单价计费。 厂商将一次请求中的多次采样拆分在 `usage.iterations` 中时(服务端压缩 `context_management` 的 `compact_*` 编辑、按需压缩 `compaction`、advisor 工具、`fallbacks` 回退),按 `iterations` 逐条计费: | 迭代 | 计费 | |---|---| | 本模型的迭代(含压缩) | 并入本次用量 | | advisor 子推理、回退模型的迭代 | 按该模型在平台上的价格另行计费 | `scirouter.cost_quota` 为合计。`fallbacks` 写成模型列表时,每个模型都须在平台上有定价且调用方有权调用,否则返回 400 `sub_model_unpriced`;写 `"default"` 时由厂商选择模型,按其返回的模型结算。 ## 错误 `/messages` 与 `/messages/count_tokens` 的错误使用 Anthropic 的格式,鉴权失败与路径或方法错误(404 / 405)也是如此: ```json { "type": "error", "error": { "type": "rate_limit_error", "message": "请求过于频繁,请稍后再试", "code": "rate_limited", "details": { "retry_after_seconds": 12 } }, "request_id": "req_88a1" } ``` - 状态码与对话补全逐码相同,`error.code` 使用同一套小写错误码,按 `error.code` 分支处理,对照见[错误码](https://www.scirouter.cn/docs/errors)。 - `error.type` 按状态码给出;配额、权限、Key 状态等策略拒绝例外,见下表。 平台拒绝请求时的标记: | 标记 | 出现条件 | Claude Code 的处理 | |---|---|---| | `message` 末尾带 `capability_rejected: ` | 平台自身拒绝、关闭对应能力即可恢复的 400(结构化输出、思考强度、图片、文档、超长等) | 关闭该能力后重发 | | `error.type` 为 `policy_blocked`,带 `x-should-retry: false` | 配额、权限、Key 状态等策略拒绝 | 直接展示,不重试 | | `message` 为 `prompt is too long: N tokens > M maximum` 的格式 | 上下文超长 | 见 [Claude Code](https://www.scirouter.cn/docs/claude-code)「上下文窗口」 | ## 计价参数与模型变体 部分参数会使厂商按另一档单价计费。计价参数由平台配置,当前为走 Anthropic 入口时的以下参数: | 参数 | 按另一档计价的取值 | |---|---| | `speed` | `standard` 以外的值 | | `inference_geo` | 任意取值 | | `service_tier` | `auto`、`standard_only` 以外的值 | 模型的线路都没有 Anthropic 入口时,这些参数无法带到线路上,不做检查。请求带有计价参数时: | 情况 | 结果 | |---|---| | 平台已上架覆盖这些参数的模型变体(id 格式为 `厂商/模型名:fast`) | 自动改用变体,按变体的价格结算。响应中的 `model` 为变体的 id,响应头 `X-SciRouter-Variant-Switch` 列出触发的参数(逗号分隔) | | 没有对应的变体 | 400 `validation_failed`,`details.reason` 为 `price_param_unsupported`,`details.params` 列出参数 | 也可直接将 `model` 设为变体的 id,或在别名后加后缀(`别名:fast`)。模型的变体、各变体强制的参数与自动改用的格式,见[模型中心](https://www.scirouter.cn/models)的详情页或 `GET /models` 扩展字段中的 `variant_params` 与 `variant_switch_formats`(见[模型列表](https://www.scirouter.cn/docs/models))。对话补全(OpenAI 格式)默认只记录,不改用变体。 ## 统计 token 数 ```bash curl https://api.scirouter.cn/v1/messages/count_tokens \ -H "x-api-key: $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_MODEL_ID", "messages": [{"role": "user", "content": "这段序列的二级结构倾向?"}] }' ``` ```json { "input_tokens": 1834, "scirouter": { "model": "YOUR_MODEL_ID", "estimated": false, "request_id": "req_…" } } ``` 数值为示例。 | 项 | 说明 | |---|---| | 请求体 | 与 `/messages` 相同,不需要 `max_tokens`。`context_management` 原样转给厂商,计数结果为裁剪后、实际计费的上下文。可携带 `mcp_servers` 中的平台托管工具声明,与 `/messages` 一样摘除后计数 | | 授权与限频 | 模型解析与授权与正式调用相同,计入一次每分钟请求数 | | 计费与日志 | 不计费,不进入请求日志 | | 计数方 | 模型有带 Anthropic 入口的可用线路时由厂商计数;没有、厂商 5 秒内未响应或报错时由平台估算(同一条线路故障后约 1 分钟内直接估算),此时 `scirouter.estimated` 为 `true` | ## 模型列表 `GET /models` 与 `GET /models/{id}` 带 `anthropic-version` 请求头时,按 Anthropic 的格式返回(Claude Code 与 Anthropic SDK 列出模型时会携带): ```json { "data": [{ "type": "model", "id": "YOUR_MODEL_ID", "display_name": "…", "created_at": "2026-09-01T00:00:00Z" }], "has_more": false, "first_id": "YOUR_MODEL_ID", "last_id": "YOUR_MODEL_ID" } ``` 一次返回全部模型,`has_more` 恒为 `false`;查询单个模型时也接受别名。不带该请求头时按 OpenAI 的格式返回,见[模型列表](https://www.scirouter.cn/docs/models)。 ## 请求头与响应头 ### 请求头 | 请求头 | 取值 | 说明 | |---|---|---| | `x-api-key` | API Key | 携带 Key 的另一种方式,见[认证与 API Key](https://www.scirouter.cn/docs/authentication) | | `anthropic-version` | 如 `2023-06-01` | 走 Anthropic 入口时透传给上游,不带时默认为 `2023-06-01`;线路可按配置改成别的值,改了请求里带的值时记在控制台调用记录的「请求参数」里(`param` 为 `anthropic_version`)。在 `/models` 上决定返回哪种格式 | | `anthropic-beta` | beta 名称 | 可写多个请求头或逗号分隔。走 Anthropic 入口时透传给上游;走其他入口转换时按线路配置转发,默认不转发。线路可按配置去掉其中几项,去掉时记在控制台调用记录的「请求参数」里(`scirouter.param_actions` 中 `param` 为 `anthropic_beta`、`reason` 为 `header_rule`) | | `anthropic-dangerous-direct-browser-access` | — | Anthropic SDK 在浏览器中直连时携带,网关的跨源预检放行该请求头。Key 不应放入浏览器,见[认证与 API Key](https://www.scirouter.cn/docs/authentication) | | `X-SciRouter-Unsupported-Params` | `strict` / `lenient` | `strict`:提示类参数无法带到线路上时也返回 400;`lenient`:契约类参数也去掉。见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `X-SciRouter-Validate-Schema` | `1` | 结构化输出由平台模拟时按 schema 校验结果,写入 `scirouter.schema_valid` | ### 响应头 | 响应头 | 取值 | 说明 | |---|---|---| | `request-id` | 与 `X-Request-Id` 相同 | Anthropic SDK 读取该名称。每个响应都带,包括鉴权与请求体校验失败的响应 | | `X-SciRouter-Variant-Switch` | 触发的参数 | 请求被自动改用模型变体时出现,见[计价参数与模型变体](#计价参数与模型变体) | | `X-SciRouter-Max-Tokens-Clamped` | 如 `requested=32000; effective=8192; limit=model` | `max_tokens` 超过模型或套餐的单次上限、按上限发出时出现;`limit` 为 `model` 或 `plan` | | `X-SciRouter-Param-Actions` | 如 `dropped=top_k; translated=reasoning` | 有参数被去掉、翻译、模拟、整形或自愈时出现,见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `x-should-retry` | `false` | 本次错误重试无效(不带 `Retry-After` 的 503,以及 `policy_blocked` 的策略拒绝,见[错误码](https://www.scirouter.cn/docs/errors))。Anthropic SDK 与 Claude Code 收到后不再自动重试 | 其余 `X-SciRouter-*`、`x-ratelimit-*` 响应头与对话补全相同,见[可观测性](https://www.scirouter.cn/docs/observability)。 ## 缓存、幂等与重试 `Idempotency-Key` 与平台响应缓存的规则与对话补全相同,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 Anthropic SDK 默认自动重试 429 与 5xx,不检查 `error.code`,但先检查 `x-should-retry`:平台判定重试无效的 503 与策略拒绝(`policy_blocked`)带 `x-should-retry: false`,SDK 与 Claude Code 收到后不再重试。可重试的错误见[错误码](https://www.scirouter.cn/docs/errors)。 --- # Responses(OpenAI Responses 格式) > POST /v1/responses 的接入、无状态约束、请求转发方式、流式事件与错误格式。 来源:https://www.scirouter.cn/docs/responses · 更新于 2026-10-24 ```http POST https://api.scirouter.cn/v1/responses ``` 请求与响应格式与 OpenAI Responses API 一致。新版 OpenAI SDK 的 `client.responses.*` 与 Codex CLI(`wire_api = "responses"`)等按 Responses 格式发送请求的客户端,替换 base URL 与 Key 即可调用。平台上的所有对话模型均可通过此接口调用;线路不原生支持 Responses 时,网关转换请求,见[请求的转发方式](#请求的转发方式)。 ## 接入 OpenAI SDK 在 base URL 后拼接 `/responses`,base URL 为 `https://api.scirouter.cn/v1`(带 `/v1`),与对话补全相同。Key 为 SciRouter 控制台创建的 API Key(以 `sk-sr-` 开头,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)),使用 OpenAI 官方的 Key 返回 401。 Python: ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") r = client.responses.create( model="YOUR_MODEL_ID", instructions="你是一个严谨的科研助手。", input="这段序列的二级结构倾向?", max_output_tokens=1024, ) print(r.output_text) ``` TypeScript: ```typescript import OpenAI from 'openai' const client = new OpenAI({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn/v1' }) const r = await client.responses.create({ model: 'YOUR_MODEL_ID', input: '这段序列的二级结构倾向?', max_output_tokens: 1024, }) console.log(r.output_text) ``` curl: ```bash curl https://api.scirouter.cn/v1/responses \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_MODEL_ID", "input": "这段序列的二级结构倾向?", "max_output_tokens": 1024 }' ``` ## Codex CLI Codex 的 `config.toml` 写法与平台对 Codex 请求的处理见 [Codex](https://www.scirouter.cn/docs/codex)。 ## 请求 | 字段 | 必填 | 说明 | |---|---|---| | `model` | 是 | 平台的模型 id,也可填写平台为该模型配置的别名。响应中的 `model` 为解析后的平台模型 id | | `input` | 是 | 字符串或输入项数组,不能为空。输入项:`message`(`input_text` / `input_image` / `output_text` / `refusal`)、`function_call`、`function_call_output`、`reasoning`(客户端带回的推理项,见[转换](#转换)) | | `instructions` | 否 | 系统提示 | | `max_output_tokens` | 否 | 正整数。超过模型或套餐的单次输出上限时按上限发出,并在响应头 `X-SciRouter-Max-Tokens-Clamped` 与 `scirouter.max_tokens_clamped` 中写明,不静默截短。预扣按输入估算加输出上限冻结配额,充值余额大于 0 的账户输出只按输出上限与平台设定值中的较小者估算,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)「预扣」 | | `stream` | 否 | `true` 时为流式,见[流式响应](#流式响应) | | `tools` / `tool_choice` / `parallel_tool_calls` | 否 | 函数工具(`{"type": "function", "name", "parameters", "strict"}`)照常使用;`namespace` 工具展开为 `{namespace}__{name}` 的函数工具。厂商的服务端工具(`web_search`、`file_search`、`code_interpreter`、`computer_use`、`image_generation`、`mcp` 等)不支持,返回 400 `validation_failed`,`details.reason` 为 `server_tool_unsupported` | | `store` | 否 | 平台不保存响应,一律按 `false` 处理:不传(SDK 默认不传,厂商默认为 true)或传 `true` 均按 `false` 处理,响应中写 `"store": false`,透传给上游时也强制写为 `false` | | `reasoning` / `text` / `temperature` / `top_p` | 否 | 按线路处理,见[请求的转发方式](#请求的转发方式);各参数无法带到线路上时的处理见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `metadata` / `user` / `safety_identifier` | 否 | 用作平台的归因标签与终端用户标识(见[可观测性](https://www.scirouter.cn/docs/observability)),不转给上游 | 请求体上限为 32 MB(与 `/messages` 相同),超过时返回 413 `payload_too_large`。 ### 不支持的字段 平台无状态。以下字段返回 400 `validation_failed`,`details.reason` 为固定值: | 字段 | `details.reason` | 处理方式 | |---|---|---| | `previous_response_id`、`conversation`、`prompt`、`input` 中的 `item_reference` | `stateful_unsupported` | 将完整的对话历史放入 `input` | | `background` | `background_unsupported` | 改为同步调用 | 按 id 操作已保存响应的接口(`GET` / `DELETE` / `cancel`)不存在,返回 404。 ## 请求的转发方式 | 方式 | 条件 | |---|---| | [原样转发](#原样转发) | 模型的线路标为「原生 Responses」 | | [转换](#转换) | 其他线路,不论入口协议 | 请求包含只能原样转发的内容时,另见[只能原样转发的内容](#只能原样转发的内容)。 ### 原样转发 线路标为「原生 Responses」时,请求原样转发到上游的 `/responses`。该标记由平台在线路的接口能力中设置,线路可用的入口中须有 OpenAI 兼容的 `openai` / `custom`(见[多厂商差异](https://www.scirouter.cn/docs/vendors)「字段生效规则」)。 平台只修改以下几处: - `model` 换成上游的模型名; - 去掉 `metadata` / `user` / `safety_identifier`; - `store` 写为 `false`; - `max_output_tokens` 写入生效值。 `include`、`prompt_cache_key`、`text.verbosity`、`reasoning.summary`、客户端带回的带 `encrypted_content` 的推理项与厂商自定义字段均到达上游。响应事件原样返回,只将 `model` 换回平台的模型 id;`id` 保留厂商的值,Codex 续接推理依赖该值。 「原样」指请求的格式与字段:鉴权、计费、限额与线路选择仍由平台完成,发给厂商的凭据是平台在该厂商的凭据,调用方的 SciRouter Key 不会到达厂商。 ### 转换 线路未标「原生 Responses」时,网关将请求转为对话补全格式后调用,再将结果转回 Responses 格式: | 请求内容 | 转换为 | |---|---| | `instructions` | system 消息 | | `input` 中的消息、`function_call`、`function_call_output` | 逐项转换;输出中的图片移入紧随其后的用户消息 | | 函数工具的 `strict` | 保留 | | `max_output_tokens` | `max_tokens` | | `reasoning.effort` | 按模型的思考控制翻译;强度不在模型的档位中时降档,模型没有思考能力时去掉并留痕 | | `text.format`(`text` / `json_object` / `json_schema`) | `response_format`;模型没有原生结构化输出时由平台模拟 | 各参数的规则见[参数如何被处理](https://www.scirouter.cn/docs/params)。 客户端带回的推理项按来源处理: | 推理项 | 处理 | |---|---| | 平台生成的(id 格式为 `rs_<请求 id>_0`,带 `encrypted_content`) | 解回为带签名的思考块,按入口支持的写法发给上游:Anthropic 入口原样写回思考块;OpenAI 兼容入口按线路配置,以上游支持的扩展写法带上签名。平台优先将请求发回签发该签名的线路 | | 其他厂商签发的 `encrypted_content`,以及 `include: ["reasoning.encrypted_content"]` | 丢弃,不报错。平台在请求日志的 `scirouter.converted_dropped` 中记录丢弃的内容 | 转回的响应与原生响应的差异: | 项 | 转换方式下的值 | |---|---| | `id` | `resp_<请求 id>`,与 `X-Request-Id` 对应 | | 输出项的 id | `msg_<请求 id>_0`、`rs_<请求 id>_0`、`fc_` | | 思考过程 | `reasoning` 项的 `reasoning_text`。思考块带签名或加密数据时,`rs_` 项另带 `encrypted_content`(可验证思考块的序列化),下一轮原样放入 `input` 即可续接,内容不做修改 | | 工具调用 | 在流的末尾整块发出,参数完整 | ### 签名被拒时的重试 推理项落到其他线路时,签名可能无效并被厂商拒绝。线路走 Anthropic Messages 入口时,平台在同一条线路上重试一次: | 情况 | 重试方式 | `param_actions` 的 `reshaped` | |---|---|---| | 厂商判定这些思考块属于其他对话(此前的历史有改动),且该线路支持 | 请厂商只丢掉对不上的块及其后的思考块。此后发往该线路的请求均如此发送 | 厂商给出的原因,如 `thinking(prefix_binding_mismatch)` | | 其他情况 | 去掉请求历史中的思考块后重试 | `thinking(signature_rejected)` | - 第一种方式重试后仍被拒,或线路不支持该选项时,去掉思考块再重试一次。 - 第二种方式下,平台记录该线路拒绝过的思考块。此后发往该线路的请求,去掉历史中最后一条带有被拒块的消息及其之前的思考块。 - 重试仍失败时按普通失败处理。 线路走其他入口时,厂商的 400 照旧原样交回。Anthropic 格式的 `/v1/messages` 不做上述重试,签名被拒的 400 照旧原样交回。 ### 只能原样转发的内容 以下内容只走标为「原生 Responses」的线路: - `input_file`; - 按 `file_id` 引用的图片; - `include` 中厂商工具的输出; - 厂商定义的客户端工具,如 `local_shell` / `apply_patch` / `custom`; - `text.format` 为 `grammar` 等非标准格式; - `context_management`。 模型没有此类线路时,返回 400 `unsupported_param`,`details.reason` 为 `unsupported_content`,`details.unsupported_content` 列出相应内容(如 `["include:code_interpreter_call.outputs"]`)。平台不会丢弃这些内容后作答。该错误由请求内容引起,重试无效。 ## 响应 非流式: ```json { "id": "resp_req_…", "object": "response", "status": "completed", "model": "YOUR_MODEL_ID", "store": false, "output": [ { "id": "msg_req_…_0", "type": "message", "role": "assistant", "status": "completed", "content": [{ "type": "output_text", "text": "…", "annotations": [] }] } ], "usage": { "input_tokens": 42, "input_tokens_details": { "cached_tokens": 0 }, "output_tokens": 318, "output_tokens_details": { "reasoning_tokens": 0 }, "total_tokens": 360 }, "scirouter": { "request_id": "req_…", "attempts": 1, "cost_quota": 18240, "…": "…" } } ``` 数值为示例。 顶层的 `scirouter` 是平台的扩展块,内容与[对话补全](https://www.scirouter.cn/docs/chat-completions)相同,SDK 忽略该字段。单次调用扣除的配额见 `scirouter.cost_quota`。 | 字段 | 说明 | |---|---| | `status` | 回答达到 `max_output_tokens` 时为 `incomplete`,`incomplete_details.reason` 为 `max_output_tokens`,与厂商一致 | | `usage.input_tokens` | 包含命中缓存的部分,`cached_tokens` 单列 | | `usage.output_tokens` | 包含推理,`reasoning_tokens` 单列 | `usage` 的维度与账单一一对应。 ## 流式响应 请求带 `"stream": true` 时按 Responses 的事件格式发送,每条事件带 `event:` 行与连续的 `sequence_number`。事件顺序: 1. `response.created` 2. `response.in_progress` 3. 每个输出项:`response.output_item.added` → `response.content_part.added` → `response.output_text.delta`… → `response.output_text.done` → `response.content_part.done` → `response.output_item.done`。推理项为 `response.reasoning_text.delta` / `done`,`function_call` 项为 `response.function_call_arguments.delta` / `done` 4. `response.completed` 或 `response.incomplete` 与对话补全的流式响应的差异: - 终态事件(`response.completed` / `response.incomplete`)中的 `response` 为完整结果,与非流式响应逐字段相同。平台在结算后才发送终态事件,事件顶层多一个 `scirouter` 字段(含本次的 `cost_quota`)。 - 终态事件之后还有一行 `data: [DONE]`。OpenAI 官方不发送该行,Open Responses 规范要求发送;官方 SDK 与 Codex 在终态事件处结束读取,不受影响。 - 开始输出后出错时,发送 `event: response.failed` 事件,随后发送 `[DONE]`。`response.status` 为 `failed`,`response.error` 带 `code` / `message` / `request_id`;`code` 只使用原厂支持的值,平台错误码在 `scirouter_code` 中。上下文超长时无论在开流前后都按此发送,`code` 为 `context_length_exceeded`。 - **未收到终态事件即结束的流按失败处理。** - 流中有以 `:` 开头的心跳注释行,SDK 自动忽略。 非流式请求最长等待约 270 秒,超时返回 504 `upstream_timeout`(`details.timeout` 为 `response`),不计费;回答可能很长时使用流式,见 [SDK 与框架](https://www.scirouter.cn/docs/sdks)「重试与超时」。 ## 错误 - 错误体为 OpenAI 格式,与对话补全相同,鉴权失败与路径错误也是如此。按小写的 `error.code` 分支处理,对照见[错误码](https://www.scirouter.cn/docs/errors)。 - 上下文超长、参数不支持与内容审核三类上游语义错误的 `error.code` 为原厂兼容值(如 `context_length_exceeded`),平台错误码在 `error.scirouter_code` 中。 - 流式请求的上下文超长返回 HTTP 200 加 `response.failed` 事件,不返回 400,见 [Codex](https://www.scirouter.cn/docs/codex) 与[流式响应](#流式响应)。 - 本接口特有的 400 见[不支持的字段](#不支持的字段)与[只能原样转发的内容](#只能原样转发的内容)。 ## 计价参数与模型变体 透传到「原生 Responses」线路时,`service_tier` 取 `auto`、`default` 以外的值会使厂商按另一档单价计费: | 情况 | 结果 | |---|---| | 平台已上架覆盖该参数的模型变体(id 格式为 `厂商/模型名:priority`) | 自动改用变体,按变体的价格结算,响应头 `X-SciRouter-Variant-Switch` 列出触发的参数 | | 没有对应的变体 | 400 `validation_failed`,`details.reason` 为 `price_param_unsupported` | 转换方式不带 `service_tier`,不做检查。规则与 [Messages](https://www.scirouter.cn/docs/messages) 相同。 ## 请求头与响应头 ### 请求头 | 请求头 | 取值 | 说明 | |---|---|---| | `X-SciRouter-Unsupported-Params` | `strict` / `lenient` | 参数无法带到线路上时的默认处置,见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `X-SciRouter-Validate-Schema` | `1` | `text.format` 由平台模拟时按 schema 校验结果,写入 `scirouter.schema_valid` | ### 响应头 | 响应头 | 取值 | 说明 | |---|---|---| | `X-SciRouter-Variant-Switch` | 触发的参数 | 请求被自动改用模型变体时出现,见[计价参数与模型变体](#计价参数与模型变体) | | `X-SciRouter-Max-Tokens-Clamped` | 如 `requested=32000; effective=8192; limit=model` | `max_output_tokens` 超过模型或套餐的单次上限、按上限发出时出现 | | `X-SciRouter-Param-Actions` | — | 有参数被去掉、翻译、模拟、整形或自愈时出现,见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `x-should-retry` | `false` | 本次错误重试无效(不带 `Retry-After` 的 503,见[错误码](https://www.scirouter.cn/docs/errors)) | 其余 `X-SciRouter-*`、`x-ratelimit-*` 响应头与对话补全相同,见[可观测性](https://www.scirouter.cn/docs/observability)。 ## 缓存、幂等与重试 - `Idempotency-Key` 与平台响应缓存的规则与对话补全相同,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。同一问题以三种格式调用时分别缓存,互不命中。 - OpenAI SDK 默认自动重试 429 与 5xx,并先检查 `x-should-retry`。 - 控制台的请求日志按调用格式筛选时,本接口的调用格式为 `responses`。 --- # 向量 > POST /v1/embeddings 的请求与响应、默认开启的按条缓存,以及批量调用的限制。 来源:https://www.scirouter.cn/docs/embeddings · 更新于 2026-10-24 ```http POST https://api.scirouter.cn/v1/embeddings ``` 将文本转换为向量,用于检索、聚类与去重。请求与响应格式与 OpenAI Embeddings 一致。 ## 请求 ```bash curl https://api.scirouter.cn/v1/embeddings \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_EMBEDDING_MODEL_ID", "input": ["铁电材料的畴壁迁移", "钙钛矿太阳能电池的稳定性"] }' ``` Python: ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") resp = client.embeddings.create( model="YOUR_EMBEDDING_MODEL_ID", input=["铁电材料的畴壁迁移", "钙钛矿太阳能电池的稳定性"], ) vectors = [item.embedding for item in resp.data] ``` | 字段 | 必填 | 说明 | |---|---|---| | `model` | 是 | 向量模型的 id,见[模型中心](https://www.scirouter.cn/models)或 [`GET /models`](https://www.scirouter.cn/docs/models) | | `input` | 是 | 字符串、字符串数组(一次向量化多条),或 token 数组(`[1, 2, 3]` 为一条,`[[1, 2], [3]]` 为多条) | | `metadata` / `user` | 否 | 归因标签,不转给上游,见[可观测性](https://www.scirouter.cn/docs/observability) | | 其他字段 | 否 | 原样转给上游,如 `dimensions`、`encoding_format`,上游支持时生效 | ## 响应 ```json { "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456] }, { "object": "embedding", "index": 1, "embedding": [0.0789, 0.0012] } ], "model": "YOUR_EMBEDDING_MODEL_ID", "usage": { "prompt_tokens": 24, "total_tokens": 24 }, "scirouter": { "request_id": "req_…", "cache": "miss", "cost_quota": 480, "…": "…" } } ``` 数值为示例,`embedding` 只列出前两维。 | 字段 | 说明 | |---|---| | `data` | 按 `index` 与输入一一对应 | | `usage` | 全部输入的 token 数,包括来自缓存的条目 | | `scirouter.cost_quota` | 本次实际扣除的配额。按输入 token 计费,来自缓存的条目不计费 | | `scirouter.cache` | `hit` / `partial` / `miss` / `bypass` | ## 按条缓存 向量接口默认开启响应缓存,每条输入分别缓存,默认保存 24 小时。命中条件为同一 API Key、同一模型,且其他参数相同(如 `dimensions` / `encoding_format`)。 - 同一段文字在任一批次、任一位置都能命中。 - 一批中只有未命中的条目发给上游,结果按原顺序拼回。此时响应头为 `X-SciRouter-Cache: PARTIAL`,`scirouter.cache_items` 给出命中的条数。 - 命中的条目不计费,但请求仍计入每分钟请求数。 - 不同 API Key 之间不共享缓存。 | 请求头 | 取值 | 作用 | |---|---|---| | `X-SciRouter-Cache` | `disabled` | 不使用缓存 | | `Cache-Control` | `no-store` | 不使用缓存 | | `Cache-Control` | `no-cache` | 刷新缓存,不读取旧结果 | 缓存规则见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 ## 批量调用 一次传入数组比逐条调用快,也更不容易触发每分钟请求数的限频。单次请求受以下限制: | 限制 | 上限 | 超出时 | |---|---|---| | 请求体 | 4 MB | 413 `payload_too_large` | | 一批输入的 token 估算 | 套餐的每分钟 token 上限 | 400 `validation_failed`,`details.reason` 为 `plan_tpm_exceeded`、`param` 为 `input`,`details.limit` 为上限、`details.estimated` 为估算 | | 单批条数 | 上游通常有上限 | — | 列表较长时按几百条一批切分。 **批量任务带上 `Idempotency-Key`**:成功的结果保存 24 小时,同键重试直接返回该次结果(响应头 `Idempotent-Replayed: true`),不重复扣费,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 --- # 图片 > POST /v1/images 的生图、改图(含遮罩)、图生图与变体:参数、响应、流式、计费、限额与错误。 来源:https://www.scirouter.cn/docs/images · 更新于 2026-10-23 ```http POST https://api.scirouter.cn/v1/images/generations POST https://api.scirouter.cn/v1/images/edits POST https://api.scirouter.cn/v1/images/variations ``` 接口格式与 OpenAI Images API 一致,OpenAI 官方 SDK 将 base URL 设为 `https://api.scirouter.cn/v1` 即可调用。 **只能调用生图模型**,即 [`GET /models`](https://www.scirouter.cn/docs/models) 中 `scirouter.kind` 为 `image` 的模型。`scirouter.image` 说明该模型支持的尺寸、质量档位、单次最多张数、是否支持改图与变体的生成方式。模型种类不符时的错误见[错误](#错误)。 ## 生图 ```bash curl https://api.scirouter.cn/v1/images/generations \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "YOUR_IMAGE_MODEL_ID", "prompt": "一张钙钛矿太阳能电池结构的示意图,扁平插画风格", "size": "1536x1024", "quality": "high", "n": 1 }' | jq -r '.data[0].b64_json' | base64 --decode > out.png ``` Python: ```python import base64, os from openai import OpenAI client = OpenAI(base_url="https://api.scirouter.cn/v1", api_key=os.environ["SCIROUTER_API_KEY"]) img = client.images.generate( model="YOUR_IMAGE_MODEL_ID", prompt="一张钙钛矿太阳能电池结构的示意图,扁平插画风格", size="1536x1024", quality="high", ) open("out.png", "wb").write(base64.b64decode(img.data[0].b64_json)) ``` Node: ```javascript import OpenAI from 'openai' const client = new OpenAI({ baseURL: 'https://api.scirouter.cn/v1', apiKey: process.env.SCIROUTER_API_KEY }) const img = await client.images.generate({ model: 'YOUR_IMAGE_MODEL_ID', prompt: '一张图形摘要', size: '1024x1024' }) ``` | 字段 | 必填 | 说明 | |---|---|---| | `model` | 是 | 生图模型的 id,或平台为其配置的别名 | | `prompt` | 是 | 画面描述。长度上限由模型决定,常见为 32,000 字符 | | `n` | 否 | 单次生成的张数,缺省为 1,上限为模型的 `scirouter.image.max_outputs` | | `size` | 否 | `宽x高`。须为模型 `sizes.presets` 中的值,或满足 `sizes.custom` 的规则(宽高均为 `multiple_of` 的倍数,长宽比、像素与边长在范围内);模型接受 `auto` 时可写 `auto`。不写时使用模型的 `sizes.default` | | `quality` | 否 | 模型 `qualities` 中的一档,不写时使用 `default_quality`;模型 `quality_auto` 为 true 时可写 `auto`。不接受 `standard` / `hd` 等旧值 | | `background` | 否 | `auto` / `transparent` / `opaque`。透明背景须模型支持(`transparent`),且输出格式为 `png` 或 `webp` | | `output_format` | 否 | 模型 `output_formats` 中的一种,缺省为 `png` | | `output_compression` | 否 | 0–100,只对 `jpeg` / `webp` 生效 | | `response_format` | 否 | `b64_json`(缺省)或 `url`,见[响应](#响应) | | `stream` / `partial_images` | 否 | 见[流式响应](#流式响应) | | `moderation` | 否 | 平台固定按 `auto` 发送,写 `low` 时改为 `auto` | | `user` / `safety_identifier` / `style` | 否 | 接收但不转给上游(`style` 是 DALL·E 时代的退役参数)。其他无法识别的字段同样丢弃,记录在调用记录的参数中 | 尺寸不合规时返回 400 `validation_failed`,`param` 为 `size`,`details.reason` 指明不满足的规则(`size_multiple_of`、`size_ratio`、`size_max_edge` 等)。 ## 改图与图生图 ```bash curl https://api.scirouter.cn/v1/images/edits \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -F "model=YOUR_IMAGE_MODEL_ID" \ -F "image[]=@figure.png" \ -F "image[]=@reference.jpg" \ -F "mask=@mask.png" \ -F "prompt=把背景换成浅灰色,保留主体" \ -F "response_format=b64_json" ``` | 项 | 规则 | |---|---| | 请求格式 | `multipart/form-data` | | 图片字段 | 一张图写 `image`,多张写 `image[]`(官方 SDK 的发送方式;`image[0]`、`image[1]` 也可识别)。第一张为待修改的图 | | 图片张数 | 上限为模型的 `scirouter.image.edit.max_images`(不超过 16)。模型的 `edit` 为 null 时不支持改图 | | 图片格式 | PNG、JPEG、WebP,按文件内容识别,不看扩展名 | | 图片与请求体大小 | 见[限额](#限额) | | `mask`(可选) | 带透明通道的 PNG,与第一张图同宽同高,透明区域为待修改区域。模型 `edit.mask` 为 false 时不接受 | | 其他字段 | 与生图相同。`input_fidelity` 只在模型声明支持时转发,否则丢弃 | - 遮罩是给模型的参考,模型不一定严格按遮罩的形状修改。 - 不带遮罩、带多张参考图时为图生图:按描述用这几张图生成新图。 ## 变体 `/images/variations` 在 OpenAI 侧已退役(DALL·E 2 / 3 也已下线)。平台保留该接口(`multipart`,一张 `image`,可带 `n`、`size`、`response_format`),按模型的 `scirouter.image.variations` 处理: | 取值 | 平台的处理 | |---|---| | `native` | 原样转给仍支持该接口的上游 | | `via_edit` | 用该图调用改图接口,提示词为平台的一句固定文字(「生成这张图片的一个变体:保持主体、构图与风格,细节可以不同。」),按改图计费 | | `none` | 400 `validation_failed`,`details.reason` 为 `variations_unsupported` | ## 响应 ```json { "created": 1760918400, "data": [{ "b64_json": "iVBORw0KGgo…" }], "background": "opaque", "output_format": "png", "quality": "high", "size": "1536x1024", "usage": { "input_tokens": 24, "input_tokens_details": { "text_tokens": 24, "image_tokens": 0 }, "output_tokens": 6208, "output_tokens_details": { "image_tokens": 6208, "text_tokens": 0 }, "total_tokens": 6232 }, "scirouter": { "request_id": "req_…", "cost_quota": 186240, "…": "…" } } ``` 数值为示例。 | `response_format` | 返回内容 | |---|---| | `b64_json`(缺省) | 上游返回的原始字节,不重新压缩,保留透明背景;只在文件元数据中加入 AI 生成内容标识,见 [AI 生成内容标识](#ai-生成内容标识) | | `url` | 图片存入平台的对象存储,`data[].url` 有效期为 1 小时(平台运行参数可调),对象 24 小时后删除。流式不支持 `url` | - `size`、`output_format` 按实际生成的图片填写。 - `usage` 为本次计费所用的用量。上游未返回用量、平台按估算扣费时,`scirouter.estimated` 为 true。 ## 流式响应 请求带 `"stream": true` 时返回 `text/event-stream`: - 生成期间每隔几秒发送一行 `: ping` 心跳。 - 每张图生成后发送一个完成事件:生图为 `image_generation.completed`,改图与变体为 `image_edit.completed`。字段包括 `b64_json`、`size`、`quality`、`output_format`、`usage`;用量只在最后一个事件中给全,之前的事件为 0。全部图片发送后结束。 - `partial_images` 接收但不发送中间图。OpenAI 的官方说明中,中间图本就可能少于请求数量或没有,SDK 照常处理。 - 出错时发送一帧带 `error` 的数据,SDK 抛出异常。 高质量大图通常需要一到两分钟。非流式请求平台最多等待 270 秒,超过后会被前置的网络设施断开。**大尺寸、高质量的请求使用流式**,流式有心跳,不受该限制。 ## 计费 按 token 计费,单价见[定价](https://www.scirouter.cn/pricing)或 `scirouter.pricing`: | 计价维度 | 内容 | |---|---| | `input_tokens` | 文本输入 | | `image_input_tokens` | 图像输入(改图、图生图的输入图) | | `image_output_tokens` | 图像输出 | | 两个缓存输入维度 | 直接调用图片接口时上游一般不返回 | 单次生成多张、带多张参考图,均体现在 token 数中。 - 平台按上游返回的用量扣费;上游未返回时,按模型的估算表与实际出图的尺寸扣费(`scirouter.estimated`)。 - 开始前按估算的上界预扣,结束后多退少补。失败、超时与审核拦截均不扣费。 - 少数模型按张计费(`scirouter.image.metering` 为 `per_image`,维度为 `image_count`),此时响应不含 `usage`。 ## 限额 | 项目 | 上限 | |---|---| | 请求体 | 64 MB(413 `payload_too_large`) | | 单张输入图 | 20 MB,边长 8192,像素 4,000 万 | | 并发的图片请求 | 个人 4 个,团队 16 个,与站内绘图合计。超出时返回 429 `rate_limited`,`details.scope` 为 `images` | | 非流式等待 | 270 秒 | 每分钟请求数照常按套餐计算;图片的 token 不计入每分钟 token 数的限频。 ## 幂等 带 `Idempotency-Key` 时,同键重试的结果: | 情况 | 结果 | |---|---| | 同键的请求仍在处理 | 409 | | `url` 模式,已完成 | 直接返回该次的结果 | | `b64_json` 与流式,已完成 | 结果不保存,返回 409 `idempotency_conflict`,`details.reason` 为 `result_not_replayable`。不会重复生成、重复扣费 | `b64_json` 与流式模式下需要再次生成时,更换 `Idempotency-Key`。 判断是否为同一请求时按字段与图片内容比较,同一张图重新上传、`multipart` 的分隔符不同不影响判断。 ## 错误 | 状态码 | code | 触发条件 | 说明 | |---|---|---|---| | 400 | `validation_failed` | 模型种类不符:对话模型调用图片接口,或生图模型调用对话接口 | `details.reason` 为 `model_kind_mismatch` | | 400 | `validation_failed` | 尺寸、质量、张数、格式或遮罩不符合模型要求 | `param` 指明字段 | | 400 | `validation_failed` | 模型不支持改图或变体 | `details.reason` 为 `edit_unsupported` / `variations_unsupported` | | 400 | `moderation_blocked` | 上游审核未通过 | 平台错误码 `scirouter_code` 为 `CONTENT_FILTERED`(对话接口此处为 `content_filter`)。不扣费 | | 502 | `upstream_error` | 上游返回了响应,但不是可用的图片 | `details.reason` 为 `bad_image_output`。不扣费 | | 503 | `model_unavailable` | 模型有计价维度尚未定价 | `details.reason` 为 `model_offline` | 其他错误(认证、余额、限频、上游超时)与对话接口相同,见[错误码](https://www.scirouter.cn/docs/errors)。 ## AI 生成内容标识 按《人工智能生成合成内容标识办法》,平台在每张图片的文件元数据中写入 AI 生成内容的隐式标识(`AIGC` 字段),不在画面上叠加可见角标。 - 调用方将图片发布或提供给公众时,须按规定自行添加显式标识。 - 平台按规定留存提供记录(调用方、时间与图片的哈希,不含图片与提示词)不少于六个月。 - 站内百宝箱「绘图」生成的图片直接带有「AI生成」角标。 --- # 模型列表 > 列出与查询模型的接口:模型 id 格式、按 API Key 权限过滤的规则、scirouter 扩展字段与计价维度。 来源:https://www.scirouter.cn/docs/models · 更新于 2026-10-23 ```http GET https://api.scirouter.cn/v1/models GET https://api.scirouter.cn/v1/models/{model_id} ``` 返回调用所用 API Key 可调用的模型。响应格式与 OpenAI 模型接口一致,每个模型另带 `scirouter` 扩展字段;官方 SDK 忽略该字段,`client.models.list()` 可直接使用。 ## 模型 id 模型 id 的格式为 `厂商/模型名`,调用时原样填入 `model` 字段。 | 部分 | 规则 | |---|---| | 厂商 | 接入该线路的厂商。以小写字母或数字开头,只含小写字母、数字、`.`、`_`、`-` | | 模型名 | 以字母或数字开头,可含大写字母 | | 整体 | 只含一个 `/`,不超过 160 个字符,区分大小写 | 模型 id 以列表接口的返回为准,不由展示名推断。示例中的 `YOUR_MODEL_ID` 为占位,使用时替换为列表中的 id。 ## 列出模型 ```bash curl https://api.scirouter.cn/v1/models \ -H "Authorization: Bearer $SCIROUTER_API_KEY" ``` ```json { "object": "list", "data": [ { "id": "YOUR_MODEL_ID", "object": "model", "created": 1757894400, "owned_by": "…", "display_name": "…", "context_length": 128000, "scirouter": { "domain": "life-science", "display_name": "…", "status": "available", "pricing": [ { "dimension": "input_tokens", "dimension_label": "输入", "unit": "1M tokens", "ratio_micro": 20000000 }, { "dimension": "output_tokens", "dimension_label": "输出", "unit": "1M tokens", "ratio_micro": 60000000 } ], "features": ["tools", "vision", "reasoning", "json_mode"], "reasoning": { "controls": ["effort"], "efforts": ["low", "medium", "high"] }, "supported_params": ["temperature", "top_p", "stop", "tools", "tool_choice", "response_format", "reasoning", "seed"], "emulated_params": ["parallel_tool_calls"] } } ] } ``` 倍率与上下文长度为示例值。 ### 顶层字段 | 字段 | 说明 | |---|---| | `id` | 模型 id | | `object` | 固定为 `model` | | `created` | 模型在平台登记的时间,Unix 时间戳(秒) | | `owned_by` | 厂商标识 | | `display_name` | 展示名 | | `context_length` | 上下文长度,单位 token。未登记上下文长度的模型不返回该字段 | 前四项是 OpenAI 的标准字段,`display_name` 与 `context_length` 是聚合平台的通行字段。SciRouter 作为上游接入其他平台时,对方读取模型列表顶层即可获得展示名与上下文长度。 ### 权限过滤 列表按该 Key 当前的权限过滤,判定规则与调用时的授权相同。同时满足以下四项的模型才会列出,已停用的模型不列出: 1. Key 的模型白名单; 2. Key 所属项目的模型白名单; 3. 账户套餐; 4. 受限模型的团队授权。 因此同一账户下的不同 Key 可能得到不同的列表。列表中的模型均有调用权限,配额与限频另行判定。 | 情况 | 列表行为 | 调用结果 | |---|---|---| | `status` 为 `maintenance` | 列出 | 503 `model_unavailable`,`details.reason` 为 `model_offline` | | 设为完全隐藏的受限模型 | 不列出,即使所在团队的项目 Key 已获授权 | 无权时 404 `model_not_found` | 该 Key 无法调用任何模型时,列表接口返回与调用相同的错误,不返回空列表: | 状态码 | code | 触发条件 | |---|---|---| | 422 | `project_archived` | Key 所属项目已归档 | | 404 | `project_not_found` | Key 所属项目不存在 | | 404 | `team_not_found` | 团队项目的 Key 的所有者已不在该团队 | | 403 | `team_suspended` | 团队已停用 | ## `scirouter` 扩展字段 | 字段 | 说明 | |---|---| | `domain` | 科研领域:`life-science`、`medicine`、`chemistry`、`materials`、`physics`、`math`、`earth`、`agriculture`、`environment`、`engineering`、`cs`、`general` | | `display_name` | 展示名 | | `status` | `available`:正常;`degraded`:部分线路异常,仍可调用;`maintenance`:维护中,调用返回 503 | | `pricing` | 计价维度列表,见[计价维度](#计价维度) | | `context_tiers` | 长上下文分档,见[长上下文分档](#长上下文分档)。不分档的模型不返回该字段 | | `variant_of` / `variant` | 变体的基础模型 id 与后缀(如 `fast`);非变体为 `null`。变体是单独定价的独立模型,见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages) | | `variant_params` | 仅变体返回。调用该变体时平台强制写入请求的参数,格式为 `[{ "path", "value" }]`:`path` 为点分路径(如 `speed`、`thinking.type`),`value` 为原样的 JSON。请求中的同名字段以此为准。只强制 beta 的变体不返回该字段 | | `variant_betas` | 仅变体返回。调用该变体时平台并入 `anthropic-beta` 请求头的值;未强制 beta 的变体不返回该字段 | | `variant_switch_formats` | 仅变体返回,取值 `openai` / `anthropic`。以列出的格式调用基础模型、并带齐取值相同的 `variant_params` 时,平台自动改用该变体并按其计价。不返回该字段表示不会自动改用,需将 `model` 设为变体的 id | | `features` | 模型声明的能力标识,如 `tools`、`vision`、`reasoning`、`json_mode`、`structured_output`、`logprobs`、`seed`、`prompt_cache`、`audio`。需要某项能力的参数,模型未声明该能力时无法带到线路上 | | `reasoning` | 思考控制方式;不返回表示模型不思考。`controls` 为支持的控制方式(`toggle` 开关、`effort` 强度、`budget` 预算的子集),`efforts` 为 `effort` 方式支持的档位。请求的强度不在其中时平台降档,见[参数如何被处理](https://www.scirouter.cn/docs/params) | | `supported_params` | 原生支持或经翻译可带到线路上的标准参数,取模型当前启用线路的并集。不在其中的提示类参数被去掉并留痕,契约类参数返回 400 | | `emulated_params` | 线路不支持、由平台模拟的参数,范围为 `stop`、`response_format`、`tool_choice`、`parallel_tool_calls` 与向量接口的 `encoding_format` | | `kind` | 模型种类:`chat`(对话接口)、`embedding`(向量接口)、`image`([图片接口](https://www.scirouter.cn/docs/images))、`video` 与 `speech`(仅限站内百宝箱)。调用种类不符的接口返回 400 `validation_failed`,`details.reason` 为 `model_kind_mismatch` | | `image` | 仅生图模型返回,说明图片接口接受的参数,见下表 | `features`、`reasoning`、`supported_params`、`emulated_params` 是模型的能力自述,随平台配置与线路启停变化,以调用时的值为准。各参数无法带到线路上时的处理方式见[参数如何被处理](https://www.scirouter.cn/docs/params)。 `image` 的字段: | 字段 | 说明 | |---|---| | `sizes` | 尺寸。`presets`:标准尺寸;`auto`:是否接受自动尺寸;`custom`:任意尺寸的约束 `{multiple_of, min_pixels, max_pixels, max_edge, max_ratio}`;`default`:缺省尺寸 | | `qualities` / `quality_auto` / `default_quality` | 支持的质量档位、是否接受自动质量、缺省质量 | | `output_formats` | 支持的输出格式 | | `transparent` | 是否支持透明背景 | | `edit` | 改图能力 `{max_images, mask, input_fidelity}`;不支持改图时为 `null` | | `variations` | 变体生成方式:`native`、`via_edit` 或 `none` | | `max_outputs` | 单次请求最多生成的张数 | | `metering` | 计量方式:`tokens` 按 token,`per_image` 按张 | ### 计价维度 `pricing` 的每一项: | 字段 | 说明 | |---|---| | `dimension` | 计价维度,如 `input_tokens`、`output_tokens`、`cached_input_tokens`、`reasoning_tokens`(见[多厂商差异](https://www.scirouter.cn/docs/vendors));生图模型为 `image_input_tokens`、`cached_image_input_tokens`、`image_output_tokens`(见[图片](https://www.scirouter.cn/docs/images)) | | `dimension_label` | 维度的展示名 | | `unit` | 展示粒度,如 `1M tokens`。仅用于展示,不参与计价 | | `ratio_micro` | 定点倍率,`1000000` 表示 1.0 倍:该维度每 1 个计量单位(1 个 token)扣除的配额 | | `tiers` | 可选。`[{ "from", "ratio_micro" }]`:用量达到 `from` 后整笔按该档计价,不累进 | | `min_billable` | 可选。最小计费量,不足时按该值计 | ### 长上下文分档 `context_tiers` 的每一档为 `{ "above_prompt_tokens", "ratios" }`。单次请求的输入合计(普通输入、缓存命中、缓存写入与 1 小时缓存写入之和)超过 `above_prompt_tokens` 时(等于不算),整笔按该档计价:`ratios` 中列出的维度使用该档倍率,未列出的维度沿用基础倍率。同时超过多档时,取阈值最高的一档。 ### 实际扣费 实际扣费还要乘以模型倍率,模型倍率不在本接口返回,因此不能用本接口的数值自行计算费用。单次调用的扣费见响应中的 `scirouter.cost_quota`;各模型的完整价格表见[模型中心](https://www.scirouter.cn/models)的详情页。 `pricing` 与 `context_tiers` 是读取列表时生效的价格。平台可随时调价,也可预先设定将来某一时刻生效的新价格;每次调用按请求开始时生效的价格结算。程序中不要长期缓存或写死价格,使用前重新读取列表。 ## 查询单个模型 ```bash curl https://api.scirouter.cn/v1/models/YOUR_MODEL_ID \ -H "Authorization: Bearer $SCIROUTER_API_KEY" ``` - 模型 id 中的 `/` 直接写入路径,写成 `%2F` 也可识别。 - 可使用平台为模型配置的别名,响应中的 `id` 为平台的模型 id。 - 列表中看不到的模型返回 404 `model_not_found`,不存在与无权调用不作区分。完全隐藏的受限模型在调用时同样返回 404。 - 调用接口对白名单外的模型返回 403 `model_not_allowed`,与本接口不同。 ## Anthropic 格式 请求带 `anthropic-version` 请求头时(Claude Code 与 Anthropic SDK 会自动携带),两个接口均按 Anthropic 的格式返回,见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages)。 ## 选择模型 列表接口供程序读取。比较模型的能力、上下文长度、价格与近期可用率,使用[模型中心](https://www.scirouter.cn/models):可按领域筛选,最多并排对比五个模型。 --- # 错误码 > /v1 会返回的每一个错误码:触发条件、是否可重试、处理方式,以及两种格式的错误体。 来源:https://www.scirouter.cn/docs/errors · 更新于 2026-10-24 对话补全、向量与模型列表接口的错误体与 OpenAI 格式兼容,另带 `request_id` 与 `details`。`/messages` 使用 Anthropic 格式,见 [Anthropic 格式的错误体](#anthropic-格式的错误体)。 ```json { "error": { "message": "请求过于频繁,请稍后再试", "type": "rate_limit_error", "code": "rate_limited", "scirouter_code": "RATE_LIMITED", "request_id": "req_88a1", "details": { "retry_after_seconds": 12 } } } ``` | 字段 | 说明 | |---|---| | `message` | 供人阅读的错误说明,措辞可能变更,不用于程序分支 | | `type` | 按状态码映射的错误类别,粒度较粗,见 [type 与状态码](#type-与状态码) | | `code` | 小写的平台错误码,程序按它分支。三个上游语义错误例外,取原厂兼容值(如 `context_length_exceeded`),见[上游语义错误](#上游语义错误) | | `scirouter_code` | 大写的平台错误码,OpenAI 格式的错误体均返回。需要对全部错误统一分支时读取该字段 | | `param` | 仅参数错误时返回,指出出错的字段 | | `request_id` | 本次调用的编号,与响应头 `X-Request-Id` 相同 | | `details` | 附加信息,如 `retry_after_seconds`、`limit`、`scope`。官方 SDK 忽略该字段,不影响兼容 | 返回 `details.retry_after_seconds` 时,响应头 `Retry-After` 必定取相同的值。 报障时提供 `request_id`,平台按它定位单次调用。控制台请求日志可按 `request_id` 查到对应记录,详情页的「复制报障信息」汇总排障所需的全部信息,见[可观测性](https://www.scirouter.cn/docs/observability)。 ## 可重试的错误 按指数退避重试;响应带 `Retry-After` 时按其等待。重试须设置次数上限。 | 状态码 | code | 触发条件 | 处理方式 | |---|---|---|---| | 429 | `rate_limited` | 超出每分钟请求数、每分钟 token 数或并发请求数;上游厂商限流;达到套餐每日配额上限。见 [HTTP 429 的来源](#http-429-的来源) | 有 `Retry-After` 时按其等待,否则指数退避 | | 429 | `upstream_saturated` | 上游线路的名额已满,排队未成功;`details` 带 `queue_position` 与 `queue_length` | 按 `Retry-After` 退避,或更换模型 | | 502 | `upstream_error` | 上游返回 5xx;上游拒绝平台的凭证或找不到模型;响应无法解析;流意外中断(`details.provider_error.code` 为 `stream_interrupted`) | 指数退避 | | 503 | `model_unavailable` | 线路暂时都无法接收请求(熔断、限额、并发已满),或模型的全站并发已满。`details.reason` 为 `endpoints_busy` 或 `model_busy`,带 `Retry-After` | 按 `Retry-After` 等待。不带 `Retry-After` 的 503 见[不可重试的错误](#不可重试的错误) | | 504 | `upstream_timeout` | 上游超时。`details.timeout` 取 `connect`、`first_byte`、`idle`、`response`(非流式等待完整响应)、`total` 或 `upstream` | 指数退避;持续出现时调小 `max_tokens` 或改用流式 | | 409 | `idempotency_conflict` | 请求带 `Idempotency-Key`,同一个键的请求仍在处理中 | 等待后重试,并设次数上限。同一 code 的另一种含义见[不可重试的错误](#不可重试的错误) | | 500 | `internal` | 服务内部错误 | 指数退避;反复出现时提供 `request_id` 报障 | ## 不可重试的错误 重试不改变结果,须先修改请求或设置。 | 状态码 | code | 触发条件 | 处理方式 | |---|---|---|---| | 400 | `validation_failed` | 请求不合法,或上游拒绝请求而平台未识别其语义。具体情况见表下 | 按 `message` 与 `param` 修改请求 | | 400 | `context_window_exceeded` | 输入(或输入加 `max_tokens`)超出模型的上下文窗口。`param` 为 `messages`,`code` 为 `context_length_exceeded`;两种来源见表下 | 缩短输入、调小 `max_tokens`,或换用窗口更大的模型,见[参数如何被处理](https://www.scirouter.cn/docs/params)「上下文窗口」 | | 400 | `unsupported_param` | 参数或内容无法带到线路上,或远程图片无法取回。具体情况见表下 | 去掉 `param` 所指的参数或内容,或更换模型,见[参数如何被处理](https://www.scirouter.cn/docs/params) | | 400 | `content_filtered` | 上游内容审核拒绝。`details.semantic` 为 `content_filtered`,`code` 为 `content_filter`;[图片接口](https://www.scirouter.cn/docs/images)上 `code` 为 OpenAI 图片接口的 `moderation_blocked` | 修改内容。各厂商审核标准不同,更换模型不一定有效 | | 400 | `unsupported_protocol` | 模型所在线路的入口不支持该操作。目前只有一种情况:调用向量接口,而线路只有 Anthropic 入口(向量只走 `openai`、`custom`、`gemini` 入口,见[多厂商差异](https://www.scirouter.cn/docs/vendors)) | 更换模型 | | 401 | `unauthenticated` | 未带 Key、Key 格式错误(常见原因是填入了其他厂商的 Key)或 Key 不存在 | 不自动重试。检查环境变量,值应为以 `sk-sr-` 开头的 SciRouter Key | | 401 | `key_revoked` / `key_expired` | Key 已吊销或已过期 | 在控制台更换 Key | | 401 | `account_suspended` | 账号已停用 | 联系平台 | | 402 | `insufficient_quota` | 余额不足以预扣(按输入估算加输出上限预扣,充值余额大于 0 的账户输出只按预留估,见[认证与 API Key](https://www.scirouter.cn/docs/authentication)「预扣」),或此前结算使配额变为负数;带 `details.required_quota`,团队账户另带 `details.account_kind: "team"` | 充值(团队账户联系负责人)。`max_tokens` 小于平台设定的输出预留时,调小它可减少预扣 | | 403 | `model_not_allowed` | 模型不在白名单中;`details.scope` 为 `key`、`project` 或 `plan` | 修改白名单、更换 Key 或更换模型 | | 403 | `model_restricted` | 受限模型,本次调用所在的工作区未获授权 | 使用已获授权的团队项目下的 Key | | 403 | `team_suspended` | Key 属于团队项目,该团队已停用 | 联系团队负责人 | | 404 | `model_not_found` | 模型 id 不存在,或是对调用方不可见的受限模型 | 检查 id(区分大小写),以 `GET /models` 的返回为准 | | 404 | `project_not_found` / `team_not_found` | 前者:Key 所属项目已不存在;后者:Key 的所有者已不在该团队 | 更换 Key | | 409 | `idempotency_conflict` | 同一个 `Idempotency-Key` 用于不同的请求体,通常是代码复用错了键 | 检查键的生成与复用。该 code 与「处理中」的 409 相同,仅 `message` 不同;有限次重试后仍返回 409 时按本行处理 | | 409 | `idempotency_conflict`(`details.reason = result_not_replayable`) | [图片接口](https://www.scirouter.cn/docs/images)不保存 `b64_json` 与流式结果:同一个键的请求已完成,无法重放 | 需要重新生成时使用新的键 | | 413 | `payload_too_large` | 请求体超过上限(默认 4 MB) | 拆分后再发送 | | 422 | `project_archived` | Key 所属项目已归档 | 使用不属于该项目的 Key | | 429 | `key_quota_exceeded` | 该 Key 的月度上限不足(已用量加本次估算超过上限);不带 `Retry-After` | 下月恢复。上限创建后不可修改,急需时更换 Key | | 429 | `project_budget_exceeded` | 项目的月预算已用完;`Retry-After` 指向下月 1 日 | 在控制台调高项目预算 | | 503 | `model_unavailable` | 本次请求在该模型上无法完成(如带 `tools` 而没有支持工具调用的线路、超过单次上限),或模型已下线、维护中、尚未定价。不带 `Retry-After`,带响应头 `x-should-retry: false`;`details.reason` 见 [HTTP 503 的 details.reason](#http-503-的-details-reason) | 重试无效。按 `details.reason` 修改请求或更换模型 | `validation_failed` 的触发条件: - 请求体不是 JSON 对象、字段类型错误、缺少 `model`、`messages` 为空、`stop` 类型错误; - `max_tokens` 超过模型或套餐的单次上限(`details.limit`); - 输入的 token 估算超过套餐的每分钟上限:`details.reason` 为 `plan_tpm_exceeded`,见 [HTTP 400 的 details.reason](#http-400-的-details-reason); - `metadata`、托管工具声明或缓存相关请求头写法错误; - `Idempotency-Key` 超长; - 上游拒绝请求,而平台未识别是哪种语义:`details.source` 为 `upstream`,带 `provider_error`。已识别语义的归入 `context_window_exceeded`、`unsupported_param`、`content_filtered`。 `context_window_exceeded` 的两种来源: - 平台发出前估算得出:带 `details.limit`、`details.estimated`、`details.max_tokens`; - 上游报告:`details.semantic` 为 `context_window_exceeded`,厂商文案含数字时才带 `limit` 与 `estimated`。 `unsupported_param` 的触发条件: - 契约类参数在该模型的所有线路上都无法带到(`details.param`、`details.cause`); - 上游明确拒绝某个参数,而平台无法去掉它(`details.semantic` 为 `unsupported_param`,`code` 为 `unsupported_parameter` 或 `unsupported_value`); - 请求含只能原样转发的内容,而没有可转发的线路(`details.reason` 为 `unsupported_content`,`details.unsupported_content` 列出这些内容); - 远程图片无法取回(`details.reason` 为 `media_fetch_failed`)。 ## `type` 与状态码 `type` 按状态码映射,与 OpenAI 的惯例一致。程序分支使用 `code`。 | `type` | 状态码 | |---|---| | `authentication_error` | 401 | | `insufficient_quota` | 402 | | `permission_error` | 403 | | `rate_limit_error` | 429 | | `upstream_error` | 502、503、504 | | `server_error` | 其他 5xx | | `invalid_request_error` | 其他 4xx | ## 上游语义错误 平台将上游错误中的三种常见语义归为固定的 code:`context_window_exceeded`(上下文超长)、`unsupported_param`(参数不支持)、`content_filtered`(内容审核)。三者均为 400,不可重试,须修改请求。错误体分两层: | 平台码(`scirouter_code`) | OpenAI 格式的 `error.code` | Anthropic 格式的 `message` | |---|---|---| | `CONTEXT_WINDOW_EXCEEDED` | `context_length_exceeded`,`param` 为 `messages`,`message` 以 `This model's maximum context length is {limit} tokens. However, …` 开头 | 输入本身超出时含 `prompt is too long: {estimated} tokens > {limit} maximum`;输入未超出、加上 `max_tokens` 后超出时含 ``input length and `max_tokens` exceed context limit: {estimated} + {max_tokens} > {limit}``;上游报告且无法提取数字时只有 `prompt is too long` | | `UNSUPPORTED_PARAM` | `unsupported_parameter`(取值不支持时为 `unsupported_value`),`param` 为参数名 | 写明参数名与原因 | | `CONTENT_FILTERED` | `content_filter` | — | - 平台码在 `error.scirouter_code`(OpenAI 格式)或 `error.code`(Anthropic 格式,小写)中;`details` 照常带 `param`、`limit`、`estimated`、`semantic`、`provider_error`。 - `code` 只取原厂可识别的值,供现有客户端使用:Claude Code 按 `prompt is too long` 中的两个数字裁剪历史、按 `exceed context limit` 调小 `max_tokens`;Codex 仅在 `response.failed` 中出现 `context_length_exceeded` 时压缩对话;不少 OpenAI 兼容客户端按 `context_length_exceeded` 或 `unsupported_parameter` 分支。 - 无法带到线路上的提示类参数默认由网关去掉并留痕,不返回 400,见[参数如何被处理](https://www.scirouter.cn/docs/params)。 - 上下文超长通常由平台在发出前估算得出(带 `details.estimated`),此时不预扣、不占名额。 - 上游不支持某个参数时,平台先尝试去掉该参数后重发(响应头 `X-SciRouter-Param-Actions` 中记为 `healed`)。返回 400 表示该参数无法去掉,或没有可换的线路。 ## Anthropic 格式的错误体 `/messages` 与 `/messages/count_tokens`(以及带 `anthropic-version` 请求头的 `/models`)返回 Anthropic 格式的错误体,鉴权失败时也是如此,Anthropic SDK 可直接识别: ```json { "type": "error", "error": { "type": "overloaded_error", "message": "…", "code": "model_unavailable", "details": { "reason": "endpoints_busy" } }, "request_id": "req_88a1" } ``` 状态码、`code` 与 `details` 与[可重试的错误](#可重试的错误)、[不可重试的错误](#不可重试的错误)两张表完全相同(`error.code`、`error.details` 为扩展字段),`request_id` 位于顶层。`error.type` 按状态码映射,平台策略类拒绝例外,取 `policy_blocked`: | `error.type` | 状态码 | |---|---| | `invalid_request_error` | 400,以及 422 等其余 4xx | | `authentication_error` | 401 | | `billing_error` | 402 | | `permission_error` | 403 | | `not_found_error` | 404 | | `conflict_error` | 409 | | `request_too_large` | 413 | | `rate_limit_error` | 429 | | `api_error` | 500、502,以及不带 `Retry-After` 的 503(本次请求在该模型上无法完成) | | `overloaded_error` | 带 `Retry-After` 的 503(线路或模型暂时繁忙) | | `timeout_error` | 504 | | `policy_blocked` | 平台策略类拒绝,不按状态码映射,见下表 | `policy_blocked` 覆盖下列 code。状态码保持各自的 401、402、403、404、422 或 429,并带 `x-should-retry: false`。修改请求或重试均无效,需人工处理;Claude Code 直接展示该错误,不重试。 | 类别 | code | |---|---| | 配额 | `insufficient_quota`、`key_quota_exceeded`、`project_budget_exceeded` | | 权限与受限模型 | `model_not_allowed`、`model_restricted` | | Key、账号、团队、项目的状态 | `key_revoked`、`key_expired`、`account_suspended`、`team_suspended`、`project_not_found`、`project_archived` | 模型暂时不可用时仍返回 503,不使用 Anthropic 的 529。Anthropic SDK 对 5xx 自动重试,带 `x-should-retry: false` 的除外。程序分支使用 `error.code`。 以下两项遵循 Claude Code 的网关约定: - 能力类拒绝带固定标记:平台自身拒绝、且客户端关闭对应能力即可恢复的 400,在 `message` 末尾追加 `capability_rejected: `,`details.capability_rejected` 取相同值。Claude Code 收到后关闭该能力并重发。class 取值见下表。 - 转发上游的 4xx 时,厂商原文保留在 `message` 中(前缀为「上游拒绝了请求:」),按子串匹配的客户端不受影响。 | class | 含义 | |---|---| | `prompt_too_long` | 输入超出窗口;或输入估算超过套餐每分钟 token 数(`details.reason` 为 `plan_tpm_exceeded`),此时 `message` 同样以 `prompt is too long: N tokens > M maximum` 开头,M 为套餐每分钟上限 | | `max_tokens_context_overflow` | 输入加 `max_tokens` 超出窗口 | | `thinking_signature` | 思考块的签名被拒 | | `structured_outputs_unsupported` | 结构化输出(`response_format`)被拒 | | `effort_unsupported` | 思考参数被拒 | | `image_block` | 图片输入被拒 | | `document_block` | 文件输入被拒 | ## HTTP 503 的 `details.reason` `model_unavailable` 同时覆盖「暂时繁忙」与「本次请求在该模型上无法完成」两类情况,以 `details.reason` 区分。`details.reason` 为固定的英文码,可用于程序分支。 | reason | 含义 | 带 `Retry-After` | 处理方式 | |---|---|---|---| | `endpoints_busy` | 该模型的线路暂时都无法接收请求(熔断、限额或并发已满) | 是 | 按 `Retry-After` 等待 | | `model_busy` | 该模型在平台上的并发请求数已满 | 是 | 按 `Retry-After` 等待 | | `tools_unsupported` | 请求带 `tools`,而该模型没有支持工具调用的线路 | 否 | 去掉 `tools`,或更换模型 | | `streaming_unsupported` | 请求为流式,而该模型没有支持流式的线路 | 否 | 改用非流式,或更换模型 | | `input_too_large` | 预计 token 数(输入加 `max_tokens`)超过线路的单次上限 | 否 | 缩短输入、调小 `max_tokens` | | `no_capable_endpoint` | 没有一条线路同时满足本次请求的要求(工具调用、流式、长度) | 否 | 更换模型 | | `no_endpoint` | 该模型当前没有可用的线路 | 否 | 更换模型,稍后再查看模型状态 | | `model_offline` | 模型已下线、维护中或尚未定价 | 否 | 更换模型,稍后再查看模型状态 | **不带 `Retry-After` 的 503 重试无效。** 这类响应带 `x-should-retry: false`。OpenAI 与 Anthropic 的官方 SDK 以及 Claude Code 先读取该响应头,值为 `false` 时停止自动重试并直接返回错误;自行实现的重试逻辑也应读取该响应头。 请求含只能原样转发的内容、而没有可转发的线路时,返回 400 `unsupported_param`(`details.reason` 为 `unsupported_content`),不再归入 `no_capable_endpoint`。503 只用于等待后可恢复或更换模型可解决的情况。 ## HTTP 400 的 `details.reason` `validation_failed` 多数情况下不带 `details.reason`,按 `message` 与 `param` 处理即可。下列情况带固定的 reason,适用的接口见各行: | reason | 含义 | 处理方式 | |---|---|---| | `server_tool_unsupported` | `/messages` 或 `/responses` 的请求使用了厂商的服务端工具或连接器(`web_search_*`、`web_fetch_*`、`code_execution_*`、`mcp_servers`、`container` 等) | 去掉这些工具,改用自定义工具 | | `price_param_unsupported` | 请求带了会使厂商按另一档单价收费的参数(`details.params` 列出),而平台未上架对应的模型变体 | 去掉这些参数,或改用变体,见 [Messages](https://www.scirouter.cn/docs/messages) | | `sub_model_unpriced` | `/messages` 的 advisor 工具或 `fallbacks` 列表引用的模型未在平台上架或未定价(`param` 指向该字段)。无权调用该模型时,与直接调用它一样返回 403 | 换成平台上已定价的模型(正名或别名),见 [Messages](https://www.scirouter.cn/docs/messages)「计费」 | | `stateful_unsupported` | `/responses` 带了 `previous_response_id`、`conversation`、`prompt` 或 `item_reference`。平台不保存响应,没有可引用的状态 | 将完整的对话历史放入 `input`,见 [Responses](https://www.scirouter.cn/docs/responses) | | `background_unsupported` | `/responses` 带了 `background: true` | 去掉该参数,改为同步调用 | | `plan_tpm_exceeded` | 输入的 token 估算本身超过了套餐每分钟的 token 数,无论等多久都发不出去(`param` 为 `messages`;[向量](https://www.scirouter.cn/docs/embeddings)为 `input`)。Anthropic 格式的 `message` 以 `prompt is too long:` 开头并带 `capability_rejected: prompt_too_long`,Claude Code 据此尝试自动压缩对话后重发;对话太长、压缩请求本身也超过上限时,压缩会失败。`details.limit` 为套餐每分钟上限,`details.estimated` 为输入估算。`max_tokens` 不参与这一判定 | 缩短输入(如压缩对话历史),或升级套餐 | | `model_kind_mismatch` | 模型种类与接口不符:对话类接口(`/chat/completions`、`/responses`、`/messages`、`/embeddings`)调用了生图等媒体模型,或[图片接口](https://www.scirouter.cn/docs/images)调用了非生图模型(此前对话接口调用生图模型返回 503) | 按 `/models` 的 `scirouter.kind` 调用对应的接口 | | `edit_unsupported` / `variations_unsupported` | 该生图模型不支持改图或不支持变体(见 `scirouter.image.edit` 与 `variations`) | 更换模型 | | `size_multiple_of`、`size_ratio`、`size_max_edge`、`size_min_pixels`、`size_max_pixels`、`size_not_preset`、`size_auto_not_allowed`、`size_format` | 图片的 `size` 不符合模型 `scirouter.image.sizes` 的规则 | 按 `sizes` 修改尺寸 | `unsupported_param` 与 `context_window_exceeded` 的 `details.reason` 同样固定: | reason | code | 含义 | 处理方式 | |---|---|---|---| | `unsupported_param` | `unsupported_param` | 契约类参数无法带到线路上:`details.param` 为参数名,`details.cause` 为原因,取值见下表 | 去掉该参数,或更换模型 | | `unsupported_content` | `unsupported_param` | 请求含只能原样转发的内容(Anthropic 格式的 `search_result`、按需压缩、advisor 工具等;Responses 的 `input_file`、厂商定义的客户端工具等),`details.unsupported_content` 列出这些内容,而该模型没有可原样转发的线路 | 去掉这些内容,或更换模型 | | `media_fetch_failed` | `unsupported_param` | 平台无法取回远程图片(非公网地址、过大、超时、数量过多) | 改为 data URL 内联,或更换地址 | | `context_window` | `context_window_exceeded` | 平台发出前估算出输入(加 `max_tokens`)超出窗口;`details.scope` 为 `endpoint` 时为线路级窗口 | 缩短输入、调小 `max_tokens` | | `details.cause` | 含义 | |---|---| | `feature_missing` | 模型未声明对应能力 | | `rule_unsupported` | 模型的请求规则不接受该参数 | | `not_carried` | 所有线路都无法带到,`details.params` 列出全部这类参数 | | `strict` | 调用方通过请求头要求严格处理,见[参数如何被处理](https://www.scirouter.cn/docs/params) | ## HTTP 429 的来源 `rate_limited` 与另外两个配额类 code 的区别: | code | 来源 | `details` | `Retry-After` | |---|---|---|---| | `rate_limited` | 每分钟请求数、每分钟 token 数或并发请求数超限 | `scope`:`personal`(账号)、`key`(该 Key)或 `team`(团队项目下的 Key 按团队限额计,成员共用) | 通常为秒级 | | `rate_limited` | 套餐每日配额上限;`message` 为「今日用量已达套餐上限」 | `limit_quota`、`spent_quota` | 指向次日零点(平台时区) | | `key_quota_exceeded` | Key 的月度上限 | — | 不带;下月恢复 | | `project_budget_exceeded` | 项目的月预算 | — | 指向下月 1 日 | 每分钟 token 数在请求开始时按「输入估算 + 输出预留」计入,输出预留是 `max_tokens` 与平台设定值中的较小者;请求结束后按实际用量多退少补,实际输出超过预留的部分补记。因此 `max_tokens` 写得大不会被提前拒绝,但同一分钟里的长输出会让后续请求收到 429。 按 `code` 与 `details` 分支,不只看状态码。等待时长以 `Retry-After`(或 `details.retry_after_seconds`)为准。 ## 重试策略 网关内置故障转移:默认在上游超时、返回 5xx 或被上游限流时,自动转到该模型的下一条可用线路,最多再转 2 次,总耗时不超过 60 秒(各模型可单独配置)。只有一条线路的模型、已开始输出的流式请求不做转移。 因此调用方收到 5xx 时,网关通常已尝试过其他线路;尝试次数见成功响应中的 `scirouter.attempts` 或响应头 `X-SciRouter-Attempts`。客户端的重试使用指数退避,不立即重发。 **非流式请求重试时带同一个 `Idempotency-Key`**,首次请求实际已成功时不会重复扣费。前提是首次请求未被客户端先断开:客户端断开的请求由服务端取消且不保存结果,见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 官方 SDK 默认自动重试 429 与 5xx,不区分 `code`,见 [SDK 与框架](https://www.scirouter.cn/docs/sdks)「重试与超时」。 ## 流式响应中的错误 流式响应可能在已输出部分内容之后出错。此时 HTTP 状态码已是 200,错误以带 `error` 字段的分片出现在流中,随后流直接结束,不再发送 `data: [DONE]`: ```text data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"这段序列的"}}]} data: {"error":{"message":"上游模型服务响应超时","type":"upstream_error","code":"upstream_timeout","request_id":"req_88a1","details":{"timeout":"idle"}}} ``` 只检查 HTTP 状态码会把截断的回答当作完整回答。三种格式的流式结束标志与出错方式: | 接口 | 正常结束 | 输出开始后出错 | |---|---|---| | 对话补全(`/chat/completions`) | `data: [DONE]` | 带 `error` 字段的分片,之后没有 `[DONE]` | | `/messages`(Anthropic 格式) | `message_stop` 事件,没有 `[DONE]` | `event: error` 事件,内容为 [Anthropic 格式的错误体](#anthropic-格式的错误体),随后断开 | | `/responses` | `response.completed` 或 `response.incomplete` 事件,之后一行 `[DONE]` | `event: response.failed` 事件,`response.error` 带 `code` 与 `message` | **未收到正常结束标志即结束的流,一律按失败处理。** 上下文超长例外:`/responses` 的流式调用无论在开流前还是开流后判定超长,均返回 HTTP 200 与 `response.failed` 事件(`response.error.code` 为 `context_length_exceeded`),Codex 只在收到该事件时压缩对话。非流式调用仍返回 HTTP 400。 流中错误帧的 `code` 只取原厂可识别的值,平台码仍在 `scirouter_code`: | 流中的 `code` | 对应情况 | |---|---| | `rate_limit_exceeded` | 限流与上游满载 | | `insufficient_quota` | 配额类错误 | | `server_is_overloaded` | 带 `Retry-After` 的 503 | | `server_error` | 其余 5xx | | `context_length_exceeded` 等 | 上游语义错误,见[上游语义错误](#上游语义错误) | ## 未知路径 请求 `/v1` 下不存在的路径(如 `/v1/completions`)时返回 404,错误体为站内接口的格式(大写的 `NOT_FOUND`),与本页其他错误体不同。官方 SDK 同样抛出「未找到」异常。出现该错误时检查请求路径与 `base_url`,确认没有多写或少写一段 `/v1`。 --- # 缓存与幂等 > 提示词缓存与响应缓存的命中条件、请求头与计费,以及用 Idempotency-Key 避免重试重复扣费。 来源:https://www.scirouter.cn/docs/caching · 更新于 2026-10-23 SciRouter 上有两层缓存,作用不同: | 项目 | 上游提示词缓存 | SciRouter 响应缓存 | |---|---|---| | 缓存位置 | 模型厂商 | SciRouter 网关 | | 命中条件 | 请求开头一段与之前的请求相同 | 整个请求与之前的请求完全相同 | | 计费 | 命中部分按较低的缓存命中价计费,模型仍会推理 | 不调用模型,不计费 | | 调用方操作 | 多数情况无需操作;单轮批量调用见[单轮批量调用](#单轮批量调用) | 对话将 `temperature` 设为 0 即自动缓存;其他情况带请求头 | ## 上游提示词缓存 同一段长前缀(系统提示、参考文档、工具定义)重复发送时,上游会缓存该前缀。命中部分按模型详情页的缓存命中价计费,通常远低于输入价。 部分上游首次写入缓存时按缓存写入价计费,略高于输入价,之后几轮的命中可抵消这部分差价。Anthropic 协议的 1 小时缓存写入单独计价(`cache_write_1h_input_tokens`,通常更贵):模型未单独定价时按缓存写入价计,缓存写入价也未设置时按输入价计。模型未单独设置缓存价时,对应部分按输入价计费。 网关在以下两种上游上自动处理缓存: | 上游类型 | 网关行为 | |---|---| | 需要显式标记缓存位置 | 输入较长(约 1000 token 起)且为多轮对话(system 之外至少两条消息)时,在工具定义、系统提示、上一轮末尾与最后一块内容上加标记 | | 支持缓存分组键 | 计算分组键后发送。默认按 API Key 隔离;请求带 `prompt_cache_key` 时使用该键,仍按账号隔离 | ### 用量与计费 | 位置 | 内容 | |---|---| | `usage.prompt_tokens_details.cached_tokens` | 命中缓存的输入 token 数 | | `usage.prompt_tokens_details.cache_write_tokens` | 写入缓存的输入 token 数,仅在有写入时返回 | | 响应体 `scirouter.prompt_cache` | 单次调用的缓存明细,见[可观测性](https://www.scirouter.cn/docs/observability) | | 控制台[用量页](https://www.scirouter.cn/console/usage)的「上游缓存命中」一栏 | 一段时间内的命中率、命中与写入的 token 数、命中节省的配额 | 走 OpenAI 兼容入口时,`usage` 由上游原样返回;个别兼容服务只在顶层返回 `prompt_cache_hit_tokens`,两种写法均按其计费。 命中部分按缓存命中价计费,写入部分按写入价计费,均不免费。用量页的命中率 = 命中 ÷ 全部输入 token(普通输入、命中与两种写入之和)。 ### 单轮批量调用 一批请求共用同一段很长的系统提示、但每条只有一个问题时,网关不自动加标记。在需要缓存的内容段上加 `cache_control`: ```json { "model": "YOUR_MODEL_ID", "messages": [ { "role": "system", "content": [ { "type": "text", "text": "(很长的评测规则与参考资料…)", "cache_control": { "type": "ephemeral" } } ] }, { "role": "user", "content": "第 17 题:…" } ] } ``` - 同一请求最多保留 4 个标记,超出时保留最后 4 个。 - 需要标记的线路按标记缓存;其他线路按线路画像保留或去掉该字段(自动缓存的上游一律去掉,不影响缓存效果)。 - Anthropic 格式的请求经转换时,断点同样按画像带或不带,见 [Messages](https://www.scirouter.cn/docs/messages)「请求的转发方式」。 - 上游明确不支持该字段时,平台去掉后重发(响应头 `X-SciRouter-Param-Actions` 中为 `healed=cache_control`),调用方不会收到 400,见[参数如何被处理](https://www.scirouter.cn/docs/params)。 ### 提高命中率 将不变的内容放在前面,变化的内容放在后面。系统提示开头写入当前时间、随机 id 等内容时,每次请求的前缀都不同,无法命中。 ## SciRouter 响应缓存 对话的 `temperature` 显式为 0 时自动缓存:1 小时内完全相同的请求,第二次起直接返回上一次的结果,无需带请求头。对话接口的缓存规则: | 条件 | 缓存行为 | |---|---| | `temperature` 显式为 0,未带 `X-SciRouter-Cache` | 缓存 | | 带 `X-SciRouter-Cache: enabled` | 缓存,不论 `temperature` 取值 | | 带 `X-SciRouter-Cache: disabled` | 本次不缓存 | | 未写 `temperature`(或不为 0),且未带请求头 | 不涉及缓存 | 向量接口(`/embeddings`)默认缓存,且按条缓存,见[向量按条缓存](#向量按条缓存)。不需要时带 `X-SciRouter-Cache: disabled`。 以下示例带请求头,不依赖 `temperature`: ```bash curl https://api.scirouter.cn/v1/chat/completions \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "X-SciRouter-Cache: enabled" \ -d '{ "model": "YOUR_MODEL_ID", "temperature": 0, "messages": [{"role": "user", "content": "列出这段序列里所有的跨膜区段"}] }' ``` ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") response = client.chat.completions.create( model="YOUR_MODEL_ID", temperature=0, messages=[{"role": "user", "content": "列出这段序列里所有的跨膜区段"}], extra_headers={"X-SciRouter-Cache": "enabled"}, ) ``` 适用场景:批量评测反复运行同一套题、向量化含重复文本的批次、开发时反复调试同一请求。要求每次重新生成的场景不适用:命中时返回的回答与首次完全相同。 带 `X-SciRouter-Cache: enabled` 时不论 `temperature` 取值都缓存;温度不为 0 时,之后每次得到的都是首次那一份随机结果。 ### 请求头 | 请求头 | 取值 | 说明 | |---|---|---| | `X-SciRouter-Cache` | `enabled` / `disabled` | 开启或关闭本次请求的缓存。对话 `temperature` 显式为 0 时不带该请求头也开启 | | `X-SciRouter-Cache-TTL` | 正整数(秒) | 本次结果的保存时长。对话默认 1 小时、向量默认 24 小时;超过上限(默认 24 小时)时按上限计 | | `Cache-Control` | `no-cache` | 不读取旧结果,调用模型后用新结果覆盖缓存 | | `Cache-Control` | `no-store` | 本次既不读取也不写入 | `X-SciRouter-Cache` 不是上述两个取值、`X-SciRouter-Cache-TTL` 不是正整数时,请求直接返回 400。`Cache-Control` 的其他取值(如 `max-age`)被忽略。 ### 命中状态 响应头 `X-SciRouter-Cache` 的取值: | 取值 | 含义 | |---|---| | `HIT` | 来自缓存,未调用模型,不扣配额 | | `MISS` | 未命中,正常调用并计费;成功的结果会被缓存 | | `PARTIAL` | 仅向量接口:一批输入中部分命中,只有未命中的条目发给模型并计费,见[向量按条缓存](#向量按条缓存) | | `BYPASS` | 本应走缓存,但调用方要求不读取(`Cache-Control: no-cache` / `no-store`,或对向量、`temperature` 为 0 的对话带 `X-SciRouter-Cache: disabled`),或请求形状不可缓存,见[不缓存的情况](#不缓存的情况) | | 无该响应头 | 本次不涉及缓存。例如对话未带 `X-SciRouter-Cache: enabled`,且 `temperature` 不是显式的 0(对话只带 `Cache-Control` 或 `disabled` 不会开启缓存) | 其他相关的响应头与响应体字段: | 响应头 / 字段 | 说明 | |---|---| | `X-SciRouter-Cache-Age` | 命中时返回:该结果产生至今的秒数 | | `X-SciRouter-Cache-TTL` | 结果将被保存时返回:实际保存的秒数。请求的时长超过上限时为截断后的值 | | `scirouter.cache`、`scirouter.cache_age_s`、`scirouter.cache_ttl_s` | 与上述响应头的结论相同,取值小写 | | `scirouter.saved_quota` | 命中时返回:按当前倍率计算的节省配额 | | `scirouter.cache_items` | 仅向量接口:`{"hit": 命中条数, "total": 总条数}` | 流式响应在 `data: [DONE]` 之前、`choices` 为空的扩展分片中也带这些字段。排队较久、心跳已先发出响应头时,响应头中不带这些信息,以扩展分片或请求日志为准。 命中时响应中的 `usage` 是首次调用的真实用量(与无缓存时相同),但本次不扣费;本次消耗见 `scirouter.cost_quota`(命中时为 0)。控制台[请求日志](https://www.scirouter.cn/console/logs)中命中的记录带「缓存」标记,token 与费用记为 0;用量页的请求数、Tokens、配额均不含命中,命中次数单独列在「缓存命中」。 ### 相同请求的判定 按规范化之后的请求体比较: - 键的顺序、空白、`1` 与 `1.0` 等写法差异不影响比较; - `stream`、`stream_options`、`user`、`safety_identifier`、`metadata`、`prompt_cache_key`、`store` 不参与比较。流式与非流式共用一份缓存,非流式保存的结果也可以流式回放; - `max_completion_tokens` 与 `max_tokens` 视为同一参数,`n: 1` 与不写相同; - 其余任何字段不同(更换模型、修改一个标点、`temperature` 不同)均视为另一个请求。 ### 向量按条缓存 向量接口按每一条输入分别缓存,不按整批缓存:同一段文字无论出现在哪一批、排在第几条,都能命中。一批中只有部分命中时(`PARTIAL`),网关只将未命中的条目发给模型,再按原顺序拼回。计费只计发给模型的条目,命中部分记为节省的配额(`scirouter.saved_quota`);响应中的 `usage` 仍为整批输入的 token 数。 ### 不缓存的情况 - 要求多个候选(`n` 大于 1)或逐 token 概率(`logprobs` / `top_logprobs`)的对话:回放无法提供这些内容,响应头为 `BYPASS`; - 带平台托管工具的请求(结果随网页内容变化); - 失败的调用,以及未正常结束的回答:只保存 `finish_reason` 为 `stop` / `tool_calls` 且有内容的结果,被截断(`length`)、被过滤(`content_filter`)或内容为空的均不保存; - 过大的结果:对话单条超过 256 KB,或向量中单条输入的结果超过 2 MB(按压缩前的大小计); - 缓存服务自身故障时,一律按未命中处理,调用照常进行。 ### 隔离与计费 - 缓存按 API Key 隔离:同一账号下的不同 Key 互相看不到对方的缓存。 - 命中计入每分钟请求数(RPM),不计入每分钟 token 数与并发;命中不扣配额,因此不受 Key 月度上限、项目预算与套餐每日上限的约束。 - 平台更换该模型背后的上游,或管理员清空该模型的缓存后,旧结果不再命中。 - 响应缓存只作用于 `/v1` 的调用;Playground 与 Chat 不使用响应缓存。 ## 幂等 网络抖动时客户端可能重试。为避免一次重试产生两次计费,在请求中带调用方自行生成的 `Idempotency-Key`: ```python import os import uuid from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") key = str(uuid.uuid4()) # 同一个逻辑请求的所有重试用同一个值 response = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "帮我判断这段序列的二级结构倾向"}], extra_headers={"Idempotency-Key": key}, ) ``` `/chat/completions`、`/messages`、`/responses` 与 `/embeddings` 支持该请求头。键最长 128 字节,按 API Key 隔离,各接口各自独立,保留 24 小时。下表与下方说明适用于这四个接口;图片接口同样接受该请求头,但按规整后的请求判定,`b64_json` 与流式的结果不保存,规则见[图片](https://www.scirouter.cn/docs/images)「幂等」。 | 情况 | 结果 | |---|---| | 同一个键、同一个请求体 | 直接返回首次的响应体,带响应头 `Idempotent-Replayed: true`,不再调用模型、不再计费 | | 首次请求尚未处理完,同一个键再次请求 | 409 `idempotency_conflict` | | 同一个键、不同的请求体 | 409 `idempotency_conflict`,通常是代码将键复用到了其他请求 | | 首次请求失败(非 2xx) | 不保存,可用同一个键修正后重试 | | 首次请求被客户端先断开 | 服务端取消该次调用、不保存结果;**之后同一个键的重试会重新调用模型并照常计费** | | 流式请求 | 流未结束时,同一个键的重试返回 409;流结束后,同一个键重新执行一次并照常计费。流式结果无法重放 | - 请求体按原始字节比较。重试时发送完全相同的字节(SDK 的自动重试即如此);重新拼接 JSON 导致键的顺序变化时返回 409。 - 重放的响应体中 `scirouter.request_id` 仍为首次的编号,按它查询日志。`X-SciRouter-*` 与 `x-ratelimit-*` 响应头不重放,重放也不产生新的日志记录。 - 两种 409 的 `code` 相同,只有 `message` 不同。确定是重试同一个请求时,退避等待后再试,并设次数上限。 - 客户端超时应长于模型的正常耗时;回答可能很长时使用流式。 - 幂等存储自身故障时平台放行请求,不拒绝;极少数情况下可能重复执行一次。 幂等与响应缓存相互独立:幂等只识别调用方提供的键,保证同一个请求只计费一次;响应缓存按请求内容识别,使不同时间发出的相同请求共用结果。两者可同时使用。 --- # 可观测性 > 响应头与扩展字段、控制台日志与用量、调用告警与 webhook,以及 OpenTelemetry 链路导出。 来源:https://www.scirouter.cn/docs/observability · 更新于 2026-10-25 SciRouter 在响应头与响应体中返回单次调用的实际情况,在控制台请求日志中提供完整的时间线与尝试明细。这些都是 OpenAI 格式之外的附加项,官方 SDK 忽略不认识的字段,调用方无需修改代码。 ## 响应头 非流式响应(对话补全、Messages 与向量)带下列响应头。流式响应只带 `X-Request-Id`、`X-SciRouter-Cache` 与限额响应头(表中注明流式也发出的除外);其余各项在调用结束后才能确定,放在流末尾的扩展分片中,见[响应体的 scirouter 字段](#响应体的-scirouter-字段)。 | 响应头 | 说明 | |---|---| | `X-Request-Id` | 本次调用的编号,始终由服务端生成,不沿用请求中携带的值。报障时提供该值,平台据此定位单次调用 | | `request-id` | 与 `X-Request-Id` 取值相同(Anthropic SDK 读取该名称),`/v1` 的每个响应都带 | | `X-SciRouter-Model` | 实际提供服务的模型 id | | `X-SciRouter-Provider` | 实际提供服务的厂商 id。同一模型可能接入多个厂商的线路,失败时自动转移 | | `X-SciRouter-Attempts` | 上游尝试总数(含跳过的线路)。值为 `2` 及以上表示发生过自动转移;费用只按最终成功的一次结算 | | `X-SciRouter-Upstream-Request-Id` | 厂商返回的请求 id,厂商未返回时不带。向厂商提交工单时用于对账 | | `X-SciRouter-Cost-Quota` | 本次消耗的配额,命中缓存时为 0。流式响应头在正文之前发出,此时消耗未知;流式调用的消耗见末尾扩展分片中的 `scirouter.cost_quota` | | `X-SciRouter-Cache` | `HIT`、`MISS`、`PARTIAL`(仅向量)或 `BYPASS`;另有 `X-SciRouter-Cache-Age`、`X-SciRouter-Cache-TTL`,见[缓存与幂等](https://www.scirouter.cn/docs/caching) | | `X-SciRouter-Variant-Switch` | 请求带了会改变计价档位的参数、被自动改用模型变体时返回;值为触发的参数,以逗号分隔。目前只出现在 `/messages`,流式响应同样在正文之前发出,见 [Messages(Anthropic 格式)](https://www.scirouter.cn/docs/messages) | | `X-SciRouter-Max-Tokens-Clamped` | Messages(Anthropic 格式)的 `max_tokens` 超过模型或套餐的单次上限、平台按上限发出时返回,格式为 `requested=…; effective=…; limit=model`(套餐的上限更小时为 `limit=plan`)。流式响应同样在正文之前发出 | | `X-SciRouter-Param-Actions` | 有参数被平台去掉、翻译、模拟、整形或自愈时返回,如 `dropped=seed,top_k; translated=reasoning(xhigh→high); emulated=response_format`。五组固定顺序,超过 512 字节截断。三种格式均返回,流式响应同样在正文之前发出。各参数的处理见[参数如何被处理](https://www.scirouter.cn/docs/params) | ### 限额响应头 限额响应头与 OpenAI 同名,SDK 已有的退避逻辑可直接识别: | 响应头 | 说明 | |---|---| | `x-ratelimit-limit-requests` | 每分钟请求数上限 | | `x-ratelimit-remaining-requests` | 每分钟请求数余量 | | `x-ratelimit-reset-requests` | 距当前窗口结束的时长,如 `42s` | | `x-ratelimit-limit-tokens` | 每分钟 token 数上限 | | `x-ratelimit-remaining-tokens` | 每分钟 token 数余量 | | `x-ratelimit-reset-tokens` | 距当前窗口结束的时长 | - 余量按 Key 与账号两级中较小的一级返回。没有限额时不返回这组响应头。 - 流式响应的限额响应头在第一个分片之前写入。例外:排队较久、心跳已先发出响应头时,这组响应头与 `X-SciRouter-Cache` 均不带。 - 被限频的 429 响应仍带 `Retry-After` 与 `error.details.retry_after_seconds`。 - 浏览器跨源调用时,上述响应头均列在 `Access-Control-Expose-Headers` 中,`fetch` 可以读取。 ## 响应体的 `scirouter` 字段 非流式响应的顶层多一个 `scirouter` 对象: ```json { "id": "chatcmpl-…", "choices": [], "usage": {}, "scirouter": { "request_id": "req_…", "model": "YOUR_MODEL_ID", "provider": "…", "cost_quota": 18240, "cache": "miss", "attempts": 2, "upstream_request_id": "…", "timings": { "queue_wait_ms": 830, "ttfb_ms": 412, "total_ms": 5688 } } } ``` 数值为示例,`choices` 与 `usage` 省略了内容。 | 字段 | 说明 | |---|---| | `timings.queue_wait_ms` | 在线路容量队列中等待的时长,未排队时为 0。该段耗时表示厂商分配的容量已满,与模型推理速度无关 | | `timings.ttfb_ms` | 成功的那次尝试从发出到收到上游首字节的时长;未到达上游时为 `null` | | `timings.total_ms` | 端到端总耗时 | 以下字段按需返回: | 字段 | 说明 | |---|---| | `saved_quota`、`cache_age_s`、`cache_ttl_s`、`cache_items` | 响应缓存相关,见[缓存与幂等](https://www.scirouter.cn/docs/caching) | | `tool_rounds`、`tool_calls` | 使用平台托管工具时返回,见 [MCP 与托管工具](https://www.scirouter.cn/docs/mcp) | | `variant_switch` | `{from, to, params}`,自动改用模型变体时返回 | | `max_tokens_clamped` | `{requested, effective, limit}`,Messages 的输出上限被按上限发出时返回 | | `param_actions` | `{dropped, translated, emulated, reshaped, healed}`,各项为参数名列表,与响应头 `X-SciRouter-Param-Actions` 内容相同 | | `schema_valid` | 结构化输出经平台模拟、且带 `X-SciRouter-Validate-Schema: 1` 时返回,表示正文是否符合 schema | | `finish_detail` | 值为 `repetition` 时表示模型陷入复读、平台中断了上游,此时 `finish_reason` 为 `length` | | `prompt_cache` | `{read, write, write_1h, saved_quota}`:命中上游提示词缓存、写入 5 分钟缓存、写入 1 小时缓存的输入 token 数,`saved_quota` 为命中节省的配额。未到达上游或四项均为 0 时不返回 | | `endpoint_provider` | `provider` 的旧名,取值相同。新代码读取 `provider` | `param_actions`、`schema_valid`、`finish_detail` 的规则见[参数如何被处理](https://www.scirouter.cn/docs/params)。 提示词缓存的命中部分按缓存命中价计费、写入部分按写入价计费,节省的配额不并入 `cost_quota`。一段时间内的命中率见控制台[用量页](https://www.scirouter.cn/console/usage)的「上游缓存命中」一栏,统计口径见[缓存与幂等](https://www.scirouter.cn/docs/caching)。 ### 流式响应的扩展分片 流式响应在 `data: [DONE]` 之前多一个 `choices` 为空的分片,带同一个 `scirouter` 字段。该分片的形状与 OpenAI 最后一个 usage 分片相同,SDK 均可识别: ```text data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[{"delta":{"content":"…"},…}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":…,"model":"…","choices":[],"scirouter":{"request_id":"req_…","attempts":1,…}} data: [DONE] ``` 其中 `cost_quota` 为本次的准确消耗。上游未输出任何分片即结束的流不带该分片;流开始后出错时,最后一个分片为 `{"error": {…}}`,没有扩展分片,也没有 `[DONE]`。 ## 请求日志 控制台 `/console/logs` 可按 `request_id` 查询单条记录,也可按结束原因、来源、慢请求、缓存命中、调用格式(OpenAI / Anthropic)、错误码与自定义时间区间(最长 90 天)筛选。同一个 Key 同时供 OpenAI SDK 与 Claude Code 使用时,可按调用格式分开查看。 每条记录可展开为调用详情: | 部分 | 内容 | |---|---| | 时间线 | 准入 → 路由 → 排队 → 每次尝试 → 上游首字节 → 推流 → 结算,未发生的阶段不显示。两个首字节(平台发给调用方的 / 上游返回的)各有一条标记线,差值为 SciRouter 侧的耗时 | | 路由 | 实际厂商、每次尝试的结果与耗时 | | 诊断提示 | 只解释已有的事实:被 `max_tokens` 截断、主要耗时在排队、发生过转移、用量为估算、客户端中途断开 | | 复制报障信息 | 将 `request_id`、时间、模型、错误码、厂商请求 id 汇总为一段文本,用于报障 | ## 归因标签 一个 Key 下运行多个实验时,账单只能按 Key 区分。在请求体中带 OpenAI 原生的 `metadata` 字段(字符串键值对),每次调用即带上自定义的归因标签: ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "…"}], metadata={"exp": "abc", "run": "12"}, user="researcher-42", ) ``` ```typescript import OpenAI from 'openai' const client = new OpenAI({ apiKey: process.env.SCIROUTER_API_KEY, baseURL: 'https://api.scirouter.cn/v1' }) await client.chat.completions.create({ model: 'YOUR_MODEL_ID', messages: [{ role: 'user', content: '…' }], metadata: { exp: 'abc', run: '12' }, user: 'researcher-42', }) ``` | 项目 | 规则 | |---|---| | 键的数量 | 最多 8 个 | | 键 | 1–32 个字符,只含小写字母、数字、`_`、`.`、`-` | | 值 | 字符串,最长 64 个字符,不能含控制字符(换行、制表符等) | | 超出限制 | 返回 400 | | `user`(`/v1/messages` 为 `metadata.user_id`) | 超过 512 个字符时截断保存,不报错 | - `metadata` 与 `user` 不转发给模型厂商,只记录在控制台日志中。 - 日志页可按标签筛选(`?tag=exp:abc`,点击记录上的标签即可);用量页可按标签分组查看花费、错误率与截断率(窗口不超过 30 天)。 - 站内对话(Chat)的每次调用自动带 `chat_session` 标签,值为会话 id:日志页可从一条消息跳转到对应调用,也可筛选出一场对话的全部调用。 - `session_id` 是保留键:取值相同的调用归入同一个会话,控制台按会话列出各条执行链路,导出时也带该值,见[会话 id](#会话-id)。 ## 用量页 控制台 `/console/usage` 可按模型、Key、项目、来源、状态、标签分组,查看请求数、Tokens、配额、错误率与截断率;按模型分组时另有 P50 / P95 延迟。开启「与上期对比」后,上一个等长窗口画在同一张图上。窗口可选近 24 小时、7 天、30 天、90 天,或自定义区间(最长 90 天)。 团队工作区还可按成员分组。统计口径: - 请求数不含响应缓存命中。命中单独计数,这些调用未调用模型、不计费。 - 延迟分位只在按模型分组时提供。分位数不能跨模型合并,按其他维度分组时表中没有 P50 / P95 两列,图上也不能选择 P95,表格上方有说明。 ## 实时限额 控制台概览页的「实时」卡每 10 秒刷新一次,显示: - 每分钟请求数与每分钟 token 数在当前窗口的用量(与 `x-ratelimit-*` 响应头为同一组读数); - 同时进行的模型调用数; - 同时运行的 agent 数; - 正在进行的请求; - 近 1 小时的错误。 agent 指 Chat 的一轮、课题的一步或研读的一次生成,一个 agent 可能同时调用多次模型。agent 数已满时新的 agent 排队,不报错。 在团队工作区中,卡片显示团队的限额:在团队工作区发起的调用(包括团队项目下的 Key)按团队限额计、成员共用,不占个人限额。进行中的请求与错误只列出当前用户自己的。 程序中读取同一组读数,使用每次响应的 `x-ratelimit-*` 响应头。 ## 导出 日志页的「导出当前筛选」将当前筛选的记录导出为 CSV(UTF-8 BOM,Excel 可直接打开)或 JSON Lines。单次上限 50 000 行;超过时先提示命中条数并要求缩小范围,不导出部分结果。 - 文件中不含提示词、返回片段与请求参数。 - 包含已打码的来源 IP、`user`、标签、`saved_quota`、调用格式 `api_format` 等列;列顺序固定,新列只追加在末尾。 - 时间列按账号设置的显示时区输出,列名中注明时区(如 `created_at (Asia/Shanghai)`)。 ## 调用告警 账号页「通知」中有五项调用告警,默认开启,选择通知渠道后即发送。每 5 分钟检查一次: | 通知项 | 触发条件 | 冷却 | |---|---|---| | 错误率飙升 | 单个 Key 近 15 分钟的错误(不含限频)超过 20%,且样本 ≥ 20 | 每个 Key 1 小时 | | 延迟劣化 | 单个模型近 15 分钟的 P95 比近 7 天基线高出一倍以上,且样本 ≥ 20 | 每个模型 1 小时 | | 频繁被限频 | 近 15 分钟 429 ≥ 30 次 | 1 小时 | | 配额即将耗尽 | 按近 24 小时的消耗速度,剩余配额不足 3 天 | 24 小时 | | 回答频繁被截断 | 单个模型近 1 小时被 `max_tokens` 截断的回答超过 30%,且样本 ≥ 20 | 每个模型 24 小时 | 告警正文只含数字与名称,不含链接;每条写明应查看控制台的哪一页。 ## 通用 webhook 通知渠道除企业微信、飞书、Bark 外,还可以是自有的 https 地址(须为公网地址;本机与内网地址被拒绝)。渠道创建时显示一次签名密钥(`whsec_…`),之后无法读回;更换密钥须删除渠道后重建。 每条提醒以一次 JSON POST 发送: ```json { "id": "whd_01HZX…", "event": "error_rate_spike", "scope": "user", "subject": "错误率飙升", "text": "…纯文本…", "markdown": "…Markdown…", "data": { "key": "生产", "percent": "35", "requests": "40", "errors": "14", "topCode": "UPSTREAM_ERROR", "window": "15 分钟", "site": "SciRouter", "time": "2026-09-22 10:30" }, "site": "SciRouter", "time": "2026-09-22T02:30:00Z" } ``` | 请求头 | 取值 | 说明 | |---|---|---| | `X-SciRouter-Event` | 通知项 id;试发时为 `test` | 事件类型 | | `X-SciRouter-Delivery` | 投递 id | 重试时不变,用于去重 | | `X-SciRouter-Signature` | `t=,v1=` | 签名,验证方法见下 | `secret` 为渠道创建时显示的完整字符串(含 `whsec_` 前缀),**直接作为 HMAC 的 key,不做 base64 解码**。`v1` 为以 `secret` 为 key、对 `{t}.{原始请求体}` 计算的 HMAC-SHA256 十六进制值。验签示例: ```python import hashlib import hmac import time def verify(secret: str, raw_body: bytes, signature: str) -> bool: parts = dict(item.split("=", 1) for item in signature.split(",")) t, v1 = parts["t"], parts["v1"] expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, v1) and abs(time.time() - int(t)) < 300 ``` - 接收端返回任意 2xx 即视为成功;5 秒未响应或返回非 2xx 时再重试 3 次(分别在 0.5、1、2 秒后)。 - 连续失败 10 次后渠道自动停用,原因记录在渠道的「上次失败」中;修复地址后重新启用即可。此处的「一次」指一条提醒的完整投递(含 3 次重试);投递成功即清零,24 小时内没有新的失败也重新计数。 - `data` 中的键与通知模板的变量同名,后台修改模板不影响 `data`。 ## Prometheus 指标 自部署时,网关的 `/metrics` 提供调用指标。对外经 nginx 访问时返回 404,只供内网抓取;生产环境须配置 Basic Auth,用户名默认为 `collector`。 | 指标 | 标签 | |---|---| | `scirouter_request_duration_seconds` | `model`、`source`、`status` | | `scirouter_request_ttfb_seconds` | `model`、`source` | | `scirouter_tokens_total` | `model`、`direction` | | `scirouter_attempts_total` | `provider`、`outcome` | | `scirouter_ratelimited_total` | `scope` | | `scirouter_finish_reason_total` | `model`、`reason` | 另有提示词缓存与响应缓存的计数。标签只到模型、厂商、来源、状态一级,不含用户与 Key。后端仓库附带一份 Grafana 面板(`server/scirouter/scripts/grafana/scirouter.json`)。按用户或按 Key 查看时,使用控制台的用量页与日志页。 ## 链路导出 日志中的一条记录对应一次调用。Chat 的一轮、课题与研读的一次运行、`/v1` 的托管工具循环通常包含多次模型调用以及其间的工具、检索与等待,平台将其记录为一条执行链路:以运行为根的树,每个节点有起止时刻、结局与用量。 添加导出目的地后,这些链路以 OTLP/HTTP JSON 发送到调用方自有的 Langfuse 或任意 OpenTelemetry 后端,与应用自身的链路一起查看。 ### 添加目的地 | 配置位置 | 配置者 | 导出的链路 | 可带正文 | |---|---|---|---| | 控制台侧栏「[链路导出](https://www.scirouter.cn/console/trace-destinations)」 | 用户本人 | 个人工作区内的:个人 Key 的 `/v1` 调用,个人工作区内的 Chat、课题、研读 | 可以(默认关闭) | | 团队详情中的「链路导出」 | 团队 owner / admin(成员不可见) | 该团队工作区内的,含团队项目下的 Key 发起的 `/v1` 调用 | 不可以 | 平台运维另在管理后台配置平台级目的地,导出全部链路的元数据,不带正文。每个目的地的配置项: | 配置项 | 说明 | |---|---| | 地址 | OTLP/HTTP 的基地址,导出时请求 `POST {地址}/v1/traces`。只接受 https、端口 443、公网可达的地址;地址中不能含用户名与密码,也不能含 `?` 或 `#` | | 类型 | `langfuse` 或 `otel`。`langfuse` 另加请求头 `x-langfuse-ingestion-version: 4` 与 Langfuse 识别的若干属性,见[导出内容](#导出内容) | | 鉴权 | 不鉴权、Basic(用户名与凭据)、Bearer、自定义请求头(请求头名与凭据)。凭据加密保存,保存后无法读回;地址改到另一台主机时须重新填写凭据,已保存的凭据不会发往新地址 | | 采样率 | 0–1,默认 1(全部导出),见[采样、重试、停用与测试](#采样-重试-停用与测试) | | 带上内容 | 默认关闭,只有个人目的地可以开启,见[导出内容](#导出内容) | 个人默认最多配置 3 个目的地,每个团队最多 5 个。 ### Langfuse 1. 在 Langfuse 项目的 Settings → API Keys 中新建一对 key:public key(`pk-lf-…`)与 secret key(`sk-lf-…`)。 2. 在「链路导出」中添加目的地,按下表填写: | 配置项 | 取值 | |---|---| | 类型 | `langfuse` | | 地址 | Langfuse Cloud 欧洲区 `https://cloud.langfuse.com/api/public/otel`,美国区 `https://us.cloud.langfuse.com/api/public/otel`;自托管填 `https://<域名>/api/public/otel` | | 鉴权 | Basic(`langfuse` 类型只支持 Basic):用户名填 public key,凭据填 secret key | 3. 点击「测试」。成功时 Langfuse 中出现一条名为 `scirouter connectivity test` 的链路。 自托管的 Langfuse 同样须使用 https、端口 443 且公网可达;只在内网可达的实例无法连接。 ### 其他 OpenTelemetry 后端 类型选择 `otel`,地址填写后端 OTLP/HTTP 接收端的基地址(不含 `/v1/traces`,平台自动追加): | 后端 | 地址 | 鉴权 | |---|---|---| | 自建 OpenTelemetry Collector(再转发给 Jaeger、Tempo 等) | 接收端对外的 https 地址,如 `https://otel.example.org` | 按 Collector 的配置:`bearertokenauth` 扩展对应 Bearer,`basicauth` 对应 Basic | | Jaeger | OTLP/HTTP 接收端对外的 https 地址 | 按前置反向代理的要求填写 | | Honeycomb | `https://api.honeycomb.io`(欧洲区 `https://api.eu1.honeycomb.io`) | 自定义请求头:请求头名 `x-honeycomb-team`,凭据填 Honeycomb 的 API Key | - 平台只发送 OTLP/HTTP 的 JSON 编码,不使用 gRPC;接收端须接受 `application/json`(Collector 与 Jaeger 的 OTLP 接收端均支持)。 - Collector 与 Jaeger 的 OTLP/HTTP 接收端默认使用 4318 端口与明文 http,平台只连接 https 的 443 端口:须在前面加一层 https 反向代理,或为接收端配置证书并监听 443。 - 单次发送的请求体默认不超过 4 MiB,接收端的请求体上限须大于该值。 ### 导出内容 一条链路是 trace id 相同的一组 span,每个节点对应一个 span: | 节点 | span 名 | `gen_ai.operation.name` | Langfuse 类型 | |---|---|---|---| | 运行:Chat 的一轮、课题 / 研读的一次运行、`/v1` 托管工具循环的根(`v1_tool_loop`) | `invoke_agent {名字}` | `invoke_agent` | agent | | 步骤 | `invoke_agent {步骤种类}` | `invoke_agent` | agent(主 agent)/ chain(其余) | | 模型调用 | `chat {模型 id}` | `chat` | generation;验收评审的调用为 evaluator | | 检索 | `execute_tool {名字}` | `execute_tool` | retriever | | 工具、沙箱、MCP、读技能、读回原文、留言 | `execute_tool {名字}` | `execute_tool` | tool | | 等待:排队等名额、撞沙箱闸放回、等待用户回答 | `wait {名字}` | 无 | span | | 截断标记:该链路记录的节点数已达上限,之后的节点不再记录 | `marker truncated` | 无 | event | - 重试、换模型、续写、压缩、退回队列不单独成为 span,记为所在节点上的 span event(事件名为 `retry`、`fallback`、`continue`、`compaction`、`requeue` 或 `other`;能对应到某次调用时带该调用的 `scirouter.request_id`)。 - 模型调用的 span kind 为 CLIENT,其余为 INTERNAL;出错节点的 status 为 ERROR,消息为错误码。 - resource 只有 `service.name = scirouter`;instrumentation scope 为 `scirouter.traceexport`,版本为 `gen-ai-dev/1.42.0-dev`。属性名遵循 OpenTelemetry GenAI 语义约定的该版本;该约定处于 Development 阶段,上游改名时平台同步修改,scope 的版本号标明所用版本。 每个节点都有的属性: | 属性 | 说明 | |---|---| | `gen_ai.operation.name` | 见上表;等待与截断标记没有该属性 | | `gen_ai.conversation.id` | 会话 id:Chat 会话、课题、论文,或 `/v1` 的 `metadata.session_id`;不属于任何会话时没有该属性 | | `scirouter.trace.kind` | `chat` / `campaign` / `paper` / `api` | | `scirouter.node.type` | `run` / `step` / `generation` / `tool` / `retrieval` / `sandbox` / `mcp` / `skill` / `recall` / `post` / `wait` / `marker` | | `scirouter.status` | `ok` / `error` / `cancelled` / `skipped`;运行收尾时仍未结束的节点为 `running` | | `scirouter.error_code` | 出错时的错误码 | 按节点类型另有的属性: | 节点 | 属性 | |---|---| | 模型调用 | `gen_ai.provider.name`(厂商 id,没有时为 `scirouter`)、`gen_ai.request.model`、`gen_ai.usage.input_tokens`、`gen_ai.usage.output_tokens`、`gen_ai.usage.cache_read.input_tokens`(命中提示词缓存的部分,大于 0 时才有)、`gen_ai.response.finish_reasons`;`scirouter.request_id`(控制台日志可按它查到该次调用)、`scirouter.cost_quota`、`scirouter.attempts`、`scirouter.provider`、`scirouter.purpose`(`turn` / `review` 验收评审 / `compaction` 压缩摘要 / `other`)、`scirouter.first_token_ms` | | 工具类 | `gen_ai.tool.name`;`scirouter.cost_quota`(工具自身按次的花费,有时才返回);`scirouter.tool.<键>`:只含白名单中的计数、布尔值与短枚举,即 `argsBytes`、`resultChars`、`results`、`sources`、`papers`、`reused`、`prefetched`、`gated`、`empty`、`sandboxStatus`、`wallMs`、`timeout`、`exitCode`、`round`、`rounds`、`toolCalls`、`failure` | | 运行、步骤 | `gen_ai.agent.name` | 类型为 `langfuse` 时,每个 span 另加: | 属性 | 说明 | |---|---| | `langfuse.observation.type` | 上文节点表中的 Langfuse 类型 | | `langfuse.trace.name` | 链路标题,如「第 3 轮对话」 | | `session.id` | 与 `gen_ai.conversation.id` 相同,Langfuse 的 Sessions 据此将多条链路归为一个会话 | | `langfuse.observation.completion_start_time` | 模型调用的首字时刻 | | `user.id` | 仅团队目的地:节点所属成员的用户 id。个人目的地不带 | trace id 与 span id 由平台的链路 id、节点 id 经 SHA-256 截取为 16 / 8 字节,同一节点每次导出的 id 相同;带 `traceparent` 的链路直接使用调用方的 trace id,见 [traceparent](#traceparent)。 正文默认不导出。节点中只有上述计数、长度与枚举,不含提示词、回答、检索词与网址。个人目的地开启「带上内容」后,模型调用另带 `gen_ai.input.messages` 与 `gen_ai.output.messages` 两个属性(按约定的消息结构序列化的字符串:输入整段记为一条 `user` 消息,输出记为一条 `assistant` 消息): - 内容取自请求日志保存的正文片段,因此只有该次调用保存了正文时才有(账号设置「数据保留」中的「保存请求与响应正文」,见[隐私](#隐私)); - 平台内部的验收评审与压缩摘要调用一律不带正文; - 单个节点带上正文后超过请求体上限时,该节点不带正文发送; - 团队与平台级目的地不能开启该选项。 导出时机: - 导出每分钟运行一轮。Chat、课题、研读的链路在整次运行结束后一次发送;`/v1` 的节点在各自结束后发送。 - 节点结束 2 分钟后才发送(等待全部落库),因此后端中看到的数据比调用晚两三分钟。 - 每个节点对每个目的地只发送一次。例外:对方已接收、平台尚未记录进度时实例恰好重启,该批会重发一次。 - 只发送归属该目的地的节点,同一条链路中其他用户的调用不会一并发出。 - 向量调用(`/embeddings`)不在链路中。 ### traceparent `/v1/chat/completions`、`/v1/messages`、`/v1/responses` 识别 W3C Trace Context 的 `traceparent` 请求头。带该请求头时,本次调用记录在调用方的 trace 之下: - 链路 id 为调用方的 trace id;本次调用(使用托管工具时为循环的根节点)的父节点为调用方的 span id。导出时两者原样使用,平台的节点挂在发起调用的 span 之下,在后端中属于同一棵树。 - 同一个 trace id 的多次请求,在控制台中也属于同一条链路。 - 只识别 version `00`:`00-<32 位小写十六进制 trace id>-<16 位小写十六进制 span id>-<2 位十六进制 flags>`。格式错误、id 全为零或带多个 `traceparent` 时视为未带,不报错;不读取 `tracestate`;flags 中的采样位不影响平台是否记录与导出。 - 未带时本次请求自成一条链路,链路 id 为本次调用的 `request_id`(托管工具循环的各轮沿用第一轮的值)。 `traceparent` 只负责关联两侧的链路。要在后端中看到完整的树,还须添加指向同一后端的导出目的地,见[添加目的地](#添加目的地)。 ```bash curl https://api.scirouter.cn/v1/chat/completions \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" \ -d '{ "model": "YOUR_MODEL_ID", "messages": [{"role": "user", "content": "…"}], "metadata": {"session_id": "notebook-42"} }' ``` Python(OpenAI SDK 与 OpenTelemetry SDK)在每次调用时用 `extra_headers` 带上当前 span: ```python import os from openai import OpenAI from opentelemetry import trace from opentelemetry.propagate import inject client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") tracer = trace.get_tracer("my-agent") with tracer.start_as_current_span("summarize-paper"): headers = {} inject(headers) # 把当前 span 写成 traceparent 头 response = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "…"}], metadata={"session_id": "notebook-42"}, extra_headers=headers, ) ``` - 整个脚本在同一个 span 下运行时,也可以在创建 client 时用 `default_headers={"traceparent": …}` 一次带上。 - 安装 OpenTelemetry 的 httpx 自动埋点(`opentelemetry-instrumentation-httpx`)后,OpenAI SDK 发出的请求自动带 `traceparent`,无需手动设置。 ### 会话 id 请求体 `metadata` 中的 `session_id` 是保留键,取值为调用方自定义的会话 id。`traceparent` 决定一条链路中节点的父子关系,`session_id` 决定多条链路是否属于同一个会话,两者可同时使用。 - 控制台:会话链路逐行列出该会话中的链路(调用次数、Token、配额、耗时,表头为整个会话的合计)。`session_id` 同时是普通的归因标签,日志页按 `session_id:<值>` 可筛选出该会话的全部调用。 - 导出:写入 `gen_ai.conversation.id`,`langfuse` 类型另写 `session.id`。 - 规则与其他标签相同,见[归因标签](#归因标签):值为字符串,最长 64 个字符,不能含控制字符,占 8 个键中的一个;格式错误时返回 400。 - `/v1/messages` 同样写在 `metadata` 中(`user_id` 之外的字符串键均视为标签);`/v1/responses` 写在其自身的 `metadata` 中。 ### 采样、重试、停用与测试 | 项目 | 规则 | |---|---| | 采样 | 按链路 id 的哈希判定,同一条链路整条导出或整条不导出 | | 失败与重试 | 对方返回 2xx 视为已接收(含 OTLP 的部分成功);连接失败、10 秒未响应、返回非 2xx 均视为失败。失败的批次不丢弃,1 分钟后重试,之后每次等待时间翻倍,最长 1 小时;成功一次后失败计数清零 | | 停用 | 连续失败 10 次后自动停用,目的地上注明原因(对方最近一次的响应,截取 300 字,凭据会被抹去)。修复后修改配置保存或重新启用:失败计数清零,从停止处继续发送;停用较久的只补发最近 24 小时的链路 | | 测试 | 用已保存的配置发送一条只含一个 span 的合成链路(span 名 `scirouter connectivity test`,属性 `scirouter.test = true`),当场返回对方的状态码、错误原因与耗时。不计入导出条数,也不改变失败计数与状态 | | 平台暂停导出 | 不能新建、不能测试;已有目的地可以查看、修改、删除,但不发送。恢复后从停止处继续发送(同样最多补发 24 小时) | ## 易误读的字段 - `finish_reason: "length"` 表示回答被 `max_tokens` 截断,与模型故障无关。需要完整回答时调大 `max_tokens`。 - `attempts` 统计的是尝试次数,不等于失败次数:`2` 可能是一次失败加一次成功,也可能是一条线路已满被跳过加一次成功。 - 首字节有两种口径。SDK 测得的首字节包含网络与边缘节点的耗时;`timings.ttfb_ms` 只计网关到上游的一段。判断模型速度以后者为准。 - 命中响应缓存(`cache: "hit"`)的调用不经过上游、不计费,`attempts` 为 0,`timings.ttfb_ms` 为 `null`。 ## 隐私 - 请求日志默认不保存提示词与返回正文。在账号设置「数据保留」中开启「保存请求与响应正文」后,之后的调用才会保存(脱敏后每段最多 16 000 字,更长的只保留开头,并在日志详情中标注)。 - **正文由平台保留 7 天后自动清空**(天数由平台策略决定,页面上显示当前值)。关闭开关只影响之后的请求,已保存的正文按期过期。 - 调用记录本身(模型、耗时、token、配额、状态、标签等)保留 90 天,到期整行删除;按小时、按天汇总的用量不受影响。 - 日志不存储在浏览器中。响应中的厂商只返回 id(控制台中显示名称),不返回接口地址与线路信息。 - 执行链路只发送到已添加的导出目的地:个人工作区的链路发往用户本人添加的目的地,团队工作区的链路发往团队 owner / admin 添加的目的地,平台级目的地只接收元数据。只有个人目的地开启「带上内容」时才带正文,见[链路导出](#链路导出)。发出后的存储方式与保存时长由接收方决定。 --- # 多厂商差异 > 兼容度标识、各入口协议下的字段生效规则、厂商专有参数、输出上限、用量与计价维度。 来源:https://www.scirouter.cn/docs/vendors · 更新于 2026-10-23 平台上的模型来自不同厂商,各厂商的原生协议不完全相同。统一入口支持三种格式: | 接口 | 格式 | |---|---| | `/v1/chat/completions`、`/v1/embeddings` | OpenAI 格式 | | `/v1/responses` | OpenAI Responses 格式 | | `/v1/messages` | Anthropic Messages 格式 | 三种格式均使用 SciRouter 的 API Key,网关调用厂商时换用平台在该厂商的凭据。`/v1` 不替换模型(响应中的 `model` 即请求的模型),只在同一模型的多条线路之间自动转移。 ## 兼容度标识 模型详情页第一屏有一行兼容度标识(模型对比页中为「接入兼容度」一行),共三种: | 标识 | 含义 | |---|---| | 「完全兼容 OpenAI 接口」 | 现有的 OpenAI 代码修改 `base_url` 与 `model` 即可使用 | | 「兼容,专有参数需放 extra_body」 | 标准字段照常使用;该厂商特有的参数按[厂商专有参数](#厂商专有参数)的方式传递 | | 「需专用调用方式」 | 经统一入口可使用 OpenAI 或 Anthropic Messages 格式;只有绕过平台直连厂商时才需要该厂商的原生协议 | 标识下方如有一行说明,为平台针对该模型写明的具体差异,以说明为准。兼容度是平台标注的说明,不改变网关的行为;哪些字段生效,由模型背后线路的入口与本次调用所走的入口决定,见[字段生效规则](#字段生效规则)。 ## 字段生效规则 模型背后的每条线路对应一个上游账号,可接入多种协议;每种协议是线路的一个入口(`openai`、`anthropic`、`gemini`、`custom`,由平台配置)。每次调用先按调用方使用的格式选择入口: | 调用格式 | 可原样处理该格式的入口 | |---|---| | OpenAI 格式 | `openai`、`custom` | | Anthropic Messages 格式 | `anthropic` | | Responses 格式 | 标记为「原生 Responses」的 `openai`、`custom` | 线路有可原样处理该格式的入口时走该入口;没有时走线路的主入口,由网关转换为该入口的协议。 无论走哪个入口,网关都不会原样复制请求体:三种格式先归一为同一份请求意图,经参数门按模型声明的能力与请求规则检查,再按入口的协议渲染为该厂商接受的写法。例外:Anthropic 格式发往 Anthropic 入口、Responses 格式发往原生 Responses 入口时原样转发,只修改少数几处,见 [Messages](https://www.scirouter.cn/docs/messages) 与 [Responses](https://www.scirouter.cn/docs/responses)。 每个参数的结局只有四种:原样带过去、翻译、平台模拟、明确告知(去掉并留痕,或返回 400)。逐个参数的规则,以及如何从响应头 `X-SciRouter-Param-Actions` 查看平台的修改,见[参数如何被处理](https://www.scirouter.cn/docs/params)。本节只说明协议之间的主要差异。 ### OpenAI 兼容入口 走 `openai` 或 `custom` 入口时: - 标准参数按意图渲染(输出上限按该厂商接受的字段名写入,思考强度按该厂商的写法写入等);登记表之外的专有参数原样带过去。 - `user` 与 `metadata` 不发给上游,只记录在请求日志中;按需补上 `stream_options.include_usage`。 - 上游明确不支持某个参数时:提示类参数由平台去掉后重发(响应头中记为 `healed=…`);契约类参数换线路,都不行时将上游的 400 返回调用方(`code` 为 `unsupported_parameter`,`param` 为参数名)。 - 无法识别是哪个参数的上游 400 仍为 `validation_failed`,`error.details.source` 为 `upstream`,厂商的原始错误在 `error.details.provider_error` 中。 ### Anthropic 入口 `anthropic` 入口使用 Anthropic Messages 协议,有该入口的线路可原样处理 Anthropic 格式。 - 调用方使用 `/v1/messages` 时请求原样转发:只替换 `model`、去掉平台自用的 metadata、写入生效的 `max_tokens`,历史只追加、不改写。响应保持 Anthropic 格式,厂商自定义参数、思考块与签名、文档块、`anthropic-beta` 均会到达上游。 - 调用方使用 OpenAI 格式、且线路没有 OpenAI 兼容入口时,才按登记表将请求翻译过去。 ### 格式转换 走 `gemini` 入口,或以 OpenAI 格式调用只有 Anthropic 入口的线路时,网关将请求翻译为入口的格式。常见字段: | 字段 | anthropic | gemini | |---|---|---| | `messages`(文本、`image_url` 图片、PDF) | ✓(`http://` 图片由平台取回后内联) | ✓(远程图片由平台取回后内联) | | `max_tokens` / `max_completion_tokens` | ✓(不写时按 4096) | ✓ | | `temperature`、`top_p`、`stop`、`stream` | ✓(开启思考时去掉 `temperature`;去掉纯空白的 `stop`) | ✓(`stop` 超过 5 个时由平台截断) | | `tools`、`tool_choice`、`tool` 角色的消息、`parallel_tool_calls` | ✓ | ✓(`parallel_tool_calls: false` 由平台只保留第一个) | | `response_format`(`json_object` / `json_schema`) | 原生结构化输出,否则由平台模拟 | ✓ | | `reasoning_effort` | 翻译为 `thinking`,按模型的思考控制 | 翻译为思考配置,按模型的思考控制 | | `seed`、`presence_penalty` / `frequency_penalty` | 去掉并留痕 | ✓ | | 内容段上的 `cache_control` | ✓ | 去掉 | | `n` > 1、`logprobs` | 400 `unsupported_param` | ✓ | | `logit_bias`、音频输出 | 400 `unsupported_param` | 400 `unsupported_param` | 调用方使用 Anthropic 格式、线路没有 Anthropic 入口时,网关先转为同一份意图再渲染,规则相同,并尽量不丢失内容:缓存断点、思考签名、`anthropic-beta` 按线路配置以扩展字段带过去;OpenAI 格式中没有对应概念的块改写为等价的文字或普通工具。分级规则与只能返回 400 的内容见 [Messages](https://www.scirouter.cn/docs/messages)「请求的转发方式」。 ### 能力标签 模型详情页的「能力」标签(工具调用、JSON 模式、看图等)即 `GET /models` 中的 `features`,参数门按其判断。例如给未标注「工具调用」的模型带 `tools` 时,请求不发往上游,直接返回 400 `unsupported_param`(`details.cause` 为 `feature_missing`)。 不确定时先在 [Playground](https://www.scirouter.cn/playground) 中试用,或读取 `GET /models` 中的 `supported_params`。 ## 厂商专有参数 模型详情页的参数表将参数分为通用与「该厂商专有」两组,名称、类型、范围、默认值来自平台维护的能力描述符;`/v1` 不按其校验请求。 专有参数写在请求体顶层,与 `temperature` 并列。OpenAI Python SDK 的 `extra_body` 将字典中的字段合并到请求体顶层: ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SCIROUTER_API_KEY"], base_url="https://api.scirouter.cn/v1") response = client.chat.completions.create( model="YOUR_MODEL_ID", messages=[{"role": "user", "content": "…"}], temperature=0.7, extra_body={"top_k": 20}, # 发出去的请求体里是顶层的 "top_k": 20 ) ``` 使用 curl 或其他语言时直接写在顶层: ```bash curl https://api.scirouter.cn/v1/chat/completions \ -H "Authorization: Bearer $SCIROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "YOUR_MODEL_ID", "messages": [{"role": "user", "content": "…"}], "top_k": 20}' ``` **请求体中不写名为 `extra_body` 的字段**:`/v1` 不展开该字段,会将其原样转给上游(通常被忽略或拒绝)。 - 参数表中写作 `extra_body.xxx` 的,`xxx` 即顶层字段名;写作嵌套路径的(如 `chat_template_kwargs.enable_thinking`),按该嵌套结构写入请求体。 - 专有参数只在走 OpenAI 兼容入口(`openai`、`custom`)时生效,见[字段生效规则](#字段生效规则);走 Anthropic 或 Gemini 入口时去掉并留痕(响应头 `X-SciRouter-Param-Actions` 中记为 `other`)。 ## 输出上限 各模型的单次最多输出不同,见模型详情页「单次最多输出」。`max_tokens` 超过模型的上限或套餐的单次上限时: | 接口 | 处理 | |---|---| | 对话补全(`/chat/completions`) | 直接返回 400,`error.details.limit` 为允许的最大值;不截断到上限 | | Anthropic 格式(`/messages`) | 按上限发出,响应头 `X-SciRouter-Max-Tokens-Clamped` 写明请求值、实际值与生效的是哪一道上限,见 [Messages](https://www.scirouter.cn/docs/messages) | ## 用量与计费 响应中的 `usage` 采用 OpenAI 的格式:`prompt_tokens`、`completion_tokens`、`total_tokens`,另有以下细分字段: | 字段 | 说明 | |---|---| | `usage.prompt_tokens_details.cached_tokens` | 命中上游提示词缓存的输入,已含在 `prompt_tokens` 中 | | `usage.prompt_tokens_details.cache_write_tokens` | 本次写入上游缓存的输入。非 OpenAI 标准字段,有写入时才返回 | | `usage.completion_tokens_details.reasoning_tokens` | 思考过程的 token,已含在 `completion_tokens` 中 | - 走 OpenAI 兼容入口时 `usage` 由上游原样返回,细分字段是否存在、名称如何取决于上游(个别兼容服务只在顶层返回 `prompt_cache_hit_tokens`);经其他入口转换时由网关按上表生成。 - 对账不使用 `usage` 自行计算费用。单次调用扣除的配额见响应体的 `scirouter.cost_quota`(非流式另有响应头 `X-SciRouter-Cost-Quota`),或控制台请求日志与导出中的 `cost_quota`。 - 上游未返回用量时平台按估算计费(日志中标注「估算」);命中响应缓存时 `usage` 为原结果的数值,但不扣费。这两种情况只能以 `cost_quota` 为准。 ### 计价维度 账单按各维度的用量乘以倍率计算,各维度互不重叠: | 维度 | 含义 | 模型未单独设置倍率时 | |---|---|---| | `input_tokens` | 普通输入(不含缓存命中与写入) | — | | `cached_input_tokens` | 命中上游缓存的输入 | 按 `input_tokens` 的倍率 | | `cache_write_input_tokens` | 写入上游缓存的输入(5 分钟缓存) | 按 `input_tokens` 的倍率 | | `cache_write_1h_input_tokens` | 写入上游 1 小时缓存的输入 | 按 `cache_write_input_tokens` 的倍率;该倍率也未设置时按 `input_tokens` | | `output_tokens` | 普通输出(不含思考) | — | | `reasoning_tokens` | 思考过程 | 按 `output_tokens` 的倍率 | - 维度可能有阶梯:用量达到某个值之后,整笔按另一档倍率计,不累进。 - 维度可能有最小计费量:不足时按最小量计。 - 部分模型有长上下文分档:输入合计超过某个值时整笔换用另一套倍率,见[模型列表](https://www.scirouter.cn/docs/models)的 `context_tiers`。 各模型的维度与倍率以[模型中心](https://www.scirouter.cn/models)详情页的价格表为准。代码中按数组遍历维度,不只读取两个键。 ## 流式 所有对话模型均支持流式(`stream: true`)。对话补全的分片为 OpenAI 的 `chat.completion.chunk`,经转换的调用也由网关转为相同的形状;`/messages` 的流为 Anthropic 的事件,见 [Messages](https://www.scirouter.cn/docs/messages)。对话补全与直连 OpenAI 相比有以下差异: | 项目 | 说明 | |---|---| | 心跳 | 长时间无输出时(如排队),约每 10 秒发送一行 `: ping`。这是 SSE 注释,官方 SDK 会忽略;自行解析 SSE 时跳过以 `:` 开头的行 | | 收尾扩展分片 | `data: [DONE]` 之前多一个 `choices` 为空、带顶层 `scirouter` 字段的分片(本次消耗、尝试次数、耗时,见[可观测性](https://www.scirouter.cn/docs/observability))。上游未输出任何分片即结束时不发送 | | 中途出错 | 流开始后出错时,最后一个分片为 `{"error": {…}}`(与非流式错误体格式相同,带 `request_id`),之后没有 `[DONE]` | | 用量分片 | 只在请求带 `stream_options: {"include_usage": true}` 时转发;未带时平台仍按上游用量结算 | | 工具进度分片 | 使用平台托管工具时,另有 `choices` 为空、带 `scirouter.tool` 的工具进度分片 | 解析时忽略无法识别的分片,不作为错误处理。 ## 思考过程与结束原因 | 项目 | 对话补全 | `/messages` | |---|---|---| | 思考过程 | 带思考的模型在 `reasoning_content` 与 `reasoning` 两个字段中返回相同的思考内容(非流式在 `message`,流式在 `delta`),读取任一个即可。对思考过程签名的模型另有 `thinking_blocks`(带签名的思考块,多轮工具调用时原样带回,见[对话补全](https://www.scirouter.cn/docs/chat-completions)「思考过程」) | Anthropic 的 `thinking` 块 | | 结束原因 | 统一为 OpenAI 的取值 `stop` / `length` / `tool_calls` / `content_filter` | Anthropic 的 `stop_reason` | ## 错误 各厂商的错误均归一为平台错误码,见[错误码](https://www.scirouter.cn/docs/errors)。厂商原始的错误码与信息在 `error.details.provider_error` 中,只用于排障,不用于程序分支(随上游变化)。 上游拒绝请求时返回 400: - 平台识别出语义的归为固定的 code:上下文超长 `context_window_exceeded`、参数不支持 `unsupported_param`(提示类参数平台会先自行去掉后重发)、内容审核 `content_filtered`。这三个的 `error.code` 为原厂兼容值,平台码在 `error.scirouter_code`。 - 无法识别语义的仍为 `validation_failed`,`error.details.source` 为 `upstream`。 --- # 参数如何被处理 > 参数分类与各入口协议的处理表,模拟、自愈与上下文窗口预检,以及响应头中的处理留痕。 来源:https://www.scirouter.cn/docs/params · 更新于 2026-10-23 每个参数到达模型背后的线路时只有四种结局:原样带过去、翻译为该线路接受的写法、由平台模拟、明确告知(去掉并留痕,或返回 400)。平台不会在不告知的情况下丢弃参数。 三种格式(对话补全、Messages、Responses)共用这套规则,各接口的字段表见对应页面。参数能否带到线路上,由模型声明的能力与请求规则、本次所走入口的协议、线路的画像共同决定,由管理员在后台维护。`GET /models` 返回每个模型的能力自述,见[模型能力自述](#模型能力自述),接入前可先读取。 ## 参数分类 | 类别 | 示例 | 无法带到线路时 | |---|---|---| | 平台 | `model`、`messages` / `input`、`stream`、`stream_options`、`user`、`metadata`、`prompt_cache_key` | 由平台自行写入,或只记录在请求日志中(`user`、`metadata`),不涉及 | | 提示类 | 采样(`temperature`、`top_p`、`top_k`、`min_p`、`seed`、惩罚项)、思考强度、`verbosity`、内容段上的 `cache_control`、`context_management`、`prediction`、`store`、向量的 `input_type` | 去掉并留痕,默认不报错。此类参数只影响质量、不改变返回的形状,模型照常回答 | | 契约类 | `max_tokens`、`stop`、`response_format` / 结构化输出、`tools`、`tool_choice`、`parallel_tool_calls`、`n`、`logprobs`、`logit_bias`、音频输出、图片与文件输入、末尾的助手消息(预填)、向量的 `dimensions` / `encoding_format` | 依次尝试翻译、平台模拟、换用能带的线路,都不行时返回 400 `unsupported_param`,并说明参数与原因。此类参数改变返回的形状,去掉后返回的内容与请求不符 | | 计价类 | `service_tier`、`speed`、`inference_geo`、`web_search_options` | 会使厂商按另一档单价收费:平台上架了对应的模型变体时自动改用变体,否则返回 400,见 [Messages](https://www.scirouter.cn/docs/messages)「计价参数与模型变体」。`web_search_options` 按次计费、没有能表达它的变体,一律返回 400 | 默认分级不符合需要时,带请求头 `X-SciRouter-Unsupported-Params`: | 取值 | 效果 | |---|---| | `strict` | 提示类参数无法带到时也返回 400(`details.cause` 为 `strict`)。适用于宁可报错、也不接受未按所给参数生成的回答的场景 | | `lenient` | 契约类参数无法带到时也去掉并留痕。适用于宁可接受形状可能不同的回答、也不要 400 的场景 | 其他取值视为未带。三种格式均识别该请求头。 ## 处理表 每个标准参数一行:三种格式中的写法、类别、各协议入口的处理方式,以及无法带到时的结局。处理方式的取值: | 取值 | 含义 | |---|---| | 带 | 原样带过去 | | 翻译 | 转换为该协议的写法 | | 模拟 | 协议本身不接受,由平台补充实现 | | 不收 | 无法带到 | 一条线路可以有多个入口(同一个上游账号接入的多种协议),每次调用按调用方的格式选择入口:有可原样处理该格式的入口时走该入口,否则走主入口并转换,见[多厂商差异](https://www.scirouter.cn/docs/vendors)「字段生效规则」。表中的列为入口的协议:`openai` 与 `custom` 合为一列,`anthropic`、`gemini` 各一列。 | 参数(写法) | 类别 | openai / custom | anthropic | gemini | 无法带到时 | |---|---|---|---|---|---| | `max_tokens`(`max_tokens` / `max_completion_tokens` / `max_output_tokens`) | 契约 | 带(按线路接受的名称写入) | 翻译 | 翻译 | 超过模型或套餐的单次上限:对话补全返回 400,另两种格式按上限发出并告知;输入加上它超出窗口:返回 400,见[上下文窗口](#上下文窗口) | | `temperature`、`top_p` | 提示 | 带 | 带 | 翻译 | 去掉并留痕。模型的请求规则给出范围时,超出的值夹到范围内(留痕 `translated`);模型不接受采样参数时去掉 | | `top_k`(OpenAI 格式写在顶层也识别) | 提示 | 带 | 带 | 翻译 | 去掉并留痕 | | `min_p`、`repetition_penalty` | 提示 | 带 | 不收 | 不收 | 去掉并留痕 | | `seed`(需模型声明 `seed` 能力) | 提示 | 带 | 不收 | 翻译 | 去掉并留痕 | | `presence_penalty`、`frequency_penalty` | 提示 | 带 | 不收 | 翻译 | 去掉并留痕 | | `reasoning`(`reasoning_effort` / `thinking`、`output_config` / `reasoning`;也识别 `enable_thinking`、`chat_template_kwargs`、`thinking_budget` 等私有写法;需模型声明 `reasoning` 能力) | 提示 | 翻译 | 翻译 | 翻译 | 去掉并留痕,模型照常回答(不思考);强度不在模型的档位中时降档,见[思考强度](#思考强度) | | `verbosity` | 提示 | 带 | 不收 | 不收 | 去掉并留痕 | | 内容段上的 `cache_control`(需模型声明 `prompt_cache` 能力) | 提示 | 带(按线路的画像保留或去掉) | 带 | 不收 | 去掉。见[缓存与幂等](https://www.scirouter.cn/docs/caching) | | `context_management` | 提示 | 翻译(`clear_tool_uses_*` 由平台在转换后的历史上补充实现;`compact_*` 等其余编辑去掉并留痕) | 带 | 不收 | 去掉并留痕 | | `prediction`、`store` | 提示 | 带 | 不收 | 不收 | 去掉并留痕 | | 向量 `input_type` | 提示 | 带 | — | 翻译 | 去掉并留痕 | | `stop`(`stop` / `stop_sequences`) | 契约,可模拟 | 带 | 翻译(去掉纯空白的停止词) | 翻译(超过 5 个时由平台截断) | 模拟:平台在输出中找到停止词即截断 | | `response_format`(`response_format` / `output_format`、`output_config.format` / `text.format`;需模型声明 `json_mode` 或 `structured_output` 能力) | 契约,可模拟 | 带 | 翻译(原生结构化输出;否则模拟) | 翻译 | 模拟,见[模拟](#模拟);模拟也无法实现时返回 400 | | `tools`(需模型声明 `tools` 能力) | 契约 | 带 | 翻译 | 翻译 | 换线路 → 400 | | `tool_choice` 为 `required` / 指定工具 | 契约,可模拟 | 带 | 翻译 | 翻译 | 模拟:降为 `auto`,并在提示中要求调用工具(尽力而为,留痕);`strict` 时返回 400 | | 末尾的助手消息(预填) | 契约 | 带 | 带 | 带 | 模型的请求规则不接受预填 → 换线路 → 400 | | `parallel_tool_calls: false` | 契约,可模拟 | 带 | 翻译 | 模拟 | 模拟:平台只保留第一个工具调用 | | `n` > 1 | 契约 | 带 | 不收 | 翻译 | 换线路 → 400 | | `logprobs`、`top_logprobs`(需模型声明 `logprobs` 能力) | 契约 | 带 | 不收 | 翻译 | 换线路 → 400 | | `logit_bias` | 契约 | 带 | 不收 | 不收 | 换线路 → 400 | | 音频输出(`modalities`、`audio`;需模型声明 `audio` 能力) | 契约 | 带 | 不收 | 不收 | 换线路 → 400 | | 图片输入(需模型声明 `vision` 能力) | 契约 | 带 | 翻译 | 翻译 | 换线路 → 400。线路不接受远程地址时,平台取回图片后内联(只接受图片与 PDF,有大小、时长与数量上限);取回失败时返回 400 `unsupported_param`,`details.reason` 为 `media_fetch_failed` | | PDF / 文件输入 | 契约 | 带 | 翻译 | 翻译 | 换线路 → 400 | | 向量 `dimensions` | 契约 | 带 | — | 翻译 | 换线路 → 400 | | 向量 `encoding_format: base64` | 契约,可模拟 | 带 | — | 模拟 | 模拟:平台将浮点数编码为 base64 | 表外的键(厂商私有参数):走 `openai` 或 `custom` 入口时原样带过去,写法见[多厂商差异](https://www.scirouter.cn/docs/vendors)「厂商专有参数」;走 `anthropic` 或 `gemini` 入口时去掉并留痕(留痕中记为 `other`,不记录键名)。 ## 两层判断 | 层 | 时机 | 判断与处理 | 400 时的 `details` | |---|---|---|---| | 模型层 | 选择线路之前 | 参数所需的能力模型未声明(`features`),或模型的请求规则不接受该参数或该取值:按类别处置 | `cause` 为 `feature_missing` 或 `rule_unsupported` | | 线路层 | 选择线路时 | 模型具备该能力,但某条线路无法带到(可用的入口都不接受,或线路的画像、改写规则去掉了该参数):跳过该线路,换用能带的线路;所有线路都无法带到时按类别处置 | `cause` 为 `not_carried`,`params` 列出所有无法带到的参数 | 线路级的上下文窗口也在线路层判断:放不下的线路被跳过,全部放不下时返回 400 `context_window_exceeded`,`details.scope` 为 `endpoint`。 400 `unsupported_param` 的错误体如下(OpenAI 格式;Anthropic 格式见[错误码](https://www.scirouter.cn/docs/errors)): ```json { "error": { "message": "参数 logprobs 带不过去:这个模型没有声明对应的能力", "type": "invalid_request_error", "code": "unsupported_parameter", "scirouter_code": "UNSUPPORTED_PARAM", "param": "logprobs", "request_id": "req_88a1", "details": { "param": "logprobs", "reason": "unsupported_param", "cause": "feature_missing" } } } ``` `code` 为原厂兼容值,供现有客户端识别;平台码在 `scirouter_code`;`param` 为登记表中的参数名。此类错误在预扣之前返回,不扣费、不占并发名额。 ## 思考强度 OpenAI 格式的 `reasoning_effort`、Messages 的 `thinking`、Responses 的 `reasoning.effort` 归一为同一个意图,再按模型的思考能力(`GET /models` 的 `reasoning`:支持的控制方式、强度档位、能否关闭)落到线路上: | 情况 | 处理 | 留痕 | |---|---|---| | 模型没有思考能力 | 去掉,模型照常回答 | `dropped=reasoning` | | 要求关闭思考,而模型无法关闭 | 去掉 | `dropped=reasoning(always_on)` | | 强度不在模型支持的档位中 | 按链降档:`max → xhigh → high`、`xhigh → high`、`minimal → low`。`none` 在有开关的模型上等同于关闭 | `translated=reasoning(xhigh→high)` | | 同一请求中提示类与契约类参数冲突 | 去掉提示类参数。典型情况是强制工具(`tool_choice` 指定工具)遇到模型「手动思考时不接受强制工具」的规则:关闭思考,强制工具照常带,不返回 400 | `dropped=reasoning(forced_tool_choice)` | 强度翻译成思考预算时(以预算控制思考的模型),预算与 `max_tokens` 一起确定:未填写 `max_tokens` 时取预算加 4096,不超过模型与套餐的输出上限;预算不超过 `max_tokens` 减去 1024 与 `max_tokens` 四分之一中的较大者;预算不足 1024 时不开启思考,留痕 `budget_below_min`。Anthropic 格式的请求被平台截短 `max_tokens` 时,不小于截短后上限的 `thinking.budget_tokens` 降到该上限减 1。上一轮的思考块与签名只交还给签发它的厂商,其他厂商无法识别,见 [Messages](https://www.scirouter.cn/docs/messages)。 ## 模拟 契约类参数线路不接受时,平台在请求侧修改、在响应侧补全,使返回的形状与请求一致: | 参数 | 模拟方式 | |---|---| | `response_format` / 结构化输出 | 按顺序选择:模型有原生结构化输出时原样带;没有、但模型接受强制工具且未开启思考时,强制调用一个平台工具,将其参数写回正文,`finish_reason` 为 `stop`;仍不满足时改用 `json_object` 并将 schema 写入提示(尽力而为);都不行时返回 400。留痕 `emulated=response_format(…)`,括号中为所用的一档 | | `stop` | 平台扫描输出,命中停止词即截断(流式截断后取消上游),`finish_reason` 为 `stop` | | `tool_choice` 为 `required` / 指定工具 | 降为 `auto`,并在提示中要求模型调用工具(指定工具时写明工具名)。尽力而为,模型仍可能不调用。留痕 `emulated=tool_choice(…)` | | `parallel_tool_calls: false` | 平台只保留第一个工具调用(流式只转发第一个) | | 向量 `encoding_format: base64` | 平台将浮点数按 float32 小端编码为 base64(与 OpenAI 的格式一致) | 不模拟的参数:`n` > 1、`logprobs`、`logit_bias`、音频输出,以及对不支持工具调用的线路用提示词模拟工具调用。这些参数无法生成相同的结果,或会产生误导。 结构化输出经模拟时,如需确认结果是否符合 schema,带请求头 `X-SciRouter-Validate-Schema: 1`。平台按 schema 校验最终正文一次,结果写入扩展块 `scirouter.schema_valid`(`true` / `false`);不符合时不重试、不报错,由调用方决定是否重发。走原生结构化输出的调用不校验(由厂商保证),不返回该字段。 ## 留痕 有参数被去掉、翻译、模拟、整形或自愈时,以下三处均有记录,内容相同: | 位置 | 说明 | |---|---| | 响应头 `X-SciRouter-Param-Actions` | 三种格式均返回,流式也在正文之前发出。五组按固定顺序 `dropped`、`translated`、`emulated`、`reshaped`、`healed` 排列,组内按名称排序,括号中为补充说明(降到哪一档、用了哪种模拟);超过 512 字节时截断,以 `...` 结尾 | | 扩展块 `scirouter.param_actions` | 非流式在响应顶层,流式在末尾的扩展分片中,见[可观测性](https://www.scirouter.cn/docs/observability) | | 控制台请求日志的参数快照 | 键名相同 | ```text X-SciRouter-Param-Actions: dropped=seed,top_k; translated=reasoning(xhigh→high); emulated=response_format ``` ```json { "param_actions": { "dropped": ["seed", "top_k"], "translated": ["reasoning(xhigh→high)"], "emulated": ["response_format"] } } ``` 没有任何动作时,该响应头与字段均不出现。参数门有「只观察」与「生效」两档:只观察期间动作不生效、请求按原样发出,但该响应头与扩展块照常返回。切换到生效之前平台会发布公告,调用方可先根据响应头评估自身调用受到的影响。 ## 消息整形 出站前平台按本次所走入口的协议整理消息列表与工具定义。每条规则对应一条留痕(`reshaped=<规则>`),处理结果是确定的:同一请求整理两次逐字节相同,不影响提示词缓存。整形规则: - 补上缺失的工具结果; - 丢弃没有对应调用的工具结果; - 去重 `tool_call_id`; - 工具名不符合线路要求时改写,响应中换回原名; - 对不接受 `developer` 角色的线路,将其改为 `system`; - 只保留 `function` 类工具; - 没有 `tools` 时去掉 `tool_choice`; - 去掉 Claude Code 的归因块。 改写历史的三条(补上、丢弃、去重)默认开启,平台可逐条关闭。原样转发到 Anthropic 入口的 Messages 请求一律不改写历史,只追加。 ## 自愈 线路背后的服务明确报错不支持参数 X(平台从报错中识别出参数名)时: | X 的情况 | 处理 | |---|---| | 提示类;或调用方带了 `lenient`;或 X 不在登记表中(厂商私有键) | 平台去掉 X,在同一条线路上重发。不算故障转移、不计该线路的失败,首次请求厂商未收费;留痕 `healed=X`。同一线路对同一参数多次出现此情况后,一段时间内在发出前直接去掉该参数,留痕 `healed=X(cached)` | | 契约类 | 不自愈(去掉会改变返回的形状),换一条线路;都不行时将上游的 400 返回调用方:`code` 为 `unsupported_parameter`(取值不支持时为 `unsupported_value`),`param` 为厂商给出的名称,`details.semantic` 为 `unsupported_param` | 无法识别参数名的上游 400 仍为 `validation_failed`(`details.source` 为 `upstream`,厂商原文在 `details.provider_error` 中)。 ## 上下文窗口 发出之前平台估算一次。输入超出模型的上下文窗口,或输入未超出、但加上调用方显式给出的 `max_tokens` 后超出时,返回 400 `context_window_exceeded`,不预扣、不占名额: | 字段 | 说明 | |---|---| | `details.limit` | 上下文窗口 | | `details.estimated` | 估算的输入 token 数 | | `details.max_tokens` | 调用方给出的 `max_tokens`;未给出时不返回 | 两种情况的 `message` 不同(见[错误码](https://www.scirouter.cn/docs/errors)),Claude Code 等客户端据此分别压缩历史或调小 `max_tokens` 后重发。 - 只计入显式给出的 `max_tokens`。未给出时,走 OpenAI 兼容入口不发送该字段,由厂商自行决定。 - 估算按模型的分词器族校准,取偏小的一侧,使估算值不超过实际值;没有分词器族信息的模型只拒绝明显超出的请求;未填写窗口的模型不预检。 - 线路级的窗口(自部署服务的窗口常小于模型的窗口)在选择线路时过滤,全部放不下时返回同一个 code,`details.scope` 为 `endpoint`。 - 上游报告超长时同样归为该 code:`details.semantic` 为 `context_window_exceeded`,厂商文案含数字时才带 `limit` 与 `estimated`,不含时不推算。 模型的窗口见[模型中心](https://www.scirouter.cn/models)的详情页。 ## 模型能力自述 `GET /models` 与 `GET /models/{model_id}` 的 `scirouter` 扩展字段列出模型当前接受的参数: | 字段 | 说明 | |---|---| | `supported_params` | 原生支持或经翻译可带到线路上的标准参数,取模型当前启用线路的并集 | | `emulated_params` | 线路不支持、但平台可以模拟的参数 | | `features` | 模型声明的能力 | | `reasoning` | 思考的控制方式与档位 | 字段的格式见[模型列表](https://www.scirouter.cn/docs/models)。 ## 复读保护 模型陷入复读(同一段内容反复出现)时,平台中断上游,`finish_reason` 为 `length`(各格式均有该取值),扩展块 `scirouter.finish_detail` 为 `repetition`,用于区分达到上限与被平台中断。 --- # MCP 与托管工具 > MCP 服务端的接入、工具清单、提示与资源、限额与错误码,以及 /v1 托管工具的请求、响应、计费与数据流向。 来源:https://www.scirouter.cn/docs/mcp · 更新于 2026-10-23 SciRouter 通过两个入口提供联网检索与读库工具。两个入口使用同一份工具与同一套安全限制,见[数据流向与限制](#数据流向与限制)。 | 入口 | 地址 | 适用场景 | |---|---|---| | MCP 服务端 | `https://api.scirouter.cn/mcp` | 调用方自己的 agent(Claude Code、Cursor、Codex CLI 或任意 MCP 客户端)以 API Key 接入并调用工具 | | `/v1` 托管工具 | `POST https://api.scirouter.cn/v1/chat/completions` | 在请求的 `tools` 中声明一次,平台执行工具、多轮调用模型并返回最终答案;调用方无需实现工具循环 | 工具覆盖搜索网页、读网页、查文献、核对序列 / 结构 / 化合物的标识符、读序列记录原文、查基因邻居与找先例。claude.ai 与 ChatGPT 网页端的连接器暂不支持,见 [claude.ai / ChatGPT 网页端的连接器](#claude-ai-chatgpt-网页端的连接器)。 `web_search`、`fetch_page` 读到的 PDF 与 `run_code` 按平台服务计费,其余工具不计费,见[计费](#计费)。 ## 工具 | 工具 | 入参 | 出参 | |---|---|---| | `web_search` | `{ query(1–300 字), lang?: "zh" \| "en"(默认 zh), kind?: "web" \| "scholar" \| "news"(默认 web) }` | `{ kind, items: [{ n, title, url, site, date?, snippet }], related: string[], cached }` | | `fetch_page` | `{ url(http / https,最长 2048) }` | `{ url, finalUrl, title, site, date?, text, chars, truncated, cached }` | | `search_literature` | `{ query(1–300 字), limit?: 1–10(默认 5) }` | `{ items: [{ n, title, authors[], year?, venue?, doi?, arxiv?, url, abstract?, source? }] }` | | `resolve_identifier` | `{ kind: "sequence" \| "structure" \| "compound", identifier }` | 随 `kind` 不同,见[证据层工具](#证据层工具) | | `read_record` | `{ accession, start, stop }`(从 1 起,含两端,一次最多 6000 个) | `{ accession, start, stop, residues, truncated, sequence, features: [特征], sourceUrl, fetchedAt }` | | `gene_neighbors` | `{ accession, target, flank?: 100–50000(默认 10000) }` | `{ accession, target: 特征, from, to, neighbors: [特征], sourceUrl, fetchedAt }` | | `find_precedents` | `{ kind: "accession" \| "gene" \| "compound", accession?, gene?, organism?, cid?, inchiKey? }` | `{ basis, basisKey, source, total, papers: [{ pmid, doi, title, journal, year, firstAuthor, chapter, url }], ambiguous, fetchedAt, cached }` | 「特征」的结构为 `{ kind, start, stop, strand, gene?, locusTag?, product?, proteinId?, note?, partialStart?, partialStop? }`,坐标为整条记录上的位置。 可用的工具集由部署决定,以 `tools/list` 的实际返回为准:平台未接入搜索时没有 `web_search`;平台开放「运行代码」后另有 `run_code`(默认不开放)。 - `web_search` 的 `scholar` / `news` 需平台开启对应的搜索种类。未开启时返回一条 `isError` 结果「这种搜索没有开」,不返回协议错误。查文献使用 `search_literature`,不依赖该开关。 - `fetch_page` 在平台配置了文档解析时可读取 PDF。`truncated` 为 true 表示正文超过字数上限,超出部分被截去。读取失败的原因见[读网页失败的原因](#读网页失败的原因)。 - `search_literature` 合并 arXiv、CrossRef、Semantic Scholar 的结果并去重,`source` 标明每条结果的来源。 - `resolve_identifier`、`read_record`、`gene_neighbors`、`find_precedents` 是站内证据层的能力(消息中的核对徽章、读原始记录、找先例),出参与站内相同。 ### 工具结果 每个工具的结果包含两份同源内容:供人或模型阅读的文字(MCP 的 `content[0].text`)与结构化 JSON(MCP 的 `structuredContent`)。 工具已执行但未成功时(网站无法打开、被策略拒绝、搜索种类未开启、库中没有该记录),返回 `isError: true` 的正常结果,并附一句原因。JSON-RPC 错误只用于协议层面的问题,见[限额与错误码](#限额与错误码)。 `tools/list` 与 `/v1` 展开的工具描述按 `Accept-Language` 选择语言:以 `en` 开头时为英文,其余为中文。 ### 证据层工具 `resolve_identifier` 用标识符从公共库取回记录,出参随 `kind` 不同: | `kind` | 标识符格式 | 出参 | |---|---|---| | `sequence` | NCBI(RefSeq / GenBank)、UniProt(`P60709`)或 Ensembl 登录号,可带区间:`NC_012920.1:648-1601` | `kind, accession, source(ncbi / uniprot / ensembl), molecule(nucleotide / protein), start, stop(整条为 null), header, length, sequence(最多 10000 位,超出则截断、truncated=true), release, sourceUrl, fetchedAt, cached` | | `structure` | `pdb:1HEL`、`pubchem:2519` | `kind, ref, source, id, format(pdb / sdf), bytes, sourceUrl, pageUrl, fetchedAt, cached`。不含文件本身,需要文件时按 `sourceUrl` 自行获取 | | `compound` | PubChem CID 或英文名。PubChem 不识别中文名与多数商品名,有 CID 时使用 CID | `kind, cid, title, iupacName, formula, molecularWeight, inchiKey, smiles, ambiguous(按名称查到多条时取第一条), sourceUrl, fetchedAt, cached` | `read_record` 读取一条序列记录中的一段原文。`accession` 只写登录号本身(NCBI 核酸 / 蛋白、UniProt、Ensembl),区间写在 `start` / `stop`。结果包括原样序列(文字版每行 60 个,行首为位置)与该段内注释的基因、CDS 与产物(`features`,仅 NCBI 记录返回)。终点超过记录长度时返回到记录末尾为止,`truncated` 为 true;起点已超出记录长度时返回 `-32602`。 `gene_neighbors` 列出一条 NCBI 核酸记录上,目标上下游各 `flank` 个碱基内已注释的特征:名称、坐标、链、产物。目标(`target`)可以是 locus_tag、基因名、蛋白登录号或一个坐标。结果只含已注释的特征,没有注释不代表没有基因。特征表中找不到目标时,返回 `isError` 的结论文本。 `find_precedents` 按登录号、基因(可加物种)或化合物(CID 或 InChIKey)查找关联文献:NCBI 登录号、基因与化合物经 PubMed 查找,UniProt 登录号取 UniProt 条目自身引用的文献。出参字段: | 字段 | 说明 | |---|---| | `basis` / `basisKey` | 查找依据的种类(`accession` / `uniprot` / `gene` / `cid` / `inchikey`)与实际使用的键 | | `source` | `pubmed` 或 `uniprot` | | `total` | 库中关联文献的总数 | | `papers` | 按发表日期最新的前若干条,默认 10 条 | | `papers[].chapter` | 为 true 时表示书籍章节(GeneReviews、StatPearls),此时 `journal` 为书名,`year` 为最近一次修订的年份 | | `ambiguous` | 基因名或化合物名匹配到不止一条 | 证据层工具的共同规则: - 结果只说明库中有该记录及记录的内容,不判断回答是否正确。 - 库中没有该记录时,返回 `isError: true` 的结论文本(例如「NCBI 里没有 NC_000000.1 这条记录」「……已失效(记录被删除或并入了别的条目)」),不返回协议错误。 - 入参不合法时返回 JSON-RPC `-32602`:不认识的 `kind`、缺少对应字段、标识符格式不对、区间超出记录长度、写了 schema 中没有的字段。 - 调用次数与站内证据层共用同一份限额,按用户计,见[限额与错误码](#限额与错误码)。 - 团队项目的 Key 受团队「外部检索」档位约束,见[团队项目的 Key](#团队项目的-key)。发出的只有标识符,不含对话内容。 ## MCP 服务端接入 ### 鉴权 在请求头中写 `Authorization: Bearer YOUR_API_KEY`。Key 与 `/v1` 相同,在[控制台的 API Keys 页面](https://www.scirouter.cn/console/keys)创建。鉴权失败返回 HTTP 401 / 403,错误体为 OpenAI 格式(同[错误码](https://www.scirouter.cn/docs/errors)),不使用 JSON-RPC 错误。 ### 协议 - 传输方式为 Streamable HTTP:单个端点,只接受 `POST`;`GET` / `DELETE` 返回 405。 - 实现 MCP 规范 2026-07-28(无状态,支持 `server/discover`),同时兼容 2025-03-26 / 2025-06-18 / 2025-11-25 版本的客户端:正常应答 `initialize` 握手,不下发 session id。 - 支持的方法:`server/discover`、`initialize`、`ping`、`tools/list`、`tools/call`、`prompts/list`、`prompts/get`、`resources/list`、`resources/templates/list`、`resources/read`,其余方法返回 `-32601`。提示与资源见[提示与资源](#提示与资源)。 - 不支持 sampling、roots、订阅与变更通知(能力表中 `listChanged`、`subscribe` 均为 false)。 - 响应一律为 `application/json`。工具均在几秒到几十秒内完成,不使用 SSE 流。 旧版客户端无需携带 `MCP-Protocol-Version`。按 2026-07-28 版本发送的请求须携带下列请求头,取值须与请求体一致: | 请求头 | 取值 | 适用方法 | |---|---|---| | `MCP-Protocol-Version` | `2026-07-28` | 全部 | | `Mcp-Method` | 请求的 `method` | 全部 | | `Mcp-Name` | 工具名 / 提示名 | `tools/call`、`prompts/get` | | `Mcp-Name` | 资源地址 | `resources/read` | 无法放入 ASCII 请求头的值写成 `=?base64?…?=`。 ### 客户端配置 Claude Code: ```bash claude mcp add --transport http scirouter https://api.scirouter.cn/mcp --header "Authorization: Bearer YOUR_API_KEY" ``` Cursor(`~/.cursor/mcp.json` 或项目中的 `.cursor/mcp.json`): ```json { "mcpServers": { "scirouter": { "url": "https://api.scirouter.cn/mcp", "headers": { "Authorization": "Bearer YOUR_API_KEY" } } } } ``` Codex CLI(`~/.codex/config.toml`,Key 存放在环境变量 `SCIROUTER_API_KEY` 中): ```toml [mcp_servers.scirouter] url = "https://api.scirouter.cn/mcp" bearer_token_env_var = "SCIROUTER_API_KEY" ``` Anthropic Messages API(请求带 beta 请求头 `anthropic-beta: mcp-client-2025-11-20`): ```json { "mcp_servers": [ { "type": "url", "url": "https://api.scirouter.cn/mcp", "name": "scirouter", "authorization_token": "YOUR_API_KEY" } ], "tools": [ { "type": "mcp_toolset", "mcp_server_name": "scirouter" } ] } ``` OpenAI Responses API: ```json { "tools": [ { "type": "mcp", "server_label": "scirouter", "server_url": "https://api.scirouter.cn/mcp", "authorization": "YOUR_API_KEY", "require_approval": "never" } ] } ``` Anthropic Messages API 与 OpenAI Responses API 两种方式由厂商的云端连接 SciRouter 的 MCP 端点:要求该端点对厂商的公网可达,Key 交由厂商转发。这两种方式可用,但不在 SciRouter 的保证范围内;出现问题时先查看厂商侧的日志。 ### 手动调用示例 ```bash # 列出工具(旧版写法,可不带协议版本请求头) curl https://api.scirouter.cn/mcp \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # 调用工具(2026-07-28 写法:带协议版本请求头,Mcp-Method / Mcp-Name 与请求体一致) curl https://api.scirouter.cn/mcp \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "MCP-Protocol-Version: 2026-07-28" \ -H "Mcp-Method: tools/call" \ -H "Mcp-Name: web_search" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"web_search","arguments":{"query":"钙钛矿 封装 稳定性","lang":"zh"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' ``` 成功响应: ```json { "jsonrpc": "2.0", "id": 2, "result": { "content": [{ "type": "text", "text": "网页搜索「钙钛矿 封装 稳定性」,8 条:\n1. …(example.org,2026-08-01)\n https://example.org/…\n …" }], "structuredContent": { "kind": "web", "items": [ { "n": 1, "title": "…", "url": "https://example.org/…", "site": "example.org", "snippet": "…" } ], "related": ["…"], "cached": false }, "isError": false, "resultType": "complete", "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "scirouter", "version": "1.0" } } } } ``` 工具已执行但未成功时,`result.isError` 为 true,`content[0].text` 为原因(例如「读网页失败:不允许的地址」),HTTP 状态仍为 200。 ### 提示与资源 提示(prompts)为平台的方法卡,即写给执行者的操作方法(见[课题](https://www.scirouter.cn/docs/campaigns)「方法卡」)。每张方法卡对应一个提示,名称为方法卡的英文短名(如 `causal-inference`)。 - `prompts/list` 按名称排序。每个提示只有一个可选参数 `task`,即要用该方法卡处理的问题或材料。 - `prompts/get` 返回一条 `user` 消息,内容为方法卡全文;带 `task` 时在全文前加上该问题。`arguments` 的值必须为字符串;`task` 以外的参数、不存在的提示均返回 `-32602`。 资源(resources)为可整篇读入上下文的 Markdown: | 地址 | 内容 | 可读取的 Key | |---|---|---| | `method://<短名>` | 平台方法卡的全文 | 所有 Key | | `skill://<短名>` | 团队未归档的技能(团队方法卡)的当前版本 | 仅该团队项目的 Key | - `resources/list` 列出该 Key 可读取的全部资源。 - `resources/templates/list` 返回 `method://{slug}`;团队项目的 Key 另返回 `skill://{slug}`。 - `resources/read` 带 `params.uri`,返回 `text/markdown` 全文。地址读取不到时,按 2026-07-28 版本发送的请求返回 `-32602`,旧版返回 `-32002`(`data.uri` 为请求的地址)。 `prompts/list`、`resources/list`、`resources/templates/list` 分页,每页 50 项。有下一页时结果带 `nextCursor`,原样放入下一次请求的 `params.cursor`;游标无效时返回 `-32602`。 结果中的 `ttlMs` 为缓存提示:工具与提示 1 小时,资源 1 分钟(团队技能随时可能修改)。 ### 限额与错误码 | 限额 | 计入的调用 | 计数对象 | 上限 | |---|---|---|---| | MCP 总次数 | `tools/call`、`prompts/get`、`resources/read` 合计;各种列表与 `ping` 不计 | 每个 Key | 默认每分钟 120 次 | | 核对 | `resolve_identifier`、`read_record`、`gene_neighbors` | 每个用户,与站内证据层共用 | 每分钟 60 次 | | 找先例 | `find_precedents` | 每个用户,与站内证据层共用 | 每小时 30 次 | 按用户计的两项在每个 Key 的 MCP 总次数之外另行计算。超出任一限额时返回 JSON-RPC 错误 `-32000`,`data.retryAfterSeconds` 为需等待的秒数;不以 `isError` 结果返回。 `/v1` 托管工具被限频时不报错:本轮该工具的结果为失败态(`tool_calls` 中该条为 `status: "failed"`,文本为「调用太频繁,这次没有执行:稍后再试或换个办法」),循环照常继续,由模型决定重试或换用其他方法。 | 错误码 | HTTP 状态 | 触发条件 | |---|---|---| | `-32700` | 400 | 请求体不是合法 JSON | | `-32600` | 400 | 不是合法的 JSON-RPC 请求(缺少 `jsonrpc: "2.0"` 或 `method`);批量请求(数组)不支持。`GET` / `DELETE` 返回 405,错误体同本条 | | `-32601` | 200;按 2026-07-28 版本发送的请求为 404 | 方法不支持 | | `-32602` | 200 | 入参不合法(含写了 schema 中没有的字段、`params` 不是对象、缺少 `params.name` / `params.uri`、翻页的 `cursor` 无效);工具或提示不存在;按 2026-07-28 版本发送的请求读取不到资源 | | `-32002` | 200 | 旧版客户端读取不到资源,`data.uri` 为请求的地址 | | `-32603` | 200 | 内部错误 | | `-32000` | 200 | 被限频(每个 Key 的总次数,或按用户计的核对 / 找先例次数),`data.retryAfterSeconds` 为需等待的秒数 | | `-32020` | 400 | 按 2026-07-28 版本发送的请求缺少 `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` 请求头,或请求头与请求体不一致(含 `_meta` 中的版本) | | `-32022` | 400 | 协议版本不支持,`data.supported` 列出支持的版本 | 通知(没有 `id` 的消息,例如 `notifications/initialized`)返回 HTTP 202,无响应体。 限频错误示例: ```json { "jsonrpc": "2.0", "id": 2, "error": { "code": -32000, "message": "…", "data": { "retryAfterSeconds": 12 } } } ``` ### 团队项目的 Key Key 属于团队项目时,工具受团队「外部检索」档位约束。档位分三档:核对 + 相似性(`all`)、只核对(`verify`)、全部关闭(`off`)。 | 工具 | 所需档位 | |---|---| | `resolve_identifier`、`read_record`、`gene_neighbors` | 只核对(`verify`)及以上 | | `web_search`、`fetch_page`、`search_literature`、`find_precedents` | 核对 + 相似性(`all`) | `resolve_identifier`、`read_record`、`gene_neighbors` 只发送登录号、区间与基因名,因此在「只核对」档即可使用。 档位不足时工具返回 `isError`:`off` 档为「团队关闭了外部检索」,`verify` 档为「团队策略不允许联网检索(只允许核对标识符)」。团队设置的档位会被平台设置的上限压低,以更严的一方为准。个人 Key 不受此约束。 ## claude.ai / ChatGPT 网页端的连接器 暂不支持。这两个网页端的连接器不能填写 API Key,只支持 OAuth 登录;SciRouter 目前未开放 OAuth 授权,在其中添加 SciRouter 会失败。 接入 MCP 使用可填写 API Key 的客户端:Claude Code、Cursor、Codex CLI,或[客户端配置](#客户端配置)中 Anthropic Messages API / OpenAI Responses API 的写法。 ## `/v1` 托管工具 在对话补全请求中声明托管工具,由平台执行工具循环: ```http POST https://api.scirouter.cn/v1/chat/completions ``` ```json { "model": "YOUR_MODEL_ID", "messages": [{ "role": "user", "content": "近一年钙钛矿封装稳定性有哪些新进展?给出处。" }], "tools": [ { "type": "mcp", "server_label": "scirouter", "allowed_tools": ["web_search", "fetch_page"], "require_approval": "never" } ], "scirouter": { "max_tool_rounds": 6 } } ``` ### 请求 `tools` 中加入一项 `type: "mcp"`。该格式沿用 OpenAI Responses 的写法,官方 SDK 不会拒绝。 | 字段 | 说明 | |---|---| | `tools[].type` | 固定为 `"mcp"`。`tools` 中只能有一项 `type: "mcp"`;调用方自己的 `function` 工具可同时存在 | | `tools[].server_label` | 只接受 `"scirouter"` | | `tools[].allowed_tools` | 可省略,省略时为该部署开放的全部工具;也可写成 `{ "tool_names": [...] }`。为空数组或含不存在的工具名时,整个请求返回 400,`details.available` 列出可用的工具 | | `tools[].server_url` | 不接受。连接外部 MCP 服务器时,按[客户端配置](#客户端配置)中的方式由厂商连接 | | `tools[].require_approval` | 只能为 `"never"` 或不填 | | `scirouter.max_tool_rounds` | 可选,1–30 的整数,缺省 6。带工具调用模型的轮数上限 | - 达到 `max_tool_rounds` 后,平台再调用一次不带工具的模型,由模型根据已有资料作答,因此请求总能得到回答。需要更多轮检索时调大该值,最大 30。 - 顶层 `scirouter` 对象只接受 `max_tool_rounds`。未声明托管工具却带了该字段,同样返回 400。 - 使用 OpenAI 官方 Python SDK 时,将顶层的 `scirouter` 放入 `extra_body`,SDK 会将其合并到请求体顶层。 ### 执行流程 1. 模型请求托管工具时,平台执行该工具,将结果以 `role: "tool"` 消息接入上下文,再调用模型。 2. 模型请求调用方自己的函数时,循环结束,该轮原样返回调用方;调用方执行后发送下一轮,与不使用托管工具时相同。 3. 同一轮中模型同时请求托管工具与调用方的函数时,返回调用方的函数,托管工具的这一轮不执行(扩展字段中为 `status: "skipped"`);调用方回复后,模型会重新请求。 4. 带 `tools` 的请求只发往支持工具调用的线路,任何支持函数调用的模型均可使用托管工具。模型没有支持工具调用的线路时返回 503 `model_unavailable`(同[对话补全](https://www.scirouter.cn/docs/chat-completions)),不退回文本协议。 5. 托管工具的入参不合法、工具不存在或被限频时不报错:该条的 `status` 为 `failed`,原因作为工具结果交回模型,由模型决定重试或换用其他方法。 ### 响应 响应仍为 OpenAI 格式,顶层 `scirouter` 扩展字段(见[可观测性](https://www.scirouter.cn/docs/observability))增加 `tool_rounds` 与 `tool_calls` 两项。以下示例省略 `choices` 与 `usage`: ```json { "scirouter": { "request_id": "req_…", "cost_quota": 23180, "tool_rounds": 3, "tool_calls": [ { "round": 0, "id": "call_…", "name": "web_search", "status": "done", "summary": "web 8 条", "ms": 1320 }, { "round": 1, "id": "call_…", "name": "fetch_page", "status": "failed", "summary": "读网页失败:不允许的地址", "ms": 45 } ] } } ``` 数值为示例。 | 字段 | 说明 | |---|---| | `tool_rounds` | 调用模型的次数 | | `tool_calls` | 每项为一次工具调用。`round` 从 0 起,与请求日志的 `v1_tool_round` 标签口径相同;`status` 为 `done` / `failed` / `skipped`。不含入参与正文 | | `cost_quota` | 各轮之和 | | `request_id` | 每轮使用不同的 `request_id`,此处为最后一轮的 | - `usage` 同样为各轮之和,`prompt_tokens_details` 等嵌套字段逐项相加。`/v1/responses` 与 `/v1/messages` 的托管循环规则相同:`response.usage` 与 Anthropic 格式的 `usage` 均为各轮合计。 - 控制台中每轮记录一条请求日志,标签为 `v1_tool_round`;请求的 `metadata` 已有 8 个键时不添加该标签。 - 带托管工具的请求不进入响应缓存(结果随网页内容变化),`Idempotency-Key` 照常生效。 ### 流式响应 - 中间轮的正文照常流出;托管工具的 `tool_calls` 增量不下发。 - 每次工具开始与结束各发送一个 `choices: []` 的分片,`scirouter.tool` 为该条工具调用:开始分片的 `status` 为空、`ms` 为 0,结束分片带 `status` / `summary` / `ms`。该机制与[可观测性](https://www.scirouter.cn/docs/observability)中的扩展分片相同,官方 SDK 会跳过这些分片。 - `[DONE]` 之前的收尾分片带各轮合计;末尾的 usage 分片同样为各轮之和。 - 扩展分片沿用该流第一个上游分片的 `id` / `created` / `model`。 ```text data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"tool":{"round":0,"id":"call_…","name":"web_search","status":"","ms":0}}} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"tool":{"round":0,"id":"call_…","name":"web_search","status":"done","summary":"web 8 条","ms":1320}}} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"近一年…"}}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"request_id":"req_…","tool_rounds":3,"cost_quota":23180,"tool_calls":[…]}} data: [DONE] ``` ## 计费 MCP 与 `/v1` 托管工具中,下列工具按平台服务单价计费,由调用所用 Key 的账户承担(团队项目下的 Key 由团队承担),计入该 Key 的月度上限: | 工具 | 计费方式 | |---|---| | `web_search` | 按次;有结果才收,10 分钟内同一检索词命中缓存不收 | | `fetch_page` | 读普通网页不收;读到 PDF 按文档解析的页数收 | | `run_code` | 按 CPU 秒;沙箱自身出错不收 | 其余工具不计费。`/v1` 托管工具的每一轮另按普通模型调用计费。单价见[定价页](https://www.scirouter.cn/pricing)。 控制花费的方式:调小 `max_tool_rounds`,或用 `allowed_tools` 只放开需要的工具。 ## 数据流向与限制 MCP 与 `/v1` 托管工具的安全限制相同: - 只读取公网的 http / https;私网地址、平台自身的站点、拒绝名单中的站点一律拒绝。 - robots.txt 只遵守写给 `SciRouterBot` 的规则。 - 每个站点有并发与频率限制。 - 网页正文有字数上限。 | 工具 | 发出的内容 | 接收方 | |---|---|---| | `web_search` | 检索词 | 搜索服务商,见[子处理者清单](https://www.scirouter.cn/legal/subprocessors) | | `search_literature` | 检索词 | arXiv、CrossRef、Semantic Scholar | | `resolve_identifier`、`read_record`、`gene_neighbors`、`find_precedents` | 只发标识符(登录号、区间、基因名、物种名、CID、InChIKey) | NCBI、UniProt、Ensembl、RCSB PDB、PubChem | - 读网页以 `SciRouterBot` 的 UA 访问,见 [SciRouterBot 抓取器说明](https://www.scirouter.cn/bot);网页正文不落库。 - MCP 调用日志只记录 Key、工具名、耗时与一句摘要,不记录正文。 ### 读网页失败的原因 读网页失败的常见原因如下,具体原因写在结果的 `isError` 文字中: - 地址为私网或本机地址,或端口不是 80 / 443; - 链接带有疑似凭据的参数(`token=`、`api_key=`、`sig=` 等); - 平台自身的站点; - 在拒绝名单中; - 站点的 robots.txt 明确拒绝 `SciRouterBot`; - 页面过大; - 短时间内对同一站点读取过于频繁; - 网站拒绝访问、页面不存在或超时; - 页面主要依靠脚本渲染,读到的内容很少。 ## 相关 - Key 的边界与权限:[认证与 API Key](https://www.scirouter.cn/docs/authentication) - `scirouter` 扩展字段与流式分片:[可观测性](https://www.scirouter.cn/docs/observability) - 工具调用只发往支持的线路:[对话补全](https://www.scirouter.cn/docs/chat-completions)