ARTICLE DETAIL

资讯详情

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

LiteLLM大模型网关实践:模型路由、用户隔离与用量控制全指南

LiteLLM大模型网关实践:模型路由、用户隔离与用量控制全指南 上个月我把团队里散落在大模型项目上的各种调用统一收敛到了一个 LiteLLM 网关后面。起因特别现实组里有人接 OpenAI有人走 Anthropic还有人用本地 LMStudio 跑的私有模型每个项目一套 SDK、一把 API Key月底账单拉出来根本分不清哪些项目到底烧了多少钱。架设 LiteLLM 之后模型、用户、用量管理这些事终于可以塞进一个入口解决客户端只需要改 base_url路由、重试、配额、审计全部交给网关。这篇东西不是官方文档翻译而是我实际搭建和运行过程中的完整记录适合正在选型、或者已经用上 LiteLLM 但还没把用户和预算体系理顺的团队参考。后面谈的东西不绕弯子重点就三个模型怎么接入、用户怎么隔离、用量怎么控住再加几段生产环境里真正遇到过的问题。1. LiteLLM 到底是什么为什么我拿它当“模型调度中枢”先回答一个反复有人问的问题LiteLLM 不是模型也不是模型训练框架它是一个开源的大模型网关Proxy。它对外暴露的是 OpenAI 兼容的 HTTP 接口对内可以路由到 OpenAI、Anthropic、Azure OpenAI、AWS Bedrock、Vertex AI、Ollama、LMStudio 等上百个模型服务商。客户端原来的 OpenAI SDK 基本不用动只需要把 base_url 换成 LiteLLM 的地址POST /chat/completions 这个请求就到了网关接下来转给哪个模型后端由网关决定。这个“对外一个接口、对内一堆后端”的设计解决的是三类实际问题。第一协议统一团队不用再为不同厂商各写一套调用代码第二密钥集中API Key 不再散落在代码仓库和配置文件中第三网关能拦下每个请求做路由、重试、限流、用量记录也就是文章后面要展开的模型、用户、用量管理三个核心模块。换句话说LiteLLM 让“多个模型共存、按需切换、按量计费”这套体系有了一个具体的落地点。1.1 一个 base_url 就能解释它的存在价值我第一次感受到这玩意儿省事是在一个内部工具里。原本工具直连 OpenAI写死了 gpt-4o后来想换 Claude按老办法得改代码、换 SDK、调参数前后至少折腾半天。接上 LiteLLM 之后操作变成了两步先在 LiteLLM 的 model_list 里注册一个逻辑名 gpt-4o 并指向 Claude 的模型再把客户端的 base_url 改成 LiteLLM 地址。客户端完全感知不到后端换了厂商甚至可以把同一个逻辑名指向多个模型让网关自动做负载均衡。这个思路的核心是逻辑名与物理模型的解耦。客户端永远只认逻辑名比如 gpt-4o、claude-sonnet、local-qwen背后具体用哪个厂商的哪个版本是网关管理员在 config.yaml 里定义的。好处非常直接以后更换模型版本、切换供应商、淘汰某个模型都不用动客户端代码。对团队里那些不爱改代码的业务同学来说这个解耦几乎是救命级别的体验。1.2 我最终没有自研网关的三个理由有同事问过这东西我们自己拿 Node 写一个代理不就行了当时确实认真评估过自研方案最后放弃有三个原因。第一生态兼容成本太高。OpenAI 的接口格式已经成为事实标准市面上几乎所有 LLM 客户端、开源工具、低代码平台都默认兼容它。自研代理要复刻的不只是 /chat/completions 这一个端点还有 embeddings、models 列表、流式输出、错误格式和限流返回规范。做出来容易做到全面兼容很难后续还要不停追新特性。第二多租户和预算能力是深水区。LiteLLM 开箱就有虚拟密钥、团队管理、预算上限、用量日志、配额限制这些功能在很多企业里需要一两个月才能自研出来。如果从零开始我预估我们的团队至少要投入三个人周去写基础版而且大概率没有 LiteLLM 设计得细致。第三运维模式成熟。官方镜像加 Postgres 就能跑管理台自带了密钥生成、用量查看、预算设置界面团队内部使用不需要额外开发后台。自研的话后台、报表、告警全得自己造这些活看着不起眼真做起来相当耗时。后来我们连计量计费的部分也都直接基于它实现没有再动自研的念头。1.3 起步部署中最容易忽略的一个配置部署本身不复杂官方镜像加一个 Postgres 就能跑起来。我见过不少人在这一步为了省事不配置 DATABASE_URL让 LiteLLM 落到默认的 SQLite 上。SQLite 在本地验证时能用但一旦跑多个副本或者日志积累到一定量就会出现写锁、性能抖动而且配置变更在某些版本里会随着容器重建丢失。我直接从第一天就上了独立 Postgres一个实例足够。docker run -d \ -p 4000:4000 \ -e LITELLM_MASTER_KEYsk-master-xxxx \ -e DATABASE_URLpostgres://user:passwordhost:5432/litellm \ ghcr.io/berriai/litellm:main-latest启动后管理台在 4000 端口master key 用来生成管理员 token。这里有个细节坑LITELLM_MASTER_KEY 必须带 sk- 前缀官方启动时有校验写错了容器会直接退出。另外如果计划后面做多副本Postgres 要设置好连接池上限Redis 也要提前备好这些在本地“能跑”的阶段通常感受不到问题。2. 模型接入与切换从单一模型到多模型路由的落地细节模型管理是所有后续工作的基础。LiteLLM 的模型接入方式非常统一都是往 config.yaml 的 model_list 里加条目。每个条目包含两部分给客户端用的 model_name也就是逻辑名以及给网关自己用的 litellm_params里面说明实际要调用的模型标识、API Key、API Base 地址等。2.1 用一份 config.yaml 把三种后端模型接到同一个入口下面是我在内部环境用的一份精简配置覆盖了一种云端闭源模型、一种云端开源模型和一种本地私有大模型model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY - model_name: local-qwen litellm_params: model: openai/qwen2.5:7b-instruct api_base: http://lmstudio:1234/v1 api_key: sk-local注意一个容易搞混的点model 字段里的 openai/、anthropic/ 前缀指的是 LiteLLM 的 provider 标识不是模型名的一部分。比如 openai/qwen2.5:7b-instruct意思是“用 OpenAI 兼容协议去调用本地地址上的 Qwen 模型”这里 provider 前缀是 openai模型名字段写的是 qwen2.5:7b-instruct。很多人在接本地模型时在这里卡住以为 local-qwen 必须写成 local/qwen其实只要你的本地服务是 OpenAI 兼容格式就直接用 openai/ 前缀接上 api_base。逻辑名设计上也有讲究。我建议对外暴露的逻辑名不要带厂商名比如不要叫 openai-gpt4o直接叫 gpt-4o 就行。这样以后 backend 从 OpenAI 换到 Azure OpenAI或其他任何兼容模型逻辑名不用变客户端配置零改动。反而是那种把供应商写进逻辑名的命名方式会让后续切换模型变成一次客户端发布。2.2 路由、fallback 和重试怎么缓解“模型繁忙请重试”模型接入不只是配置一个可调用地址更核心的是要应付模型繁忙和临时故障。把多个模型挂到同一个逻辑名后面再配上 fallback 和重试是让线上服务稳定下来的关键一步。router_settings: routing_strategy: usage-based-routing allowed_fails: 3 cooldown_time: 30 retry_policy: Timeout: 2 RateLimitError: 3 BadRequestError: 0allowed_fails 控制某个模型连续失败多少次后进入冷却cooldown_time 是冷却的秒数。这段时间内网关不会再把新请求分配给该模型直到冷却结束重新试探。retry_policy 针对不同错误类型设置重试次数我最强调的一点是BadRequestError 绝对不要重试。请求参数写错了重试一万次结果都一样只会白白浪费预算和放大上游负载。而 RateLimitError 这类限流错误值得多试几次因为上游可能只是瞬时过载稍等一会儿就有位置。“模型繁忙请重试”这个用户侧提示本质就是网关已经把请求转发给上游、上游返回限流/过载类错误之后的表现。如果希望用户真正“等一下就能成功”那么背后必须有 fallback 和冷却机制在兜底否则用户点了重试也大概率还是失败。2.3 客户端切换模型后对话不停跳闪一次完整的排查链路有段时间我们内部用 cc 这类支持多模型的工具切换模型后原对话窗口里的内容会不停跳闪看起来像前端在反复重绘。排查链路如下这条链路后来也被我写成了团队排查手册。第一步先确认网关有没有收到异常请求。查看 LiteLLM 日志如果发现客户端在切换模型后频繁请求 /v1/models这通常是前端在重新拉取模型列表。跳闪的直接原因往往就是模型列表接口返回异常导致前端拿不到可用模型界面反复回到默认状态重绘。第二步检查 model_list 是否完整注册。切换到新模型时如果客户端传的 model_name 没有出现在 model_list 里LiteLLM 会返回 model_not_found。有些客户端对这类错误处理得很不优雅不是直接报错而是自动切回上一个模型再触发一轮界面刷新看起来就是不停跳闪。第三步排查 fallback 带来的副作用。我们在一个逻辑名后面挂了多个真实模型但流量路由策略和 fallback 顺序配置不合理导致同一请求被转发到多个后端前端收到了重复的 assistant 内容块界面出现重复追加的闪烁效果。解决方法是调整 fallback 顺序保证同一会话内的请求尽量落在同一个模型上。整个排查下来跳闪基本都不是客户端本身坏了而是网关返回的模型列表、错误类型和直连接口不一致把前端原本能正常工作的状态机搞乱了。统一 base_url 到网关之后这种兼容性责任就从客户端转移到了网关卡上配置时反而要更仔细。3. 用户维度的管理体系密钥、身份标识与权限隔离很多团队把 LiteLLM 当成一个“转发代理”来用所有人共用一把 Key这就等于放弃了它最好用的用户能力。LiteLLM 的用户管理核心是虚拟密钥Virtual Keys机制。它不仅是认证凭证更是身份标识、预算载体和审计单元。3.1 虚拟密钥不是普通 API Key而是“身份 配额 审计”的载体在管理台里可以手工生成密钥也可以调用 /key/generate 接口批量创建。每把虚拟密钥都可以绑定 user、team、organization还可以设置 max_budget、expires 等参数。我用一个非常简单的原则来管理谁调用谁就拥有独立密钥。即使是对内部系统也不允许在配置里写死一把全队共享的 key。一把虚拟密钥大致对应这样一条记录curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-master-xxxx \ -H Content-Type: application/json \ -d { user_id: zhang-san, team_id: data-platform, max_budget: 500, budget_duration: 30d, metadata: {source: internal-tool} }生成之后这把 key 的每一次调用都会被记录到 spend log关联到 zhang-san 这个用户。月底做成本分摊时不再需要猜是谁用了模型直接按 user_id 聚合即可。密钥还可以设置过期时间适合临时任务和外部协作到时间自动失效不需要手动回收密钥列表。3.2 把团队用户中心与 LiteLLM 的 user 体系映射起来LiteLLM 本身不强制你注册用户账号它更希望你把自己系统的用户标识传进来。常规做法是在请求里带上 user 字段同时通过 metadata 补充更完整的上下文。我这里列一份实际用的映射规则外部系统字段LiteLLM 字段说明用户唯一IDuser_id用于审计和用量归因部门/项目组team_id用于预算分摊和权限隔离联系人邮箱metadata.email告警通知用成本中心编码metadata.cost_center财务核算用调用来源应用metadata.app_name排障时区分流量来源这里有个经验之谈如果应用程序在调用时没有传入 user 字段LiteLLM 会把请求归到一个匿名用户上限流、预算、审计全部失效。比如用 Dify 低代码平台接进来的工作流人工介入等待用户补充内容时如果 HTTP 节点里只写了公共网关地址没有带用户专属密钥那么这次“用户补充内容”的模型调用就彻底没了身份后面想按用户做成本归因根本做不到。正确做法是让工作流拿到当前操作人的用户ID通过密钥或 user 参数透传给网关。3.3 按最小权限分配模型和预算虚拟密钥解决了“谁在用”接下来要解决“这个人能用什么、能用多少”。我一般按三层来做第一层是模型可见性。团队A只需要文本模型就不要把图像模型挂到团队A的 key 上。在 team 配置里可以限定这个团队只能访问 model_list 中的部分模型。这既是为了预算也是安全考虑避免业务同学因为好奇去调不熟悉的昂贵模型。第二层是预算上限。每个 key 设置独立预算每个 team 设置团队级总预算一旦触发LiteLLM 会直接返回 budget exhausted 类错误不会让超支静默发生。第三层是临时权限。CI/CD、临时测试、外部供应商集成都用短时效密钥到期自动失效。这个习惯有效避免了“半年前的测试 key 一直活着”的风险。另外现在模型来源越来越多元化建议对模型来源做白名单式管理不要允许任意第三方模型无审核接入网关至少要对模型来源做一次审核再挂到线上环境这个管理动作的成本很低收益是长期的。4. 用量追踪与消费限额从“能跑”到“成本可控”模型接入和用户体系搭好后真正的重心其实是成本。LLM 网关一旦开始被多个团队使用用量数据就是所有预算讨论的依据。LiteLLM 默认会把每次调用的 token 数、费用、模型、用户、响应时长等写入用量日志这一步帮我省掉了很大的工作量。4.1 用量日志里最该盯的字段我实际每天会看的字段大致是这些SELECT request_id, api_key, user, model, spend AS cost_usd, prompt_tokens, completion_tokens, total_tokens, response_time_s, created_at FROM spend_logs ORDER BY created_at DESC LIMIT 200;cost_usd 是 LiteLLM 根据上游单价预估的费用对内部成本归因完全够用total_tokens 用于判断是不是有异常大的请求response_time_s 用于发现慢模型。user 字段如果是空的那行数据基本等于废了这也是前面强调身份透传的原因。我的习惯是每天拉一次这个视图关注三个东西有没有单次调用费用畸高、有没有某个用户调用频次异常、有没有特定模型响应时间连续走高。4.2 预算限额按密钥、按用户、按团队的三级控制只记录不用来限制等于只记账不管账。LiteLLM 的预算控制有三层我在实际中是把三层同时启用的层面配置入口示例密钥级/key/generatemax_budget: 50, budget_duration: 30d用户级用户配置max_budget: 200, budget_duration: 30d团队级team 配置max_budget: 1000, budget_duration: 30d取最小生效也就是说一个用户所属团队预算剩得不多即使他个人 key 还有额度也会被团队层卡住。另外还有 RPM每分钟请求数和 TPM每分钟 token 数限制这两个主要为了防突发风暴而不是控成本。如果只是控成本团队预算和用户预算已经足够RPM/TPM 更多是保护下游模型不被单个用户打爆。4.3 从用量数据到消费预测滑动窗口与回归模型的实践用量日志积累一段时间后就可以做消费预测了。这里提一下热词里常出现的“用户消费预测”我们先用 SQL 把用量按小时聚合成时间序列然后对原始序列做滑动窗口平滑比如取近 6 小时滑动平均目的是削掉脉冲式的突发流量接着构造特征包括星期几、是不是工作时间、近 24 小时开销、近 7 天同小时均值等最后喂给 lightgbm 回归模型预测未来几天的消耗金额。SELECT date_trunc(hour, created_at) AS hour, SUM(spend) AS cost, SUM(total_tokens) AS tokens, COUNT(*) AS request_count, COUNT(DISTINCT user) AS active_users FROM spend_logs WHERE created_at NOW() - INTERVAL 30 days GROUP BY 1 ORDER BY 1;回归模型的预测精度不用强求很高我个人的目标是预测出“量级”和“趋势拐点”比如下周成本会从 500 涨到 800或者某条模型线的消耗占比在持续上升。这个信号比绝对金额更有价值。滑动窗口之所以必要是因为大模型调用天然有尖峰比如定时任务半夜批量跑一批如果不过滤模型很容易被这几小时的数据带偏。5. 服务稳定性的硬仗模型繁忙、切换跳闪与生产故障排查网关只要上线稳定性问题就会浮出水面。测试环境里一切顺畅不代表生产环境扛得住。下面这几类问题是我在过去一段时间里真正踩过、并且花时间排查清楚的。5.1 “模型繁忙请重试”背后的重试与降级策略“模型繁忙”看起来是模型侧的问题但在网关架构下这通常是你自己的重试策略没设计好。上游返回限流错误时LiteLLM 在 retry_policy 的框架下做有限次重试合理的冷却时间会避免在同一个上游实例上反复打。我之前遇到一个情况网关配置了重试客户端也配了重试两边叠加一个请求在最坏情况下会变成 6 个请求同时打到上游把本来就繁忙的模型直接打挂。我的处理方式是把重试责任明确划给网关。客户端只设置超时和一层非常保守的重试真正的 fallback 交给 LiteLLM 的 router 完成。比如retry_policy: RateLimitError: 3 Timeout: 2 InternalServerError: 1这背后的逻辑是让网关负责“对上游容错”让客户端负责“对用户负责”。用户看到模型繁忙时系统实际上已经尝试过其他副本模型如果全部失败再给用户一个明确的重试按钮。否则用户一重试等于把一批请求全部重新打一遍没有任何冷却可言反而更容易触发更长时间的限流。5.2 部署在 K8s 里时最容易出问题的四个位置开发机容器跑得好好的部署到 K8s 才暴露问题。我们遇到的四类问题很有代表性第一滚动更新断流。LiteLLM 是多副本部署pod 滚动更新时旧 pod 还没处理完长连接请求就被杀掉了客户端那边表现为连接中断。解决办法是设置 preStop 钩子延迟一定时间再终止同时给 LiteLLM 配 stranded 请求的清理时间具体值取决于你的平均响应时长我这边设的是 shutdown_timeout 30 秒。第二SQLite 换 Postgres 之后连接数没过关。多副本使用同一个 Postgres如果连接池配得太大数据库先扛不住。这里要点是数据库连接池上限要做小读多写少场景保持 20 到 50 就好而不是每副本默认几百。第三Redis 未启用导致多副本限流不准。LiteLLM 的 RPM/TPM 限流如果只落在单副本内存里多副本下就会绕开限制。生产环境只要有多副本就必须把 Redis 接上。第四liveness 和 readiness 探针的路径配置不当导致 k8s 误杀容器。LiteLLM 提供了健康检查端点readiness 可以连数据库做验证liveness 只查进程本身即可两者不要依赖同一个探针路径否则数据库抖动时所有副本都会被连环重启。5.3 一次真实故障所有请求突然被导向高成本模型有一次线上模型调用费用突然翻倍链路排查过程比较典型。我们某个逻辑名下面配置了三个模型一个低成本模型作为主路由一个中等成本模型作为备份一个高成本模型作为最后的 fallback。正常情况下流量应该主要落在低成本模型上但监控显示高成本模型的调用量占了 80%。先看用量日志确认不是用户行为变化而是路由分配异常。再看模型列表配置发现低成本模型的 allowed_fails 被设得过高加上冷却时间设得太短导致它一旦出现几次超时就迅速进入冷却并被跳过流量直接落到高成本模型。与此同时低成本模型本身没有做重试保护上游只是瞬时抖动就被判定为失败。修复分三步把 allowed_fails 从 5 降到 2把 cooldown_time 从 10 秒拉到 60 秒同时给低成本模型增加一次重试机会而不是直接跳到高成本模型。整个过程下来费用恢复了正常。事后总结出一条规则fallback 不是廉价通道它是有昂贵代价的逃逸路径路由配置时一定要给每个模型一个“耐受区间”否则一次上游抖动就会带来真金白银的损失。6. 除了成本用量管理还能支撑容量规划与运营决策用量数据不只是月底算账用的把它用好了很多决策都可以从拍脑袋变成查数据。这一部分算是我个人在运营侧的经验沉淀不一定每次都需要做得很重但把思路跑通之后收益非常明显。6.1 用量数据驱动的成本归因我每月会拉一份类似下面的表作为和团队对成本讨论的基础维度本月消耗占比环比变化用户A820 元41%15%团队B460 元23%-5%模型 gpt-4o850 元42%60%模型 local-qwen200 元10%20%这张表的价值在于把“费用增长”翻译成“哪个用户、哪个团队、哪个模型增长”。我自己每个月只做三张图按用户、按团队、按模型。只要这三张图趋势稳定就不用每天盯着原始日志。6.2 扩容与调优的信号什么时候该加配额用量数据积累三个月后我开始能从里面读出扩容信号。比较典型的几个信号包括某个模型的错误率连续一周高于 5%说明配额不够或上游不稳定峰值 RPM 已经连续打满说明用户侧在等限流释放某个模型线的预算达成率在每月的 20 号就接近 100%那下个月就可以预见到会超支。收到这些信号后可做的动作并不是单纯加钱。优先级我一般是先检查是不是路由策略不优导致流量没有分布到更便宜的模型再看有没有低频用户占用大量配额可以通过用户级限制把它收敛最后才考虑增加该模型的预算或切换到更高规格的产品。用量数据帮助我把扩容变成一个可回放的过程而不是“今年 cost 涨了很多所以要多申请预算”。6.3 用量告警的一个实用小技巧不要等到超预算才报警最后分享一个我在实际使用中觉得最有用的告警策略除了预算超支告警之外给“消耗速度”单独设一套阈值。比如团队预算周期是 30 天常规按天平均理想消耗应该是每日 1/30。我在 cron 里跑一条统计每天比较当前消耗和已过天数/周期天数的百分比如果超过 1.2 倍就提前发消息到项目群。这条简单规则帮我抓到了好几次因为测试脚本死循环导致 token 消耗飙升的问题。比起等预算被触发提前两天看到消耗速度异常处理起来从容得多。用量管理做到这一步才算是真正从“事后算账”变成了“事中控制”。
返回列表