# 参数如何被处理

> 参数分类与各入口协议的处理表，模拟、自愈与上下文窗口预检，以及响应头中的处理留痕。

来源：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`，用于区分达到上限与被平台中断。
