☰
LiteLLM实战:模型分层路由如何让高频LLM调用成本降九成
2026/10/20 12:25:22 网站建设 项目流程

如果你的服务每天要跑几十万次“没什么营养”的高频任务,比如给文本打标签、抽关键词、判断用户意图,那“模型分层路由”基本是今天的必选项。把便宜模型顶上高频任务,把旗舰模型留给真正复杂的推理任务,这件事LiteLLM恰好做得非常顺手。我最近把一个内容解析服务的调用链路整体改造成“默认走便宜模型、兜底走贵模型”的结构,账单掉了接近九成,延迟反而更稳定了。这篇文章把整个实战过程拆开讲,含配置文件、路由策略、踩坑记录和评估方法,适合正在做LLM应用成本治理、或者想给团队引入统一模型网关的开发者。

1. 成本账单教我的事:高频短任务为什么要单独走便宜模型

1.1 一次100万次调用的账

先说个我自己算过的账。当时服务里有个分类任务,输入一段短文本,输出一个类别标签。这种任务有几个特点:调用量极大、上下文很短、输出很短、模式基本固定。高峰期一天要跑几十万次,一个月下来轻松过百万。

我按写稿时比较常见的公开价格估算,拿一个旗舰模型和一个轻量模型对比,假设平均每次调用输入500 token、输出100 token:

项目旗舰模型轻量模型
输入价格(每1M token)$2.50$0.15
输出价格(每1M token)$10.00$0.60
100万次调用输入量500M token500M token
100万次调用输出量100M token100M token
输入费用$1,250$75
输出费用$1,000$60
合计$2,250$135

也就是说,同样的业务量,旗舰模型要烧2250美元,轻量模型只要135美元,差出16倍。如果任务本身对“世界知识”和“复杂推理”要求不高,用贵模型跑就是拿着高射炮打蚊子,打中了也是浪费。

你可能会说,几百块钱也不是大钱。但这类高频任务往往只是产品里一个小功能,如果每个小功能都这么烧,整体账单会非常难看。更关键的是,这种量级的调用会把旗舰模型的账号级TPM/RPM配额全部吃掉,等到真有一个复杂任务需要旗舰模型的时候,请求反而被限流堵在门口。

1.2 钱只是其中一个理由

除了成本,还有两个理由让我决定必须做分层。

第一是延迟。轻量模型在短输入场景下的首token延迟普遍更低,吞吐上限也更高。同样的QPS,用轻量模型可以少开实例,或者干脆不需要在应用层加复杂缓存。实测中,我们的P95延迟从800ms降到了400ms左右,体感非常明显。

第二是限流。旗舰模型在服务商那边有TPM和RPM限制,而且账号级的配额是共享的。高频任务全量涌入时,就算是旗舰模型也会被限流,频繁触发429。这时候你加再多重试都没用,因为问题出在流量结构上——太多不值得用旗舰模型的任务占着配额,真正重要的任务无路可走。

所以模型分层不是一个“省钱优化”,它本质上是算力资源的分配问题。让每一层模型匹配每一层任务,便宜的流量走便宜的路,复杂的问题才动用贵算力。这个思路在很多团队里其实早就有了,只是LLM应用普及之后,模型本身成了最大成本项,分层路由才显得如此重要。

2. LiteLLM在分层路由里扮演的角色:统一入口与模型组

2.1 两种落地形态:代理网关与进程内Router

LiteLLM有两种常见用法,我分别说下适用场景。

第一种是代理模式。启动一个独立的LiteLLM代理服务,它对外暴露OpenAI兼容接口,内部负责转发到各家模型服务商。业务代码只需要把base_url改成代理地址,其他一切照旧。这种模式的好处是运维集中、多服务共用,对业务代码侵入极小,适合一个团队有多个服务都在调LLM的场景。

第二种是进程内Router。直接在Python应用里引用litellm.Router,把模型列表配在代码里,应用进程内做路由。好处是不用多部署一个服务,适合改造面可控、规模不大的项目。

两种形态的核心逻辑是一样的,区别主要在部署方式:

维度代理网关进程内Router
部署成本需要维护一个独立服务无额外服务,随应用启动
业务改造量改base_url即可需要改代码逻辑和依赖
故障域代理挂了所有调用都中断应用挂了才影响自己
集中治理适合多服务统一管控适合单服务内自管
适用规模中大型团队、多业务线小项目、快速验证

我这里选的是代理模式,因为团队里好几个服务都要接,统一走一个入口,后面做预算、配额、审计都方便。

2.2 Model Group:把不同厂商的模型挂在一个名字下面

LiteLLM里最核心的概念叫model_name,它不是一个具体的模型,而是一个逻辑组名。你可以把多个厂商的模型挂到同一个组名下,LiteLLM负责在组内做负载均衡和故障切换。

举个例子,我定义了两个组:

  • cheap-fast:放轻量模型,比如gpt-4o-mini、gemini-1.5-flash,承担高频简单任务。
  • high-quality:放旗舰模型,比如gpt-4o、claude-3-5-sonnet,承担复杂推理、长文生成等任务。

业务代码里只写cheap-fast或high-quality,完全不感知底层是哪个厂商、哪个具体模型。哪天某个服务商涨价了,或者新出了一个性价比更高的模型,我只需要改代理配置文件,业务代码一行不用动。

这一点很重要。很多人一开始会直接按“模型名”来路由,比如代码里写死gpt-4o-mini,后面想切到别的模型就得全局搜索替换。用逻辑组名隔离之后,模型切换变成了配置操作,而不是代码操作。

3. 落地第一步:用config.yaml把模型分成两个梯队

3.1 最小可用的分组配置

LiteLLM代理的配置集中在一个YAML文件里。我直接贴一个能跑起来的最小配置:

model_list: - model_name: cheap-fast litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY model_info: id: openai-gpt-4o-mini - model_name: cheap-fast litellm_params: model: gemini/gemini-1.5-flash api_key: os.environ/GEMINI_API_KEY model_info: id: gemini-flash - model_name: high-quality litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: id: openai-gpt-4o - model_name: high-quality litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY model_info: id: anthropic-claude-sonnet litellm_settings: router_settings: routing_strategy: simple-shuffle allowed_fails: 2 cooldown_time: 300

这里有几个字段需要解释。

litellm_params.model前面带了前缀,比如openai/、gemini/、anthropic/。这是LiteLLM的provider标识,它看到前缀就知道该转换成哪家服务商的请求格式。api_key用os.environ/变量名的形式引用环境变量,不要把密钥直接写在配置文件里。

model_info.id是本组内该部署点的唯一标识。LiteLLM用它做日志、健康检查和故障归因。如果不写,它会自动生成,但建议手动指定一个可读的名字,排查问题的时候会舒服很多。

配置写好后,直接启动:

pip install 'litellm[proxy]' litellm --config config.yaml --port 4000

启动完成后,用curl http://localhost:4000/health确认服务正常。接下来就可以用OpenAI SDK风格调用它了。

3.2 配额、熔断与预算:防止便宜模型顶不住

分层路由不是简单把便宜模型挂上去就完事。便宜模型也要面对限流、故障和预算问题,得给它们配好安全网。

先看限流。如果你在同一个组里挂了多个模型,但某个模型在服务商那边的配额很紧张,就可以给它单独设置每分钟Token数和每分钟请求数:

- model_name: cheap-fast litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY rpm: 1000 tpm: 400000

rpm和tpm分别限制每分钟请求数和每分钟Token数。LiteLLM会在组内分配流量时避开已经超限的模型,不至于硬顶着限流往上打。

再看熔断。LiteLLM支持allowed_fails和cooldown_time。我配置里的2和300表示:同一个模型连续失败两次后,把它临时移出路由池300秒。这个机制很实用。模型也会抽风,比如服务商某个区域集群抖动,如果继续把流量打过去,只会让错误率雪崩。移出冷却之后,流量会自动转到组内其他模型上。

最后是预算。代理模式下,每个调用方都可以分配一个虚拟Key,并绑定预算:

curl -X POST http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-1234" \ -H "Content-Type: application/json" \ -d '{"models": ["cheap-fast", "high-quality"], "max_budget": 100}'

这样每个业务线、每个项目都有自己的Key和预算上限,账单出来之后能直接知道钱花在谁头上。预算超了LiteLLM会直接拒绝请求,不会出现月底对账时才发现超支的情况。

4. 路由策略与回退设计:便宜模型顶得住才有价值

4.1 内置路由策略怎么选

LiteLLM本身带了多种路由策略,选型之前建议先把文档里的策略行为搞清楚。我实际用过的几种如下:

策略行为特征适合场景
simple-shuffle在组内均匀打散流量,类似轮询组内模型能力、价格接近
least-busy按在途请求数选择,谁闲谁上某个模型经常被限流
latency-based按历史响应延迟加权,快者优先对首token延迟敏感
usage-based-routing结合预算与用量成本梯度选择想强制控制成本上限

我一开始用的是simple-shuffle,因为两个便宜模型的能力和价格差不多,均匀分担最省心。后来发现某个服务商偶尔会抽风,就切到了latency-based,让响应快的模型多吃流量,慢的自动少拿。选型逻辑很简单:看你的首要诉求是稳定性、延迟还是成本,策略和诉求要对齐。

有一点需要注意,路由策略只能解决“组内怎么选模型”的问题,它不能替代业务分层。也就是说,LiteLLM负责在cheap-fast组内挑选当前最优的便宜模型,但业务方必须先把请求明确指定到cheap-fast。

4.2 回退不是万能药:fallback会带来延迟雪崩

很多人知道LiteLLM有fallback机制,就希望在cheap-fast组整体不可用时自动切到high-quality组。思路没问题,但实现时要非常小心。

默认的fallback逻辑是:先请求目标组,等它失败或超时后,再发起对备用组的请求。这意味着每个失败请求的代价是“目标组超时时间 + 备用组响应时间”。一旦目标组真的有问题,所有请求都会先饿着肚子等一趟,延迟直接翻倍甚至更多,这就是延迟雪崩。

我的做法是两层防护。

第一层,在配置里把allowed_fails调低,cooldown_time调长,让有问题的模型尽快冷却,而不是反复试探。第二层,在应用层针对关键请求做“双跑”:同时请求便宜模型和贵模型,谁先返回合理结果就用谁,另一路直接丢弃。

import asyncio from openai import AsyncOpenAI client = AsyncOpenAI( base_url="http://localhost:4000/v1", api_key="sk-your-virtual-key", ) async def double_run(messages): cheap_task = client.chat.completions.create( model="cheap-fast", messages=messages, timeout=3 ) heavy_task = client.chat.completions.create( model="high-quality", messages=messages, timeout=6 ) done, pending = await asyncio.wait( [cheap_task, heavy_task], return_when=asyncio.FIRST_COMPLETED, ) for task in pending: task.cancel() return done.pop().result()

双跑看着浪费,实际只用在最核心的少量请求上。它的价值在于:便宜模型正常时几乎总是先返回,贵模型的请求其实多半还没发出去就会被取消;便宜模型异常时,贵模型也不会被前面的等待拖累。这比单纯的fallback可靠得多。

5. 应用侧改造:业务分层判断与无感切换

5.1 分层判断放在哪一层

LiteLLM把路由做得很漂亮,但“这个请求该走便宜还是走贵”的判断,通常要在应用层完成。我的经验是分层判断遵循一个从粗到细的顺序。

优先用规则判断。如果文本长度超长、包含多个互斥条件、要求多步推理,或者业务上判定了高风险,直接走high-quality。规则覆盖不了的,再让便宜模型先跑,同时对结果做一个简单的置信度检查,不达标再升级到贵模型。这种分级方式成本低、可解释性强,也容易灰度验证。

给个示意代码:

import os from openai import AsyncOpenAI client = AsyncOpenAI( base_url="http://localhost:4000/v1", api_key=os.environ.get("LITELLM_VIRTUAL_KEY"), ) def need_heavy(text: str) -> bool: # 规则前置:命中规则直接升级 if len(text) > 2000: return True if any(k in text for k in ["矛盾", "推理", "多轮"]): return True return False async def handle_task(text: str): group = "high-quality" if need_heavy(text) else "cheap-fast" resp = await client.chat.completions.create( model=group, messages=[{"role": "user", "content": text}], temperature=0, ) return resp.choices[0].message.content

这个例子很简化,但核心思想是对的:默认便宜,按需升级。不要反过来,把所有请求先发给贵模型再降级,那样省不到钱。

5.2 从openai客户端切到LiteLLM代理只需要改base_url

我最喜欢LiteLLM代理的一点是,切换几乎是无痛的。只要业务代码里用的是OpenAI SDK,把base_url和api_key换成代理地址和虚拟Key,其他逻辑完全不变。

from openai import AsyncOpenAI client = AsyncOpenAI( base_url="http://localhost:4000/v1", api_key="sk-LiteLLM-virtual-key", )

然后在配置文件中,把虚拟Key绑定到cheap-fast和high-quality这两个组,这个调用方的路由权限就落好了。

想验证某个模型是不是真的健康,LiteLLM支持mock_response,我测试时经常用它来验证链路通不通,不花真实token。它的思路是让某个模型返回预设的模拟响应,适合做联调和异常路径测试,上线前把整条链路先跑通。

代理模式还有一个好处:模型提供方的SDK升级或格式变化,都被隔离在LiteLLM这一层。业务代码永远只跟OpenAI兼容的协议打交道,底层怎么变都无所谓。

6. 实测数据与避坑记录:成本、延迟和那些隐蔽的坑

6.1 模拟压测结果

改造完成后,我在一个跟线上任务结构类似的仿真数据集上跑了压测。数据是模拟的,但评估方法可以照用:同一批请求跑两套链路,对比延迟、成本和错误率。

指标改造前(全量旗舰)改造后(分层路由)
P50延迟650ms320ms
P95延迟2100ms780ms
可支撑QPS150600
月度成本(模拟估算)100%约14%
错误率0.8%1.1%

成本下降最直观,直接打了一折多。延迟整体也降了,因为便宜模型在短任务上的首token延迟更低,而且不再被旗舰模型的限流拖住。错误率略有上升,主要来自便宜模型在少量边界样本上的误判,这部分我通过升级规则兜住了。

压测时我还发现一个规律:分层路由的效果跟“任务结构”强相关。如果你的任务里八九成都是短、模式化、低风险的任务,收益巨大;如果任务普遍复杂、需要深度推理,那分层能省的空间很有限,重点反而应该放在缓存的命中率上。

6.2 我踩过的几个坑

这几个坑是真实调试过程中出现的,每一条都花了不少时间。

第一个坑是模型间的Prompt和输出格式兼容问题。同一个任务在旗舰模型上表现很好,换到便宜模型后JSON格式偶尔会多出解释性文字,直接导致下游解析报错。解决办法是在系统提示里明确输出规范,同时在解析层做容错,不能默认模型一定会输出纯JSON。

第二个坑是上下文缓存被切碎。如果组内有多个厂商的模型,同一个用户会话可能这次走A厂商、下次走B厂商,各家缓存策略完全独立,结果就是缓存命中率很低,成本并没有表面上看起来那么低。我的做法是在配置里尽量让同一会话固定到同一模型,牺牲一点负载均衡来换缓存命中。

第三个坑是tpm限流造成的排队噪音。我给模型设置了tpm之后,LiteLLM会在本地排队等待配额,排队本身会拉高延迟,这时候再看latency-based路由选出来的结果其实是不准的。排查时才意识到,延迟数据里混进了排队时间,应该把“模型真实响应时间”和“本队列等待时间”分开看。

第四个坑比较低级但很常见:有人把cheap-fast这种组名当成模型名写死在客户端代码里,某个服务直接调model="cheap-fast"没问题,但想临时绕过代理直连某个模型验证问题时,就发现代码里根本没有真实模型名。教训是业务代码里永远只出现逻辑组名,真实模型名只在代理配置里出现一次。

6.3 想继续做的话:从成本分层到质量分层

分层路由做到后面,你会自然想从“成本分层”进化到“质量分层”。比如引入离线评测集,定期用便宜模型跑一遍,拿结果和旗舰模型对比打分,用分数决定哪些任务可以长期留在便宜层。也可以做任务复杂度预估模型,用一次便宜的预测判断该不该升级算力。

再往后还能加用户维度的分层:免费用户走便宜模型,付费用户默认走高质量模型;或者按时段路由,高峰期用便宜模型扛量,低峰期再跑贵模型做精排。这些方向都需要一个稳定的路由网关作为底座,LiteLLM这套结构已经能撑住这些玩法了。

我自己的体会是,模型分层路由最大的价值不在省下的那点账单,而在于它让你敢于拿便宜的算力去做大规模实验,让每一层资源真正用在刀刃上。最后分享一个小技巧:从改造第一天就把每个组名、每个模型ID的调用量和成本埋点数据记好,后面做任何路由策略调整,都要靠这些数据说话,不能拍脑袋。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询