先说一件最近发生在我自己项目里的事。某天我习惯性去后台拉了一下模型调用账单,发现光是一个自动摘要功能,一个月居然烧掉了六位数(单位是分)。点开日志一看,80%的请求都是那种输入很长、输出很短、逻辑简单的“体力活”,却在用最强也最贵的旗舰模型跑。那一刻我意识到,问题不在模型不够聪明,而在路由太粗糙——所有流量都挤一条高价通道,自然账单难看。后来我把路由层重做了一遍,核心工具换成了 LiteLLM,把便宜模型顶到高频任务上,贵模型只处理真正复杂的请求,一个月后成本下降了将近90%,延迟还更稳了。整个过程我踩了不少坑,今天这篇就完整复盘一遍:为什么做模型分层、LiteLLM 的路由机制怎么理解、具体配置怎么写、上层业务怎么接,以及我最想吐槽的几个翻车现场。1. 为什么要把模型分层?先算清这笔成本账1.1 模型调用账单的真实构成先别急着换模型,你得知道自己钱到底花在哪。大模型计费主要按 token,分输入和输出两个维度,输出单价通常是输入的 3 到 5 倍。很多团队只盯着“单次调用多少钱”,却忽略了三个放大器:调用量:一天几十万次调用,单价差一点,乘出来的数字就非常可怕。输入 token 浪费:长文档、长对话历史,每次都原封不动塞进去,输入成本直线上升。输出 token 不可控:有些任务你只想要一句话,模型却给你写三大段,费用翻倍还不止。我当时的项目结构很简单:一个内容平台,每天有大量文章需要自动打标签、生成摘要、做情绪分析、判断是否合规,另外还有一块实时客服问答。前者是高并发、逻辑相对固定,后者需要理解复杂上下文、生成自然回复。两者对模型能力的要求完全不一样,但代码里写死的却是同一个最强模型。这里就不难看出问题了。最强模型贵,不只是单价贵,而是你在为大部分根本用不到的能力买单。就像一个团队里每个岗位都配了高管,普通数据录入的活儿也交给高管干,效率不一定更高,成本一定爆炸。1.2 高频任务的分层判定方法我后来把项目里的所有模型调用场景列了一张表,按两个维度打分:任务复杂度和容错程度。这是最简单也最有效的分层方式。场景任务复杂度容错度适合的模型层级文章自动打标签低高便宜模型短文本摘要中中便宜模型情绪/意图识别低高便宜模型内容合规初筛低中便宜模型客服问答(复杂多轮)高低贵模型法律/医疗等专业推理高极低贵模型代码生成与调试高低贵模型判断标准就三条。第一,输出是否容易验证:打标签可以用规则校验,答错了顶多标签不准;客服问答错了用户立刻感知。第二,语义理解深度:任务只需抽取关键词还是需要多步推理。第三,延迟敏感度:异步任务可以容忍几秒,在线交互必须在 1 秒内响应。这个分层动作看似简单,但价值极高。因为后续所有路由配置都建立在这张表上。没有这张表,你后面无论用什么工具都是瞎配。2. LiteLLM 在路由方案里的定位2.1 为什么选 LiteLLM 而不是自己写路由市面上其实有几种做法:自己封装一层 SDK、用某个云厂商的模型网关、或者部署开源网关。我当时直接排除了“自己写”,因为模型调用层的复杂度远超想象,远不只是发 HTTP 请求这么简单。需要处理的东西包括:多厂商 SDK 的差异、token 计数与计费模型、模型限流与重试、故障转移、密钥管理、调用日志、预算控制、还有按 key 或按用户做成本追踪。这些东西自己从头写,没有两三个月做不完,而且很容易在某些角落留下坑。LiteLLM 是一个开源的大模型网关项目,提供了统一的 OpenAI 兼容接口,背后接各种模型服务商。它解决了我最头疼的一个问题:业务代码只需要认一个 API 格式,模型怎么选、怎么路由、怎么兜底,全部在配置层解决。这意味着换模型、加新模型、切换流量,都不需要改业务代码重新发版。尤其适合我这种小团队。我们没有专人维护基础设施,LiteLLM 部署简单,一个 Python 进程就能跑,配置也是 YAML,可读性好。之后真要拆成高可用集群,它也支持对接 Redis、Postgres 和各种观测后端,天花板够高。2.2 路由到底在解决什么问题很多人第一次接触 LiteLLM 会混淆一个概念:它不是帮你选模型,而是帮你把“请求该走哪条模型通道”这件事从代码里抽出来,放到运行时决定。我最开始以为路由就是“随机挑一个模型发请求”,其实这是对路由最狭隘的理解。实际场景里,路由至少要解决四类问题:按模型组隔离:定义一个逻辑名,比如“cheap-model”代表一组便宜的模型,业务代码只认这个名字。故障转移:主模型超时或报错时,自动切到备选模型,而不是让用户看到 500。流量分配:灰度阶段让 1% 的请求走新模型,观察质量后再逐步放量。成本与配额控制:给不同团队、不同 API key 设置不同模型访问权限和预算上限。这四类问题合在一起,才是“模型分层路由”的完整含义。把便宜模型顶到高频任务上,只是其中一个落地形态。3. 部署与配置实战:用一份配置搞定分层路由3.1 网关安装与基础配置LiteLLM 的安装很简单,官方推荐通过 Python 安装代理包。我实际用的是:pip install 'litellm[proxy]'装完后有个litellm命令,可以直接起一个代理服务。但先别急,我们得准备配置文件。下面是我当时实际用过的精简版配置,脱敏后分享:model_list: - model_name: cheap-model litellm_params: model: provider-a/cheap-chat api_key: os.environ/CHEAP_API_KEY - model_name: premium-model litellm_params: model: provider-b/premium-chat api_key: os.environ/PREMIUM_API_KEY litellm_settings: cooldown_time: 30 fallbacks: [{"cheap-model": ["premium-model"]}] max_budget: 200 budget_duration: "30d" general_settings: master_key: sk-your-master-key database_url: sqlite:///litellm.db这里有几个关键点需要解释。第一,model_list里每个元素就是一个“模型条目”,model_name是暴露给上层调用的逻辑名,litellm_params里写真实的后端模型标识和密钥。provider-a/cheap-chat这种带前缀的写法是 LiteLLM 识别具体厂商的方式,前缀后面才是模型自身的名字。不管底层厂商是谁,对上层来说,它们就只是两个逻辑名。第二,litellm_settings里的fallbacks配置是我整个分层路由的核心。它的含义是:当cheap-model这个组里的模型连续出错或超时,网关会自动把请求转发给premium-model组。这样便宜模型扛大流量,万一它抽风了,贵模型作为安全网兜底,不会让线上功能直接挂掉。第三,budget_duration和max_budget是成本保险丝。30 天周期内总花费超过 200 美元,网关直接拒绝新请求,防止模型 API 密钥泄露或程序死循环导致费用失控。启动网关也非常简单:litellm --config config.yaml --port 4000默认监听 4000 端口,兼容 OpenAI 的/v1/chat/completions、/v1/completions、/v1/embeddings等路径。你业务代码里的base_url一改,就能把流量切过来。3.2 路由策略参数与失败转移细节配置好之后,你要理解流量在网关内部到底怎么走的。带模型组逻辑名的请求进来时,LiteLLM 会做三件事:找到对应model_name映射的真实模型列表。根据当前各模型的健康状态、冷却时间、路由策略选出目标。发起请求,如果失败则按fallbacks配置寻找下一个可用模型。这里我必须提醒一个很容易踩的坑:不要把 fallback 配置成双向的。有人为了让路由更“稳”,给模型组 A 配了兜底 B,又给模型组 B 配了兜底 A。结果某天两个模型同时出问题,请求在 A 和 B 之间来回反弹,直到超时,日志里全是循环重试。我更推荐单向 fallback,并且只在业务容忍延迟的接口上用。冷却时间cooldown_time也很关键。默认 30 秒的意思是,某个模型报错后,网关会把它标记为冷却状态,30 秒内不再把新请求发给它。这个值太短,模型刚恢复又被打挂;太长,则流量会过早转移到成本更高的备用模型上。我当时线上实测下来,30 秒到 60 秒是个比较合适的区间。另外,如果你有多个真实模型可以承担同一类任务,还可以在model_list里为一个model_name配多条记录。网关默认按权重轮询,这样可以天然做负载均衡,也能在某个模型被限流时自动换另一个。3.3 成本追踪与预算管理LiteLLM 带上数据库之后,会自动记录每次请求的模型、token 数、费用。我强烈建议从第一天起就接上数据库,不要用纯内存模式跑,否则你连问题都追溯不到。有两个接口我几乎天天用:# 查看所有模型信息,包括单价、上下文窗口等 curl http://localhost:4000/model/info # 按 key 查询花费日志 curl http://localhost:4000/spend/logs -H "Authorization: Bearer sk-your-master-key"成本追踪本身不产生直接收益,但没有它,你根本不知道便宜模型到底给你省了多少钱。我后来做了个小看板,按天对比“如果全用贵模型”和“实际分层路由”的花费差异,这两个数字的差距,就是技术决策带来的价值证明。预算管理这块,还能做得更细。LiteLLM 支持为每个 API key 设置独立的max_budget,也就是说可以按团队、按项目、按功能模块隔离成本。我建议不要把预算上限设得太紧,否则流量尖峰时会被直接拒绝,影响业务。保险丝的意义在于防失控,不在于精准刹车。4. 上层业务对接:把模型选择权交给路由层4.1 客户端只改一个地址LiteLLM 最香的一点,是它完全兼容 OpenAI SDK 的调用方式。对于用 Python 的项目来说,改造量小到可以忽略:from openai import OpenAI client = OpenAI( api_key="sk-your-master-key", base_url="http://localhost:4000", ) resp = client.chat.completions.create( model="cheap-model", messages=[ {"role": "user", "content": "给这篇文章打三个标签"} ], )原来业务代码里写死的具体模型名,现在换成model="cheap-model"这个逻辑名。请求先到 LiteLLM 网关,网关再根据配置转发给真实后端。等于在业务和真实模型之间加了一层“寻址”抽象。这里有个容易被忽略的细节:不要在前端直接暴露网关地址和 master key。我见过有人把base_url写死在浏览器代码里,任何用户都可以拿这个 key 去调用你网关背后的所有模型。你应该把网关放在内网,或者前面再加一层 BFF(Backend For Frontend),让用户请求只打到你的应用服务,由应用服务去访问 LiteLLM。4.2 按任务类型动态选择模型组光把地址改掉还不够,真正的分层路由要让不同任务自动走到不同的模型组。我的做法是在应用服务里加一个极轻量的任务分类函数。思路是这样:所有请求进来,先经过一层规则判断,决定它属于“高频简单任务”还是“低频复杂任务”,然后把对应的模型组名填到请求的model字段里。def route_model(task_type: str) -> str: if task_type in {"tagging", "summary", "sentiment"}: return "cheap-model" if task_type == "customer_service": return "premium-model" return "premium-model" resp = client.chat.completions.create( model=route_model(task.task_type), messages=[ {"role": "system", "content": task.system_prompt}, {"role": "user", "content": task.user_content} ] )你现在看到的是一个非常简单的 if-else。当时我甚至用的是一组关键词正则,成本几乎为零。真正有价值的是这个模式:业务侧只负责判断“这个任务的类别”,模型选择完全由路由配置负责。以后你发现某个便宜模型质量不行想换掉,改的是 LiteLLM 的 config;想给某个模型灰度放量,改的是配置里的权重;想临时把所有简单任务切到另一个模型,也不用动业务代码。还有一个进阶玩法:在网关前面再套一层“模型选择器”,用便宜模型来决定请求该去哪个模型组。这个思路比较取巧,等于用“便宜模型当路由器的 CPU”。我当时没有在生产环境这么干,主要是怕链路太长延迟叠加,但在一些异步批量任务里是可行的。4.3 改造过程中的兼容性提醒我改造的时候还踩了一个典型坑:老业务代码里有一些直接依赖具体模型返回格式的逻辑。比如某模型返回的content里自带换行、某些模型对max_tokens的参数名有差异。LiteLLM 虽然做了大量兼容,但不同模型厂商返回的风格还是会有微妙差异。我的建议是,不要指望所有模型都输出一模一样的格式,你必须在应用层做一层后处理。例如把结果统一做 strip、JSON 解析容错、字段兜底。否则你今天切到便宜模型,功能看似正常,但线上偶发解析失败,排查半天才发现是输出格式变了,那才是灾难。5. 容易被忽视的安全与运维细节5.1 API Key 管理与鉴权LiteLLM 的 master key 相当于整个网关的超级管理员权限,可以调用所有模型、查看所有日志、创建所有 key。所以 master key 一定要用足够随机的长字符串,并且只保存在服务端环境变量里。日常调用不应该直接用 master key。正确做法是调用它的 key 管理接口,为不同业务创建独立的 key:curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-your-master-key" \ -H "Content-Type: application/json" \ -d '{"models": ["cheap-model"], "max_budget": 50}'这个接口返回一个新的 key,你可以配置这个 key 只能访问cheap-model,并且 30 天内最多花 50 美元。即使这个 key 泄露,攻击者也只能用便宜模型,损失可控。我给不同渠道都分了不同 key:线上小程序一个 key、内部异步任务一个 key、测试环境一个 key。这样出了问题,按 key 就能定位到具体来源,审计成本低很多。5.2 限流、高并发与观测模型网关的吞吐能力取决于上层模型服务的限流配额。我遇到过最尴尬的情况:便宜模型本身不贵,但厂商接口每秒并发限制很低,请求一多就被 429。LiteLLM 提供了 per-model 和 per-key 的限速配置,可以给每个模型设置rpm(每分钟请求数)和tpm(每分钟 token 数)。更合理的做法是在网关层做请求排队和并发控制,把峰值流量削平,避免直接触发远端限流。观测方面,LiteLLM 支持接入 Prometheus 指标。我强烈建议至少把以下指标拉出来看:每个模型的请求量、错误率、延迟分位数fallback 触发次数冷却状态与持续时间每日花费总额与趋势有一次我排查线上某个接口变慢,查了半天发现不是模型变慢,而是某个便宜模型被限流后,请求全部 fallback 到贵模型,贵模型并发被打满,整体延迟反而上升。如果没有 fallback 触发次数这个指标,这种问题会非常难定位。6. 实测遇到的问题与排查记录6.1 常见问题速查表现象可能原因解决办法请求返回 ModelNotSupportedError模型名带错了前缀或拼写不对用/model/info核对真实模型标识流量全部走到贵模型fallback 配置过宽,或便宜模型持续报错被冷却检查冷却时间与模型健康状态某模型频繁 429厂商限流配额不足在网关层加 rpm/tpm 限制,做请求排队费用不降反升输入 token 没控制,或 fallback 比例太高优化 prompt 长度,检查 fallback 触发次数调用日志查不到没有配置数据库配置database_url,重启网关模型输出格式异常不同模型返回风格差异应用层做统一后处理,不依赖单一模型格式6.2 几次真实的翻车经历第一次配置时,我把模型前缀写错了,网关直接报“模型不存在”。我以为是对接问题,反复检查业务流程,最后发现只是字符串多了一个空格。这种问题看起来很蠢,但确实会浪费半小时,所以后来我坚持写一段极短的连通性测试脚本,配完立刻打一个真实请求验证。还有一次,我把 fallback 配错了方向。本意是便宜模型挂了用贵模型,结果配置写反了,变成了贵模型挂了才用便宜模型。平时流量少看不出来,直到一天贵模型服务异常,线上大量请求自动切到便宜模型,质量肉眼可见地下降,我才意识到配置写反了。从那以后,我每次改配置都会仔细核对 fallback 的方向,还会故意停掉主模型做一次故障演练。最让我心疼的一次,是便宜模型的 token 计数偏差导致成本预估失真。某些提供商的 API 对输入 token 的计数口径不一样,LiteLLM 虽然内置了各家模型的成本映射表,但新模型上市初期,映射表可能还没更新。我的经验是,刚接入一个新模型时,先小流量跑几天,对比网关统计的费用和厂商控制台账单,误差超过 5% 就要去检查成本映射配置。6.3 给刚上手的人几个小建议先别急着把所有流量都切到便宜模型。我建议按这个顺序来:先做流量分析,搞清近 30 天哪些任务调用量最大、花费最多。挑 1 到 2 个典型的高频简单任务接入 LiteLLM,先小流量灰度。对比路由前后的质量评估指标(比如准确率、用户投诉率)。确认质量没掉,再逐步扩大范围。最后把成本看板接好,让节省效果可视化。另外,如果你所在团队对稳定性要求很高,千万不要只依赖一个网关进程。LiteLLM 支持挂 Redis 做多实例协调,也支持 Postgres 作为共享数据库,前面再挂一层负载均衡。但这些都是第二步的事了,刚开始单机跑完全够用。我个人在实际操作中最大的体会是:所谓“便宜模型顶上高频任务”,不是用低质量换成本,而是把每类任务分配给性价比最优的模型。便宜模型能扛住 90% 的请求,剩下的难题再交给强模型,整体体验并不会有明显下降。而且随着新模型不断出来,模型的价格和性能每天都在变,有了 LiteLLM 这层路由抽象,你可以永远用极低的迁移成本去拥抱新选择。以后如果业务量再涨,我会考虑把路由网关部署成多实例,加上更细粒度的按用户分桶和模型质量埋点,让每次模型切换都有数据支撑,而不是拍脑袋决定。
先说一件最近发生在我自己项目里的事。某天我习惯性去后台拉了一下模型调用账单,发现光是一个自动摘要功能,一个月居然烧掉了六位数(单位是分)。点开日志一看,80%的请求都是那种输入很长、输出很短、逻辑简单的“体力活”,却在用最强也最贵的旗舰模型跑。那一刻我意识到,问题不在模型不够聪明,而在路由太粗糙——所有流量都挤一条高价通道,自然账单难看。后来我把路由层重做了一遍,核心工具换成了 LiteLLM,把便宜模型顶到高频任务上,贵模型只处理真正复杂的请求,一个月后成本下降了将近90%,延迟还更稳了。整个过程我踩了不少坑,今天这篇就完整复盘一遍:为什么做模型分层、LiteLLM 的路由机制怎么理解、具体配置怎么写、上层业务怎么接,以及我最想吐槽的几个翻车现场。1. 为什么要把模型分层?先算清这笔成本账1.1 模型调用账单的真实构成先别急着换模型,你得知道自己钱到底花在哪。大模型计费主要按 token,分输入和输出两个维度,输出单价通常是输入的 3 到 5 倍。很多团队只盯着“单次调用多少钱”,却忽略了三个放大器:调用量:一天几十万次调用,单价差一点,乘出来的数字就非常可怕。输入 token 浪费:长文档、长对话历史,每次都原封不动塞进去,输入成本直线上升。输出 token 不可控:有些任务你只想要一句话,模型却给你写三大段,费用翻倍还不止。我当时的项目结构很简单:一个内容平台,每天有大量文章需要自动打标签、生成摘要、做情绪分析、判断是否合规,另外还有一块实时客服问答。前者是高并发、逻辑相对固定,后者需要理解复杂上下文、生成自然回复。两者对模型能力的要求完全不一样,但代码里写死的却是同一个最强模型。这里就不难看出问题了。最强模型贵,不只是单价贵,而是你在为大部分根本用不到的能力买单。就像一个团队里每个岗位都配了高管,普通数据录入的活儿也交给高管干,效率不一定更高,成本一定爆炸。1.2 高频任务的分层判定方法我后来把项目里的所有模型调用场景列了一张表,按两个维度打分:任务复杂度和容错程度。这是最简单也最有效的分层方式。场景任务复杂度容错度适合的模型层级文章自动打标签低高便宜模型短文本摘要中中便宜模型情绪/意图识别低高便宜模型内容合规初筛低中便宜模型客服问答(复杂多轮)高低贵模型法律/医疗等专业推理高极低贵模型代码生成与调试高低贵模型判断标准就三条。第一,输出是否容易验证:打标签可以用规则校验,答错了顶多标签不准;客服问答错了用户立刻感知。第二,语义理解深度:任务只需抽取关键词还是需要多步推理。第三,延迟敏感度:异步任务可以容忍几秒,在线交互必须在 1 秒内响应。这个分层动作看似简单,但价值极高。因为后续所有路由配置都建立在这张表上。没有这张表,你后面无论用什么工具都是瞎配。2. LiteLLM 在路由方案里的定位2.1 为什么选 LiteLLM 而不是自己写路由市面上其实有几种做法:自己封装一层 SDK、用某个云厂商的模型网关、或者部署开源网关。我当时直接排除了“自己写”,因为模型调用层的复杂度远超想象,远不只是发 HTTP 请求这么简单。需要处理的东西包括:多厂商 SDK 的差异、token 计数与计费模型、模型限流与重试、故障转移、密钥管理、调用日志、预算控制、还有按 key 或按用户做成本追踪。这些东西自己从头写,没有两三个月做不完,而且很容易在某些角落留下坑。LiteLLM 是一个开源的大模型网关项目,提供了统一的 OpenAI 兼容接口,背后接各种模型服务商。它解决了我最头疼的一个问题:业务代码只需要认一个 API 格式,模型怎么选、怎么路由、怎么兜底,全部在配置层解决。这意味着换模型、加新模型、切换流量,都不需要改业务代码重新发版。尤其适合我这种小团队。我们没有专人维护基础设施,LiteLLM 部署简单,一个 Python 进程就能跑,配置也是 YAML,可读性好。之后真要拆成高可用集群,它也支持对接 Redis、Postgres 和各种观测后端,天花板够高。2.2 路由到底在解决什么问题很多人第一次接触 LiteLLM 会混淆一个概念:它不是帮你选模型,而是帮你把“请求该走哪条模型通道”这件事从代码里抽出来,放到运行时决定。我最开始以为路由就是“随机挑一个模型发请求”,其实这是对路由最狭隘的理解。实际场景里,路由至少要解决四类问题:按模型组隔离:定义一个逻辑名,比如“cheap-model”代表一组便宜的模型,业务代码只认这个名字。故障转移:主模型超时或报错时,自动切到备选模型,而不是让用户看到 500。流量分配:灰度阶段让 1% 的请求走新模型,观察质量后再逐步放量。成本与配额控制:给不同团队、不同 API key 设置不同模型访问权限和预算上限。这四类问题合在一起,才是“模型分层路由”的完整含义。把便宜模型顶到高频任务上,只是其中一个落地形态。3. 部署与配置实战:用一份配置搞定分层路由3.1 网关安装与基础配置LiteLLM 的安装很简单,官方推荐通过 Python 安装代理包。我实际用的是:pip install 'litellm[proxy]'装完后有个litellm命令,可以直接起一个代理服务。但先别急,我们得准备配置文件。下面是我当时实际用过的精简版配置,脱敏后分享:model_list: - model_name: cheap-model litellm_params: model: provider-a/cheap-chat api_key: os.environ/CHEAP_API_KEY - model_name: premium-model litellm_params: model: provider-b/premium-chat api_key: os.environ/PREMIUM_API_KEY litellm_settings: cooldown_time: 30 fallbacks: [{"cheap-model": ["premium-model"]}] max_budget: 200 budget_duration: "30d" general_settings: master_key: sk-your-master-key database_url: sqlite:///litellm.db这里有几个关键点需要解释。第一,model_list里每个元素就是一个“模型条目”,model_name是暴露给上层调用的逻辑名,litellm_params里写真实的后端模型标识和密钥。provider-a/cheap-chat这种带前缀的写法是 LiteLLM 识别具体厂商的方式,前缀后面才是模型自身的名字。不管底层厂商是谁,对上层来说,它们就只是两个逻辑名。第二,litellm_settings里的fallbacks配置是我整个分层路由的核心。它的含义是:当cheap-model这个组里的模型连续出错或超时,网关会自动把请求转发给premium-model组。这样便宜模型扛大流量,万一它抽风了,贵模型作为安全网兜底,不会让线上功能直接挂掉。第三,budget_duration和max_budget是成本保险丝。30 天周期内总花费超过 200 美元,网关直接拒绝新请求,防止模型 API 密钥泄露或程序死循环导致费用失控。启动网关也非常简单:litellm --config config.yaml --port 4000默认监听 4000 端口,兼容 OpenAI 的/v1/chat/completions、/v1/completions、/v1/embeddings等路径。你业务代码里的base_url一改,就能把流量切过来。3.2 路由策略参数与失败转移细节配置好之后,你要理解流量在网关内部到底怎么走的。带模型组逻辑名的请求进来时,LiteLLM 会做三件事:找到对应model_name映射的真实模型列表。根据当前各模型的健康状态、冷却时间、路由策略选出目标。发起请求,如果失败则按fallbacks配置寻找下一个可用模型。这里我必须提醒一个很容易踩的坑:不要把 fallback 配置成双向的。有人为了让路由更“稳”,给模型组 A 配了兜底 B,又给模型组 B 配了兜底 A。结果某天两个模型同时出问题,请求在 A 和 B 之间来回反弹,直到超时,日志里全是循环重试。我更推荐单向 fallback,并且只在业务容忍延迟的接口上用。冷却时间cooldown_time也很关键。默认 30 秒的意思是,某个模型报错后,网关会把它标记为冷却状态,30 秒内不再把新请求发给它。这个值太短,模型刚恢复又被打挂;太长,则流量会过早转移到成本更高的备用模型上。我当时线上实测下来,30 秒到 60 秒是个比较合适的区间。另外,如果你有多个真实模型可以承担同一类任务,还可以在model_list里为一个model_name配多条记录。网关默认按权重轮询,这样可以天然做负载均衡,也能在某个模型被限流时自动换另一个。3.3 成本追踪与预算管理LiteLLM 带上数据库之后,会自动记录每次请求的模型、token 数、费用。我强烈建议从第一天起就接上数据库,不要用纯内存模式跑,否则你连问题都追溯不到。有两个接口我几乎天天用:# 查看所有模型信息,包括单价、上下文窗口等 curl http://localhost:4000/model/info # 按 key 查询花费日志 curl http://localhost:4000/spend/logs -H "Authorization: Bearer sk-your-master-key"成本追踪本身不产生直接收益,但没有它,你根本不知道便宜模型到底给你省了多少钱。我后来做了个小看板,按天对比“如果全用贵模型”和“实际分层路由”的花费差异,这两个数字的差距,就是技术决策带来的价值证明。预算管理这块,还能做得更细。LiteLLM 支持为每个 API key 设置独立的max_budget,也就是说可以按团队、按项目、按功能模块隔离成本。我建议不要把预算上限设得太紧,否则流量尖峰时会被直接拒绝,影响业务。保险丝的意义在于防失控,不在于精准刹车。4. 上层业务对接:把模型选择权交给路由层4.1 客户端只改一个地址LiteLLM 最香的一点,是它完全兼容 OpenAI SDK 的调用方式。对于用 Python 的项目来说,改造量小到可以忽略:from openai import OpenAI client = OpenAI( api_key="sk-your-master-key", base_url="http://localhost:4000", ) resp = client.chat.completions.create( model="cheap-model", messages=[ {"role": "user", "content": "给这篇文章打三个标签"} ], )原来业务代码里写死的具体模型名,现在换成model="cheap-model"这个逻辑名。请求先到 LiteLLM 网关,网关再根据配置转发给真实后端。等于在业务和真实模型之间加了一层“寻址”抽象。这里有个容易被忽略的细节:不要在前端直接暴露网关地址和 master key。我见过有人把base_url写死在浏览器代码里,任何用户都可以拿这个 key 去调用你网关背后的所有模型。你应该把网关放在内网,或者前面再加一层 BFF(Backend For Frontend),让用户请求只打到你的应用服务,由应用服务去访问 LiteLLM。4.2 按任务类型动态选择模型组光把地址改掉还不够,真正的分层路由要让不同任务自动走到不同的模型组。我的做法是在应用服务里加一个极轻量的任务分类函数。思路是这样:所有请求进来,先经过一层规则判断,决定它属于“高频简单任务”还是“低频复杂任务”,然后把对应的模型组名填到请求的model字段里。def route_model(task_type: str) -> str: if task_type in {"tagging", "summary", "sentiment"}: return "cheap-model" if task_type == "customer_service": return "premium-model" return "premium-model" resp = client.chat.completions.create( model=route_model(task.task_type), messages=[ {"role": "system", "content": task.system_prompt}, {"role": "user", "content": task.user_content} ] )你现在看到的是一个非常简单的 if-else。当时我甚至用的是一组关键词正则,成本几乎为零。真正有价值的是这个模式:业务侧只负责判断“这个任务的类别”,模型选择完全由路由配置负责。以后你发现某个便宜模型质量不行想换掉,改的是 LiteLLM 的 config;想给某个模型灰度放量,改的是配置里的权重;想临时把所有简单任务切到另一个模型,也不用动业务代码。还有一个进阶玩法:在网关前面再套一层“模型选择器”,用便宜模型来决定请求该去哪个模型组。这个思路比较取巧,等于用“便宜模型当路由器的 CPU”。我当时没有在生产环境这么干,主要是怕链路太长延迟叠加,但在一些异步批量任务里是可行的。4.3 改造过程中的兼容性提醒我改造的时候还踩了一个典型坑:老业务代码里有一些直接依赖具体模型返回格式的逻辑。比如某模型返回的content里自带换行、某些模型对max_tokens的参数名有差异。LiteLLM 虽然做了大量兼容,但不同模型厂商返回的风格还是会有微妙差异。我的建议是,不要指望所有模型都输出一模一样的格式,你必须在应用层做一层后处理。例如把结果统一做 strip、JSON 解析容错、字段兜底。否则你今天切到便宜模型,功能看似正常,但线上偶发解析失败,排查半天才发现是输出格式变了,那才是灾难。5. 容易被忽视的安全与运维细节5.1 API Key 管理与鉴权LiteLLM 的 master key 相当于整个网关的超级管理员权限,可以调用所有模型、查看所有日志、创建所有 key。所以 master key 一定要用足够随机的长字符串,并且只保存在服务端环境变量里。日常调用不应该直接用 master key。正确做法是调用它的 key 管理接口,为不同业务创建独立的 key:curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-your-master-key" \ -H "Content-Type: application/json" \ -d '{"models": ["cheap-model"], "max_budget": 50}'这个接口返回一个新的 key,你可以配置这个 key 只能访问cheap-model,并且 30 天内最多花 50 美元。即使这个 key 泄露,攻击者也只能用便宜模型,损失可控。我给不同渠道都分了不同 key:线上小程序一个 key、内部异步任务一个 key、测试环境一个 key。这样出了问题,按 key 就能定位到具体来源,审计成本低很多。5.2 限流、高并发与观测模型网关的吞吐能力取决于上层模型服务的限流配额。我遇到过最尴尬的情况:便宜模型本身不贵,但厂商接口每秒并发限制很低,请求一多就被 429。LiteLLM 提供了 per-model 和 per-key 的限速配置,可以给每个模型设置rpm(每分钟请求数)和tpm(每分钟 token 数)。更合理的做法是在网关层做请求排队和并发控制,把峰值流量削平,避免直接触发远端限流。观测方面,LiteLLM 支持接入 Prometheus 指标。我强烈建议至少把以下指标拉出来看:每个模型的请求量、错误率、延迟分位数fallback 触发次数冷却状态与持续时间每日花费总额与趋势有一次我排查线上某个接口变慢,查了半天发现不是模型变慢,而是某个便宜模型被限流后,请求全部 fallback 到贵模型,贵模型并发被打满,整体延迟反而上升。如果没有 fallback 触发次数这个指标,这种问题会非常难定位。6. 实测遇到的问题与排查记录6.1 常见问题速查表现象可能原因解决办法请求返回 ModelNotSupportedError模型名带错了前缀或拼写不对用/model/info核对真实模型标识流量全部走到贵模型fallback 配置过宽,或便宜模型持续报错被冷却检查冷却时间与模型健康状态某模型频繁 429厂商限流配额不足在网关层加 rpm/tpm 限制,做请求排队费用不降反升输入 token 没控制,或 fallback 比例太高优化 prompt 长度,检查 fallback 触发次数调用日志查不到没有配置数据库配置database_url,重启网关模型输出格式异常不同模型返回风格差异应用层做统一后处理,不依赖单一模型格式6.2 几次真实的翻车经历第一次配置时,我把模型前缀写错了,网关直接报“模型不存在”。我以为是对接问题,反复检查业务流程,最后发现只是字符串多了一个空格。这种问题看起来很蠢,但确实会浪费半小时,所以后来我坚持写一段极短的连通性测试脚本,配完立刻打一个真实请求验证。还有一次,我把 fallback 配错了方向。本意是便宜模型挂了用贵模型,结果配置写反了,变成了贵模型挂了才用便宜模型。平时流量少看不出来,直到一天贵模型服务异常,线上大量请求自动切到便宜模型,质量肉眼可见地下降,我才意识到配置写反了。从那以后,我每次改配置都会仔细核对 fallback 的方向,还会故意停掉主模型做一次故障演练。最让我心疼的一次,是便宜模型的 token 计数偏差导致成本预估失真。某些提供商的 API 对输入 token 的计数口径不一样,LiteLLM 虽然内置了各家模型的成本映射表,但新模型上市初期,映射表可能还没更新。我的经验是,刚接入一个新模型时,先小流量跑几天,对比网关统计的费用和厂商控制台账单,误差超过 5% 就要去检查成本映射配置。6.3 给刚上手的人几个小建议先别急着把所有流量都切到便宜模型。我建议按这个顺序来:先做流量分析,搞清近 30 天哪些任务调用量最大、花费最多。挑 1 到 2 个典型的高频简单任务接入 LiteLLM,先小流量灰度。对比路由前后的质量评估指标(比如准确率、用户投诉率)。确认质量没掉,再逐步扩大范围。最后把成本看板接好,让节省效果可视化。另外,如果你所在团队对稳定性要求很高,千万不要只依赖一个网关进程。LiteLLM 支持挂 Redis 做多实例协调,也支持 Postgres 作为共享数据库,前面再挂一层负载均衡。但这些都是第二步的事了,刚开始单机跑完全够用。我个人在实际操作中最大的体会是:所谓“便宜模型顶上高频任务”,不是用低质量换成本,而是把每类任务分配给性价比最优的模型。便宜模型能扛住 90% 的请求,剩下的难题再交给强模型,整体体验并不会有明显下降。而且随着新模型不断出来,模型的价格和性能每天都在变,有了 LiteLLM 这层路由抽象,你可以永远用极低的迁移成本去拥抱新选择。以后如果业务量再涨,我会考虑把路由网关部署成多实例,加上更细粒度的按用户分桶和模型质量埋点,让每次模型切换都有数据支撑,而不是拍脑袋决定。