跳至指南正文
智能路由 · 函数 API v1

编写 smartChoose

用一个简短的 JavaScript 函数,为每次请求选择合适的模型。从可运行的示例开始,按你的模型和流量需求调整。

快速开始

  1. 新建智能模型,选择客户端 API 协议,并为模型别名命名。
  2. 选择兼容的候选模型和默认模型。在“模型偏好”中设置函数需要的标签、优先级或权重。
  3. 在第 3 步展开“高级:编辑函数和参数”,粘贴下方示例,按需填写“参数(JSON)”。内置策略也是可以编辑的函数模板。
  4. 在第 4 步自定义示例请求,保存并预览,随后校验并发布。只有已发布的版本会处理实际请求。
从默认模型开始
function smartChoose(request, context) {
  if (!context.defaultModel) {
    throw new Error("No eligible default model");
  }
  return { model: context.defaultModel };
}

在第 2 步选择默认模型。此函数仅在默认模型可用时选择它。

函数约定

定义同步函数 smartChoose(request, context),返回模型选择结果。网关会将原始请求发送给所选模型,函数不会改写请求体。

{ model: string, fallbackModels?: string[] }
  • model 必须是 context.candidates 中实际模型的代码,网关在执行前会再次校验。
  • fallbackModels 为可选字段:省略时使用已配置且可用的回退顺序,返回 [] 则不执行回退。显式列表最多包含两个不同的、已配置且可用的回退模型,并且不能包含已选择的模型。
  • 回退需要在第 2 步明确启用,且仅在提供方安全拒绝后执行。已经产生输出或执行情况不明确时,不会重试请求。
  • 输入对象已被深度冻结。排序前先复制数组,例如 [...context.candidates].sort(...)。

保持函数简短、同步

不使用 async/await、网络调用、文件系统、宿主访问或持久状态。Date 和 Math.random 不可用,请使用 context.requestTimeMs 和 context.routingSeed。执行有时间限制,应避免无限循环或昂贵计算。

完整类型参考 · 与编辑器自动补全共用
函数 API 类型
interface SmartRequest {
  readonly apiVersion: 1;
  readonly apiDialect: string;
  readonly stream: boolean;
  readonly body: Readonly<Record<string, unknown>>;
  readonly features: {
    inputTokenEstimate: number;
    outputTokenLimit: number;
    hasTools: boolean;
    hasImageInput: boolean;
    structuredOutput: boolean;
    taskTag: string | null;
  };
}

interface SmartCandidate {
  readonly model: string;
  readonly displayName: string;
  readonly tags: readonly string[];
  readonly priority: number;
  readonly weight: number;
  readonly capabilities: {
    contextWindowTokens: number;
    maxOutputTokens: number;
    streaming: boolean;
    tools: boolean;
    structuredOutput: boolean;
  };
  readonly cost: {
    currency: string;
    microUnits: string;
    snapshotVersion: string;
  } | null;
  readonly latency: {
    p95Ms: number;
    samples: number;
    observedAtMs: number;
  } | null;
}

interface SmartContext {
  readonly candidates: readonly SmartCandidate[];
  readonly fallbackCandidates: readonly SmartCandidate[];
  readonly defaultModel: string | null;
  readonly params: Readonly<Record<string, any>>;
  readonly billingCurrency: string;
  readonly routingSeed: string;
  readonly requestTimeMs: number;
  readonly snapshotVersion: number;
}

interface RoutingDecision {
  model: string;
  fallbackModels?: string[];
}

declare function smartChoose(
  request: SmartRequest,
  context: SmartContext
): RoutingDecision;

读取请求

请求字段
字段 / 类型用途
apiVersion
1
函数 API 版本。
apiDialect
string
可选值为 OPENAI_CHAT_COMPLETIONS、OPENAI_RESPONSES、ANTHROPIC_MESSAGES 或 GEMINI_GENERATE_CONTENT。
stream
boolean
客户端是否请求流式输出。
body
read-only object
清理后的请求 JSON。结构取决于客户端协议,messages、input 和 contents 并不通用。
body.metadata
optional value
客户端传入的 metadata(若有)。使用前检查其结构。它可以作为路由提示,但不代表授权信息。
features.inputTokenEstimate
number
输入 Token 数的估算值,包含系统文本和工具定义,不是账单 Token 数。
features.outputTokenLimit
number
请求指定的输出上限;未指定时使用路由估算的默认值。
features.hasTools / hasImageInput / structuredOutput
boolean
提取的工具调用、图片输入和 JSON/Schema 输出需求。跨协议判断时优先使用这些字段。
features.taskTag
string | null
当 body.metadata.taskTag 是不超过 128 个字符的字符串时,提供其快捷值,否则为 null。

请求体经过清理;HTTP 请求头不可用

可以通过 request.body 读取消息、工具、生成参数和普通 metadata。已识别的凭证字段会被隐藏,媒体和提供方不透明状态会被替换为描述其是否存在的对象。当前没有 request.headers 字段,在 JSON 请求体中放入 headers 也不会使其可读。

编写跨协议规则时优先使用 request.features。读取某种协议专有的请求字段前,先检查 apiDialect 和字段类型。支持的协议用于文本生成,图片输入属于兼容文本生成模型的能力。

使用路由上下文

上下文字段
字段 / 类型用途
candidates
SmartCandidate[]
仅包含本次请求可用的已配置模型,已检查权限、协议、能力、限制和线路健康状态。
defaultModel
string | null
所配置默认模型的实际模型代码;若不可用则为 null,不能假设它始终可用。
fallbackCandidates
SmartCandidate[]
明确配置用于回退且本次可用的模型。未启用回退或没有可用项时为空。
params
object
与函数版本一起保存的“参数(JSON)”,由模型所有者设置,与客户端 metadata 分开。
billingCurrency
string
用于比较成本估算的币种,只比较相同币种。
routingSeed
string
服务端提供的分配种子。预览时使用相同种子和候选快照,可复现选择结果。
requestTimeMs / snapshotVersion
number
服务端请求时间和候选快照时间,均为 Unix 毫秒时间戳。用 requestTimeMs 代替 Date.now()。

每个候选模型

候选模型字段
字段 / 类型用途
model / displayName
string
选择结果应返回 model,不要返回显示名称、目录 ID 或智能模型别名。
tags
string[]
在“模型偏好”中设置的标签,例如 coding、tools 或 long-context。
priority
integer · 0–10000
优先级模板优先选择数值较小的模型,自定义函数可自行决定是否使用。
weight
integer · 1–10000
相对流量权重,默认 1。只有函数使用此值时,才会影响选择结果。
capabilities
object
包含 contextWindowTokens、maxOutputTokens、streaming、tools 和 structuredOutput。
cost
object | null
包含 currency、microUnits(整数字符串)和 snapshotVersion。使用 BigInt 比较金额。null 表示未知,不表示免费;估算不替代最终计费。
latency
object | null
包含 p95Ms、samples 和 observedAtMs。null 表示无测量数据。比较前检查样本量和时效性;流式请求测量首段内容的响应时间。

成本和延迟可能为 null。可以从内置“优先低成本”和“优先低延迟”模板开始处理这些数据。低延迟模板在延迟距最快值 10% 以内的模型间使用权重分配,数据不足时使用优先级。

可修改的示例

根据客户端 metadata 选择

在“模型偏好”中为候选模型添加 coding 标签。发送下方 OpenAI Chat Completions 示例,或在第 4 步预览。标签缺失或匹配模型不可用时,选择可用的默认模型。metadata 仍须符合所选提供方的协议规则。

根据客户端 metadata 选择
function smartChoose(request, context) {
  const tag = request.body.metadata?.taskTag;
  const chosen = typeof tag === "string"
    ? context.candidates.find(model => model.tags.includes(tag))
    : undefined;
  const model = chosen?.model ?? context.defaultModel;
  if (!model) throw new Error("No eligible model");
  return { model };
}
示例请求 · OpenAI Chat Completions
{
  "model": "smart-assistant",
  "messages": [
    {
      "role": "user",
      "content": "Write a sorting function"
    }
  ],
  "metadata": {
    "taskTag": "coding"
  },
  "max_tokens": 512
}

组合请求特征与配置参数

为候选模型设置 tools、long-context 或 general 标签,并填写下方“参数(JSON)”。工具请求优先匹配 tools;否则,输入估算超过阈值时匹配 long-context。没有匹配项时使用可用的默认模型。模型仍须通过网关的能力检查。

组合请求特征与配置参数
function smartChoose(request, context) {
  const configured = context.params.longInputTokens;
  const threshold = Number.isFinite(configured) && configured > 0
    ? configured : 8000;
  const tag = request.features.hasTools ? "tools"
    : request.features.inputTokenEstimate > threshold
      ? "long-context" : "general";
  const chosen = context.candidates.find(model => model.tags.includes(tag));
  const model = chosen?.model ?? context.defaultModel;
  if (!model) throw new Error("No eligible model");
  return { model };
}
参数(JSON)
{
  "longInputTokens": 8000
}

先尝试纯文本请求,再尝试包含 tools 定义的请求。用短示例测试长上下文分支时,可在预览前临时调低 longInputTokens。请求仍需满足所选模型的上下文限制。

按权重分配

在第 2 步的“模型偏好”中设置权重。当两个模型都可用时,权重 3 和 1 对应大约 75% 和 25% 的请求。每次请求按当时可用的模型重新计算比例。直接选择内置“按权重分配”策略,也可实现此行为,无需编辑代码。

按权重分配
function smartChoose(request, context) {
  if (!context.candidates.length) throw new Error("No eligible model");
  let seed = 2166136261;
  for (const ch of context.routingSeed) {
    seed = Math.imul(seed ^ ch.charCodeAt(0), 16777619) >>> 0;
  }
  const total = context.candidates.reduce((sum, model) => sum + model.weight, 0);
  let slot = (seed / 4294967296) * total;
  for (const candidate of context.candidates) {
    slot -= candidate.weight;
    if (slot < 0) return { model: candidate.model };
  }
  return { model: context.candidates[0].model };
}

预期比例 = 模型权重 ÷ 所有可用模型的权重之和。相同权重对应相同比例。比例是大量请求下的近似分布;相同种子与候选列表会产生相同选择。

预览与排查

在第 4 步点击“保存并预览”,保存草稿并使用实际执行器运行示例,不调用提供方,也不扣费。检查所选模型、排除原因、执行结果以及是否使用错误回退的默认模型。点击“校验并发布”后,经过验证的版本才会生效。

候选列表中缺少模型

检查预览中的排除原因:权限、协议、工具/图片/JSON/流式能力、Token 限制和健康线路决定可用性。标签和自定义代码不能绕过这些检查。

INVALID_DECISION

同步返回仅包含 model 和可选 fallbackModels 的对象,选择可用的实际模型代码。返回 null、Promise、未知模型或未配置的回退模型都会校验失败。

使用了配置的默认模型

运行时异常、超时、无效结果或执行器不可用时,仅在配置的默认模型仍可用时使用它。默认模型不可用则请求失败。发布校验要求示例成功执行,且未使用此错误回退。

预览与实际请求结果不同

未选择本人 App Key 时,预览只模拟配置授权。选择本人密钥可加入其权限检查。候选健康状态、成本和延迟可能变化;相同快照下固定种子与请求时间,可复现预览结果。

后续请求继续使用原模型

携带已绑定提供方会话状态的请求会恢复模型和提供方绑定,不会重新运行 smartChoose。无状态请求可独立选择模型。

打开智能路由