尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

LiteLLM统一网关实战:多模型接入与API管理的完整方案

LiteLLM统一网关实战:多模型接入与API管理的完整方案 先说我在项目里遇到的一个真实问题——当模型调用从一个封装类够用变成多个供应商、多个服务、多人共用Key之后我开始认真评估litellm这个开源项目。最初团队接入模型只是在代码里封装了一个类把API Key一存Prompt一拼上层直接调就行。可当模型供应商从一个变成三个从只调一次变成日志、摘要、Embedding、Agent工具都有需求问题马上就来了每个供应商的SDK写法不一样鉴权方式不一样超时重试逻辑也得各写一套更头疼的是Key散落在每个人的环境变量里月底想统计一下模型调用花了多少钱根本对不上账。我当时在选型时试过好几个方案最后常用的是LiteLLM也就是大家平时说的litellm。它做的事情用一个不太准确但很好懂的说法来讲就是给所有大模型API装了一个“万能转换头”对外只暴露一个OpenAI兼容的接口后面接哪个供应商由配置决定。这篇文章从我实际项目里从零到落地的过程写起内容包括两种部署方式、config.yaml的完整拆解、虚拟密钥与预算管理、生产部署的关键动作以及跑了大半年之后我认为最有价值的几个避坑经验。适合刚接触litellm、准备把多模型接入统一管理的团队参考如果你只是想让本地脚本少写点胶水代码代码内嵌部分也足够用。1. 多个模型供应商接入之后我需要一个统一的“网关”1.1 每个SDK都有各自写法切换供应商等于重构接口层先说说“没有网关”的时候是什么感受。假设你今天在代码里接入供应商A官方提供了Python SDK你按它的方式构造请求、处理流式返回、解析usage明天要接入供应商BSDK又换了套风格参数名不同、返回结构不同连错误码都不是一套。如果项目里十几个服务都各自写过这些逻辑每次切换供应商就不是“改个Key”能解决的而是一轮牵一发动全身的重构。我记得有一段时间我们这边一个内部工具要从供应商A切到供应商B光是把所有调用处的异常处理和重试逻辑统一掉就花了一个完整迭代。当时我就想如果所有模型调用都走同一个内部接口上层只需要改一个“模型名”参数事情会简单很多。litellm解决的就是这个问题它在代码层和网关层都提供了统一调用方式代理模式下对外暴露OpenAI兼容接口对已有OpenAI SDK的代码几乎是无痛的。1.2 Key散落、成本算不清才是团队接入大模型真正麻烦的源头如果只接一个供应商、只有一个人用Key管理确实不是事。可一旦变成多人、多服务、多环境情况就完全不一样了。每个人的环境变量里都有各自的Key文档里贴出来的可能已经过期有些服务还在用已经泄露过的Key。有一天模型账单明显异常你根本不知道是哪个服务、哪个人的Key在大额消费也没有地方能按维度拉明细。这种时候网关的价值比“统一接口”更大它把上游供应商Key全部收回到服务端对外只发虚拟Key每个虚拟Key可以绑定模型范围、预算上限、请求速率所有调用都会留日志月底按维度统计花费也变成了查表。litellm的代理模式刚好把这些能力都包含了这也是我在团队里推行它而不是只写一个Python封装类的根本原因。2. 快速跑起来代理网关与代码内嵌两种用法2.1 安装与本地启动五分钟先看见效果litellm本身是个Python包安装很直接pip install litellm[proxy]装完之后随便准备一个最简单的config.yaml让代理先能启动model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY然后在命令行启动litellm --config config.yaml --port 4000启动成功后本地会有一个http://localhost:4000的服务/v1/chat/completions这个路径与OpenAI的接口格式一致。这一步先不展开所有细节目的只是确认环境没问题。我第一次启动时其实遇到过一个小问题litellm[proxy]的依赖比较多如果Python版本偏老或者装到了系统级site-packages里可能会装一半失败。建议直接用虚拟环境安装过程会顺畅很多。2.2 代理网关模式业务代码只需要改一个base_url代理模式最适合团队多个服务共用入口的场景。因为不管你的服务是Python、Java还是Node写的最终都是发HTTP请求。原来代码里如果用的是OpenAI SDK切到litellm代理基本就是把base_url指向http://localhost:4000Key换成虚拟Key其他逻辑不用动。举个例子from openai import OpenAI client OpenAI( base_urlhttp://localhost:4000, api_keysk-my-virtual-key ) resp client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 你好}] ) print(resp.choices[0].message.content)如果原来用的就是这类写法迁移成本很低。这也是我把litellm放进团队基础设施的根本原因不管语言栈多乱只要认准一个OpenAI兼容端点就都有了统一的接入方式。另外代理模式还天然支持流式响应、Embedding、模型列表查询等常见能力基本可以覆盖大多数业务场景。2.3 代码内嵌模式单机脚本和快速验证的轻量解法如果只是个人脚本、离线任务不想要一个常驻代理进程也可以直接在代码里用litellm的函数from litellm import completion resp completion( modelopenai/gpt-4o, messages[{role: user, content: 你好}], api_keysk-... ) print(resp[choices][0][message][content])这里model参数显式写成openai/gpt-4o是为了告诉litellm走OpenAI的供应商格式。它还支持Router类把常用的模型列表配置在内存里由代码内部做负载均衡和重试。两种模式我都在用代理模式给团队所有服务用内嵌模式给快速验证脚本用。如果是小团队初期先跑内嵌模式也能解决“一个类调多家模型”的问题等规模大到需要预算治理再平滑切到代理。3. 看懂config.yaml从model_list到路由与fallback3.1 一个最小但完整的配置长什么样litellm代理的核心配置都在config.yaml里。一个基础配置至少包含model_list它声明了这个网关能“代理”哪些模型。每个条目里有model_name和litellm_params前者是暴露给使用方的名字后者是真正上游调用的参数。我常用的最小配置是这样model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY关键点在于model_name是可以自己定的。比如你不想让业务方知道上游具体是哪家完全可以把两个模型都暴露成gpt-4o让上层无感切换。如果公司内部有自部署的模型配置也不复杂- model_name: internal-llama litellm_params: model: vllm/meta-llama-3.1-8b-instruct api_base: http://192.168.1.20:8000 api_key: dummymodel里的前缀vllm表示走vLLM的OpenAI兼容服务。自建模型没有真实Key时写一个占位符也能跑。这类模型属于团队的内部资源配置到网关里之后业务方调用它的方式和其他供应商完全一致。这是我很喜欢的一个特性底层基础设施可以五花八门但暴露给使用方的接口永远是一样的。3.2 环境变量与密钥的安全写法在config.yaml里最忌讳的事情就是明文写Key。一个配置文件经常要提交到Git仓库、同步给其他同事Key一旦进去以后改起来就是一轮“污染治理”。litellm支持os.environ/这种写法运行时读取环境变量litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY启动服务之前先确保环境变量已经设置好。生产环境我推荐用专门的密钥管理服务把Key注入到进程环境。另外代理本身也有一个master_key概念类似管理员的钥匙。默认配置里如果没改可能是一个众所周知的默认值这类默认凭据在公司内网环境尤其危险——拿到它的人可以生成任意虚拟Key、查看全部调用日志。我的建议是第一次部署就改掉并且不要把master key写在config文件里而是通过环境变量传入。3.3 负载均衡与fallback不把单点风险留在链路上当同一个model_name下挂多个上游供应商litellm会自动按路由策略做负载均衡。最典型的用法是让同一种模型能力由不同供应商同时承担一旦某一家出问题请求自动切到另一家model_list: - model_name: primary-chat litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: primary-chat litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY这其实已经不只是“统一接入”而是在做高可用设计。业务方始终只认primary-chat这个名字至于它背后是哪个供应商、哪天切到哪家都不需要感知。除了负载均衡litellm也支持显式的fallback配置当主模型连续失败时把请求降级到备用模型。这里要注意把不同供应商的模型放在同一个model_name下面意味着它们的能力要“差不多”否则上层调度会出现一些预期外的行为。这一点我会在后文的避坑清单里详细展开。4. 虚拟密钥、预算与审计把多人共享的API管起来4.1 虚拟密钥的生成与使用代理启动后先用master key调用接口生成虚拟Keycurl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-my-master-key \ -H Content-Type: application/json \ -d { models: [primary-chat], max_budget: 2.0, budget_duration: 24h, metadata: {team: test-group} }返回结果里会带一个key字段那就是虚拟Key。它长得也是sk-开头但和上游供应商的真实Key完全不同只在litellm代理内部有效。业务代码拿它当普通的OpenAI Key用即可。虚拟Key的价值在于它把“谁用了多少”和“某个具体的人”绑定了起来。谁领了哪个Key、用在哪个服务都可以在生成时通过metadata标记。即使没有正式的成本中心团队内部也能快速看懂每个Key的大概开销。另一个好处是撤销独立发现某个Key异常你只需要删除它不用动别的Key也不会干扰到其他成员的服务。4.2 预算、限流与配额的组合设置litellm的限流维度可以拆开来看一种是按Key控制预算一种是按Key控制请求速率和Token速率。我实际组合下来比较顺手的一套规则是控制目标常用字段典型值说明按预算控制max_budget5.0单位是美元也可以按人民币换算后设预算周期budget_duration7d7d是7天滚动窗口日常够用每分钟请求数rpm60防止个别服务批量刷接口每分钟Token数tpm120000防止一个Key把上游配额打爆这里的数字并不是什么标准答案主要看你们团队的调用能力和成本预期。比如测试环境的Key可以给比较紧的预算生产环境的预留Key则放宽一些。配置好之后一旦某个Key达到预算上限litellm会直接返回429而不是继续把请求转发到上游。这样做的好处是即使有人误操作写了个死循环也不会产生失控账单。4.3 用量统计如何支撑成本分摊与异常排查用好虚拟Key之后用量统计数据才真正有参考价值。litellm会把每次请求的模型、Key、Token数、预估成本、耗时写进后端存储。常见的查询入口curl -X GET http://localhost:4000/spend/logs \ -H Authorization: Bearer sk-my-master-key也可以按Key维度看统计/spend/keys。这些数据在团队内部可以当作成本分摊依据每个服务、每个Key用了多少一目了然。我自己会在每周例行检查里跑一下近7天的spend统计主要看有没有异常增长某天突然流量翻倍要么是业务放量要么是某个Key可能被滥用了。配合日志表里每个请求的时间、模型、返回状态基本能定位到具体原因。这个时候你会更理解为什么要先做好Key的划分和metadata标注没有维度就只有总数排查成本会高很多。5. 从本地Demo到稳定服务生产部署的几个关键动作5.1 换掉SQLite数据持久化交给Postgreslitellm本地默认用SQLite保存Key、预算、调用日志等数据这在小规模验证时没有任何问题。但是一旦进入生产环境、开了多个worker进程SQLite很容易出现“database is locked”的报错——多个进程并发写同一个SQLite文件一会儿就被锁住了日志和预算数据也会丢得不痛快。正确的做法是给它配一个Postgres。设置环境变量即可export DATABASE_URLpostgresql://user:password127.0.0.1:5432/litellm建议在项目里单独为litellm建一个库表结构由它自己管理。换库的时机其实不用太晚只要你计划把代理正式提供给多个服务使用一开始就上Postgres最省心。这个迁移我后来回想真的很庆幸没有在SQLite上积累太多数据否则迁移和补数据都是额外的工作。5.2 多进程部署与超时、重试参数本地跑单个进程没问题生产环境要撑住并发就需要多worker。litellm可以指定--num_workers或者把它挂在gunicorn后面litellm --config config.yaml --port 4000 --num_workers 4提起多worker是为了并发能力但多worker也意味着多个进程共享一套配置和数据库所以“配置统一、数据库统一”这两件事必须提前想清楚。同时有几个体验相关的参数值得在litellm_settings里统一设置litellm_settings: request_timeout: 600 num_retries: 3request_timeout设成600秒是考虑到大模型生成长文本很慢短超时会造成大量无谓重试num_retries控制失败重试次数。要注意重试不是越多越好尤其是下游供应商已经出现限流时盲目重试只会加重拥堵。我一般会结合上游返回的429/5xx状态码去观察再决定调大还是调小。5.3 监控指标与告警接入litellm代理暴露了一个/metrics端点格式兼容Prometheus。如果你所在的环境已经有一套监控体系可以直接把这个端点接进去。值得关心的指标包括请求总数、成功率、延迟、Token消耗、按供应商和模型拆分的数据等。我自己在落地时最看重两个指标一个是上游供应商返回429/5xx的比例另一个是请求延迟的P95。前者说明当前路由或配额是否合理后者能反映某家供应商是否在变慢。把这些指标配上告警之后就不用每天人肉盯日志了。另外litellm也有回调机制可以把请求日志推送到外部日志系统或可观测平台方便后续做更复杂的审计和链路追踪。这些不是必需项但在团队规模化使用后非常有用。6. 实测半年后我整理出的避坑清单6.1 超时设置没调长文本请求疯狂重试最开始我部署代理时没有专门配置request_timeout结果日志里出现大量超时重试。排查时发现很多请求本身没问题只是模型生成速度慢超过了默认超时时间客户端已经断了但上游还在慢慢输出。长文本、长代码生成场景尤其明显。解决办法就是在配置里统一调大超时同时让业务侧使用流式响应。对流式接口来说服务端持续有数据返回“超时”的判断标准本身也会不同。这个坑虽然不复杂但排查起来很容易被忽略因为报错看起来是“上游没响应”实际是“客户端等不及了”。6.2 不要把上下文窗口差别太大的模型放进同一个分组把多个供应商的模型放在同一个model_name下确实能实现负载均衡和fallback但有一个前提它们的上下文窗口和输出能力得基本对等。比如A模型支持200K上下文B模型只支持32K把两者放在同一个分组后业务侧如果发了一个60K tokens的请求路由到B模型身上就会直接失败。我在一个内部Agent服务里踩过这个坑平时请求不大没感觉一旦处理长文档就偶发报错查了很久才发现是分组里混入了上下文窗口偏小的模型。后来我的做法是按上下文窗口把模型分层或者干脆在配置里给不同能力档位建不同model_name上层按需选模型。这样虽然增加了一点配置量但至少不会因为模型能力差异引入隐性故障。6.3 流式请求不回传usage预算统计会失真litellm的预算和成本统计依赖每次请求的usage信息也就是prompt tokens和completion tokens。大多数供应商在普通响应里会返回usage但部分模型在流式响应下如果没有额外选项就不会有完整的usage数据。这种情况下litellm记录到的Token数可能只有一部分预算控制也会跟着失真。我的处理方式是分两层重要的成本统计尽量不让它依赖流式响应如果确实需要在客户端显式要求流式响应中携带usage字段或者在上游不支持时让litellm用自身模型配置去估算Token。准确度虽然不如上游返回值但至少比“统计不到”好得多。另外自定义价格也很重要litellm内置的价格表覆盖并不完整新增模型如果没配置价格spend会出现偏差甚至为0建议在模型配置里把单价字段写清楚。6.4 改配置前先检查环境变量litellm的多层配置设计里环境变量有时候会覆盖config文件里的值。我踩过这样一次在config.yaml里更新了一个模型的上游Key重启之后却发现实际请求还在用旧Key。后来检查发现环境变量里设着一个旧的Key优先级更高导致我误以为“配置没生效”。这不是bug是配置层级设计如此。所以排查类似问题的时候第一件事是看当前进程的环境变量里有没有设置相关的Key、模型参数、默认供应商。把env和config放到一起对比问题通常很快就能定位。也因为这个原因我现在在部署脚本里会显式清理掉不需要的旧环境变量避免“隐形配置”影响新环境。6.5 虚拟Key泄露后的应急处理顺序虚拟Key不像上游Key那样牵涉供应商账户但它同样能消耗预算、读取日志。如果发现某个虚拟Key异常比如日志里出现大量来自陌生IP的调用我一般按这个顺序处理先在管理端删掉这个Key让它在代理层面立即失效再查它最近的spend logs看主要消耗在哪些模型上估算损失最后检查是不是master key也一并泄露了如果是立刻换掉master key并重新为所有正常业务方生成虚拟Key。日常预防上我还会给不同类型的Key分开打metadata标签并给敏感操作加上审计。反正虚拟Key的生成成本很低真出了问题直接重新分发比排查半天“为什么有人能用这个Key”要高效得多。最后说一点我个人的体会。我在项目里推行litellm之前最担心的不是“又多一个要维护的组件”而是“引入一个开源网关会不会把链路搞得更复杂”。实际用下来它确实会占一点资源、多一个组件要运维但它换来的东西非常明确上层接口稳定、Key可控、成本可见、供应商可替换。如果你正处在“一个封装类已经不够用、团队多人共用模型Key”的阶段我建议先从代理模式开始把最小的config跑通再逐步叠加预算、日志、监控不要一上来就把所有功能配齐。一个能跑通的最小网关远比一个还没跑起来的大而全配置更有价值。
返回列表