资讯动态

用LiteLLM搭建AI网关:统一多模型API与成本控制的实战指南

发布时间:2026/10/14 9:19:55 来源:尧图企业网站定制
litellm这个词第一次看到的时候我以为又是一个包装精致的OpenAI封装库。真正让我决定把它留在生产环境里的是我在一周内第三次为“切换模型渠道”这件事加班到深夜之后。场景很简单项目里接了多家大模型API有国内有国外有的按token计费有的按并发包月Key散在各处测试环境用一套线上又有一套。每次要测一个新模型都得重新写一版调用逻辑每次账单出来都得人工去对是哪条业务线烧的钱。我意识到缺的不是又一个SDK而是一个能统一入口、统一鉴权、统一控制的网关层。litellm就是干这个的。如果你手头也在维护两个以上的模型渠道或者你想在团队里把“谁在用什么模型、花了多少钱”这件事管起来这篇文章应该能帮你省掉不少试错时间。我会从选型逻辑、部署配置、核心API的用法讲到实际踩过的坑尽量按照我自己跑通一个完整链路的顺序来写。1. 为什么我最后选定litellm当AI网关1.1 网关到底解决了什么问题先说痛点。假设你的业务里现在接了三个模型来源一个国内的厂商、一个国外的头部厂商、还有一个开源自托管的服务。三者API风格完全不一样有的兼容OpenAI格式有的要走自己的签名算法有的只提供流式接口。你的业务代码如果直接调用这三家那就意味着你要写三套适配层、三套鉴权逻辑、三套错误重试。更麻烦的是当你想做模型灰度切换时业务代码里到处都是写死的模型名改一次要动好几个服务。网关层的做法是业务方只面对一个统一入口这个入口长得跟OpenAI的接口一模一样你传一个model参数网关自己决定请求转发给谁。litellm就是这样一个代理服务它把几百家模型提供商的接口差异抹平对上游业务暴露一个标准的兼容层。另一个容易被忽略的价值是密钥收敛。公司的API Key如果散落在各个业务代码和环境变量里泄露面会越来越大。统一走网关之后厂商侧的Key只存在网关的环境变量或配置中心里业务侧拿到的都是网关签发的临时Key泄露一个可以单独吊销不影响其他业务。1.2 为什么不是直接用开源SDK而是部署服务在选定litellm之前我其实先试用过它提供的Python SDK也就是在业务代码里直接调用litellm.completion。这个方式对单机脚本和原型验证非常友好几行代码就能从OpenAI切到别的provider。但它解决不了我前面说的密钥管控和按业务线计量问题因为Key还是在业务进程里。litellm的服务模式也就是LiteLLM Proxy Server给了我一个独立的网关进程业务代码只跟这个进程对话。这个进程负责跟上游厂商通信、管理虚拟Key、记录每一次调用的token数和花费、执行速率限制。这样网关本身的部署、扩容、监控都跟业务服务解耦。如果你的团队有多条业务线共用模型资源这种集中式管控基本是刚需。我最终选择它的理由可以概括成几条一接口兼容OpenAI格式业务代码几乎不用改二同一个模型名可以配置多个上游渠道天然支持fallback三虚拟Key的预算和速率限制在管理层面上够用四部署形态灵活本地一个进程就能跑也可以挂到Docker里配合监控。当然它也不是没有缺点后面我会单独讲。1.3 部署方式选型本地进程与容器化litellm的部署方式有两个主流选择直接用pip安装后启动一个Python进程或者用Docker镜像跑容器。我的建议是如果你只是在本机验证功能pip就够了一条命令的事如果你要放到测试环境甚至生产环境一定要走容器。原因很简单这个服务本质上是Python进程依赖一堆Python包直接装在你自己的开发机或者服务器上很容易出现依赖冲突。我们遇到过因为本机Python版本和litellm依赖的pydantic版本不对导致服务起不来的情况。容器化之后这些乱七八糟的依赖关系都被隔离了日志和配置也更好管理。我当时用的是官方Docker镜像挂载一个config.yaml和一个存放虚拟Key的数据库文件一条docker run命令就完成了网关搭建。数据库默认是本地SQLite适合小规模验证如果你有好几个网关实例需要共享Key数据可以切换到PostgreSQL。这点往下会细说。2. 搭建网关之前必须想清楚的几个配置2.1 config.yaml的基本结构litellm的网关配置核心是一个YAML文件这个文件在启动时决定了两件事你能用哪些模型以及访问它们的密钥怎么拿。我见过很多人上来就填一堆模型结果启动时报401浪费很多时间。问题的根源是没搞清楚这个文件的字段含义。一个最小的config.yaml长这样model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY这里面最关键的字段是litellm_params.model它决定请求要转发给哪个provider。这个字段的格式是“provider/具体模型名”比如openai/gpt-4o、anthropic/claude-3-5-sonnet、azure/xxx。路由层看到这个前缀就知道该走哪家的SDK。model_name是暴露给业务方的名字业务请求里传的model参数必须跟这里的model_name完全一致。你可以自己起名比如统一叫prod-main-llm但要注意如果这个名字跟litellm_params.model不一样日志里排查问题时很容易把两个名字搞混。建议从一开始就约定清楚。2.2 环境变量与密钥管理api_key: os.environ/OPENAI_API_KEY这种写法非常值得推荐。它表示密钥从环境变量读取而不是直接写进yaml。有人图省事直接把Key明文写进配置文件这在本地实验时可以接受一旦配置文件被提交到git仓库就是一次事故。我的习惯是config.yaml只写环境变量的引用实际密钥放在网关启动时的环境变量里。如果你用的是Docker方式可以通过-e OPENAI_API_KEYxxx传进去或者更规范一点用--env-file指定一个环境变量文件。注意不是所有provider的密钥都叫api_key比如Azure OpenAI用的是api_key加api_base还有的provider需要传aws_access_key_id这类额外字段。这些认准litellm_params里对应字段就好。还有一个容易忽略的是master_key。这是网关自己的管理员密钥第一次启动时如果你没设置litellm会让你在日志里找临时生成的Key然后再手动更新。这个Key是给运维人员用的不要直接发给业务同事后面给业务方签发虚拟Key是另外一套流程。2.3 数据库选型SQLite还是PostgreSQL网关启动后虚拟Key、调用日志、预算流水都存在数据库里。默认情况下litellm会使用本地SQLite文件这对跑通功能完全够用。但它有个明显短板如果你要做多实例部署SQLite不支持多个进程同时写同一个文件轻则锁库等待重则数据错乱。所以只要你有横向扩容的打算我建议直接上PostgreSQL。在config.yaml里加一行general_settings: database_url: postgresql://user:passwordhost:5432/litellm切换数据库之后你会发现一个好处多台网关实例可以共享同一份虚拟Key和调用记录。你要是做过那种把网关跑在多个区域、前面挂负载均衡的架构就知道这点有多重要。数据库这个选择直接影响后面跟成本相关的统计能力因为litellm的预算管理是依赖数据库里的调用记录来计算的库要是锁了或者数据丢了预算就成了一笔糊涂账。3. 核心API的使用逻辑从请求转发到虚拟密钥3.1 为什么业务侧只需要OpenAI格式的接口litellm对外暴露的接口风格和OpenAI一致这是个刻意设计的决定。因为现在市面上绝大多数的LLM应用框架、LangChain之类的工具、还有各种开源项目都优先支持OpenAI格式。如果你自己从零写业务代码也可以直接用一个兼容OpenAI的客户端来请求网关不用再单独引入litellm的SDK。实际效果是业务服务里原来是OpenAI(api_key...)现在改成指向网关地址比如http://litellm-host:4000Key换成网关签发的虚拟Key代码其他部分几乎不用动。如果业务侧之前直接调用的是国内某个不兼容OpenAI服务的厂商那么切换到litellm网关之后你用OpenAI库就能请求那个厂商的模型这个体验是很直观的。当然有些特殊能力是OpenAI格式表达不了的比如某些厂商的图片生成、语音转写这些litellm也有对应的/image、/audio端点但我在实际项目里用得不多本文就不展开了。文本生成这一块OpenAI格式基本覆盖了。3.2 请求路由与自动fallback机制litellm的另一个核心玩法是同一个model_name下挂多个上游渠道网关自动做故障转移。举个例子model_list: - model_name: my-llm litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: my-llm litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY业务侧始终请求my-llm正常情况网关默认走第一条渠道。如果OpenAI那边超时或返回5xxlitellm会自动切到Claude。这个fallback功能我测试过很多次触发逻辑是第一个上游请求出错或超时网关立刻把同一个请求转给第二个渠道。有一点要提醒fallback会把请求的“原始prompt”重新发一遍如果你的业务侧对延迟敏感切换那一刻的耗时可能会翻倍。最好在业务上设置比较长的超时时间给网关让网关有足够时间完成fallback而不是由业务先掐断连接。我踩过的坑就是在业务侧把超时设成了10秒上游渠道又有个别情况要15秒才响应导致fallback还没来得及执行业务侧自己先超时了。这个调优我后面会专门讲。3.3 虚拟Key的生成、限额与吊销虚拟Key是litellm身份体系里user-facing的部分。业务侧不用知道上游厂商的真实Key只需要拿着网关签发的虚拟Key来做请求。用管理员Key调一下接口就能生成curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-admin-key \ -H Content-Type: application/json \ -d {models: [gpt-4o], max_budget: 10, expires: 2025-12-31T23:59:59Z}这个接口会返回一个sk-开头的Key。你可以给每条业务线单独生成一个Key单独设置能访问哪些模型、预算上限是多少、什么时候过期。这样做有几个直接好处一是某个服务出了问题疯狂调用模型时最多只烧掉这个Key的预算不会拖垮整个公司的额度二是要下线一个服务时直接删掉对应的Key就行不用去上游厂商那边改设置。在管理后端页面上你还能看到每个Key最近的调用次数、token消耗和预估费用。这个功能在公司内部做成本分摊时特别好用我后面会详细说怎么用这些数据。3.4 通过router做更细粒度的负载均衡除了网关Proxylitellm的Python库里还有一个Router类属于可以在业务代码中直接使用的路由组件。这种模式适合不想单独起网关服务、但又想做多provider调度的场景。from litellm import Router router Router( model_list[ { model_name: gpt-4o, litellm_params: {model: openai/gpt-4o, api_key: ...}, }, { model_name: gpt-4o, litellm_params: {model: anthropic/claude-3-5-sonnet, api_key: ...}, }, ] ) response router.completion( modelgpt-4o, messages[{role: user, content: hello}], )Router跟Proxy是同一套配置逻辑的不同形态。我个人的实践是线上环境用Proxy因为集中管控和可观测性更好本地脚本和快速原型用Router因为不需要额外维护一个服务。这两种方式没有谁绝对更优取决于你的部署条件。4. 跑通一个真实项目配置、代码与链路排查4.1 我选定的验证场景为了验证litellm能不能承接真实业务我搭了一个模拟项目X大致功能是接收用户的提问先用一个模型做意图分类再根据分类结果选择不同的生成模型做回答。这个场景很典型因为它涉及多条模型链路的切换而且不同链路的模型来源不一样正好可以测试网关的模型路由能力。整个链路规划如下业务服务通过httpx请求litellm网关网关配置了三个模型一个用于分类的小模型、一个用于常规问答的主力模型、一个用于长文档处理的大上下文模型。三个模型分布在两个不同的上游厂商。我会故意在配置里把其中一个厂商的Key设为错误值观察fallback是否生效。4.2 关键配置与代码实现网关侧的config.yaml这样写model_list: - model_name: classifier-small litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY - model_name: main-generator litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: main-generator litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY业务侧Python代码用一个标准OpenAI客户端只是改掉base_url和api_keyfrom openai import OpenAI client OpenAI( base_urlhttp://localhost:4000, api_keysk-litellm-virtual-key, ) # 第一步意图分类 resp client.chat.completions.create( modelclassifier-small, messages[{role: user, content: user_input}], ) # 根据分类结果选择生成链路 if long_doc in resp.choices[0].message.content: model_name main-long-context else: model_name main-generator # 第二步正式生成 answer client.chat.completions.create( modelmodel_name, messages[{role: user, content: user_input}], )这段代码在没有任何上游知识的前提下完成了多厂商模型的接入业务只认squad的模型名底层是OpenAI还是Anthropic对它完全透明。4.3 从401到429再到超时的完整排查链路我把这次跑通过程中实际遇到的三个问题记下来它们非常典型。第一个问题是401。现象网关能启动但请求返回401 invalid api key。排查发现不是虚拟Key的问题而是config.yaml里环境变量的名称写错了。os.environ/OPENAI_API_KEY引用了一个不存在的环境变量litellm启动时不会立刻报错直到真正转发请求时才发现没有密钥。解决方法是先确认上游Provider的Key确实能通再确认环境变量在网关进程里可见。可以用docker exec进入容器echo $OPENAI_API_KEY验证。第二个问题是429。现象用官方Demo压测时请求到某个国外厂商出现429限流。这个不全是网关的锅是上游对单Key有并发限制。但litellm暴露了一个很关键的能力同一个模型名配置多个上游渠道用同一个Key的不同配额或两个不同渠道做负载均衡。我在config里为同一个model_name配了两个上游让网关自己做轮询瞬间把单Key的压力摊开了。第三个问题最棘手超时。业务端设置的是20秒超时网关默认的上游请求超时是5分钟按说不会出问题。但有一次某个上游渠道连续假死TCP连接建立后迟迟不返回数据业务侧等了20秒后主动断开网关侧还在等上游响应最终落了一堆pending请求。最后我在网关配置里加上了request_timeout参数把单次上游请求的上限设为30秒。这个参数值得你一开始就配好不要等到出事故了再想起来。5. 稳定性治理重试、限流与实际成本控制5.1 重试机制的正确姿势litellm支持在router_settings里配置重试策略。默认情况下遇到5xx会重试一次但这远远不够原因有两个第一上游限流返回的是429不是5xx默认策略不会重试第二如果多个请求并发失败所有请求同时重试可能再次打爆限流。我现在的配置思路是对429做指数退避重试退避时间从1秒开始最重试2次5xx重试1次连接类错误重试1次。重试次数不宜太多否则一次上游故障会让网关堆积大量等待中的请求业务端的超时反而先触发。router_settings: retry_policy: TimeoutError: retries: 1 APIError: retries: 1 RateLimitError: retries: 2 min_retry_delay: 1.0 max_retry_delay: 60.0还有一个细节重试是针对同一次上游请求也就是说网关会把同一个prompt重新发给同一个provider。如果你的业务方使用流式输出重试时可能会看到重复的token这个需要业务侧自己做好去重或者干脆对非幂等请求关闭重试。我见过有团队用流式接口一次真实请求被网关重试了三次费用翻了三倍这是重试的隐性成本。5.2 限流在网关层的价值与代价litellm支持在虚拟Key上设置rpm每分钟请求数和tpm每分钟token数也支持全局层面的速率限制。我之前觉得网关层限流有点多余毕竟模型厂商自己会限制。后来发现厂商的限流是按Key维度如果所有业务共用同一个上游Key一个异常业务就会把其他正常业务的额度全吃光。在网关层给每条业务线设置独立的rpm相当于“隔离故障单元”。比如A业务配置rpm100B业务配置rpm50A业务写了个死循环疯狂调用最多也就到100rpmB业务完全不受影响。不过限流也有代价网关本身要维护令牌桶状态如果你用多实例部署这个状态在多个实例之间怎么同步就成了一个麻烦。官方文档建议用Redis作为分布式限流存储我在生产环境里就是这么干的。代价是需要额外维护一个Redis但换来的是限流数据在多实例间一致。如果只是单实例用默认的本地内存就可以。5.3 预算控制与成本观测litellm的预算控制分两级一是虚拟Key级别的max_budget二是用户或团队级别的预算。我实际用得最多的是虚拟Key级别的预算。方法是给每条业务线一个Key设置“单日预算上限”比如50美元。这样即使业务方上了一个有漏洞的功能导致token消耗暴增账单也不会失控。预算触发的时机值得注意litellm是在每次请求结束时计算累计消耗如果某一次请求消耗了超预算的token这次请求本身不会被拦截但下一刀请求会被拒绝。所以它本质上是“事后熔断”不是“事中拦截”。要想更精细地控制单次请求大小需要在业务侧配合max_tokens参数把单次请求的token上限先控制住。成本观测方面litellm提供了调用日志表里面记录了每次请求的model、prompt_tokens、completion_tokens、total_cost。我后来写了个定时任务把这张表按key和model字段汇总每天推送到内部报表系统团队里每个人都能看到自己负责的业务线烧了多少钱。这个机制几乎零成本却解决了部门级成本分摊的大问题。5.4 流式请求与日志记录的坑流式请求是litellm的一个特殊场景。网关在透传SSE流时日志系统要等整个流结束才能统计token数和花费因为token数是按最终生成的增量汇总的。如果在流传输过程中网关重启这一次调用可能只记录了一半token数。这个对成本统计影响不大但如果你用日志数据做实时监控要注意这个延迟。另一个问题是流式请求中如果上游在某一个chunk之后断流网关会给业务侧一个不完整的流然后根据retry_policy决定是否重试整个请求。重试流式请求会造成业务侧出现重复段落的概率大增。我的处理方式是关键业务流不开启自动重试让业务侧自己判断是否重发请求避免客户端那边出现内容拼接错误。6. 实测检出的坑与现在的落地架构6.1 最大的坑model id名称混乱第一个真正烦人的坑是不同厂商对一个模型可能有不同叫法。比如某个开源模型在厂商A那里叫llama-3.1-8b-instruct在厂商B那里叫llama-3.1-8b-chat。如果你在config.yaml里把两个模型都映射到同一个model_name表面上没问题但实际请求时同一个提示词在两个厂商那里可能产生不一样的格式行为尤其涉及系统提示词时。更隐蔽的坑出现在embedding模型上。很多厂商的embedding模型名称后缀不一样有的带-v2有的不带如果你在业务侧写死了模型名网关这边一换厂商就废了。建议是在配置阶段就把每个上游渠道的“实际模型名”打印出来人工核对一遍别相信文档。解决方式是维护一份内部模型对照表统一业务侧的命名规范。我现在的config里每个model_name都用业务语义命名比如embedding-main、chat-default而不是直接用厂商模型名。这样将来换厂商时只需要改config里对应渠道的litellm_params.model业务侧完全无感。6.2 测试工具与压测注意点跑通网关之后我建议你做一轮完整的接口测试。litellm本身带了一个Swagger页面在浏览器打开http://localhost:4000就能看到可交互的API文档这个对快速验证特别有用。但Swagger页面上有些字段是必填的比如messages不填会直接报校验错误这不是网关bug是OpenAI接口的参数要求。压测要注意一个问题直连上游厂商和经由网关节点的延迟差异。网关本身只是一层转发正常情况下增加的延迟在10毫秒以内但如果配置了router_settings里的重试和fallback最坏情况下的延迟可能由fallback链路的数量决定。也就是说你压测时看到的p99延迟很可能不是网关的转发开销而是重试策略在极端情况下的开销。这一点在做性能评估时一定要区分开。我还发现一个测试时容易栽的跟头网关的虚拟Key在生成时如果设置了models白名单而你的压测脚本用了model_list里没有的新模型名会直接报404 model not found。这个报错在业务方看来莫名其妙因为它觉得“明明昨天还能用”。实际上就是你改了配置但没重新生成Key或者Key的白名单不够全。6.3 我现在会推荐的落地架构经过这段时间的使用我现在给团队推荐的架构分三层第一层是接入层也就是litellm网关实例至少两个node前面挂一个负载均衡接受来自各业务服务的请求。第二层是数据层用PostgreSQL统一存所有虚拟Key、调用记录和预算数据限流状态放Redis。第三层是观测层定时从PostgreSQL捞调用日志汇总按Key、按模型的费用报告再配一个简单的告警当某个Key的消耗速度超过前一天的3倍时提醒运维。网关实例本身不存任何业务状态所以出故障了随时可以重启新的实例启动后自动从PostgreSQL加载配置和Key数据。这个架构到目前为止跑得很稳再也没有出现“换模型要改代码、对账单要翻Excel”的情况。如果你只是单机试玩不用上这么重的架构一个docker run加SQLite就够了。但只要你打算引入第二条业务线、第二个上游渠道我建议还是尽早切到PostgreSQL模式后面迁移成本会小很多。我在实际使用中最有感触的一点是litellm最大的价值不是把多家API统一成一套接口而是把“谁在用模型、用了多少、花了多少钱”这件事变成了可管理、可审计、可控制的正常运维对象。如果你也到了被模型渠道和账单反复折磨的阶段值得花半天时间把网关搭起来试试。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑