路由规则
基于条件表达式的动态路由——可用变量与运算符、作用域优先级与首条命中、加权分流目标、规则链与回退,覆写默认加权择优的进阶手段
通用接入规则里的分组、优先级、权重三项,描述的是上游接入后的静态加权择优:一个查询在同分组、同优先级内按固定权重落地。路由规则则是在此之上的动态层——它用条件表达式在每次请求时即时研判,可以在静态择优之前覆写默认的上游选择,让路由依据请求上下文、请求头、子账户归属、容量水位等运行时条件灵活分流。
本页面向运营控制台的网关管理人员,讲清路由规则的求值模型、可用变量、作用域优先级、加权分流目标、规则链与回退,以及它与默认加权择优的衔接关系。
何时用路由规则。 静态加权择优能覆盖大多数常规分流;当你需要"按请求头分级路由""容量逼近上限时切到备用上游""按子账户给不同模型""灰度切流做 A/B"等运行时条件驱动的决策时,才引入路由规则。规则只覆写上游/模型的选择,不改变计量、护栏与能力边界。
1. 求值模型:先于默认择优、首条命中即止
路由规则在路由中间件的前置段求值,位置在默认加权择优之前:
- 先于默认择优: 只要有一条路由规则命中,默认的分组/优先级/权重择优即被跳过,改用规则给出的目标。
- 首条命中即止: 规则按作用域与优先级排序逐条求值,第一条条件成立的规则胜出,后续规则不再求值(规则链除外,见 §6)。
- 无命中则回落: 若没有任何规则命中,路由退回到通用接入规则的默认加权择优,行为与未配置路由规则时完全一致。
2. 可用变量
条件表达式可读取本次请求的运行时上下文。变量分四组:
| 分组 | 变量 | 含义 |
|---|---|---|
| 请求上下文 | model | 请求声明的模型中性名 |
complexity | 路由中间件研判的复杂度(simple / complex) | |
request_type | 请求类型(如 chat / embedding) | |
| 请求头 | headers["<头名>"] | 客户应用透传的请求头(键名大小写不敏感) |
| 归属上下文 | api_key_id | 发起请求的子账户标识 |
group | 请求归属的路由分组 | |
| 容量水位(百分比 0–100) | budget_used | 当前子账户/分组的额度已用占比 |
tokens_used | 词元速率上限已用占比 | |
request_rate | 请求速率上限已用占比 |
容量水位口径。 三个水位变量反映"当前用量相对所配上限的百分比",超过 100 表示已耗尽。当某请求在多个层级(子账户 / 分组 / 上游)都配了上限时,取各层级中最高的占比。若对应维度未配上限,变量取
0——budget_used > 80这类规则永不命中。规模性的额度阈值属商务约定,不在文档固化,以服务协议与控制台为准。
3. 条件运算符
表达式支持常见的比较、逻辑与字符串运算:
| 类别 | 运算符 / 函数 | 示例 |
|---|---|---|
| 比较 | == != > < >= <= | budget_used > 80 |
| 逻辑 | &&(与)||(或)!(非) | complexity == "complex" && budget_used < 50 |
| 字符串 | .startsWith(...) .endsWith(...) .contains(...) | model.startsWith("flagship-") |
| 集合 | <值> in [...] | headers["x-env"] in ["staging", "prod"] |
求值的健壮性约定:表达式语法非法时该规则记一条告警并跳过、继续求值后续规则;引用了缺失的请求头时表达式取假(优雅不命中);空表达式视为恒真(用 true / false 显式表达"总是命中 / 从不命中")。
4. 作用域与优先级
路由规则按三层作用域组织,按"范围越窄、优先级越高"逐层求值,首条命中即止:
子账户作用域(最高)
│
▼
分组作用域
│
▼
全局作用域(最低,对所有请求生效)- 同一作用域内的多条规则,按
priority(整数,值小者先)排序求值;priority相同时按创建先后保序。 - 跨作用域时,先求值更窄的作用域(子账户 → 分组 → 全局),任一层命中即止,不再下探更宽的层。
- 建议把关键规则放在
priority0–10、回退兜底规则放在 100+,并在数值间留出间隔(0、10、20)便于后续插入重排。
5. 加权分流目标与回退
每条规则携带一个或多个目标,命中后按目标的权重概率性地选定一个:
curl https://your-platform/api/v1/routing-rules \
-X POST \
-H "Content-Type: application/json" \
-H "Cookie: <控制台会话凭证>" \
-d '{
"name": "复杂查询走旗舰模型",
"enabled": true,
"expression": "complexity == \"complex\"",
"targets": [
{ "model": "<旗舰模型中性名>", "weight": 0.7 },
{ "model": "<次旗舰模型中性名>", "weight": 0.3 }
],
"fallbacks": ["<备用模型中性名>"],
"scope": "global",
"priority": 10
}'| 字段 | 含义 |
|---|---|
expression | 条件表达式;为空或 true 时恒命中 |
targets | 一个或多个加权目标,各目标可指定 model(中性名)与 weight;权重之和须为 1,多目标时按权重概率性选一 |
fallbacks | 选定目标不可用时的备用中性名序列,按序降级 |
scope / scope_id | 作用域(global / group / api_key)及其标识(非全局时必填) |
priority | 作用域内求值顺序,值小者先 |
加权分流即 A/B 切流。 给同一条规则配多个目标并设权重,即可把流量按比例切到不同模型(如 70% 旗舰、30% 次旗舰),用于灰度发布或成本与质量的折中。权重始终须和为 1。
规则的增删改查走控制平面 /api/v1/routing-rules:
| 方法 | 端点 | 用途 |
|---|---|---|
| GET | /api/v1/routing-rules | 列出路由规则(可按 scope / scope_id 过滤) |
| POST | /api/v1/routing-rules | 新建规则 |
| PUT | /api/v1/routing-rules/{ruleId} | 变更规则(字段可选,仅传需改字段) |
| DELETE | /api/v1/routing-rules/{ruleId} | 删除规则 |
6. 规则链:分步改写
默认情况下,首条命中即止。若一条规则设了 chain_rule: true,则它命中后不停止——而是用它解析出的上游/模型作为新的上下文,从作用域链顶部重新求值全部规则。这样可以把"规则别名归一"与"按归一后名字选上游"拆成两步组合:
链式求值在以下任一情形终止:本轮无规则命中;命中的是终止规则(chain_rule: false,默认);上游与模型在一步后未变化(收敛,避免死循环)。每一步链式决策都会落入路由轨迹便于追溯。建议把链保持在 2–3 步内、确保每条预期链路的最后一条是终止规则,并把收敛检测当作安全网而非主要终止手段。
7. 与默认择优、回退的衔接
路由规则、默认加权择优、回退三者按固定次序协作:
| 阶段 | 行为 |
|---|---|
| ① 路由规则 | 先于默认择优求值;命中则覆写上游/模型,跳过默认择优 |
| ② 默认加权择优 | 仅当无规则命中时运行:分组筛选 → 优先级择层 → 权重择优 |
| ③ 健康检查与回退 | 无论上游由规则还是默认择优选定,都做健康检查;不健康则按规则 fallbacks 或优先级降级到下一候选 |
一次请求若发生覆写、重试或降级,其逐次尝试链(命中规则、选定模型、回退序号)落入路由轨迹,可在「请求监控」页(GET /api/v1/monitor/route-trail)逐条追溯。
能力边界不变。 路由规则只改变"把请求发给哪个上游模型",生成始终由选定的上游模型完成;平台对路由决策与回退负责,不对生成内容做实质性加工。能力边界详见中间件管道与扩展点 SDK。