ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LiteLLM网关落地实践:限流、安全、缓存与模型容灾全攻略

LiteLLM网关落地实践:限流、安全、缓存与模型容灾全攻略 这周我把公司内部的LLM调用流量全部切到了LiteLLM网关。之前各服务直连模型厂商SDKOpenAI、Azure、Anthropic各自一套鉴权密钥散落在十几个仓库的.env里月初预算经常莫名烧掉一大截有一次上游深夜降级业务停摆40分钟才靠手工改配置切到备选模型。后来我把所有调用收口到LiteLLM用两周时间补齐了限流、安全防护、缓存分流和模型容灾这四件事。这篇文章就是整个落地过程复盘包含完整的config.yaml、参数选型思路和几个真实踩坑记录适合正在接多个模型、或者已经上了LiteLLM但还没把网关能力用满的团队参考。1. 为什么模型调用要收口到网关1.1 直连模型时的真实混乱接入一个模型是件简单事接入两个也还行接入到五个就开始失控了。最常见的一个场景是业务代码里塞满了厂商判断模型A要传这样的header模型B要把参数包成那样模型C的错误码含义和另外两家完全相反。每接一个新模型就要在服务里加一段适配逻辑代码越来越像袜子补丁。密钥管理更头疼。OpenAI的Key在后台服务里Azure的Key在另一个仓库Anthropic的Key放在某台机器的环境变量里。轮换一次Key需要跨部门沟通发版窗口迁就好几个团队中间隔一个晚上就可能有人用旧Key继续调请求时而成功时而失败。审计的时候根本说不清哪个服务在调用哪个模型、花了多少钱。还有故障处理。模型厂商偶尔会降级或者某个模型因为负载太高开始疯狂报错。直连模式下没有统一的路由层只能紧急改代码换模型再走一遍构建、测试、发版流程。我见过太多团队在这种时刻手忙脚乱。这些痛点背后其实是同一个问题调用关系太散缺少一个统一的流量入口。1.2 LiteLLM在链路里的位置LiteLLM解决的就是“入口”这件事。它是一个用Python写的LLM网关代理部署起来非常轻量一条docker命令就能跑起来对外暴露的是OpenAI兼容的/v1/chat/completions接口。业务方拿到这个地址后完全不需要关心背后是OpenAI、Azure还是本地vLLM甚至连SDK都不用换只要原本会调OpenAI接口把base_url指过来就行。网关内部通过一个config.yaml把模型列表、上游密钥、限流阈值、缓存参数、fallback策略全部声明式管理起来。新增一个模型往往只是往配置文件里加一段然后reload不需要改任何业务代码。这是一套很适合“中央集权”的治理模型入口集中、策略集中、观测也集中。我在选型的时候也对比过自己写网关或者用通用API网关改造。通用网关擅长流量管理但不知道“token”是什么、“模型”是什么做不了TPM限流也无法理解模型失败时的容灾语义。自研网关听上去可控但限流要做、缓存要做、密钥体系要做很快会发现维护成本比模型费用还高。LiteLLM的定位正好卡在中间懂LLM的路由和治理又足够开放可以插入自己的逻辑。1.3 四件事的优先级怎么排标题里的四个关键词——限流、安全防护、缓存分流、模型容灾——如果只看文档会觉得是一堆独立开关实际落地要有优先级。第一优先级是限流。这是和钱直接挂钩的一个异常任务循环、一个数据同步脚本写错、一个刷子爬虫都可能让账单在几小时内飞涨。把限流做了预算基本守得住。第二优先级是安全。主密钥和业务密钥要分开不然一次泄漏就是全盘失控。第三优先级是容灾保证上游挂了业务还能跑。第四才是缓存它解决的是成本和延迟优化属于“过得更好”而不是“活下来”。这四个功能在LiteLLM里不是独立的它们会在同一份配置里互相咬合。比如缓存命中后不消耗限流额度容灾切换后缓存key要跟着模型换安全模块生成的虚拟密钥同时承载限流和预算的粒度。所以下文会按顺序逐项展开但实际配置时一定要当成一个整体来看。2. 限流先把预算守住了2.1 单机限流与Redis分布式限流怎么选LiteLLM内置的限流能力分两种形态。单机模式下它用进程内计数器做判断配置简单适合本地开发和单副本部署。但一旦生产环境开了多个副本就必须换成Redis支撑的分布式限流否则每个副本各自计数N个副本等于把限流上限放大了N倍。我见过一次事故一个服务部署了6个副本每个副本限制每分钟1000次请求结果上游按整体维度限流直接把服务商的key给封了。排查下来发现每个副本都认为自己没有超限实际6个副本合计每分钟6000次。所以多副本场景下Redis不是可选项是必须项。Redis配置也很直接在general_settings里指定host和port即可。我的建议是Redis单独部署别和业务共用实例限流计数器对延迟敏感业务高峰期可能互相拖累。2.2 三层限流配置全局并发、模型级、密钥级LiteLLM的限流可以分成三个粒度建议全部配齐。全局并发上限用max_parallel_requests控制防止同时打进来的请求数把网关或上游连接池压垮。模型级限流写在model_info里有rpm和tpm两个维度分别限制每分钟请求数和每分钟token数。密钥级限流在生成虚拟密钥时设置每个接入方可以拿到独立的rpm_limit和tpm_limit。RPM和TPM的关系要理解清楚RPM限制的是“次数”TPM限制的是“消耗量”。有的业务方每分钟只调用10次但每次请求都是几十K token的长文本RPM宽松也没用TPM会先爆。所以两个维度都得配。config.yaml里大概是这样general_settings: redis_host: localhost redis_port: 6379 max_parallel_requests: 200 model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: rpm: 1000 tpm: 120000生成密钥时的限流参数是通过管理接口传的curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-xxx-master-key \ -H Content-Type: application/json \ -d { models: [gpt-4o], rpm_limit: 100, tpm_limit: 50000, max_budget: 50 }三层限流的判断顺序是全局并发先拦一道然后到模型级RPM/TPM再到密钥级RPM/TPM。任何一个维度超了都返回429并带Retry-After头。2.3 TPM统计口径与流式请求的坑RPM的实现很简单进来一个请求计数加一完成或失败减一。TPM就麻烦很多因为只有在模型输出结束后才能精确知道一共消耗了多少token。尤其是流式响应token是边生成边吐的网关在响应结束的那一刻才能拿到准确总数。LiteLLM的做法是先用估算值占位响应完成后异步回写真实的token数。这意味着高并发场景下瞬时TPM可能会略微超过设定值几个百分点。我在压测里看到过5%左右的超限属于正常现象不用太纠结。但如果长期跑下来超限明显说明阈值配得太贴近上游上限了要往下调。2.4 限流踩坑记录Redis没配高可用。Redis一旦宕机限流就退化成单机模式甚至放行。生产环境要给Redis做高可用或者至少配上告警。阈值没有留buffer。上游服务商给你的RPM是1000你就配1000高速流量一来先是网关429再是上游429两边都在报错。建议按90%配置留10%给瞬时毛刺。只限速率不限并发。有些耗时长的任务RPM只有1但能同时跑20个。如果上游并发能力有限照样被打爆。所以要同时关注max_parallel_requests和各模型的并发表现。客户端对429处理不当。有些SDK收到429后会立刻重试反而加重压力。要在客户端做指数退避尊重Retry-After。限流日志要留全。至少记录请求id、虚拟密钥别名、命中的限流维度、被拒前的计数方便事后复盘。3. 安全防护密钥、预算与内容审核3.1 虚拟密钥把主密钥关进保险箱LiteLLM的密钥体系分两层master_key和虚拟密钥也就是Virtual Key。master_key权限最高可以调用管理接口、生成和吊销虚拟密钥、查看所有密钥的消费记录。它只应该存在于网关服务端配置或运维手里绝不能发给业务方。虚拟密钥是给业务方用的。每个业务方可以生成一个或多个独立Key并且每个Key都能单独绑定模型、单独设置预算和限流、单独做审计。出问题的时候直接吊销那一个Key就行不用全局推倒重来。我强烈建议所有外部调用都走虚拟密钥即使只有一个业务方也别用master_key直连。真实场景里我踩过这样一个坑业务方拿到master_key后直接在代码里写死后来这个Key泄漏到前端仓库整个网关等于裸奔。虚拟密钥至少能帮你把爆炸半径缩小到单业务、单Key范围。生成虚拟密钥后返回的sk-就是调用凭证管理接口要记好。吊销用/key/delete接口按key的hash值删除删除后立刻生效。这个“立刻生效”在线上是很重要的能力。3.2 预算控制不允许任何人超支除了限流安全防护里和钱相关的另一层是预算。LiteLLM可以在密钥或团队维度设置max_budget单位是美元并且可以配置budget_duration设定结算周期比如“30d”表示按月滚动。超过预算后该密钥后续请求会被拒绝并返回401之类的状态码。预算的意义不只是防恶意更是防遗忘。很多团队的模型Key是共享的月底账单出来才发现某个内部工具在疯狂调用。拆到虚拟密钥之后每个Key的消费通过接口一目了然哪个业务烧钱一清二楚。给预算设值的时候我建议按“预期消耗的两倍”来定。模型价格是波动的一行代码也可能导致某个服务多调用三倍流量预算卡得太死会让业务摸不到接口卡得太松又等于没设。留个一倍余量配合告警是成本和安全之间的平衡点。3.3 内容审核与敏感信息过滤网关层做内容审核是个容易被忽视但很实用的能力。LiteLLM支持guardrails机制可以在请求进入和响应返回时挂审核逻辑。典型做法是对输入输出做一次违规内容判断命中色情、暴力等违规内容时直接拦截请求或终止流式输出。接入审核后还有一个额外好处把违规请求挡在模型之前能省下不少token费用。有人觉得在自己的API接口里做审核就行但业务方众多的时候每个人写一套又不统一网关集中做一遍是性价比最高的方案。审核逻辑可以是内置的OpenAI Moderation也可以接自己训练的轻量分类器LiteLLM提供了钩子位置插进去就行。敏感信息过滤是另一件事。日志里不应该出现完整API Key、请求里的身份证号手机号这类隐私字段。我在配置里会做日志脱敏输出日志只保留模型名、token数、耗时、状态码不打印请求body。3.4 安全配置的几个隐蔽坑master_key泄漏一次等于全部泄漏。除了不要外传还建议定期轮换并把旧的立即吊销。生成虚拟密钥时一定要显式指定models。如果models为空LiteLLM默认允许该Key调用所有模型等于限流和预算都形同虚设。管理接口要藏好。/key、/team、/user这些管理端接口必须在防火墙或网关层做白名单别暴露在公网上任人访问。config.yaml里的真实上游Key不要明文提交到git。用os.environ/前缀从环境变量读取这是LiteLLM支持的标准做法。内容审核的误杀率要灰度验证。审核模型阈值设太严会误伤正常请求上线前用真实流量回放一遍看拦截率和误杀率再调参。4. 缓存分流把重复请求挡在模型前面4.1 先把流量分成“可缓存”和“不可缓存”缓存分流这个词听起来玄其实就是对进入网关的流量做一个分类。一类是高频重复的查询比如天气、政策问答、固定模板生成另一类是长尾个性化请求每个人问的问题几乎没有交集。分流的做法是让网关在转发前先查缓存重复请求直接返回缓存内容不经过上游模型只有缓存没命中的个性化请求才走模型。这相当于给模型前面加了一道“防洪坝”把大量一模一样或高度相似的请求从账单里剔除。我在一个FAQ场景实测过加了缓存之后高峰期命中率能做到35%到45%整体token成本下降约三成P99延迟从2.8秒降到600毫秒左右。对于以重复查询为主的业务这个数字还会更高。当然代价是需要接受“用户看到的是缓存答案不是新生成的”所以实时性要求高的数据不适合缓存这是选型时就要想清楚的。4.2 精确缓存与语义缓存的取舍LiteLLM提供两种缓存模式。精确缓存最简单请求体的关键字段完全一致才算命中。它的优点是逻辑明确、没有误命中风险缺点是用户措辞稍微变一下就会miss。语义缓存更进一步它先对请求做向量化再计算相似度超过阈值就判定为命中。比如“帮我查一下北京的天气”和“北京今天气温多少”在语义缓存看来是同一个问题可以共用答案。生产环境配置语义缓存需要额外准备一个embedding模型可以是OpenAI embedding也可以是本地模型。选择上我的建议是先上精确缓存。它零语义成本命中规则透明排错也容易。如果上线后命中率上不去比如一直低于20%再考虑加语义缓存。语义缓存需要调试的阈值参数更多embedding模型和相似度阈值都会影响准确性别一开始就把复杂度拉满。Redis作为缓存存储时配置是这样的cache: type: redis host: localhost port: 6379 ttl: 300 namespace: litellm-cache-prod4.3 缓存Key、TTL、流式回放与一致性缓存看起来是开关一开就完事实际有几个参数能明显影响效果。第一是TTL缓存有效期。设短了命中率上不去设长了会有过时内容风险。运营类知识问答我一般从300秒起步然后根据数据变化节奏调整。天气预报这种实时数据干脆不缓存。第二是缓存Key的设计。LiteLLM默认把完整请求体hash后作为Key包括model、messages、temperature等参数。这里有个容易忽略的点同一个model_name下如果有多个上游部署缓存Key里不应该带上游信息否则同一段prompt会被路由到不同上游并各缓存一份白白浪费内存。另外如果业务方的temperature在0和0.1之间浮动缓存也会miss可以尝试在网关侧做参数归一化后再入缓存。第三是流式响应。LiteLLM支持缓存流式请求命中后按SSE格式回放缓存内容。这个功能很好但注意回放时的chunk间隔不要太快否则客户端可能因为接收速度异常而产生误解。一致性上要诚实相同prompt在这个模型身上每次输出的内容本来就可能有差异缓存会把这个差异抹掉。如果你的业务对随机性敏感就不要缓存所有对话只挑适合缓存的场景。4.4 缓存、限流、容灾的联动缓存不只是省钱的工具它还能缓解限流压力。缓存命中的请求不消耗上游RPM/TPM也不消耗业务方预算相当于给整条链路增加了一档“免费流量”。当某个Key达到限流阈值时如果请求恰好是重复的公共问题缓存依然可以返回答案避免“限流把该答的问题也拦了”的尴尬。容灾场景下缓存也能兜底。上游全部故障的时候缓存里还有最近的有效答案至少保证一部分高频请求可用。但要小心一个坑缓存Key必须包含model_name不能把模型A的答案缓存在模型B的命名空间下。否则容灾切换后用户问同一个问题可能拿到另一个模型生成的完全不同的回答那才叫事故。我习惯在每个模型和每个Key维度分开观察缓存命中率。命中率突然下降往往是流量结构变了或者有人改了参数命中率突然上升则可能是某个脚本在刷同一个请求这两种情况都需要看一眼。5. 模型容灾上游挂了服务不能跟着挂5.1 重试、冷却、fallback是怎么配合的模型容灾不是“配置一个备用模型”这么简单它其实是一整套自动恢复机制核心是四个参数retries、allowed_fails、cooldown_time、fallbacks。先看单个请求的路径router把请求发给主模型如果失败先在本批次内自动重试重试次数由retries控制。重试仍然失败则根据错误类型判断是否适合切换——超时、5xx这类瞬时错误适合重试和切换4xx无效请求重试没意义。fallbacks则指定当主模型不可用时按优先级依次尝试的备选模型。再看健康状态管理一个上游连续失败次数达到allowed_fails时router会把它标记为冷却状态在cooldown_time设定的一段时间内不再向它路由流量。冷却结束后它自动恢复但下一次路由前还会有一次预检查。这套组合的效果是单个请求失败不会影响整体连续故障会被自动隔离隔离期结束后又能自动回归。不需要运维半夜起来改配置这是容灾最核心的价值。配置示例router_settings: routing_strategy: usage-based-routing-v2 retries: 2 allowed_fails: 3 cooldown_time: 120 fallbacks: - gpt-4o: [claude-3-5-sonnet]5.2 多部署模型组与动态路由策略LiteLLM支持把多个上游部署挂到同一个model_name下面。比如model_name叫gpt-4o底下可以同时挂OpenAI的gpt-4o和Azure的gpt-4o网关会按路由策略把请求分发到不同部署上。这样做的好处是单一上游挂了以后另一个还能接着扛。路由策略有很多种。simple-shuffle是轮询适合同质化部署least-busy倾向把请求发给当前等待最少的部署usage-based-routing-v2则是根据历史错误率、延迟、当前负载做综合打分适合异构部署比如OpenAI、Azure、自托管vLLM混在一起用。我在生产环境用的是usage-based-routing-v2配合fallbacks。实测下来它对故障部署的感知比轮询快因为错误率会实时影响路由权重等于一个隐性的健康检查。不过路由策略更新需要观察一段时间才能稳定刚切换配置的头几天要盯着流量分布别一上来就全量压上去。5.3 容灾切换的边界条件容灾不是把所有请求都往备选模型上切就完事有四个边界条件比路由本身更重要。备选模型的能力要和业务需求匹配。如果主模型支持function calling备选模型不支持切过去以后业务方的工具调用直接报废。所以fallback列表要做能力矩阵测试不只是测通不通还要测关键特性。超时时间不能设置得太长。如果主模型一直处于“挂起但不报错”的状态一个30秒超时意味着请求要等30秒才能fallback这个延迟对线上用户来说就是事故。我建议模型级timeout设在20到30秒之间对于对话场景可以再短一点。fallback链条不能形成环。A失败切BB失败切A两边都不行的时候请求在两个模型之间反复横跳最后超时。配fallbacks之前要手画一遍依赖关系确保它是DAG不是环。成本要监控。主模型挂了切到备选如果备选是更贵的模型容灾期间的账单会明显上升。我在告警规则里专门加了一条容灾期间的每分钟花费如果超过正常时段三倍立刻通知。容灾可以接受短暂溢价但不能无感烧钱。5.4 一次真实的故障演练配置完容灾不等于万事大吉一定要演练。我的标准动作是每个月挑一个流量低谷时段把某个上游的Key故意改错模拟一次故障然后观察整个链路的行为。第一次演练就翻车了。我把OpenAI的Key改错本以为请求会自动走Azure部署结果流量确实切换了但业务方那边报了一堆解析错误。排查下来发现业务方代码里对OpenAI的响应有一个特有的字段做了强依赖换到Azure后的response结构基本兼容但那个多出来的字段变了校验直接挂了。后来我让业务方把所有响应处理改成只依赖OpenAI兼容格式并且把容灾用的备选模型也纳入了同样的兼容性测试。演练完看效果故障期间请求成功率维持在99%以上P95延迟上升了不到300毫秒冷却结束后流量自动回切到主模型。对比之前直连模式下40分钟的人工切换时间这个自动化程度已经算可接受了。每次演练都要记录一个指标从注入故障到全链路自动恢复的时长这个数字应该越练越小。6. 完整配置与上线自检6.1 一份可以直接改的config.yaml把前面四章的内容合并成一份可运行的配置我贴一个精简但完整的版本。环境变量通过os.environ/前缀引用密钥和数据库地址不要写死在文件里model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY model_info: timeout: 30 rpm: 900 tpm: 100000 - model_name: gpt-4o litellm_params: model: azure/gpt-4o api_key: os.environ/AZURE_API_KEY api_base: https://my-azure-endpoint.openai.azure.com/ api_version: 2024-02-01 model_info: timeout: 30 rpm: 700 tpm: 80000 - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY model_info: timeout: 30 rpm: 500 tpm: 60000 router_settings: routing_strategy: usage-based-routing-v2 retries: 2 allowed_fails: 3 cooldown_time: 120 enable_pre_call_checks: true fallbacks: - gpt-4o: [claude-3-5-sonnet] cache: type: redis host: localhost port: 6379 ttl: 300 namespace: litellm-prod general_settings: master_key: os.environ/LITELLM_MASTER_KEY database_url: os.environ/DATABASE_URL redis_host: localhost redis_port: 6379 max_parallel_requests: 200 alerting: - slack这份配置里gpt-4o挂了两个部署实现模型级容灾claude-3-5-sonnet作为跨厂商fallback。缓存整链路开启限流三层都配置了。database_url是必要的虚拟密钥的持久化、预算记录都依赖数据库建议用PostgreSQL。6.2 上线前自检清单配置写完不能直接上生产我每次上线前都会过一遍自检清单这里整理成表格检查项操作方法预期结果限流是否生效用压测工具打到2倍RPM网关返回429计数器准确多副本限流一致性部署2个副本同时压测合并后总量不超过限流值虚拟密钥可吊销生成测试Key调用后删除删除后立刻返回401预算拦截把max_budget设为0.01并调用请求被拒绝状态码符合预期缓存命中同一请求连续调用两次第二次返回cache_hit标志耗时明显下降缓存key隔离切换model_name后调用不会复用其他模型的缓存fallback切换临时改错主模型Key请求自动切到备选模型无报错冷却恢复等待cooldown_time后观察主模型恢复路由不再持续失败日志脱敏查看线上日志不出现完整API Key和请求body监控指标访问/metrics有litellm_开头的deployment和spend指标这份清单我每一行都踩过对应的坑推荐至少全部执行一遍再正式切流。6.3 监控指标与告警LiteLLM自带/health/liveliness和/health/readiness探活接口K8s部署可以直接挂到探针上。更好的观测入口是/metricsPrometheus可以直接抓取指标统一以litellm_开头。我会重点关注三类deployment维度的success和failure数量、每个虚拟Key的spend金额、缓存命中率。日志这块关键是请求级的trace信息包括请求id、model_name、实际路由到的上游、耗时、token数、是否缓存命中、返回状态码。这些信息汇总之后既能做成本核算也能排查限流误伤和缓存串key问题。告警渠道我习惯用Slack的webhook接进来。告警规则除了常规的5xx比例升高还要加两条一个是某模型deployment连续失败超过allowed_fails且冷却触发说明进入了容灾状态另一个是spend金额在短时间内异常升高通常是限流没拦住或者容灾切到了高价模型。告警不是越多越好这几条是我压测和实际运行下来最有信号价值的。最后想单独说一句我自己的体会这一套系统刚落地时最费时间的不是写配置反而是把业务方的响应兼容性梳理清楚。缓存、限流、容灾本质上都是在给“不可靠的模型调用”增加缓冲但如果下游只认某一种响应格式容灾切换的价值就会大打折扣。我后来把所有内部服务对模型响应的解析全部收口到一个公共SDK里只保留OpenAI兼容格式的字段再去折腾网关的各种能力明显顺了很多。这个顺序如果反过来先把网关配置得花里胡哨再回头改业务代码会很痛苦。如果你也正在做类似的事我的建议是先用最小的配置把网关跑通再逐个叠加限流、缓存、容灾每加一个能力都做一次压测和回放不要急着一步到位。LLM网关的复杂度是慢慢长出来的你越早开始观察线上流量的真实结构后面的配置决策就越有底气。
返回列表