我在这写过不少帖子,反复讲同一个判断:编程模型已经趋同,智能体的大部分工作是机械性的,聪明的做法是默认用便宜模型,只有任务足够难时才升级到前沿模型。我写过英伟达用Switchyard把这个思路产品化,也写过自己的配置比模型本身更能解释我的结果。写到某个节点,光写已经不够了,于是我把它做出来了。
这个工具叫coding-agent-router,它坐在Claude Code前面。做它的过程让我明白了一件事:这个想法最显而易见的版本,会悄无声息地亏钱。
![]()
显而易见的版本会亏钱
最直接的方案很容易想象:拦截每一个请求,判断它有多难,把简单的发给便宜模型,把难的发给前沿模型。按请求、按步骤来。这个思路感觉很对,但它会反噬,原因就是提示缓存。
提示缓存是按模型隔离的。针对一个模型建立的缓存条目,在下一条请求指向另一个模型的那一刻就作废了。Claude Code每一步都会把你不断增长的对话发过去,正常情况下大部分是缓存命中,所以你只付一次全价,之后按折扣价走。现在把一个按步骤选模型的朴素路由器插在中间:这个工具调用走便宜模型,下一个走中档,再下一个走前沿。每一次切换都是一次缓存未命中,整个对话历史要在新模型上按全价重新读一遍。在一个长会话里,用了路由器可能比不用还贵。单次便宜调用省下的钱是真实的,但缓存惩罚会把它们吃光。
这就是陷阱。路由和缓存朝着相反的方向拉,任何忽略后者的路由器,都只是一个假装省钱、实际在悄悄烧钱的工具。
修复方案:只决定一次,锁定,之后只升不降
真正有效的设计把会话当作单位,而不是把请求当作单位。一个新会话开始时,路由器从系统提示和第一条用户消息里提取指纹,跑一个小分类器给难度打分,然后把整个会话锁定到一个层级。这个会话之后的每一步都跟着锁定走,模型保持不变,缓存保持温热。
唯一的例外是那个安全的方向。一个被锁定的会话可以向上升级,永远不能向下。如果一个本来简单的会话变难了,人类的一轮对话可以把它抬到更高层级,因为多花钱保护你的工作成果,正是你想要的交换。代码写得很直白:
const next = higher(lock.tier, suggested); // 只升级,永不降级
降级只发生在缓存本来就冷的地方:一个全新的会话,或者一次压缩、一次重启重置了历史。在这些边界上没有热缓存需要保护,所以重新分类是免费的。其他任何地方,层级被锁定,缓存就是安全的。这一条规则——只在冷边界降级——就是真正省钱的路由器和假装省钱的路由器之间的差别。
分类器到底做了什么
分类器做的事情并不复杂。它不试图理解代码的深层语义,也不预测任务最终会走多远。它只从会话开头能拿到的信息里提取信号:系统提示里写了什么,第一条用户消息在要求什么,任务描述里有没有明显的复杂度标记。
这些信号被送进一个小分类器,输出一个难度分数,然后映射到预设的层级上。整个过程刻意保持轻量,因为分类器本身也要消耗token,如果分类的成本比省下的钱还高,这个路由器就没有存在的意义。原文里没有展开分类器的具体实现细节,但核心逻辑已经清楚:用会话开头的最小信息做一次判断,然后信任这个判断,直到出现明确的升级理由。
为什么这个设计值得被写下来
做这个工具的过程暴露了一个容易被忽略的事实:省钱工具本身可能成为花钱的来源。朴素路由器的失败不是因为它选错了模型,而是因为它破坏了缓存这个更基础的省钱机制。缓存的价值在于重复,路由的价值在于差异化,两者天然冲突。
把决策粒度从请求提升到会话,再给升级留一个单向通道,这个冲突就被化解了。会话内部的每一步都享受缓存命中,会话之间的差异才由路由来承担。这个设计没有引入任何新的事实,它只是把两个已有的机制放在正确的关系里。
我写下来,是因为这个坑足够隐蔽:你看着单次调用的账单变便宜了,月底总账单却涨了。如果你也在做类似的东西,先想清楚缓存,再谈路由。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.