高级决策者 + 平台工程

客户端只有一个模型:网关按对话状态自动分档

把模型选择从用户界面拿掉 —— 用户端只暴露一个模型名,规划走强模型、执行落性价比模型,分档发生在请求本来就要经过的那一跳上。

社区真正在抱怨什么

「每个人设置里的模型都不一样,同一份 prompt 在两个人那里跑出不同结果」「新人第一周问得最多的就是该选哪个模型」「我们要下线一个模型,得逐台改开发机的环境变量」—— 模型选择被推给了最没有依据做这个判断的人:用户看不到自己的用量,更判断不出这次请求值不值得上强模型。

一刀切降到便宜模型又会掉档:规划与架构判断交给小模型,返工比省下的钱更贵。而真正该分的是「这次请求在做什么」—— 规划还是执行,这件事客户端从来就没告诉过网关。

GateLLM 怎么做

客户端只保留一个模型名,网关侧用 from "*" 的全量映射把客户端请求的任何名字归一 —— 用户在自己设置里改成别的也不改变落点。用户端不再需要解释「该选哪个」。

分档依据是对话里本来就有的标记:Claude Code 的 plan 模式会注入 Plan mode is active(进入)与 Exited Plan Mode(退出)。脚本挂在入口模型的 before 槽,从末尾消息向前扫描、取末次出现的标记判定当前状态,再调 context.useModel() 切路由 —— 判定是字符串位置比较,不另起一次分类模型调用,也不多加一跳网络。

自动分档必须挂 before 槽:after 槽拿到的是翻译后的上游 body,读不到客户端注入的标记,且 after 槽的 useModel 只能同协议,而 plan 到执行是跨模型路由切换。入口模型与执行模型的 request_payload 类规则(如 prompt_cache_key)要各配一份 —— plan 态不切走、用入口模型的规则,执行态切走后用目标模型的规则。

落地的 5 个手段

  • 入口归一:客户端只暴露一个模型名,from "*" 全量映射把任何客户端名归一为指定落点
  • 自动分档:before 槽脚本从末尾向前取末次标记切路由 —— 进入标记会永久留在对话历史,用「是否包含」判断会永远误判为 plan 态
  • 多协议护栏:脚本开头先判 context.sourceProtocol,非 Anthropic 请求直接放过 —— 同一个入口模型服务多种客户端时不会被误切走
  • 可观测:日志模型列 SW 标签标记脚本切路、MM 标签标记身份映射;统计与计费按最终模型名归集,每次分档的落点可审计
  • 零客户端配合:改配置不用逐台改开发机、映射与规则热生效(唯一例外:脚本内存上限 SCRIPT_MEMORY_LIMIT_MB 改动需重启)
完整教程:脚本按 plan 模式切模型(docs 站)

常问问题