模型路由
用 Jev 实现 LLM 模型路由:候选模型、约束与回退
Jev AI 独立教程 · 内容核对于 · Read in English
LLM 模型路由负责从已批准的候选模型中选择处理任务的一项。Jev 可以根据任务描述、候选能力和约束做有限选择,后续模型调用仍由你的应用完成。路由器不会替你发现模型,也不会核实候选能力。
本例比较两个假设候选:具备 32k 上下文的快速模型,以及描述为具备 200k 上下文和工具能力的推理模型。这些是示例标签与前提,不代表某个实际商业模型的能力。
读完你能做什么
- 先用代码过滤硬性限制,再判断语义上的适配性。
- 提供准确的候选说明,并保留升级处理分支。
- 把完成合格任务的总成本与固定模型方案比较。
把路由放在昂贵调用之前
在已知任务和可用模型后、执行下游请求前进行路由。先由代码排除不可用、缺少必要权限或已知上下文容量不足的候选。不要仅凭模型名称推断这些能力。
如果剩余选择可以用精确规则决定,继续用代码即可。当任务语义、模糊程度或质量要求会影响选择时,再考虑语义路由。它本身多一次调用,需要测量收益是否抵得过新增延迟和费用。
- 整理任务需求和批准使用的候选列表。
- 执行精确约束,再对剩余选择进行语义判断。
- 校验返回 ID,然后升级处理或调用选中模型。
描述候选能力,减少模型猜测
model-route 预设要求 task 和非空 candidates 数组。每个候选都有唯一 id,还应提供你能维护的能力、成本与延迟说明。escalate 是预留的回退选项,其余 ID 会转成 Choice 的候选键。
priorities、constraints 和 stakes 解释选择背景。涉及长记录与工具的退款纠纷,与短文本分类的要求不同。路由输入也应控制大小:说明任务需要 100k 上下文,不等于把下游全部长文本塞进路由请求。
| 输入 | 作用 |
|---|---|
| task | 描述任务及质量要求 |
| candidates | 唯一 ID 与已知能力 |
| priorities | 质量、上下文、工具、成本、延迟的相对重要性 |
| constraints | 仍然由应用代码执行的边界 |
把升级处理当作正常结果
读取 answers.model.choice,确认它是已批准 ID 或 escalate。字段缺失、概率格式异常、没有合适候选或判断模糊时,应走明确的复核路径。不要从任意返回文本中提取模型名称后直接转发给另一接口。
如果引入接受阈值,应通过标注路由案例选定,而非照搬教程中的数字。也要观察第二候选的概率以及错误类型。选择便宜但无法胜任的模型,算上重试和人工纠正后可能更贵。
说明性示例,非实时 API 结果
// 在校验原生响应后,由应用决定下一步:
const approved = new Set(["fast-model", "reasoning-model"]);
const choice = result.answers.model.choice;
if (choice === "escalate" || !approved.has(choice)) {
// 进入已配置的回退路径或人工复核。
} else {
// 再次检查可用性,将 ID 映射到服务商的实际模型。
}和固定模型基线比较
建立包含简单任务、长上下文任务、工具依赖和信息不足情况的小型标注集。对固定模型与路由方案执行相同的下游评估。判断标准应是任务最终是否合格,而不只是某一次是否选中你期待的标签。
同时记录路由和下游延迟、任务质量、重试、回退比例与总费用。调描述和阈值时保留独立测试集。候选能力、模型版本或流量结构改变后重新评估,一次旧结果不能代表永久最优的选择。
完整请求与运行方法
在 OmniaKey 创建 API Key,并在终端或服务器环境中设置 OMNIAKEY_API_KEY。下面的 curl 示例需要支持 --fail-with-body 的 curl(7.76 或更新),JavaScript 示例需要 Node.js 20 或更新。请使用测试数据;调用使用自己的账户额度,当前价格与可用性以 OmniaKey 为准。
将 JavaScript 保存为 jev-example.mjs 后运行 node jev-example.mjs。不要把密钥写进前端代码或提交到 Git。示例保留英文输入以便与调试预设对照;中文业务数据需单独验证效果。
curl
curl --fail-with-body --max-time 25 'https://api.omniakey.com/v1/alpha/search' \
-H "Authorization: Bearer ${OMNIAKEY_API_KEY}" \
-H 'Content-Type: application/json' \
--data '{
"model": "jev-latest",
"state": {
"task": "Review a complex customer dispute with 100k context and tool use",
"candidates": [
{
"id": "fast-model",
"description": "Fast general model with 32k context",
"cost": "low",
"latency": "low"
},
{
"id": "reasoning-model",
"description": "Strong reasoning, 200k context, and tool use",
"cost": "high",
"latency": "medium"
}
],
"priorities": [
"quality",
"context",
"tool_use",
"cost"
],
"constraints": [
"Customer data must remain within approved tools"
],
"stakes": "high"
},
"questions": {
"model": {
"type": "choice",
"instructions": "Select the best approved candidate using the stated quality, context, tools, cost, latency, and stakes. Do not assume undocumented capabilities. Choose escalate when no candidate is adequate or evidence is insufficient.",
"criteria": {
"fast-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"fast-model\",\"description\":\"Fast general model with 32k context\",\"cost\":\"low\",\"latency\":\"low\"}",
"reasoning-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"reasoning-model\",\"description\":\"Strong reasoning, 200k context, and tool use\",\"cost\":\"high\",\"latency\":\"medium\"}",
"escalate": "No approved candidate can safely satisfy the task, or the provided evidence is insufficient to select one."
}
}
}
}'展开 Node.js 完整示例
Node.js 20+
// Node.js 20+. Save as jev-example.mjs and run: node jev-example.mjs
// Set OMNIAKEY_API_KEY in the server/terminal environment first.
const key = process.env.OMNIAKEY_API_KEY;
if (!key) throw new Error("Set OMNIAKEY_API_KEY before running.");
const body = {
"model": "jev-latest",
"state": {
"task": "Review a complex customer dispute with 100k context and tool use",
"candidates": [
{
"id": "fast-model",
"description": "Fast general model with 32k context",
"cost": "low",
"latency": "low"
},
{
"id": "reasoning-model",
"description": "Strong reasoning, 200k context, and tool use",
"cost": "high",
"latency": "medium"
}
],
"priorities": [
"quality",
"context",
"tool_use",
"cost"
],
"constraints": [
"Customer data must remain within approved tools"
],
"stakes": "high"
},
"questions": {
"model": {
"type": "choice",
"instructions": "Select the best approved candidate using the stated quality, context, tools, cost, latency, and stakes. Do not assume undocumented capabilities. Choose escalate when no candidate is adequate or evidence is insufficient.",
"criteria": {
"fast-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"fast-model\",\"description\":\"Fast general model with 32k context\",\"cost\":\"low\",\"latency\":\"low\"}",
"reasoning-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"reasoning-model\",\"description\":\"Strong reasoning, 200k context, and tool use\",\"cost\":\"high\",\"latency\":\"medium\"}",
"escalate": "No approved candidate can safely satisfy the task, or the provided evidence is insufficient to select one."
}
}
}
};
const response = await fetch("https://api.omniakey.com/v1/alpha/search", {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(25_000),
});
if (!response.ok) {
const retryAfter = response.headers.get("retry-after");
throw new Error(`Jev HTTP ${response.status}; Retry-After: ${retryAfter ?? "not supplied"}`);
}
const result = await response.json();
console.log(JSON.stringify(result, null, 2));
// Inspect and validate the answer before connecting it to any external action.
下方是发送给 API 的原生 JSON。教程的调试入口会选中对应预设;预设输入与此原生请求不是同一个结构。使用自定义 Jev 时,直接粘贴下方 JSON。
复制原生 JSON 到调试台
Native JSON
{
"model": "jev-latest",
"state": {
"task": "Review a complex customer dispute with 100k context and tool use",
"candidates": [
{
"id": "fast-model",
"description": "Fast general model with 32k context",
"cost": "low",
"latency": "low"
},
{
"id": "reasoning-model",
"description": "Strong reasoning, 200k context, and tool use",
"cost": "high",
"latency": "medium"
}
],
"priorities": [
"quality",
"context",
"tool_use",
"cost"
],
"constraints": [
"Customer data must remain within approved tools"
],
"stakes": "high"
},
"questions": {
"model": {
"type": "choice",
"instructions": "Select the best approved candidate using the stated quality, context, tools, cost, latency, and stakes. Do not assume undocumented capabilities. Choose escalate when no candidate is adequate or evidence is insufficient.",
"criteria": {
"fast-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"fast-model\",\"description\":\"Fast general model with 32k context\",\"cost\":\"low\",\"latency\":\"low\"}",
"reasoning-model": "Choose this approved model if its documented capabilities satisfy the task, priorities, constraints, and stakes: {\"id\":\"reasoning-model\",\"description\":\"Strong reasoning, 200k context, and tool use\",\"cost\":\"high\",\"latency\":\"medium\"}",
"escalate": "No approved candidate can safely satisfy the task, or the provided evidence is insufficient to select one."
}
}
}
}如何解读结果
合成纠纷中,推理候选被描述为满足更大的上下文要求,但本页没有宣称已经得到某个实测选择。请运行示例,查看你的可用 Jev 版本返回什么,再把分布与实际需求比较。
answers.model 是路由问题的答案,而最外层 model 是执行这次判断的 Jev 版本,两者含义不同。usage 仅描述本次路由用量,不包含后续被选模型的账单。
请求失败时怎么办
- 请求格式错误(如 400)
- 核对 model、state、questions,以及各题目的 type、选项或范围。不要把 chat messages 结构发到此端点。
- 鉴权或账户拒绝(如 401、402、403)
- 核对 API Key、账户余额、模型访问权限与当前服务商政策。状态码本身不能唯一确定原因;在 OmniaKey 后台检查,避免把密钥贴进反馈。
- 限流(429)
- 读取 Retry-After(如有),降低并发并采用有上限的退避。示例不自动重试,重复请求可能额外计费。
- 5xx、网络错误或超时
- 检查服务状态和连接,再决定是否重试。本例 25 秒超时仅中止客户端等待,不保证上游停止处理或免计费。
- HTTP 成功但结果无法使用
- 检查响应结构、问题名与题目类型。缺少答案或未知选项应进入回退或人工检查,不要强制转换后直接执行。
接入前的验证
- 移除长上下文候选后,应能升级处理,而不是编造另一个候选。
- 将候选能力都设为未知,检查不确定性的处理方式。
- 输入重复 ID 时,在请求前纠正错误。
- 分别改变语言和复杂度,检测路由是否脆弱。
- 包含精确规则已足够的任务,判断额外路由是否有价值。
常见问题
Jev 会直接调用选中的模型吗?
不会。预设只返回选择。应用校验后,将已批准 ID 映射到实际配置,再使用自身凭证和限制执行下游调用。
路由一定能降低 API 费用吗?
本示例没有证明节省比例。应把路由成本、重试、质量失败和下游用量全部计入,与固定模型基线进行比较。
依据与后续阅读
协议说明依据 OmniaKey 的 Jev 接入指南与鉴权文档核对。请求示例经过本地结构校验;本文不声称对每种业务场景完成了线上效果评测。本站不是模型开发者或 OmniaKey 官方网站。
用自己的任务试一次
先用测试输入查看原生请求与模型答案。有账户即可进入 OmniaKey 密钥管理;尚未注册时,按 OmniaKey 页面提示创建账户。