
前段时间接手了一个内部工具平台的改造被十几个大模型 API 的接入折腾得够呛。各家 SDK 有自己的请求格式认证方式五花八门token 计费单位还不一样今天这家更新了接口明天那家报了个新错误码。团队里每个开发都在自己封装 HTTP 调用重复代码一堆出了问题谁也说不清是模型的问题还是自己代码的问题。后来我把 litellm 作为统一代理网关接了进去整个接入流程才算理顺。这篇就聊聊这个项目以及我在实际部署和运维中摸出来的一些经验。litellm 本质是一个大模型 API 的代理网关把市面上主流的大模型服务商接口统一成 OpenAI 兼容格式。你只要按照 OpenAI 的规范去请求它它负责把请求翻译成目标模型真正能识别的格式再把响应转回 OpenAI 结构返回给你。除了协议转换它还内置了 API Key 管理、成本追踪、限流、负载均衡、多模型 fallback 这些生产环境必须要有的能力。适合谁用如果你手里有多个模型要接或者团队里有多个人在调模型 API又或者你被各家的 SDK 版本搞到头大litellm 都能直接上手。1. 为什么我没继续让团队直接调各家 SDK1.1 多模型接入的混乱远不止“换个接口地址”先还原一下我最早遇到的问题。项目里需要同时用三个不同家的模型一个做对话一个做 embedding还有一个做长文本总结。刚开始大家各自写代码A 同学封装了甲家的 Python SDKB 同学直接拿 HTTP 工具调乙家的接口C 同学因为丙家的文档不全干脆用了一个第三方包装库。到了联调阶段就乱了请求参数命名不一样有的叫max_tokens有的叫max_new_tokens错误处理逻辑也不一样有的返回 200 加错误码有的直接 500计费口径更乱有的按字符有的按 token有的按请求次数。更麻烦的是模型升级。某家把老模型下线了我们需要把线上流量切到新模型。如果是直连各家 SDK就得逐个改代码、重新发版。有了 litellm 之后这个切换只是在网关的配置文件里改一个模型映射服务本身不用动。这个价值在频繁调整模型选型的时候特别突出。1.2 litellm 到底在请求链路的哪一层litellm 走的是“客户端 - litellm 网关 - 各家模型服务”的链路。客户端只需要认识 OpenAI 的接口协议也就是base_url指向 litellm 的地址api_key用 litellm 生成的虚拟 key然后像调用ChatCompletion.create()一样发请求。网关拿到请求后根据你配置的model_name找到对应的上游模型把请求体做一次字段映射和格式转换然后转发给真正的模型服务商。可以把它理解成公司前台。所有访客不用关心你要找的人在几号楼几层哪个工位只要告诉前台“我要找技术部”前台帮你把人带过去。技术部内部怎么组织跟访客无关。网关也一样上游是哪家服务商、模型怎么命名、认证用什么方式对客户端全部不可见。1.3 它和直接调 SDK 或者用 LangChain 的区别有朋友问我LangChain 不也能切模型吗LangChain 确实可以做模型抽象但它更偏向应用层的编排你的代码里还是需要装一堆 provider 的依赖包而且它更多解决的是“不同的链怎么串起来”的问题不太关心 API Key 管理、预算控制、统一审计这些运维层面的事。litellm 的定位更接近基础设施。它只做一件事把上游模型 API 统一成一个标准的 OpenAI 格式接口。你不一定非要用 LangChain但你一定需要一个统一的出口。就算你最终不用 OpenAI 的模型只要你的代码是按 OpenAI SDK 写的换到 litellm 代理的任意模型上代码基本不用改。我在实际项目里就是把一个基于 OpenAI SDK 写的老服务直接改了base_url下游模型换成了别的家请求照常跑通。2. 从一个最小配置开始先跑通再谈优化2.1 安装环节没有那么多花活litellm 是基于 Python 的安装用pip直接装。需要注意的是它区分两个安装目标单独的 SDK 安装和带代理的安装。如果只是想在 Python 代码里调用 litellm 的客户端能力装基本包就行如果要跑网关服务必须装带proxy的版本。pip install litellm[proxy]国内网络环境下建议指定国内镜像源加速。装完之后可以看下版本litellm --version我遇到过一个坑如果机器上之前装过比较老版本的 openai 库litellm 启动时可能会报依赖冲突。建议在干净的环境里装或者用虚拟环境隔离。我自己习惯用uv管理环境创建环境然后装依赖干净利落。2.2 写第一份 config.yamllitellm 网关的启动核心是配置文件。第一次用不需要搞得很复杂先把两家模型配置进去看看效果。下面这份配置是个可以直接抄的模板我把敏感信息全部用环境变量占位model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY api_base: https://api.openai.com/v1 - model_name: claude-3-5-sonnet litellm_params: model: anthropic/claude-3-5-sonnet api_key: os.environ/ANTHROPIC_API_KEY - model_name: embedding-all litellm_params: model: openai/text-embedding-3-small api_key: os.environ/OPENAI_API_KEY litellm_settings: drop_params: true set_verbose: false注意这里的model_name是暴露给客户端的名字可以随便起客户端请求的时候就用这个名字。而litellm_params.model里的openai/或anthropic/前缀是 litellm 内部用来判断走哪家 provider 路由的标识。比如openai/gpt-4o-mini表示调 OpenAI 的模型anthropic/claude-3-5-sonnet表示调 Anthropic 的模型。drop_params: true这个配置建议从第一天就打开。它的作用是如果客户端传了一个参数是当前模型不支持的直接丢弃而不是报错。比如 Claude 不接受某些 OpenAI 特有的参数开着这个开关网关就自动把多余参数吃掉避免请求失败。这个开关我在生产环境一直开着帮我省了不少事。2.3 启动网关并验证连通性配置文件写好之后启动命令很简单litellm --config config.yaml --port 4000 --host 0.0.0.0--host 0.0.0.0很关键默认情况下网关可能只监听本机回环地址如果不开这个参数其他机器访问不到。我第一次部署就是没加这个参数结果本机 curl 正常另外一台服务器的请求死活连不上排查了半天才发现是监听地址的问题。启动之后看到类似Uvicorn running on http://0.0.0.0:4000的日志就说明起来了。验证方式可以直接用 curl也可以写一段 Python 脚本。curl http://localhost:4000/health/live返回正常的话再用 OpenAI SDK 测一下真实调用。我用的是 1.x 版本的 openai 库写法如下from openai import OpenAI client OpenAI( api_keysk-anything, base_urlhttp://localhost:4000 ) resp client.chat.completions.create( modelgpt-4o-mini, messages[ {role: user, content: 你好介绍一下你自己} ] ) print(resp.choices[0].message.content)api_key随便填一个非空字符串就能过认证因为 litellm 默认在没有配置master_key的情况下不对虚拟 key 做校验。当然这只是本地测试用真上生产必须把 key 体系建起来这个在后面讲。2.4 模型路由和 fallback 配置模型路由是 litellm 比较实用的能力。客户端可以只请求一个逻辑模型名网关根据策略把请求分发到多个物理模型上。比如你希望对话请求主要走便宜快速的模型但允许一个备选模型在失败时顶上可以这样配置model_list: - model_name: chat-main litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY rpm: 300 - model_name: chat-main litellm_params: model: azure/gpt-4o api_key: os.environ/AZURE_API_KEY api_base: os.environ/AZURE_API_BASE api_version: 2024-06-01同一个model_name配多个条目litellm 会自动做负载均衡。压力大的时候把请求分摊到多个模型上某个模型挂了就自动重试到下一个可用模型。你可以在router_settings里控制重试次数和超时。实际效果是有一次我把主模型配错了环境变量请求自动 fallback 到了备选模型客户端无感直到我看监控日志才发现主模型一直是失败的。3. 核心功能逐个拆解Key 管理、成本追踪、限流3.1 虚拟 Key 管理权限边界一次说清如果你的网关只给自己用不配 key 也能跑。但只要团队超过两个人或者你不想让所有人的请求都“裸奔”在公网上强烈建议把虚拟 key 机制用起来。虚拟 key 就是由 litellm 自己生成的 key客户端请求时带着它网关校验通过才放行。它跟真实的上游 API Key 完全隔离客户端永远不知道真正的 key 是什么。生成方式有几种命令行、HTTP 接口、管理后台都可以。curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-1234 \ -H Content-Type: application/json \ -d {models: [gpt-4o-mini], max_budget: 20, duration: 30d}这里Authorization里的sk-1234是你在启动 litellm 时通过--master_key或环境变量LITELLM_MASTER_KEY配置的管理员 key。上面的示例里max_budget表示这个 key 在有效期内的总花费上限duration表示有效期 30 天models限制了它能访问的模型范围。生成成功后返回一个api_key这个 key 只会显示这一次后面再想看也看不到了所以要妥善保存。客户端拿到这个 key 之后就把api_key换成它base_url还是指向网关。这样团队里每个人都有自己的 key谁的调用量异常、谁超预算了一目了然。3.2 成本追踪的真实用法litellm 默认记录每次请求的 token 消耗和预估费用存在本地 SQLite 数据库里。你可以在管理后台页面看到实时数据也能通过 API 查询。查询某个 key 的花费curl http://localhost:4000/usage/key?api_keyyour-virtual-key查询全量记录curl http://localhost:4000/spend/logs -H Authorization: Bearer sk-1234这里有个细节litellm 内置了一张各模型的价格表但它也有没收录的模型。如果某次请求完成后发现 spend 统计数据不对或者很多请求没统计到成本大概率是这个模型的价格没被识别。这时候需要你在配置里手动指定模型价格在model_list的条目里加上cost_per_token或max_tokens_per_request之类的字段。我第一次接一个第三方私有化部署的模型时查了半天文档最后才发现 litellm 不知道这个模型的价格请求是通了但成本全是 0。后面手动加了价格字段才统计上。成本追踪这个功能对开发环境尤其重要。很多团队不限制开发环境的用量结果有人在测试代码里写了死循环一晚上调了几万次大模型接口月底账单数字吓人。上了 litellm 之后给每个开发环境 key 设好预算超了就自动拒绝这个事故直接被扼杀在摇篮里。3.3 限流和负载均衡生产环境不能跳过限流配置可以从两个维度做模型维度和 key 维度。模型维度是指某个模型每秒最多接收多少请求或多少 tokenkey 维度是指某个虚拟 key 每秒最多请求多少。模型维度在model_list里配置rpmrequests per minute每分钟请求数和tpmtokens per minute每分钟 token 数model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY rpm: 500 tpm: 60000key 维度在/key/generate时传入rpm和tpm字段。当请求超过限制时litellm 会返回 429 状态码。建议客户端对 429 做指数退避重试这是标准做法。负载均衡前文已经提过同一个model_name配多组上游就能自动实现。litellm 的默认策略是每次从可用列表中随机选一个也可以通过设置routing_strategy改成round-robin或者least-busiest。这个能力在应对大流量场景时非常有用但前提是你对模型服务的并发能力有真实了解别把限流数值拍脑袋。3.4 流式输出和额外参数透传很多人用大模型 API 都会开流式输出litellm 完整支持streamTrue的请求转发响应也是标准的 SSE 流。我测试过中文长文生成客户端按 OpenAI 流式格式解析没有问题。如果你在日志里看到响应卡住不结束多半是上游模型服务超时了需要在配置里调大timeout。默认超时时间不长生产环境建议至少给到 300 到 600 秒。litellm 还允许透传一些 OpenAI 标准之外的参数。比如某家模型支持top_kOpenAI 格式里没有这个字段你可以在请求体的extra_body里带上网关会把它透传给上游。这一点在对接国产模型时尤其好用各家总有自己独特的采样参数不能因为统一协议就把它们丢掉。4. 部署上线时我踩过的几个关键坑4.1 SQLite 还是 PostgreSQL这是个选择litellm 默认用 SQLite 存数据。单机、小团队用完全没问题。但当你有多个网关节点的需求或者虚拟 key 数量超过几千、日志量上来之后SQLite 会成为瓶颈尤其并发写入时会出现锁冲突。生产环境建议接 PostgreSQL。配置方式是在环境变量里指定数据库连接串export DATABASE_URLpostgresql://user:passwordhost:5432/litellmlitellm 自身有数据库迁移能力启动时会自动建表。我后来把仓库里所有 key、日志、预算都搬到了 PostgreSQL查询速度和稳定性明显提升。如果你一开始就用 SQLite后期数据量大了想迁移litellm 官方也提供了迁移脚本不过最好还是决策早一点免得后面推倒重来。4.2 用 systemd 跑网关比 nohup 靠谱得多我见过很多同学用nohup litellm --config ... 启动服务进程一挂就没人知道机器重启后服务也不会自动起来。生产环境建议直接用 systemd。下面给一份可以直接改的 unit 文件[Unit] DescriptionLiteLLM Proxy Afternetwork.target [Service] Userlitellm Grouplitellm WorkingDirectory/opt/litellm EnvironmentDATABASE_URLpostgresql://... EnvironmentLITELLM_MASTER_KEYsk-你的管理key ExecStart/usr/local/bin/litellm --config /opt/litellm/config.yaml --port 4000 --host 0.0.0.0 Restartalways RestartSec5 [Install] WantedBymulti-user.target写好之后systemctl daemon-reload然后systemctl enable litellmsystemctl start litellm。Restartalways 保证了进程挂了自动拉起。我遇到过上游 DNS 解析临时出问题导致网关崩溃的情况由于配置了自动重启服务在半分钟内就恢复了客户端受到影响的时间很短。4.3 Docker 部署方案如果你用的是 Docker Compose 管理集群litellm 官方仓库里有镜像可以直接用。下面是一个简化版的 compose 配置version: 3.9 services: litellm: image: ghcr.io/berriai/litellm:main-latest ports: - 4000:4000 volumes: - ./config.yaml:/app/config.yaml environment: - DATABASE_URLpostgresql://... - LITELLM_MASTER_KEYsk-... command: [--config, /app/config.yaml, --host, 0.0.0.0]注意镜像里的入口命令可能和本地安装的litellm命令行为不完全一致启动参数用--host 0.0.0.0以数组形式传进去更稳当。这个方案适合已经上了容器编排的团队配好一次之后扩展节点只是加个副本的事。4.4 密钥管理要有点洁癖配置文件里尽量不要出现明文真实 API Key。那些上游服务的 key 和你的 master key都通过环境变量或者密钥管理服务注入。litellm 的os.environ/XXX语法就是为了配合环境变量设计的可以用得很彻底。另外如果你的上游是各类云厂商的模型服务尽量把网关部署在靠近服务商的区域内网减少公网绕行的延迟。如果公司有合规要求也可以把 litellm 放在私有子网里客户端通过内网访问。毕竟网关手里攒着多个云厂商的 key一旦这台机器被打穿风险不小。做好安全组规则、只放行必要的端口是基本操作。4.5 监控和日志别等出了事才看litellm 自带一个管理页面默认地址是/ui如果你配置了 master key页面登录时需要填。在这个页面里可以看到请求量、模型调用分布、失败率、花费这些关键指标。我平时看的最多的就是/spend和/usage每次给老板汇报 AI 成本直接截这个页面的图比什么都直观。日志方面默认是控制台输出。日志级别可以在litellm_settings里通过set_verbose: true打开比较详细的输出但生产环境这个开关一般不建议开日志量会很大磁盘容易被打满。建议把日志重定向到日志采集系统比如 Loki 或者 ELK再把关键字告警接上。我第一次上线时没接监控某天下午模型服务商大面积故障网关日志里全是超时重试我愣是过了半个小时才从聊天里得知系统变慢了。后面接上告警5 分钟之内就能发现问题。5. 常见问题排查与应急预案5.1 请求返回 401 但 key 明明是对的出现这个情况先检查请求头里的Authorization是不是真的带上了。如果客户端用的是 OpenAI SDKapi_key参数传成None可能会让 SDK 自动尝试读环境变量里的某个 key结果那个 key 是无效的也会报 401。另一个原因是网关启动了--master_key而你没有给客户端分配虚拟 key相当于拿了一个不存在的 key 去访问当然会被拒绝。解决办法就是调用/key/generate生成一个可用的 key。5.2 模型提示不存在如果你按照文档配置了模型但请求时报模型不存在先确认请求里的model字段是不是和你配置的model_name完全一致注意大小写和连字符。之前有同学把配置里的模型名写成gpt-4o-mini客户端请求时传的是gpt-4O-mini一个大写 O 的差异让网关找不到对应项报错跟模型不存在一模一样。这种问题在本地测试时不太容易暴露因为从日志里看比较难一眼发现。另外如果你用了环境变量语法os.environ/XXX要确认这个环境变量在 litellm 进程里真的存在。我遇到过 systemd 环境下环境变量没配全的情况配置里引用了一个不存在的变量litellm 启动时并不一定报错但调用时就会失败。排查方式也很简单在服务里打一个测试请求然后看日志里日志级别为 error 的具体信息。5.3 响应格式兼容问题所有模型经过 litellm 转换后都会尽量对齐 OpenAI 的响应结构但不同模型的字段总有一些细微差异。比如某些国产模型可能不返回usage字段或者finish_reason的取值不完全一致。客户端代码不要假设所有字段都存在解析时要做容错。一个比较实用的技巧是在 litellm 配置里给某个模型加上response_format相关的参数或者让客户端不要过度依赖某个响应字段。如果你在开发时发现某个模型经过 litellm 后返回的内容和你直连时不一致可以先停掉 litellm直接用原生 SDK 或 API 请求一次对比差异点。大多数情况下是请求参数被drop_params丢掉了或者是响应字段的兼容映射问题。litellm 社区对常见模型的兼容性维护得很勤快升级到最新版本往往能解决这类问题。5.4 网关本身成为瓶颈怎么办litellm 是 Python 写的单进程性能虽然不能跟 Go 写的高性能网关比但在日常百分之几十 QPS 的场景下完全够用。如果你的并发量真的非常大可以做多实例部署前置一个负载均衡器把请求分发给多个 litellm 实例。因为 litellm 的配置和 key 数据都放在独立的数据库里多实例之间状态可以共享扩容是很直接的事。我实测过一个比较典型的场景内部系统同时有几十个用户在调用每个用户都在持续流式生成内容litellm 的 CPU 占用基本稳定在单核 20% 以下。所以对绝大多数团队来说litellm 的性能不会是短板真正需要关注的是上游模型服务的稳定性。5.5 遇到奇怪问题时的通用排查路径整理一套我自己的排查顺序看 litellm 启动日志里有没有 warn 或 error 级别信息。用 curl 直接请求 litellm 接口排除客户端代码原因。看数据库里有没有对应请求的记录如果有说明网关收到并处理了请求。把set_verbose: true临时打开重放一次请求看完整链路日志。对照 litellm 官方文档排查配置字段是否有拼写错误。升到最新版本很多兼容性坑都是老版本才有。这套流程帮我解决了至少八成的问题。剩下的两成基本都和上游模型服务商最近更新有关——原因是它们改了些接口行为而 litellm 还没来得及做兼容。这种时候先降级到已知稳定的模型或者在配置里针对那个模型单独调整参数不必死磕。6. 落地推广时的一点体会litellm 这类工具最大的价值不在于它有多炫酷而在于它把团队里“每个人各自对接模型”的混乱局面收敛成一个清晰的边界。开发不需要关心模型供应商是谁、SDK 是什么版本、价格怎么算只管像调用 OpenAI 一样调用就行了管理员只需要在一个地方配置模型、控制预算、查看消耗。这种“上游变化对下游透明”的架构方式在模型更新换代极快的当下非常实用。如果你的团队还在被多模型接入折磨与其写一堆封装代码不如直接部署一个 litellm 网关试试。先跑最小配置再逐步解锁虚拟 key、成本追踪这些能力。有个小建议尽早把虚拟 key 的管理接入到你现有的权限系统里比如通过脚本调用/key/generate接口在用户开通权限时自动发放一个 key这样整个接入流程会更顺滑也不会出现 key 满天飞没人管的情况。