我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

LLM网关litellm实战:统一模型接口、路由与生产部署

LLM网关litellm实战:统一模型接口、路由与生产部署 1. 喂到嘴边的LLM网关litellm到底是什么如果你最近在折腾大模型应用肯定绕不开一个名字litellm。我第一次见这玩意儿的时候还以为是个“轻量级学习模型”之类的轮子结果点进去一看好家伙这哪儿是模型这是个纯纯的“网关”。用大白话说litellm就是一个统一API接口层。你只需要按它规定的格式写一份请求它能帮你转发到OpenAI、Anthropic、Google Gemini、Azure OpenAI、本地Ollama、甚至各种开源模型的推理服务上。你不需要关心后端接的是哪家的模型也不需要为每个厂商单独写一套调用代码。上层的应用只管调litellmlitellm负责跟底下那些五花八门的模型服务打交道。这套东西解决什么问题最直接的痛点就俩一个是切换模型的成本另一个是管理多个模型的开销。你想象一下你公司里做了一款AI客服试了好几个模型——GPT-4o、Claude、还有国产的开源模型结果你每换一个模型就得改一遍代码还得重新处理token计费、限流、超时这些破事。用litellm之后这些全被收拢到一个入口里配置一变模型随便换。适合谁看这篇文如果你是做后端开发、AI应用集成、或者在公司里搭所谓“AI中台”的人litellm几乎是必看的。即使你只是自己写点小工具想在各种模型之间横跳对比效果litellm也能帮你省掉至少一半的胶水代码。我下面会从配置、部署、依赖、权限、监控、排错这几个维度把我在实际项目里用litellm踩过的坑和摸出来的路子一次性讲清楚。2. 为什么需要一个统一入口架构层面看litellm的价值2.1 没有网关的时候你过得有多狼狈先说一个我真实的经历。早先我维护一个内部的知识库问答系统一开始只接了OpenAI的接口。代码里到处都是openai.ChatCompletion.create这种调用参数也硬编码在多个服务模块里。后来某天老板说要对比一下另一个闭源模型在垂直领域的效果我一看就头大新模型的SDK、鉴权方式、消息结构全都不一样我得把调用层全部重写一遍。这还只是开始。对比来对比去最后发现两个模型各有千秋干脆都在生产环境上跑一个处理高并发简单问答一个处理复杂推理。这下好了代码里得写一堆路由逻辑还要自己统计两边各花了多少钱。后来第三个、第四个模型陆续接进来我就彻底投降了。那个阶段我每天干的最多的事就是在不同的API文档之间跳来跳去。当时我就想如果有个“模型代理层”就好了——上层的请求格式统一至于请求发给谁、参数怎么转换、怎么计费全在这一层解决。本质上这就是一个分布式系统里最经典的“网关模式”。litellm不是第一个做这件事的但在大模型这个领域它把这件事做得特别彻底而且面向开发者的体验做得足够好。2.2 litellm的设计哲学标准化写一次路由随便切litellm核心的抽象思路就是把“模型名”当作路由关键字。你调litellm时传一个model参数比如gpt-4o或者claude-3-5-sonnetlitellm内部会从配置里查这个模型名对应哪个供应商、用哪个API key、有什么特殊参数然后帮你完成协议转换。这个设计妙在什么地方它把“逻辑”和“配置”彻底分离了。你在代码里只需要写一次标准请求from litellm import completion response completion( modelgpt-4o, messages[{role: user, content: 你好介绍一下你自己}] )如果开发环境要用开源模型你把model换成ollama/llama3.1接口完全不变生产环境要切回GPT你改个参数就行。放在公司级别的应用里你甚至可以让非技术人员通过配置文件来控制模型路由开发完全不用动。我经常拿它类比DNS——你访问一个域名DNS帮你解析到背后的服务器IP服务器换了IP你也不感知。litellm就是模型界的DNS帮你把请求解析到模型服务的真实地址上。2.3 什么时候不建议上litellm虽然我说了这么多好处但litellm不是银弹。如果你只是写个一次性脚本只调一个模型一个月跑不了几次那直接用官方SDK反而更轻。引入litellm意味着多一层依赖、多一个进程要维护相当于你为了一瓶水专门修了一条自来水管道。另外如果你的场景特别依赖某个厂商的独家特性比如Anthropic的prompt caching特殊用法、OpenAI的某个新出的结构化输出参数而且这些特性你在可预见的未来也不会换模型那直接用官方SDK也许更快。litellm虽然一直在跟进各家新特性但毕竟有一层抽象新特性的支持总是有滞后。我的建议是当你的项目里出现“第二个模型请求”的一瞬间就应该开始考虑litellm。它能让你在模型选型阶段快速试错这在当下模型迭代速度飞快的环境里价值怎么强调都不过分。3. 从零部署一套可用的litellm代理服务3.1 两种使用姿势内置SDK还是独立代理litellm有两种玩法很多人一开始搞混。第一种是在你的Python进程里直接import litellm把它当SDK用。这种方式适合单机脚本、小型服务你不需要额外启动任何进程直接通过函数调用发请求。第二种是跑一个独立的代理服务—— litellm本身是一个基于FastAPI构建的服务端你启动它之后它会暴露一个OpenAI兼容的HTTP接口。所有应用通过HTTP请求打到这个服务由这个服务再转发到上游模型厂商。我个人推荐只要不是一次性脚本都走第二种方式。原因很简单独立代理可以把API key集中管理应用层不接触任何上游密钥。你在公司里也更容易做权限控制和审计。而且litellm代理本身提供了key管理、预算控制、请求日志等一堆运维能力这些是SDK模式给不了你的。在正式环境里我通常把litellm代理部署在一台单独的实例上或者跟你的业务服务放在同一个Kubernetes集群里作为独立Deployment。资源占用不高——主要是IO密集默认配置下几百MB内存足够跑了。3.2 快速启动一份配置文件拉起服务litellm的启动入口是配置文件默认用YAML格式。我见过很多人在这一步就卡住其实逻辑非常简单定义哪些模型可以被访问、各自的供应商和密钥、以及一些路由策略。下面是我常用的一个最小化配置model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini 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 - model_name: llama3.1 litellm_params: model: ollama/llama3.1 api_base: http://localhost:11434这里有几个关键点第一个model_name是这个模型在litellm路由里的“别名”。你可以在业务代码里写gpt-4o-mini但实际路由到的是openai/gpt-4o-mini。如果你想用同一个别名做灰度——比如model_name叫main-llm后端今天指向gpt-4o明天指向claude通过改配置就行业务代码一字不用动。这就是我前面说的配置驱动的核心价值。第二个model字段里的provider前缀比如openai/、anthropic/、ollama/是litellm识别用哪个适配器去转换协议的标记。这里必须写对否则litellm不知道该怎么解析。第三个api_key可以直接从环境变量读取os.environ/XXX。这个写法在生产环境非常有用避免把密钥写死在配置文件里提交到代码仓库。配置文件写好后一条命令就能把代理服务拉起来litellm --config config.yaml --port 4000如果要部署到生产环境我还是建议用Docker。litellm官方镜像里预装了所有依赖直接用就行。我自己生产环境里用的docker-compose通常是这样的version: 3.8 services: litellm: image: ghcr.io/berriai/litellm:main-latest ports: - 4000:4000 volumes: - ./config.yaml:/app/config.yaml environment: - OPENAI_API_KEY${OPENAI_API_KEY} - ANTHROPIC_API_KEY${ANTHROPIC_API_KEY} command: [--config, /app/config.yaml, --port, 4000]启动之后你可以用任意一个OpenAI SDK来请求它from openai import OpenAI client OpenAI( api_keysk-anything, # litellm代理的key稍后讲 base_urlhttp://localhost:4000/v1 ) resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: hello}] )你没看错用官方OpenAI SDK就能直接访问因为litellm的接口完全兼容OpenAI格式。这句话潜台词极大你项目里几万行基于OpenAI SDK的代码换到litellm之后只需要改一个base_url其余全不动。3.3 上游模型的特殊参数配置不同的模型供应商有各自的特殊参数。比如Azure OpenAI需要api_base和api_versionBedrock需要aws的密钥对Vertex AI需要GCP的服务账号。这些参数统一放在litellm_params里。举一个例子如果你接Azure版的GPTmodel_list: - model_name: azure-gpt-4o litellm_params: model: azure/gpt-4o api_key: os.environ/AZURE_OPENAI_API_KEY api_base: https://your-resource.openai.azure.com/ api_version: 2024-02-15-preview接AWS Bedrock的话参数更特殊一些- model_name: bedrock-claude litellm_params: model: bedrock/anthropic.claude-3-5-sonnet-v2 aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY aws_region_name: us-east-1这里我想强调一点litellm对各家provider的参数命名比较统一基本上就是“跟官方SDK保持一致”。所以当你需要接一个新供应商时最快的办法是去看官方文档里这个供应商的SDK初始化需要什么参数然后照搬进litellm_params即可。4. 代理背后的关键机制路由、密钥与预算控制4.1 虚拟密钥把供应商密钥藏起来litellm代理有一个对我来说极为实用的功能虚拟密钥管理。意思是你不用把OpenAI的sk-xxx发给业务服务你可以通过管理接口生成一把只属于某个业务的虚拟key。这把key在litellm内部跟真实的供应商key做映射。流程是这样的curl http://localhost:4000/key/generate \ -H Authorization: Bearer sk-1234 \ -H Content-Type: application/json \ -d { models: [gpt-4o-mini], max_budget: 10 }响应里会返回一把sk-开头的虚拟key。你把这把key给下游应用用预算上限是10美元只能访问gpt-4o-mini。如果某个业务方超支了或者被攻击了直接吊销这把key就行完全不影响其他业务也不需要去厂商后台做任何操作。这个能力在多人协作、多业务线共享模型资源的场景下简直是救命的。我之前在一家公司里三个业务线共用一个OpenAI账号每个月账单出来都不知道该让谁掏钱。上了litellm之后每条业务线一把key各花各的钱报表也分得明明白白。4.2 多模型路由策略loadbalancing和fallbacklitellm天然支持两种路由策略负载均衡和故障转移。负载均衡的场景是你在OpenAI上配了多个key想分散请求量避免触发单key的速率限制。配置里写这样一段model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_1 - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_2两个一模一样的model_namelitellm会自动在它们之间做轮询均衡。我实测下来高并发场景下确实能明显减少429限流错误。故障转移则更贴近真实业务的容错需求。比如主模型挂了自动降级到备用模型router_settings: fallbacks: [ {gpt-4o: [claude-3-5-sonnet]} ]当gpt-4o连续报错超过阈值litellm会把请求自动转发给claude-3-5-sonnet。这个能力在线上服务里非常实用——AI模型服务的稳定性再怎么吹也没人敢保证不抽风而你的业务不能因为上游抖动就一起挂了。4.3 预算控制配置里的事前限制预算控制是我觉得litellm做得最扎实的功能之一。它支持两种级别一种是在虚拟key上做预算一种是在global配置里做整体预算。我常用的配置如下general_settings: master_key: sk-1234 database_url: postgresql://user:passlocalhost:5432/litellm max_budget: 1000这里涉及一个需要重点解释的点litellm要持久化记录请求日志和用量统计必须配一个数据库。默认用SQLite就可以跑但生产环境强烈建议上PostgreSQL。数据库里存的是每一次请求的模型、token数、耗时、延迟它会基于这些数据实时累计预算。我之前遇到过一个坑刚开始没配数据库用SQLite跑了几天一切正常。后来请求量一上来SQLite的写锁导致大量请求卡顿最夸张的时候代理服务完全没响应。换到PostgreSQL之后这个问题彻底消失。所以如果你打算正经使用litellm代理一开始就配好PostgreSQL不要走弯路。5. 从开发到上线的完整实操记录5.1 本地联调阶段一次真实接入案例下面这段是我在一台测试机上的完整操作记录供你对照参考。第一步安装litellmpip install litellm[proxy]注意这里的[proxy]额外依赖它是专门给代理模式用的包含了FastAPI相关的所有包。如果你只是用SDK模式pip install litellm就够。第二步准备配置文件。因为我本地还想顺带测一下开源模型所以我配置了Ollama作为额外的上游让业务一个入口能同时访问闭源和开源模型。配置里加一段- model_name: local-llama3 litellm_params: model: ollama/llama3.1 api_base: http://localhost:11434第三步启动代理litellm --config config.yaml --port 4000看到类似Uvicorn running on http://0.0.0.0:4000的输出就说明起来了。第四步用一个简单的Python脚本验证import openai client openai.OpenAI( api_keysk-1234, base_urlhttp://localhost:4000/v1 ) for model in [gpt-4o-mini, local-llama3]: resp client.chat.completions.create( modelmodel, messages[{role: user, content: 11?}] ) print(model, resp.choices[0].message.content)模型名传的是配置里的model_name不是upstream真实名。litellm会通过model_name找到对应的供应商并转发请求。5.2 生产环境部署代理与服务分离生产环境里我的做法是让业务服务跟litellm部署在同一个网络里业务服务通过内网地址访问litellm代理。这样上游密钥完全不会暴露到公网。我还会在litellm前面再挂一层网关做基础的IP白名单。虽然litellm自己有虚拟key鉴权但多一层防护总归更稳妥。一个比较关键的经验litellm实例最好单独部署不要跟高CPU消耗的业务服务混部在同一个Pod里。因为litellm转发大模型请求时会涉及大量的流式响应处理如果业务服务本身CPU飙高会拖累代理的响应速度上游模型本来1秒的响应可能变成3秒。5.3 流式输出的关键配置大模型应用的响应普遍是流式的litellm对stream参数的穿透做得很好。你在业务代码里这么写resp client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 写一段长文}], streamTrue ) for chunk in resp: print(chunk.choices[0].delta.content or , end)litellm会把上游的流式数据实时转发给下游用户感知不到中间隔了一个代理。这块它兼容得相当不错我试过从OpenAI直接切换到litellm前端代码完全不用改。需要注意的一点是有些上游模型供应商对流式请求的响应格式跟OpenAI不完全一致比如Anthropic的流式返回就是SSE事件流格式完全两样。litellm在内部把它们全部转换成OpenAI格式后输出。但有些特殊的字段比如usage信息某些供应商在流式结束后的最后一个chunk里才返回这会影响你对token统计的精确性。解决方案是让litellm写回数据库的请求日志作为计费依据而不是依赖流式响应里的usage字段。6. 权限模型与多业务隔离的经验6.1 团队里如何分配权限如果你所在团队有多个人在对接模型权限这块最好一开始就规划好。litellm管理后台是自带的启动代理后访问http://localhost:4000/ui用master_key登录就能看到管理页面。在这里可以创建用户、创建虚拟key、设置每个key能访问的模型、设置预算上限。以我实践过的最佳实践来说每个业务线创建一个独立的“团队”团队下再建key。每个key绑定单一的模型集合最小权限原则。开发环境的key预算给得宽松一些生产环境的key预算给得紧一些并把通知告警打开。如果业务方的需求只是“我要能调GPT”他们不需要也不应该看到任何其他业务的key信息。通过团队隔离litellm能让每个业务只能看到自己的用量和key。6.2 多租户的模型路由多租户场景下你可能会遇到一个需求不同客户要用不同的模型。比如某些客户对成本敏感只能用便宜的小模型某些客户做专业领域的问答必须用大模型。litellm的team配置可以绑定模型列表。你在创建team时指定这个team能访问的model_nameteam下所有的key都继承这个限制。请求到达litellm时它会先校验这把key属于哪个team再校验请求的model是否在team允许的列表里。这里我踩过一个坑一开始没做team隔离只给key绑了模型。后来发现同一个key被多个业务公用了一个业务修改了模型的prompt格式导致另一个业务的请求出错。后来改成team隔离每个业务用独立team问题迎刃而解。建议你在建key之前先建好team和模型绑定关系不然后期调整会很痛苦。7. 监控与可观测性别等线上炸了才想起来7.1 请求日志与用量报表litellm会把所有请求的元数据记录到数据库里包括请求时间、模型名、token数上下游的延迟缓存命中情况请求里的用户标识在管理后台里你可以按维度筛选这些数据。比如查看某个team今天用了多少个token某个key的平均响应时间是多少。对于需要给业务方出成本账单的场景这基本是零成本的方案——数据已经在那里了。不过日志默认是全部记录的。如果请求量大数据库会膨胀得很快。我建议定期清理或归档历史数据或者在配置里关闭对健康检查等非业务请求的日志记录。这一块litellm本身不做自动的滚动清理需要你写个定期任务。7.2 接入Prometheus与Grafanalitellm暴露了Prometheus指标端点/metrics。默认会输出以下核心指标litellm_total_requests_total总请求数litellm_total_tokens_total总token数litellm_remaining_requests_quota剩余请求额度litellm_latency_per_request请求延迟分布我用Prometheus配合Grafana搭过一个简单的监控面板重点关注延迟和限流次数。有一次某个模型的上游稳定性下降之前完全靠用户投诉才知道。接上监控之后一个面板就能看到延迟突增提前做好降级策略。接入方法很简单在docker-compose里加一个prometheus和一个grafana服务把litellm的/metrics端点配置为采集目标就行。网上这类现成的compose模板很多根据自己的业务稍微改一改就能用。7.3 告警设置做兜底监控光看不行还得能告警。我设过两种告警模型错误率超过5%时告警通常意味着上游挂了或者API key被限额了。某team预算达到80%的时候提前通知避免月底账单突然爆炸。如果你不想折腾Prometheus告警规则litellm本身也支持Webhook通知。在config配置里指定一个回调URL当某个key超预算或模型持续失败时litellm会往你的企业微信、钉钉或者自研的告警平台推消息。我建议生产环境两套都上不嫌多。8. 常见问题与排查技巧实录8.1 模型名对应关系搞错最常见的错误是配置文件里model字段的provider前缀写错比如ollama的模型写成了openai/llama3.1litellm会拿着OpenAI的协议去请求一个OpenAI不认的模型名返回的直接就是404或400。排查方法很直接先在不经过litellm的情况下直接用官方SDK请求上游确认上游本身是通的。然后用litellm的SDK模式请求一次加上debug参数import litellm litellm.set_verbose(True) response litellm.completion( modelollama/llama3.1, messages[{role: user, content: ping}] )verbose会打印litellm内部拼接的完整上游请求URL和请求体一眼就能看出问题在哪。8.2 429限流与重试策略litellm默认自带重试功能遇到429、超时、5xx错误会进行指数退避重试。默认最大重试次数是2次但我建议调大一点尤其是面对限流频繁的小模型litellm.num_retries 5 litellm.request_timeout 30注意重试只对幂等请求安全。如果你的应用使用stream模式并且用户已经看到了部分内容重试可能导致用户看到重复的片段。更稳妥的做法是把重试集中在非流式请求上或者在流式请求里依赖litellm的fallback机制切换到别的模型而不是重试同一个可能已经写了半截的响应。8.3 时延变高检查落库的开销有一次我发现所有请求都变慢了不是上游的问题而是litellm把每次请求的日志写入PostgreSQL时数据库出现锁竞争。那时候请求量刚好到了一个阈值单库已经扛不住频繁的insert。后来我把数据库升级成大规格实例同时把日志的异步写模式打开。litellm内部支持将日志异步批量写入数据库配置里加一句general_settings: async_mode: true开启之后请求响应不再等待数据库写入完成时延立刻回到正常水平。代价是极端情况下日志可能丢失几条但这跟用户体验相比完全可以接受。8.4 请求上下文长度超限prompt太长触发上限是最常见的模型侧报错。litellm可以在中间层拦截并处理但默认不会自动截断——因为自动截断很可能影响语义。我的处理方式是在业务代码里按模型预设的token上限做分段或摘要。比如统一限制每条prompt不超过6000 token。litellm也有一个max_tokens参数可以限制输出长度但这个只是生成侧的限制不是上下文的总限制。你要结合上游模型的context window做整体规划。分享一个实用技巧litellm支持按模型设置max_input_tokens参数。如果模型context window是128k你可以在litellm_params里限制最大输入token为100k超出直接返回错误避免打到上游后才发现超限白白浪费一次上游调用费用。8.5 虚拟key鉴权失败如果应用调用返回401但key明明存在大概率是key被限定了模型范围。你在生成key时如果只给了某个模型的权限使用另一个模型访问就会401。还有一个隐蔽的坑如果litellm配置了数据库而数据库表里没有初始化对应的key信息也会导致鉴权失败。遇到这种情况先去管理后台确认key的状态再检查数据库连接是否正常。9. 一点延伸和LangChain等框架怎么配合现在很多团队用LangChain、LlamaIndex这类编排框架来写Agent应用。这些框架默认都支持自定义base_url因此接litellm非常自然。比如LangChain里原来的OpenAI调用设置如下即可切换到litellm代理from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, openai_api_basehttp://localhost:4000/v1, openai_api_keysk-1234 )框架层面的所有链式调用不受影响。Agent里的工具调用、Function Calling这些litellm也支持传递tools参数能和OpenAI的tool calling格式对齐。我个人的使用习惯是编排框架负责业务逻辑litellm负责模型路由和成本控制。两者解耦之后如果新的模型框架出来了跟litellm配合往往是改配置就能接入而不用重写任何业务代码。这是我这段时间用得最舒心的一点。10. 个人经验这几件事越早知道越省心最后聊几句实在的。第一litellm的升级频率挺快新模型一出它往往几天内就更新支持。但这也意味着API接口可能有不稳定变化。我的经验是锁定你常用的一个大版本升级前先在测试环境跑一遍关键用例再上生产。别追最新版追得太猛稳定大于一切。第二最关键密钥一定别写进配置文件仓库。使用环境变量、云厂商的密钥管理服务都行。我见过不止一个团队的API key因为写死在配置里被提交到GitHub导致被刷爆账单的事故。litellm的os.environ/XXX写法就是为这个设计的别嫌麻烦用起来。第三流式请求的故障排查比普通请求难很多。因为错误的返回可能是在流中间发出的客户端只能拿到半个响应后断开。真遇到这种问题先在非流式模式下复现把错误信息看全了再切回流式模式验证修复结果。这是我把头挠秃之后总结出来的最有效的排错思路。litellm这个项目的确把大模型接入这件“脏活累活”做得足够优雅。它不激进不革新就是把网关该干的事全部干到位了。在模型还在快速迭代的今天给自己留一条随时切换的退路这可能是你在AI应用架构里能做的最稳健的选择之一。
返回列表