前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8637
  • Cursor Bugbot 支持自定义审查力度
  • Codex 工作区进化与插件生态布局
  • AI 生成代码的真实成本——维护困境与解决思路
  • Claude 模拟网络栈:延迟和吞吐量测试
  • Swift 训练 LLM:从 Gflop/s 到 Tflop/s
  • Python GIL 工作原理及踩坑指南
  • Gemini API 文件搜索升级为多模态
  • AI Agent 框架深度对比——编排、工具、记忆、上下文的完整拆解
  • Claude Code 中 HTML 的惊人效果——超越 Markdown 的 AI 交互
  • Claude 推理能力突破:深度 Why 理解
  • AI 幻觉现象解析:为什么 AI 会说谎
  • AI Agent 版本控制:Git 融合框架
  • 自适应并行推理:LLM 推理新范式
  • 用 HTML 替代 Markdown:Claude Code 中的最佳实践
  • 大型代码库中编码 Agent 的 5 个常见失败模式
  • 用 Terraform 和 Cloud Run 部署多 Agent 系统
  • Claude 内部思路可视化:自然语言自编码器
  • 用 Claude 强化 Firefox 安全——AI 在浏览器防护中的应用
  • 设计高效的 AI Agent 协作团队
  • Unsloth 将 LLM 训练速度提升 40% 以上
  • 200 行代码的 LLM 智能路由:成本直降 41%
  • Cursor 新增并行审查和多 Agent 协作编程
  • vLLM V0→V1:强化学习中的正确性优先策略
  • 同一项目两次构建:AI vs 手工全面对比
  • Claude API 提速——Anthropic 宣布提升使用配额与计算合作
  • 打造自主运行的 AI 管家:定时 Agent 实战
  • 用 6502 汇编语言实现 AI 算法的复古实验
  • Google AlphaEvolve:Gemini 驱动的编码 Agent 应用案例
  • Cursor 新增 Agent Context 使用统计功能
  • Claude 限速之谜——Anthropic 创始人解密背后的权衡
  • AI 时代「我还算开发者吗」的职业身份讨论
  • Flutter 移动端自动化测试完整实战指南
  • 从零开始训练自己的大语言模型
  • 编程范式转变:从写代码到管理 Agent
  • OpenAI 语音 AI 的低延迟大规模部署方案
  • VR 界面同时监控多个 AI Agent 的新工作流
  • AI 时代开发者的四种认知原型分析
  • Cloud Run 上构建 AI 质量门控系统完全指南
  • 12年资深Web开发者,3天用AI写出移动应用
  • 构建企业级Slack Agent的UX、安全、扩展经验
  • Cursor企业版新增模型控制和成本管理
  • DeepClaude:多模型融合的 AI 编程 Agent
  • Wiki Builder:构建LLM知识库的开源工具
  • Astro 5升级到6的迁移实战指南
  • Kimi K2.6 编程能力超越 Claude 和 GPT-5.5
  • 企业 AI 落地的真实困局:流程和组织问题
  • AI编程不是工具差,是你的工作流不对
  • 代码库质量决定了AI Agent的能力上限
  • Uber 四个月烧完全年 Claude Code 预算
  • Apple 支持应用误泄 Claude 配置文件
  • Cursor团队市场支持不连接仓库直接创建
  • 已加载 51 / 8637
8.0
热点
AI SCORE
编程提效2026-05-07 11:34

200 行代码的 LLM 智能路由:成本直降 41%

DEV Community · GDS K S#成本优化#LLM应用#TypeScript
Editor brief · 编辑速览

开发者用 TypeScript 实现模型选择路由器,通过智能调度不同 LLM,直接减少 41% 的 API 调用成本。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

原创技术 · 通过绕过包装器上下文冗余

我跟踪自己在三个项目中的 AI 支出。在三月份,增长最快的不是 Claude 或 GPT 调用。而是我的 Cursor 席位加上 Copilot 席位加上我从个人 CLI 调用的 Anthropic API。三个订阅、三个计费表,同一个 Opus token 被重复计费,因为 Cursor 将相同的上下文发送到它自己的后端,而我已经直接传给 Anthropic 了。

这些包装器不会宣传这个。路由代码不是它们的产品。产品是不用考虑哪个模型处理哪个提示的便利性。你用座位价格中烤入的利润支付了编排税。

我厌倦了支付这笔钱。所以我写了路由。它是 200 行 TypeScript。我的四月账单比三月低 41%,工作量基本相同。

这 41% 的节省来自一件事:停止让 Sonnet 处理 Haiku 能以十分之一成本完成的任务。大多数编码查询其实是伪装成问题的查找。按意图路由,而不是按习惯。

1. 编排税是真实存在的

每个包装器都做同样的权衡。它们为你选择一个模型,它们前置一个你无法编辑的系统提示,它们持有一个你无法检查的上下文窗口。作为回报,你不必考虑。

不思考的成本以两种方式出现:

包装器调用最贵的能满足其 SLA 的模型,因为这样更容易让演示看起来很好

包装器向你收费代表你发送的上下文,包括它自己的系统提示和工具定义

我在 Anthropic 仪表板中记录了 30 天的 Cursor 使用情况。Cursor 平均每次聊天回合发送 8,400 个输入 token。我对相同聊天的直接 API 调用平均 1,900。这 6,500 token 的差值是 Cursor 的框架、索引上下文和它的 agent 脚手架。有用,但不是免费的。

当你自己构建路由器时,你选择发送什么。这就是整个游戏。

2. 200 行路由器

这是这个文件。把它放到项目中,给它你的 API 密钥,它根据你控制的规则为每个请求选择一个模型。

// router.ts
import Anthropic from "@anthropic-ai/sdk";
import OpenAI from "openai";

type Intent = "trivial" | "code" | "plan" | "embed";

interface RouteRule {
  match: (prompt: string) => boolean;
  intent: Intent;
}

interface ModelConfig {
  provider: "anthropic" | "openai";
  model: string;
  maxTokens: number;
}

const ROUTES: Record<Intent, ModelConfig> = {
  trivial: { provider: "anthropic", model: "claude-haiku-4-5-20251001", maxTokens: 1024 },
  code: { provider: "anthropic", model: "claude-sonnet-4-6", maxTokens: 4096 },
  plan: { provider: "anthropic", model: "claude-opus-4-7", maxTokens: 8192 },
  embed: { provider: "openai", model: "gpt-5-mini", maxTokens: 512 },
};

const RULES: RouteRule[] = [
  { intent: "trivial", match: (p) => p.length < 200 && /\?$/.test(p.trim()) },
  { intent: "trivial", match: (p) => /^(what is|define|fix typo|rename)/i.test(p) },
  { intent: "plan", match: (p) => /(refactor|design|architect|migrate|plan)/i.test(p) },
  { intent: "code", match: (p) => /(```|function |class |const |let )/i.test(p) },
  { intent: "embed", match: (p) => p.startsWith("CLASSIFY:") },
];

function pickIntent(prompt: string): Intent {
  for (const rule of RULES) {
    if (rule.match(prompt)) return rule.intent;
  }
  return "code";
}

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

export interface RouteResult {
  text: string;
  model: string;
  inputTokens: number;
  outputTokens: number;
  costUsd: number;
}

const PRICING: Record<string, { in: number; out: number }> = {
  "claude-haiku-4-5-20251001": { in: 0.8, out: 4 },
  "claude-sonnet-4-6": { in: 3, out: 15 },
  "claude-opus-4-7": { in: 5, out: 25 },
  "gpt-5-mini": { in: 0.5, out: 2 },
};

function priceCall(model: string, inTok: number, outTok: number): number {
  const p = PRICING[model];
  if (!p) return 0;
  return (inTok * p.in + outTok * p.out) / 1_000_000;
}

export async function route(prompt: string): Promise<RouteResult> {
  const intent = pickIntent(prompt);
  const cfg = ROUTES[intent];

  if (cfg.provider === "anthropic") {
    const r = await anthropic.messages.create({
      model: cfg.model,
      max_tokens: cfg.maxTokens,
      messages: [{ role: "user", content: prompt }],
    });
    const text = r.content
      .filter((b) => b.type === "text")
      .map((b) => (b as { text: string }).text)
      .join("");
    return {
      text,
      model: cfg.model,
      inputTokens: r.usage.input_tokens,
      outputTokens: r.usage.output_tokens,
      costUsd: priceCall(cfg.model, r.usage.input_tokens, r.usage.output_tokens),
    };
  }

  const r = await openai.chat.completions.create({
    model: cfg.model,
    max_tokens: cfg.maxTokens,
    messages: [{ role: "user", content: prompt }],
  });
  const usage = r.usage ?? { prompt_tokens: 0, completion_tokens: 0 };
  return {
    text: r.choices[0]?.message?.content ?? "",
    model: cfg.model,
    inputTokens: usage.prompt_tokens,
    outputTokens: usage.completion_tokens,
    costUsd: priceCall(cfg.model, usage.prompt_tokens, usage.completion_tokens),
  };
}

就这样。两个提供商、四个意图、五个规则和一个成本计算器。这样使用它:

import { route } from "./router";

const out = await route("rename this function from getUser to fetchUser");
console.log(out.model, out.costUsd.toFixed(5));
// claude-haiku-4-5-20251001 0.00012

这些规则故意很简单。长度加正则表达式覆盖了大约 70% 的路由决策。对于另外 30%,用前缀覆盖:

await route("[force:opus] design a permissions model for ...");

在 pickIntent 中添加一行来读取前缀。我为了保持例子简洁而省略了它。

3. 真正有效的路由规则

天真的方法是发送一个小分类器调用到便宜模型并让它选择路由。这听起来很聪明,但成本比节省更多,因为每个请求现在消耗两个 API 调用。pickIntent 的成本必须为零。

五个正则表达式规则覆盖了我的大部分工作量:

短且以问号结尾:trivial

以"what is"、"define"、"fix typo"、"rename"开头:trivial

包含"refactor"、"design"、"architect"、"migrate"、"plan":plan

包含代码围栏或 function 关键字:code

以"CLASSIFY:"前缀开头:embed(便宜分类器)

默认为 code。一个从 trivial 到 code 的错误路由在那一个请求上成本多 4 倍左右。一个从 code 到 opus 的错误路由成本多 1.6 倍。都不是灾难。要避免的 bug 是给 Haiku 发送它无法维持上下文的多步骤计划,这意味着要谨慎地默认。

我还记录每一次失误。两周后我有一个小的 CSV,记录"这个提示路由到 X 但应该是 Y"。我添加了两个正则表达式规则,失误率从 8% 降到 2% 以下。

4. 41% 的数字,详细分解

三月账单,没有路由器:

四月账单,有路由器(取消了 Cursor,仅保留 Copilot 用于 IDE 内联):

在总调用增加 30% 的情况下,低 41%。路由器将 62% 的调用转移到了 Haiku,这些调用原本由 Sonnet 处理。每次调用的平均成本从 $0.024 降到 $0.013。

Cursor 的取消做了主要的节省。路由器做了较小的、重复的、复合的节省。两者都来自同一个想法:包装器隐藏了你可以更好自己做的决策。

5. 这不做什么

这不是 agent 框架。它不流式传输。它不重试。它不缓存。它不处理速率限制。它不做工具使用。它不知道你的代码库。

添加任何这些都需要工作。流式传输需要两个改变。使用 Anthropic prompt cache 缓存是每次调用多一个 header。带指数退避的重试是 20 行。工具使用需要你无论如何都要写的架构管道。

如果你需要所有这些,使用真正的框架。如果你想停止在 80% 的调用上支付编排税,上面的 200 行会做到。在你实际遇到每个问题时添加其余部分。

包装器存在是因为路由 AI 调用很烦人。这也是你在自己的代码中能够拥有的最高杠杆的东西。上面的 200 行不是护城河。它们是周二下午。写它们的原因是你无法改进看不到的账单。

你当前的便宜模型调用与昂贵模型调用的比例是多少?如果你不知道,那是首先要修复的事情。在你设置路由器之前先设置成本日志。这些数字会让你惊讶。

GDS K S · thegdsks.com · building Glincker · follow on X @thegdsks

编排税是不会出现在定价页面上的 AI 账单的一部分。

Original source

本文由 AI 翻译整理自 DEV Community · GDS K S,原文版权归原作者所有。

阅读英文原文
上一篇
Unsloth 将 LLM 训练速度提升 40% 以上
下一篇
Cursor 新增并行审查和多 Agent 协作编程