做AI应用开发绕不开的一个现实问题,就是模型供应商越来越多,接口风格却各搞一套。今天聊的这个开源项目,圈内习惯叫它litellm——本质是一个大语言模型网关,把各家模型服务的接口统一成一套标准格式,业务代码不用再为了换模型反复改调用逻辑。我自己从单体脚本里直连各家接口,到把流量统一切到litellm代理之后再分发,体验差别还是很明显的。这篇就把这个项目讲透,包括它到底管了哪些事、怎么部署、配置怎么写、有哪些坑是文档里不常说的。
1. 这工具到底解决什么问题
先说痛点。你写一个AI功能,一开始只接了某一家模型服务,代码里是它家的SDK和消息格式。过段时间产品说要支持另一家,你发现请求格式、鉴权方式、超时语义、流式输出的结构全都不一样。最朴素的做法是写一堆适配层,每个供应商一套封装,然后业务代码里到处if else去判断当前走的是哪家。刚开始还能撑,模型一多就变成噩梦。
litellm做的事情通俗说就是加一个中间层。上游是你真实对接的各种模型服务,下游统一暴露成一套OpenAI兼容的API接口。你业务代码里只需要记住一套base_url、一套报文结构,模型在哪个服务商、叫什么名字、用什么密钥,全部由网关管理。要换模型,改配置文件就行,代码完全不动。
使用场景我总结下来主要有三类。第一类是个人或小团队快速做原型,代码里不想维护多套SDK。第二类是公司多个业务线需要集中管理模型密钥和调用量,流量统一走网关方便审计和限流。第三类是要做模型调度,比如根据成本或响应速度自动挑模型。这些场景litellm都覆盖得不错,而且它对不同基础的读者都很友好——不想了解细节的人用默认配置就能跑起来,想深入控制的人也能找到对应的参数。
2. “网关”到底管了哪些事
2.1 统一接口与多供应商适配
要说这个项目最核心的能力,就是它对上百种模型来源做了适配。这里说的适配不是简单的转发请求,而是把不同供应商的报文模型、流式格式、错误信息都做了一层转换,最终对外全部以OpenAI的ChatCompletions风格呈现。
你在客户端只需要这样:
from openai import OpenAI client = OpenAI( api_key="sk-1234", base_url="http://localhost:4000/v1" ) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "你好"}] )同一个客户端,你把model值换成“claude-3-5-sonnet-20241022”,网关就会用对应供应商的适配器转发请求。你不需要引入Anthropic的SDK,不需要处理两套消息格式,甚至超时和重试逻辑都只要写一遍。基于它内部的模型注册表,你只要在配置里声明模型名和供应商的对应关系就能立即生效。这种感觉有点像写了ORM之后,数据库换方言不用改业务代码——对接模型服务同样需要这么一层抽象。
2.2 密钥管理与多种校验策略
很多团队直接把自己某个服务的密钥写死在前后端代码里。密钥一旦泄露,损失就是全量调用的额度。litellm的另一个价值在于把密钥做成了一等公民的概念。
你可以为不同团队或应用生成多个虚拟密钥,每个虚拟密钥可以绑定不通的模型组和速率限制。比如前端应用只允许用它组装好的对话模型,数据分析组只能用特定的大上下文模型,而且每秒并发被限制在2以内。配置里是这么做的:
general_settings: master_key: sk-my-master-key litellm_settings: num_retries: 2 request_timeout: 600 max_budget: 100 budget_duration: "30d"master_key是给管理接口用的,每次虚拟密钥的生成和查询都要带上它。真正发给业务客户端的key是创建出来的虚拟密钥。即使某个虚拟密钥泄露,你只撤销那一把就行,不需要更换上游真实凭证。这一点在多人或多项目协作时价值极高,密钥审计也清晰得多。
如果你不想用虚拟密钥,只想要最朴素的代理转发,也可以直接把上游密钥配置在model_list里,网关负责存管和加载。但我的建议是无论如何都开启虚拟密钥功能,权限边界越早划清楚越好。
2.3 路由、负载均衡与故障转移
做模型接入久了你会发现,同一个模型名在不同服务商的可用性、延迟、成本差异很大,而路由能力就是决定网关最后体验的一环。
litellm支持你在配置里写多个同模型来源,然后通过router_settings指定策略。我常用的配置如下:
router_settings: routing_strategy: "usage-based-routing-v2" model_group_alias: gpt-4o: [gpt-4o-primary, gpt-4o-fallback] model_list: - model_name: gpt-4o-primary litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_1 - model_name: gpt-4o-fallback litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY_2策略选择上,有基于成本和延迟的简单轮询,也有需要额外配置的usage-based策略。后者会统计近期各上游的并发和延迟数据,动态把流量分发到更健康的一端。所以主服务商宕机或者限流时,网关会自动把请求转移到备用供应商上,业务侧基本无感知。这里我提醒一点:故障转移的前提是你能真正确认备用密钥的额度独立,并且备用服务商的协议兼容,否则转移过去也会被上游拒绝。
2.4 费用追踪与预算控制
模型费用是很多团队头痛的地方,尤其当多个业务方共享同一个服务商账号时,月底账单根本分不清楚是哪个团队花掉的。litellm把每次调用的token数、费用估算、密钥归属、模型归属都记下来了。
在虚拟密钥的详情页,你能看到这把key最近一段时间的调用次数、输入输出token、估算费用。配合max_budget参数,可以设置这把key的消耗上限。超出之后,网关会直接拒绝新的请求。这种能力在给客户提供AI能力配额时非常有用。虽然预算控制不是新鲜概念,但针对LLM调用场景,能把token和并发维度都纳入控制,对比传统API网关确实精细得多。
2.5 可观测性与日志
可观测性这一块,litellm后台自带一个可视化面板,可以看到过去一段时间的请求成功率、模型分布、Token消耗曲线。你不需要额外搭监控体系,本地部署的版本默认自带这些统计,这点比很多需要自行埋点的方案要省事得多。
不过生产环境使用,我还是建议搭配Prometheus暴露指标,或者把日志接进团队已有的日志系统。litellm官方文档里提供了metrics接口,里面包含了请求数、错误数、延迟分位数等关键指标。真到了排查线上问题的时候,这些数据比面板上的友好图表管用得多。
3. 从零搭一个可用的LLM网关
3.1 部署方式选型
litellm的部署方式很灵活,最常用的是Docker镜像运行,也有pip安装的方式。我个人的意见是:如果你只是本地测试或者写个快速脚本,直接pip install "litellm[proxy]"然后运行litellm --config /path/to/config.yaml就行。但如果你是想长期跑在服务器上给团队使用,一定要用Docker Compose部署,这样版本更新、配置切换、日志挂载都更容易管理。
还有一种部署思路是把litellm内置到自己的Python服务里,通过import调用。这种方式适合你本身就在用FastAPI这类框架,希望把网关和服务接口完全集成在一起。虽然灵活,但我不建议在产品环境里这样搞——网关本身要扛流量,应该独立部署,避免和业务服务互相影响。
3.2 Docker Compose实际部署
这里给一个可以照抄的基础配置。假设你有一台服务器,准备暴露一个统一入口供公司内部各业务调用。
version: "3.9" services: litellm: image: ghcr.io/berriai/litellm:main-stable container_name: litellm ports: - "4000:4000" volumes: - ./litellm_config.yaml:/app/config.yaml - ./litellm_data:/app/data environment: - STORE_MODEL_IN_DB=True - DATABASE_URL=postgresql://litellm:litellm@db:5432/litellm - LITELLM_MASTER_KEY=sk-master-key-change-me depends_on: db: condition: service_healthy restart: always db: image: postgres:16-alpine environment: POSTGRES_USER: litellm POSTGRES_PASSWORD: litellm POSTGRES_DB: litellm volumes: - dbdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U litellm"] interval: 5s timeout: 5s retries: 10 volumes: dbdata:第一次部署时,我建议先不开数据库,用默认的SQLite模式跑通全流程。等理解了配置项之间的关系,再切换PostgreSQL来支撑并发和多人访问。这里的DATABASE_URL如果你不提供,litellm会自动创建本地SQLite持久化文件。不过一旦要上生产,PostgreSQL几乎是必须的,原因很简单:并发执行写操作时SQLite容易遇到锁竞争,影响虚拟密钥创建和用量上报。
3.3 最小可用配置解析
一个最小可用的配置文件长这样:
model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: ${OPENAI_API_KEY} litellm_settings: drop_params: true set_verbose: false num_retries: 2 request_timeout: 600 general_settings: master_key: sk-1234 database_url: postgresql://litellm:litellm@localhost:5432/litellm注意这里model_name是暴露给客户端调用的名字,litellm_params.model则是真实模型标识。它遵循一个固定命名规则,比如openai/就是OpenAI格式,anthropic/就对应Anthropic格式,bedrock/对应AWS Bedrock,ollama/对应本地Ollama。这个映射关系可以让你随意设置对外名称,比如你内部所有人都统一调一个叫production-llm的模型名,网关帮你解析到后端实际供应商,后续换供应商大家无感,这就是model_name抽象价值的体现。
环境变量的写法很有用,api_key: os.environ/OPENAI_API_KEY表示网关会从运行环境的OPENAI_API_KEY变量里读取真实密钥值,而不是把密钥写死在配置文件里。这是一种好习惯,因为配置文件通常会进版本库,而密钥必须隔离。
3.4 启动与首次调用验证
配置就绪后,在config.yaml所在目录执行:
docker compose up -d docker compose logs -f litellm看到类似“Uvicorn running on http://0.0.0.0:4000”的日志就算是启动成功了。首次验证我建议不要直接写代码,先用curl确认为通:
curl http://localhost:4000/health/liveliness curl http://localhost:4000/v1/models \ -H "Authorization: Bearer sk-1234"这两条通过之后,再做一次真实对话请求。如果返回的格式和OpenAI官方一模一样,说明代理层工作正常。如果这一环节报错,优先检查config.yaml里的model_list是否写错、上游密钥是否有效、环境变量是否被正确注入。
3.5 虚拟密钥创建与使用
用master_key创建一个虚拟密钥,然后在客户端里用这个虚拟密钥调用。这一步建议尽早自动化,因为手动创建一次两次还能接受,模型一多、团队一多,手动管理肯定乱。
curl http://localhost:4000/key/generate \ -H "Authorization: Bearer sk-1234" \ -H "Content-Type: application/json" \ -d '{ "models": ["gpt-4o"], "max_budget": 50, "budget_duration": "30d" }'返回的 JSON 里会包含一把key,把它配到你的客户端代码中。在这个例子里,这把key只能调用gpt-4o这一个对外模型名,且30天内预算上限50美元。这和前面说的OpenAI客户端用法完全兼容。
3.6 后台管理面板使用
部署完成后,浏览器访问http://your-server:4000/ui,用master_key登录就能看到后台。面板上能看到已创建的虚拟密钥、每次调用的日志、模型消耗排名等。
日常使用中,我其实最常用的是“日志”页面。排查用户反馈“为什么刚才请求失败”,直接按时间筛选对应的key和模型,能看到具体的失败原因码和响应内容。这比去各服务商后台翻日志快很多。需要注意的是,默认UI暴露在公网会有安全隐患,建议用防火墙只允许内网IP访问,或者套一层带身份验证的Web服务,不要裸奔到公网。
4. 高频踩坑与排查速查
4.1 连接超时与重试误区
很多人部署好之后发现请求偶尔变慢甚至失败,第一反应是网关配置不对。其实大部分情况是上游服务商响应慢,而litellm默认的等待时间又比较长。当你把request_timeout调到60秒这种偏小值,单个请求很容易在高峰时段超时。
我的建议是:网关的超时设置要比上游服务商的承诺值稍短一些,比如上游最大响应时间可能是600秒,那你可以把request_timeout设为600或略低,同时开启重试。但注意,不是所有类型的请求都适合盲目重试。如果是流式输出,一旦中断,重试整个请求成本很高。如果真是上游不稳定,优先考虑加fallback模型,而不是无限重试。
这里分享一个参数:num_retries控制重试次数,但重试之间的间隔策略也值得关注。我通常配置2到3次重试就够了,再多反而会放大上游压力。
4.2 认证鉴权:别让网关裸奔
有朋友图方便,部署完master_key都不改,直接用默认的“sk-1234”。这等于把模型调用入口裸奔在公网上。litellm虽然不会暴露你的上游密钥,但任何拿到master_key的人都能管理你的虚拟密钥和查看调用日志,能消耗你的上游预算。这个风险务必高度重视。
生产环境建议在网关前面再加一层SSO认证或身份代理,只允许企业内网或特定IP访问。虚拟密钥本身就是为这种场景设计的,务必养成分密钥、限模型、限预算的习惯。另外记得,不要用同一个虚拟密钥给所有业务方,否则费用分摊又回到了原点。
4.3 400错误与参数兼容性
调用时报400的情况很常见,尤其当上游是Anthropic,网关对外暴露的是OpenAI格式。虽然litellm做了格式转换,但某些OpenAI特有参数可能在目标供应商那边不存在。
好在litellm提供了一个很实用的开关:drop_params。开了这个开关后,目标模型不支持的参数会被自动丢弃,而不是直接报错。官方推荐的合理配置建议如下:
litellm_settings: drop_params: true我要特别提醒的是:drop_params是个偷懒的好帮手,但也会掩盖掉参数不生效的问题。比如你想让某个模型强制输出JSON格式,如果drop_params把response_format直接丢了,你完全没感觉,结果却拿到了一大段纯文本。排查这类问题时的通用思路是:先看UI里的请求日志,确认转发到上游的真实报文和响应是什么。大多数参数兼容性问题在日志里一目了然。
4.4 数据库连接问题
如果你从SQLite切换到PostgreSQL,最常见的问题是启动顺序与健康检查。litellm容器启动时如果host上的数据库还没就绪,它可能直接报错退出。所以前面docker-compose里特意加了healthcheck和depends_on条件,这是避免此类问题的关键一步。
另一个常见问题是数据库URL里的账号密码和实际PostgreSQL初始化配置不一致。建议所有部署都从相同模板起步,不要每台服务器都凭感觉改用户名。检查的时候优先看容器日志里有没有DATABASE_URL或connect相关的报错,基本能快速定位。
4.5 模型名映射与分组混乱
模型名映射混乱是团队协作中的高频故障源。有人把model_name写成“gpt-4o”,有人写成“gpt4o”,还有人写成“gpt-4o-latest”。密钥配置好之后,请求总是404或模型不存在,原因往往只是名称不统一。
应对办法是在团队内部维护一份明确的模型清单表,包含对外名称、真实模型标识、可用模型分组。litellm也支持模型组(model_group_alias),你可以把多个模型浓缩成一个对外名。比如把两个不同供应商的gpt-4o能力都归到一个gpt-4o组名下,网关负责决策该转发给谁。管理上,我习惯在config.yaml顶部加一段注释,标明每个对外名称的负责人和用途,这样后续接手的人不至于一脸懵。
4.6 成本统计口径差异
使用过程会发现的另一个问题:litellm记账的费用是估算值,基于Token数和单价计算得出。如果一些自定义模型单价没有正确配置,成本统计会严重偏低或偏高。部分服务商的账单计费方式按时间段后置出账,估算值和最终账单可能会差距明显。
不用过度纠结精确的每分钱对账,litellm的价值在于趋势和相对比例,真正做财务核算还是以上游服务商账单为准。如果预算控制比较严格,就在网关这里把budget_duration和max_budget设置得保守一些,留点缓冲。
4.7 常见问题速查表
| 故障现象 | 可能原因 | 优先排查顺序 |
|---|---|---|
| 401 Unauthorized | 虚拟密钥无效或已被删除 | 1. 检查请求头Authorization 2. 后台查看密钥状态 |
| 404 Model Not Found | 对外模型名不在配置里 | 1. 检查model_list声明 2. 检查请求体里的model字段 3. 检查密钥的模型组权限 |
| 400 Bad Request | 参数不兼容上游模型 | 1. 查看代理日志 2. 开启drop_params 3. 根据日志调整参数 |
| 请求超时 | 上游响应慢或网关timeout太短 | 1. 检查request_timeout 2. 测试上游直连延迟 3. 开启重试或fallback |
| 429 Rate Limited | 超出密钥速率限制或上游限流 | 1. 检查虚拟密钥限流配置 2. 检查上游配额 |
| 面板无法访问 | UI服务没启动或端口没放行 | 1. 检查容器状态 2. 检查端口映射 |
| Token统计为零 | 自定义模型没配单价或没有入库 | 1. 检查配置里custom_llm_provider 2. 查看数据库连接 |
5. 我的几点使用体会
要把litellm用好,最终拼的不是功能参数背得熟,而是对团队工作流的理解。它是个网关,也是团队接入模型能力的基础设施。从最开始单人用SQLite模式跑通验证,到后来切了PostgreSQL、加了Prometheus采集,再到给各个业务线签发了带预算限制的虚拟密钥,这个演进过程值得每个准备引入网关的团队参考。
这里分享几个我实际踩过之后沉淀下来的习惯。第一,配置文件全部纳入版本管理,任何变更都走MR,这样出了模型名问题能快速回滚和diff。第二,给每个虚拟密钥增加描述备注,方便后面追溯是哪个业务方在用。第三,定期检查后台日志,看看有没有来自未知IP的请求,这个比看费用账单更能发现安全隐患。第四,如果调用了大量流式对话,压力测试时密切关注内存占用,因为长连接和流式转发需要更多资源。
还想提醒的是,litellm并不直接释放你关于“该选哪个模型”的决策责任,它真正解决的是“选好之后如何低摩擦地切换和治理”。所以引入之前,先想清楚自己团队缺的到底是什么——如果你连模型供应商都没有选好,直接上网关意义不大,先把业务跑通再说。
把这套网关引入现有项目后的真实感受是:开发节奏确实顺了很多。产品经理想换评估下来更便宜的模型时,我不需要改代码、发版本,只需要改一行配置文件、重启服务或者通过管理接口热加载配置,然后观察N天内的调用日志和成本曲线就行。建议所有对接了多于一家模型服务的项目,都认真考虑用一个类似的能力层来收口。