> 原始 Markdown 孪生体（构建期从源 Markdown 生成）。渲染页：https://docs.gatellm.io/zh-CN/reference/upstreams-models-fields · 文档索引：https://docs.gatellm.io/zh-CN/llms.txt


# 上游与模型字段

本章讲怎么在控制台配置上游服务（模型供应商）和模型。这是网关能转发请求的前提。

入口：控制台 → **上游服务**（仅 admin）。每个上游下挂若干模型。

## 上游服务管理

### 新建上游

控制台 → 上游服务 → 新建，填下表字段：

| 字段 | 说明 | 默认值 | 示例 |
|------|------|--------|------|
| 名称 | 上游唯一标识，模型引用它 | （必需） | `openai` |
| 协议 | 决定执行器与请求 schema（共 15 种） | （必需） | `openai` / `openai_response` / `openai_images` / `openai_embeddings` / `openai_audio` / `openai_rerank` / `openai_realtime` / `anthropic` / `google` / `aws_converse` / `aws_invoke` / `aws_codewhisperer_streaming` / `dashscope` / `dashscope_realtime` / `passthrough` |
| 基础 URL | 上游真实地址，结尾不带 `/` | （必需） | `https://api.openai.com/v1` |
| API Key | 上游密钥，可加多把；每条 = 密钥（编辑时掩码）+ 权重（`0` = 备用）+ 移除；按权重确定性加权分布，同一调用方粘同一把 | （必需） | `sk-...` |
| 启用 | 关闭则不参与路由 | `true` | ✓ |
| 自定义头 | 额外请求头，支持 `{{var}}` 与 `{{alt1\|alt2}}` 回退链 | 空 | |
| User-Agent | 覆盖全局 UA，支持模板 | 用全局 UA | |
| 代理 | 上游出站代理 | 无 | |
| DNS | per-upstream DNS（DoH/DoT/UDP 自动识别）+ TTL | 用系统 DNS | |
| 请求体规则 | 请求体改写规则（path/value/mode） | 空 | |
| 请求/响应脚本 | JS 脚本变换（详见 [脚本 API 参考](/zh-CN/reference/scripting-api.md)） | 无 | |
| 脚本错误模式 | `log-and-continue` / `log-and-reject` | `log-and-continue` | |
| 脚本位置 | `after`（规则后）/ `before` | `after` | |
| Token 计数 | `upstreamApi` / `tiktoken` | `upstreamApi` | |
| 限流 | 上游级限流：`rpm` / `max_concurrency`（并发）/ `tpm` / `tps_min_interval_ms`（相邻请求最小间隔，毫秒）/ `wait_timeout_secs`（等许可超时，默认 10s）/ `initial_tokens`（令牌桶初始填充百分比 0–100，默认 100） | 不限流 | |

### 拉取可用模型（探测）

上游表单里的**「拉取可用模型」**按钮会向该上游发起一次真实的模型列表探测（如 OpenAI 兼容上游的 `GET /models`），弹出「可用模型探测」面板：显示解析出的模型 ID 个数（含上游原始返回数与来源）、模型 ID 列表（过长时截断显示前若干个），可一键**复制全部**。用来在建模型前确认上游真实可用哪些模型 ID，避免手填拼错。

### 多密钥与权重 {#multi-key-weights}

一个上游可配多把 API Key。选择算法是**确定性加权分布 + 粘性绑定**，不是轮询：

- 首次选择用 FNV-1a 对 `(调用方 access_key, upstream 名)` 哈希，按各 key 的 `weight` 占总权重的比例落到累计权重区间。不同调用方按权重比例分散到不同 key——`weight=2` 的 key 拿到 `weight=1` 的两倍流量。
- 同一个调用方 access_key **黏到同一把 key**（绑定存入内存中的会话-密钥绑定表，仅内存、不跨节点共享——各节点各自维护本地 prompt-cache 黏性），保证上游 prompt cache 与签名一致性。绑定带**空闲 TTL**（`KEY_BINDING_TTL_SECS`，默认 1800 秒 / 30 分钟，`0` = 永久）：该调用方在 TTL 内无新请求即过期，下次重新选择。
- **配置 reload 不再整体清空绑定**，失效由**指纹**驱动：每条绑定记录其 upstream 候选 key 集的指纹（按各 key 的位置与权重算出）。读取绑定时若指纹与当前候选集不符，视为失效、重新选择。因此——**原地轮换某把 key 的值**（同一位置换值）不破坏黏性；而**增删、重排 key 或改权重**会改变指纹、触发重选。与工业级网关（Envoy / AWS ALB）的最小扰动（minimum-disruption）语义一致。
- `weight = 0` 是**备用 key**：仅当所有 `weight > 0` 的 key 都试过失败后才启用，且不存绑定。
- 某把 key 请求失败时，网关在该 upstream 内轮换到下一把未试过的 key 重试，但**不覆盖**首次粘性绑定——后续该调用方的请求仍从原绑定 key 起步。

> 这是单 upstream 内多 key 的选择机制，与**负载均衡器 entry 选择**（Smooth WRR 平滑加权轮询，见 [负载均衡字段](/zh-CN/reference/load-balancing-fields.md)）是两套独立机制：LB entry 在 handler 层选、跨 upstream；upstream 内多 key 在 dispatch 层选、同 upstream 内。两者正交叠加（LB 选中某 entry → 该 entry 的 upstream 内再按本节粘性选 key）。

**在控制台看实时绑定**：上游列表 → 该上游某模型行的 **监控**（Monitor）图标 → 「模型监控」面板。**Access Key Bindings** 标签页逐行列出每个可经分组 ACL 访问该模型的 access key，以及它**当前**粘到哪把上游 key：来源为 `binding` 表示存在活跃粘性绑定；为 `prediction` 表示此刻无活跃绑定、所示上游 key 是按**本模型候选集**算出的确定性加权预测（同一上游的不同模型预测可能不同，因为各模型候选集各自计算）。指纹列与当前候选集不符的绑定标 **stale**——仍展示，但下次请求即重选（与派发真相一致）。上方的 **上游 keys** 名册作为图例，悬停某绑定行会高亮其对应上游 key。该视图是**单节点**的（两种存储模式下绑定表都在内存、不跨节点共享），面板底部带本实例标识。面板默认每 3 秒自动刷新（可关）。限流仪表在 **Rate Limit** 标签页；该模型未配限流时该页显示空态，不影响绑定视图。完整选择/切换语义即上文所述（确定性加权哈希 + 指纹失效 + 空闲 TTL）。

### 删除上游

若该上游下还有模型引用，删除返回 **422**（先删或迁移模型再删上游）。

### 自定义 Header 与 User-Agent

为上游所有请求附加自定义 header，支持模板变量。完整变量清单与各配置处的可用范围见 [模板变量速查](/zh-CN/reference/template-variables.md)；此上下文可用的变量：

| 变量 | 来源 |
|------|------|
| `{{request_access_key_name}}` | 匹配的访问密钥名 |
| `{{request_access_key_group}}` | 访问密钥分组名 |
| `{{request_id}}` | 客户端 `z-request-id` 头 |
| `{{access_key_hash}}` | 访问密钥名 SHA-256 哈希前 16 字节 base64 |
| `{{system_prompt_hash}}` | system 提示词内容的 SHA-256（协议无关） |
| `{{header:Key}}` | 客户端请求头的值（不区分大小写） |

**回退链语法**：`{{var1|var2}}` 按顺序取第一个可用的变量；全部为空则该 header 被省略（不发送空字符串）。

**示例 — 在 User-Agent 中包含访问密钥名以便上游日志关联（控制台 → 上游服务 → 编辑该上游）：**

1. **User-Agent** 字段填 `gatellm/key-{{request_access_key_name}}`。
2. **自定义头** 区域添加两条：
   - 头名 `X-Request-Access-Key`，值 `{{request_access_key_name}}`。
   - 头名 `X-Request-Group`，值 `{{request_access_key_group}}`。

### Per-Upstream DNS 解析器

每个上游可配独立 DNS 服务器，绕过容器/OS 层 DNS 缓存，解决上游 ALB IP 轮换后旧 IP 被缓存导致的持续 503/504：

| Scheme | 协议 | 端口 |
|--------|------|------|
| （无） | UDP 标准 DNS | 53 |
| `udp://` | UDP + TCP 回退 | 53 |
| `tls://` | DNS-over-TLS | 853 |
| `https://` | DNS-over-HTTPS | 443 |

在控制台 → 上游服务 → 编辑该上游 → **DNS** 字段填入服务器列表（scheme 决定协议，见上表）：

- 用阿里 DNS（UDP）：`223.5.5.5`、`223.6.6.6`。
- 用 Cloudflare DNS-over-TLS：`tls://1.1.1.1`、`tls://1.0.0.1`。

## 模型管理

在上游列表点该行 **展开**，看到该上游下的模型子表（列：名称 / 上游模型 ID / 协议 / 别名 / 隐藏主名），每个模型有 5 个操作：**测试模型**、**模型监控**、**复制配置**（以该模型配置为模板快速新建）、**编辑**、**删除**。

### 新建模型

| 字段 | 说明 | 默认值 | 示例 |
|------|------|--------|------|
| 名称 | 对外暴露给客户端的模型名，可自定义 | （必需） | `gpt-4o` |
| 上游 | 所属上游 | （必需） | `openai` |
| 上游模型 ID | 发往上游的真实模型名 | （必需） | `gpt-4o` |
| 别名 | 额外可用的名字（与模型名共享全局唯一空间） | 空 | `gpt4o` |
| 隐藏主名 | `hide_name=true` 时主名不可访问（404），只能用别名或经负载均衡 | `false` | |
| Anthropic Signature | 在多轮对话中保留推理上下文（thinking 块的签名透传） | 关 | |
| 协议覆盖 | 不填用上游协议；填了则该模型用别的协议 | 继承上游 | |
| 基础 URL 覆盖 | 不填用上游 base_url；`direct_path` 时把此值当完整端点 URL | 继承上游 | |
| 类型 kind | DashScope 等协议的变体标识 | 无 | |
| inference_profile | Bedrock 的推理配置 ARN | 无 | |
| 请求体规则 | 模型级请求体改写规则（覆盖上游级） | 空 | |
| 请求/响应脚本 | 该模型级脚本（覆盖上游级） | 无 | |
| 限流覆盖 | `inherit`（继承上游）或与上游同形的具体值（字段见上游「限流」行） | `inherit` | |
| Token 计数覆盖 | 覆盖上游级 | 继承上游 | |
| 启用 | | `true` | ✓ |

> **名称 vs 上游模型 ID**：客户端调的是「名称」，网关发往上游用的是「上游模型 ID」。两者不同就实现了模型别名/重命名。`aliases` 是额外的可用名。

### 测试模型

模型列表 → 该模型 → **测试模型**，打开测试抽屉发起一次真实调用验证链路（`POST /console/api/models/test`）：

- **客户端协议**：可选 `openai` / `anthropic` / `openai_response` / `google`，选择后抽屉实时显示「→ 上游协议」的翻译映射——用来验证跨协议互译（如 Anthropic 客户端协议调 OpenAI 上游）。
- **请求体**：按所选客户端协议预填的 JSON 编辑器，可自由修改后点**发送测试**，返回真实上游响应（成功 / 失败及错误详情）。
- **realtime 协议**（`openai_realtime` / `dashscope_realtime`）的模型另有实时会话测试：打开一条到解析后上游的 WebSocket 会话做端到端验证（开始会话 / 结束会话，显示握手与会话建立状态）。

## 模型别名与隐藏名称

### 别名（aliases）

为模型定义多个可访问的名称。控制台 → 模型 → 新建/编辑 `gpt-4o-2024-05-13`，依次填：

- **上游** 选 `openai`。
- **上游模型 ID** 填 `gpt-4o-2024-05-13`。
- **别名** 填 `gpt-4o`、`gpt4o`（两个，与主名共享全局唯一空间）。

客户端用 `gpt-4o` 或 `gpt4o` 都能访问到同一个模型。

> **注意**：密钥组的模型 ACL 只匹配**规范名称**（`name` 字段），不解析别名。如果模型规范名是 `gpt-4o-2024-05-13`，密钥组模型列表必须列出 `gpt-4o-2024-05-13`，不能写别名。

### 隐藏主名（hide_name）

设置 `hide_name = true` 后，客户端**无法**用规范名访问模型（返回 404），只能用别名。控制台 → 模型 → 新建/编辑 `claude-sonnet-4-5`，依次填：

- **上游** 选 `anthropic`。
- **上游模型 ID** 填 `claude-sonnet-4-5`。
- **别名** 填 `writing-assistant`（自定义的对外名，示例为虚构）。
- 勾选 **隐藏主名**（`hide_name`）。

效果：
- 客户端只能用 `writing-assistant` 访问
- `/v1/models` 列表只列出别名，不列出 `claude-sonnet-4-5`
- 负载均衡器可以引用 `claude-sonnet-4-5`（隐藏模型可作为 LB 的 entry）
- 统计、日志、凭证过滤仍使用规范名

**适用场景**：
- **白标**：以品牌名称暴露模型，隐藏真实上游模型 ID
- **迁移**：暴露稳定别名，变更底层模型名
- **负载均衡专用**：隐藏底层模型，仅通过 LB 名称暴露

> `hide_name = true` 时 `aliases` 可以为空。此时模型对外部 API 不可见，但仍可被负载均衡器引用。

## 请求体修改（Request Payload）

在请求发送到上游前修改 JSON 请求体。修改规则在**协议转换之后**应用，影响最终上游请求体。

### 规则格式

每个规则包含：

| 字段 | 类型 | 说明 |
|------|------|------|
| `path` | String | 点分隔的 JSON 路径（如 `temperature`、`messages.0.content`） |
| `value` | JSON | 要设置、追加或删除的值 |
| `mode` | String | **必填**，见下方模式表 |
| `condition` | Object | 部分模式需要的条件 |

### 路径语法

| 语法 | 示例 | 说明 |
|------|------|------|
| 对象键 | `temperature` | 顶层字段 |
| 嵌套键 | `response_format.type` | 深入嵌套对象 |
| 数组索引 | `messages.0.content` | 访问索引 0 的元素 |
| 通配符 | `messages.*.content` | 匹配数组**所有**元素 |

> ⚠️ `messages[].content`、`messages[*].content` 是**非法**的。通配符用 `messages.*.content`，具体索引用 `messages.0.content`。

### 模式一览

| 模式 | 说明 | 示例 |
|------|------|------|
| `overwrite` | 替换目标路径的值 | `{"path": "temperature", "value": 0.7, "mode": "overwrite"}` |
| `remove` | 删除目标路径的键 | `{"path": "temperature", "value": null, "mode": "remove"}` |
| `add-if-absent` | 仅当键不存在时设置值 | `{"path": "top_p", "value": 0.9, "mode": "add-if-absent"}` |
| `append` | 无条件追加到数组 | `{"path": "tools", "value": {...}, "mode": "append"}` |
| `append-if-missing` | 条件追加（见下） | |
| `remove-matching` | 条件移除数组元素（见下） | |
| `strip-lines` | 从字符串中移除匹配行 | |
| `filter-content-types` | 从 content 数组中移除指定类型块 | |
| `filter-tools` | 过滤 tools 数组 | |
| `inject-system-prompt` | 在协议对应位置注入 system 提示（`value` 为提示文本） | `{"value": "Be concise.", "mode": "inject-system-prompt"}` |
| `switch-route` | **不修改 body**；在协议转换**前**按**客户端**形状评估 `when`，任一谓词成立时把本次请求改投到 `use_model`（立即切换，**支持跨协议**）。零脚本开销，谓词不读二进制、大 body 磁盘暂存保持开启 | 见下 |

### 常用示例

**简单覆盖参数** —— 控制台 → 模型详情（或上游的「默认请求体规则」）→ **请求体规则** → **+ 添加规则**，加三条：

| 路径 | 模式 | 值 |
|------|------|----|
| `temperature` | `overwrite` | `0.3` |
| `max_tokens` | `overwrite` | `4096` |
| `response_format.type` | `overwrite` | `json_schema` |

**追加 system 消息（不存在时）** —— 控制台 → 请求体规则 → **+ 添加规则**，填：

- **模式** 选 `append-if-missing`。
- **路径** 填 `messages`。
- **值** 填 `{"role": "system", "content": "You are a helpful assistant."}`。
- **条件**：scope 填 `messages`；加一条 where——路径 `role`、等于 `system`（即「messages 里已有 role=system 的元素时跳过，否则追加」）。

**追加 thinking block（不存在时）** —— 控制台 → 请求体规则 → **+ 添加规则**，填：

- **模式** 选 `append-if-missing`。
- **路径** 填 `messages`。
- **值** 填 `{"type": "thinking", "thinking": {"budget_tokens": 10000}}`。
- **条件**：scope 填 `messages`；加一条 where——路径 `type`、等于 `thinking`。

**移除 thinking block** —— 控制台 → 请求体规则 → **+ 添加规则**，填：

- **模式** 选 `remove-matching`。
- **路径** 填 `messages`。
- **值** 留空。
- **条件**：scope 填 `messages`；加一条 where——路径 `type`、等于 `thinking`（即「删掉 messages 里 type=thinking 的元素」）。

**检测图片/联网→切多模态模型（`switch-route`，零脚本开销）：**

不读写 body，在协议转换**前**按**客户端**形状评估 `when`，谓词成立时把本次请求改投到 `use_model`（翻译前 立即切换，**支持跨协议**）。谓词只做结构/小值检查、不读二进制内容，因此含 base64 的大请求体仍以 占位符 + 磁盘临时文件 留在文件里，不会像 after 槽脚本那样整段读入脚本引擎内存而 OOM。这是「检测图片→切模型」类脚本的原生替代。

**在控制台怎么配（不用写 JSON）：** 模型详情（或上游的「默认请求体规则」）→ **请求体规则** → **+ 添加规则** → 模式下拉选 **`switch-route`** → 该行会展开两个控件：在「**切换到模型 (use_model)**」下拉选目标模型（可同协议或跨协议）；在「**命中条件 when**」逐条加判定，每条填**字段路径**（按**客户端**协议形状写），**等于**留空表示「字段存在即命中」、填值表示「值相等才命中」，多条之间是「或」。

例：use_model 下拉选 `qwen-vl-max`，加三条判定——

- 路径 `messages.*.content.*.image_url`，「等于」留空（OpenAI Chat 客户端图像块，存在性）
- 路径 `messages.*.content.*.type`，「等于」填 `image`（Anthropic 客户端图像块）
- 路径 `tools.*.type`，「等于」填 `web_search_20250305`（联网搜索工具）

> ⚠️ Anthropic 客户端的图片块还可能藏在 `tool_result` 块里一层（`messages.*.content.*.content.*.type` 等于 `image`），只配顶层路径会漏掉工具历史里的图片。完整配置步骤与各客户端协议的条件路径见 [把含图片的请求路由到视觉模型](/zh-CN/howto/route-image-requests-to-vision-model.md)。

`when` 为 OR 语义：省略 `eq` 是字段存在性检查，给出 `eq` 是相等检查；`*` 通配取存在性语义。`switch-route` 按**客户端**形状评估，故路径要按调用方的协议写——上例并列了 OpenAI Chat（`messages.*.content.*.image_url`）与 Anthropic（`messages.*.content.*.type` 等于 `"image"`）两种客户端形态，OR 任一命中即切换；要兼容更多客户端协议就在 `when` 里继续并列对应形态（DashScope 客户端为 `input.messages.*.content.*.image`）。`use_model` 可与当前路由同协议或跨协议（翻译前 立即切换会重翻译 body）。切到的目标视为**管理员指定的内部路由**：网关**不再**对 `use_model` 目标重新校验调用方所属分组的模型 ACL（模型 ACL 只在请求入口对客户端原始请求的模型校验一次）。完整退役案例见 [配置索引](/zh-CN/reference/configuration.md)。

### 用表达式写动态值（缓存键）

默认规则写入 `value` 里的固定值。若希望值随请求变化——例如给上游的私有缓存字段注入"同一会话用同一键"的动态值——把 `value` 写成表达式即可：字符串值含 `{{...}}` 时按模板解析，`|` 连接回退链取首个非空结果。例如"会话头优先、system 哈希兜底"：

控制台 → 模型详情 → 请求体规则 → **+ 添加规则**，填：模式 `overwrite`、路径 `prompt_cache_key`、值 `{{header:x-claude-code-session-id|system_prompt_hash}}`。

解析结果：① 请求头 `x-claude-code-session-id` 存在且非空 → 用头值（同一会话的多次请求带同一头值，即得同一缓存键，命中上游缓存）；② 头缺失或为空 → 落到 `system_prompt_hash`，即 system 提示词内容的 sha256 哈希（同一份 system 提示词得同一哈希，也能命中缓存；协议无关，兼容 Anthropic `system`、OpenAI `messages[role=system]`、DashScope `input.messages[role=system]`、Google `system_instruction`）；③ 头缺失且无 system 提示词 → `system_prompt_hash` 退化为 `sha256("")` 的固定值，若希望此时完全不注入，则不要把哈希放进链——整条链全空时本次写入被省略。头名大小写不敏感，头值前后空白视为缺失。该上下文还可用的变量：`request_id`、`request_access_key_name`、`request_access_key_group`（`access_key_hash` 在此为空，缓存键兜底请用 `system_prompt_hash`）。不含 `{{` 的字符串作字面量、非字符串值原样写入，老规则不受影响。该规则通常**挂在模型上**（哪个模型需要缓存键是模型级策略）；规则在协议转换之后应用，故写入的上游私有字段不会被翻译丢弃。在控制台表单里，直接在规则行的"值"输入框写表达式即可（占位提示已说明语法）。完整变量清单与各配置处的可用范围见 [模板变量速查](/zh-CN/reference/template-variables.md)。

### 过滤内容类型

从消息内容数组中移除指定类型（如 `image`、`video`）的内容块。控制台 → 请求体规则 → **+ 添加规则**，填：模式 `filter-content-types`、路径 `messages`、值 `image`。

**从所有已知路径移除多种类型（自动展开）** —— 控制台 → 请求体规则 → **+ 添加规则**，填：模式 `filter-content-types`、路径 留空（即所有已知内容路径）、值 填 `image`、`video`（数组）。

移除图片块时会自动注入占位文本提示模型用户曾附带图片，可通过数据库直接配置 `hint` 字段自定义。

### 模型级规则

模型级规则优先级高于上游级。上游规则先应用，然后模型规则覆盖或扩展。控制台 → 模型 → 新建/编辑 `qwen3.6-plus-strict`，**上游** 选 `openai`，在**请求体规则**（模型级）里加两条：

| 路径 | 模式 | 值 |
|------|------|----|
| `temperature` | `overwrite` | `0` |
| `response_format.type` | `overwrite` | `json_schema` |

## 模型级 base_url 覆盖

在模型上设置 `base_url` 覆盖上游的默认值。控制台 → 模型 → 新建/编辑 `custom-model`，依次填：**上游** `openai`、**上游模型 ID** `qwen3.6-plus`、**基础 URL 覆盖** `https://custom-proxy.example.com/v1`。

凭证（API Key）仍来自上游配置，仅改变请求的目标端点。适用于将特定模型路由到独立代理、vLLM 实例或自定义端点。

### direct_path 模式

设置 `direct_path = true` 时，模型的 `base_url` 被作为**完整的端点 URL** 使用，不追加任何路径。控制台 → 模型 → 新建/编辑 `my-model`，依次填：

- **上游** 选 `azure-openai`。
- **协议覆盖** 选 `openai_images`。
- 勾选 **direct_path**。
- **基础 URL 覆盖** 填 `https://{resource}.openai.azure.com/openai/deployments/my-model/images/generations?api-version=2025-04-01-preview`。

## 模型级协议覆盖

模型可通过 `protocol` 字段覆盖上游的协议，让同一组凭据为不同 API 格式的模型服务。控制台 → 模型 → 新建/编辑 `glm-5`，依次填：**上游** `aws-global`、**上游模型 ID** `zai.glm-5`、**协议覆盖** `openai`、**基础 URL 覆盖** `https://bedrock-runtime.us-west-2.amazonaws.com/openai/v1/`。

## Upstream Inference Profile

`upstream_inference_profile` 覆盖发送给上游的模型 ID，源自 AWS Bedrock 的应用推理配置，可用作通用模型 ID 覆盖。控制台 → 模型 → 新建/编辑 `glm-5`，依次填：**上游** `aws-global`、**上游模型 ID** `zai.glm-5`、**inference_profile** `arn:aws:.../abcd1234`。

设置后，该值在所有请求中作为上游模型 ID 使用，`upstream_model_id` 作为备用。

## DashScope 模型配置

DashScope 不同类型模型有不同端点，通过 `kind` 字段选择：

| kind | 端点 | 适用模型 |
|------|------|---------|
| （默认） | `/api/v1/services/aigc/text-generation/generation` | qwen-turbo、qwen-plus、qwen-max |
| `dashscope-multimodal` | `/api/v1/services/aigc/multimodal-generation/generation` | qwen-vl-chat-v1、qwen-vl-plus、qwen-audio、fun-asr-flash |
| `dashscope-text-embedding` | `/api/v1/services/embeddings/text-embedding/text-embedding` | text-embedding-v4 |
| `dashscope-rerank` | 文本重排序端点 | gte-rerank |
| `dashscope-audio-asr` | 异步语音 ASR | fun-asr |

### 文本生成

控制台 → 模型 → 新建/编辑 `qwen-turbo`，依次填：**上游** `dashscope`、**上游模型 ID** `qwen-turbo`、**协议覆盖** `dashscope`。

### 视频生成（direct_path）

视频生成等异步模型需要 `direct_path = true`。控制台 → 模型 → 新建/编辑 `wanx2.1-t2v`，依次填：

- **上游** 选 `dashscope`。
- **上游模型 ID** 填 `wanx2.1-t2v`。
- **协议覆盖** 选 `dashscope`。
- 勾选 **direct_path**。
- **基础 URL 覆盖** 填 `https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis`。

异步模型还需在 `extra_config` 设置：`{"dashscope": {"async_mode": true}}`

### 文本向量（kind 选择端点）

文本向量模型使用百炼 MaaS 域名，需配置独立 upstream。控制台 → 模型 → 新建/编辑 `text-embedding-v4`，依次填：**上游** `dashscope-maas`、**上游模型 ID** `text-embedding-v4`、**协议覆盖** `dashscope`、**类型 kind** `dashscope-text-embedding`。

客户端用标准 OpenAI `/v1/embeddings` 协议发请求，网关自动翻译为 DashScope 格式。

### 重排序

两种路径：

**DashScope 翻译**（百炼模型）—— 控制台 → 模型 → 新建/编辑 `gte-rerank`，依次填：**上游** `dashscope-maas`、**上游模型 ID** `gte-rerank`、**协议覆盖** `dashscope`、**类型 kind** `dashscope-rerank`。

**OpenAI 兼容上游**（vLLM/Cohere/Jina）—— 控制台 → 模型 → 新建/编辑 `bge-reranker-v2-m3`，依次填：**上游** `vllm-rerank`、**上游模型 ID** `BAAI/bge-reranker-v2-m3`、**协议覆盖** `openai_rerank`。

### 语音转写（OpenAI 兼容）

`qwen-audio`、`fun-asr-flash` 等同步音频模型通过 `kind = "dashscope-multimodal"` 配置，支持 OpenAI `/v1/audio/transcriptions` 接口。控制台 → 模型 → 新建/编辑 `qwen-audio`，依次填：**上游** `dashscope`、**上游模型 ID** `qwen-audio`、**协议覆盖** `dashscope`、**类型 kind** `dashscope-multimodal`。

客户端用标准 OpenAI multipart 上传音频，网关自动翻译到 DashScope 格式。

### 异步语音 ASR

异步 ASR 需 `kind = "dashscope-audio-asr"` + `extra_config.dashscope.async_mode = true`。控制台 → 模型 → 新建/编辑 `fun-asr`，依次填：**上游** `dashscope-maas`、**上游模型 ID** `fun-asr`、**协议覆盖** `dashscope`、**类型 kind** `dashscope-audio-asr`、**extra_config** 填 `{"dashscope": {"async_mode": true}}`。

客户端向 `POST /v1/services/{*rest}` 提交，轮询 `GET /v1/services/{model}/tasks/{task_id}`。

## OpenAI Images 模型配置

通过 `openai_images` 协议 + `direct_path = true` 配置图片生成/编辑。控制台 → 模型 → 新建/编辑 `dall-e-3`，依次填：

- **上游** 选 `openai-images`。
- **上游模型 ID** 填 `dall-e-3`。
- **协议覆盖** 选 `openai_images`。
- 勾选 **direct_path**。
- **基础 URL 覆盖** 填 `https://api.openai.com/v1/images/generations`。

Gemini 图片模型用 `protocol = "google"`（非 `openai_images`），网关自动翻译。控制台 → 模型 → 新建/编辑 `gemini-3-pro-image-preview`，依次填：**上游** `google-gemini`、**上游模型 ID** `gemini-3-pro-image-preview`、**协议覆盖** `google`。

## 模型脚本配置

每个上游和模型可配 JavaScript 脚本对请求/响应体做自定义变换：

| 字段 | 说明 | 默认值 |
|------|------|--------|
| `request_transform_before` | 翻译前请求体脚本 | 无 |
| `request_transform_after` | 翻译后请求体脚本 | 无 |
| `response_transform` | 响应体脚本 | 无 |
| `script_error_mode` | `log-and-continue` / `log-and-reject` | `log-and-continue` |

**内联脚本** —— 控制台 → 模型详情（或上游）→ **请求/响应脚本** → 在**翻译后请求体**（`request_transform_after`）槽黏贴：

```javascript
function transform(body, context) { body.model = context.upstreamModel; return body; }
```

**文件脚本** —— 控制台的脚本编辑器只接受内联内容。引用外部 `.js` 文件（如 `{"file": "scripts/inject-thinking.js"}`）只能通过 Console API 设置；UI 会原样保留已设置的文件引用，直到你在该槽输入内联内容覆盖它。详见 [写第一个脚本变换](/zh-CN/howto/write-script-transform.md)。

**脚本级别**：

| 级别 | 作用范围 | 适用场景 |
|------|---------|---------|
| 上游 | 经过此上游的所有模型 | 协议适配、公共字段注入 |
| 模型 | 仅此模型 | 模型特定调整、参数调优 |

模型级脚本覆盖上游级。详细语法、内置函数、执行顺序见 [脚本 API 参考](/zh-CN/reference/scripting-api.md)。

**常见脚本示例 — 注入 System Prompt：**

```javascript
function transform(body, context) {
    if (body.messages.length === 0 || body.messages[0].role !== "system") {
        const systemMsg = { role: "system", content: "You are a helpful assistant." };
        body.messages = [systemMsg, ...body.messages];
    }
    return body;
}
```

**根据访问密钥分组执行条件逻辑：**

```javascript
function transform(body, context) {
    if (context.accessKeyGroup === "premium") {
        body.max_tokens = 8192;
    } else {
        body.max_tokens = 4096;
    }
    return body;
}
```

## 常见问题

**Q：模型设了 hide_name 后调主名返回 404？**
是的，这是设计。`hide_name=true` 的模型只能用别名或经负载均衡器访问，主名不出现在 `/v1/models` 列表。

**Q：同一个模型想配多个上游（故障转移）？**
用负载均衡器，见 [负载均衡字段](/zh-CN/reference/load-balancing-fields.md)。把多个上游+模型作为 entries 加进去。

**Q：上游密钥快到期了怎么换？**
编辑上游 → 改 API Key（轮换），旧值立即失效。或加一把新 key、删旧 key。

**Q：DashScope 模型怎么配？**
协议选 `dashscope`，基础 URL 填 DashScope 地址。文本生成模型无需 `direct_path`；视频/图像等异步模型需 `direct_path = true` + 完整 URL + `extra_config.dashscope.async_mode = true`。DashScope 客户端可走 `/v1/services/{*rest}`（透传）或 `/v1/chat/completions`（翻译模式）。

**Q：request_payload 和脚本（request_transform_before/after）怎么选？**
简单字段增删改用 `request_payload`（声明式规则，在网关内部直接改写请求体，不经过脚本引擎的序列化，性能最好）；复杂逻辑、条件分支、跨字段计算用脚本。「检测图片/联网→切模型」这类**纯路由决策**用 `request_payload` 的 `switch-route`（零脚本开销，谓词不读二进制、大 body 不读入内存，同协议或跨协议皆可——它在翻译前按客户端形状判定并 立即切换；脚本路径因懒投影也已不再整段物化 body，但纯路由决策无需脚本）；只有需要跨字段计算等复杂判定时才用脚本。详见 [脚本 API 参考](/zh-CN/reference/scripting-api.md)。

**Q：模型级和上游级的 request_payload 冲突怎么办？**
上游规则先应用，模型规则后应用。模型规则可覆盖或扩展上游的同路径规则。

**下一步**：单上游够用时本章即可；要多上游故障转移/负载均衡看 [负载均衡字段](/zh-CN/reference/load-balancing-fields.md)；脚本变换看 [脚本 API 参考](/zh-CN/reference/scripting-api.md)；模板变量看 [模板变量速查](/zh-CN/reference/template-variables.md)。
