litellm 实战:统一接口调用 100+ 大模型,详解 SDK 与代理网关 litellm 这个名字最近在大模型应用开发者圈子里出现频率很高。很多人第一次接触它是在某个项目里被“接第二家大模型 API”这件事弄烦了之后——各家模型的请求格式不一样、鉴权逻辑不一样、计费口径也不一样硬切的话业务代码得改一遍。litellm 做的就是把这堆差异收编到一套接口后面统一格式调用 OpenAI、Anthropic、AWS Bedrock、Cohere、Google Gemini 等 100 多家模型服务既能以 Python/Node SDK 的方式直接用也能部署成独立的代理网关对外提供一个 OpenAI 兼容接口。这篇文章我把它的设计思路、核心玩法、踩坑记录和典型排查过程都整理出来希望能帮你少走点弯路。1. 内容整体设计与思路拆解1.1 为什么需要一层“统一接口”现在的 AI 应用开发很少只绑一家模型。你可能在 OpenAI 上验证效果又因为成本切到别的模型或者某家大厂模型在处理中文任务上表现更好想局部换成它再或者要同时对比多个供应商的输出质量。问题在于这些供应商的 API 设计没有统一标准。OpenAI 用的是messages[{role: user, content: ...}]这种聊天补全结构Anthropic 的 Messages API 参数名、系统提示词写法都不同Cohere 又走了另一套聊天接口AWS Bedrock 更激进整个请求是 client 调用的 JSON 结构不同基础模型还各自封装。如果业务代码直接调用这些 API每接入一个模型就要写一套请求构造、鉴权、错误解析、重试逻辑。你可能会说不就是改个请求体吗但真正进到生产环境还有流式响应格式、工具调用的 field 名称、超时和限流策略、费用统计这些复杂细节工作量一点都不小。litellm 的做法很直接在上游封装各家的真实 API向下统一暴露为一个 OpenAI 兼容格式。你的业务代码只需要认识一套消息结构、一套 base_url、一套鉴权方式剩下的事情交给 litellm 去翻译、转发、回传。1.2 核心设计路线SDK 与代理网关并行litellm 有两套使用模式很多人刚接触时容易混淆。第一套是 SDK 模式安装完直接from litellm import completion然后传入modelopenai/gpt-4o或modelanthropic/claude-3-5-sonnet。这种方式适合单机脚本、快速验证、在自己后端服务里直接做模型调用层。SDK 模式的好处是零额外部署写代码时切换模型只需要改字符串。第二套是代理网关模式部署一个独立服务启动后暴露一个http://localhost:4000的 OpenAI 兼容端点。业务代码不需要安装 litellm只需要把 OpenAI SDK 的base_url指向这个代理再传入 litellm 生成的虚拟密钥即可。所有模型的真实密钥保存在代理端业务端看不到也改不了。这两种模式不是替代关系。小项目、个人开发SDK 模式就够用。但当你给团队提供模型接入能力、需要集中管理预算和权限、想统一记录所有调用日志时代理网关几乎是必选项。它为“接入外部的人”和“内部掌握模型资源的人”之间画了一条线。我的习惯是项目初期模型少、调用方就是自己SDK 直接调一旦要开放给前端或其它后端服务立刻切到代理网关。因为密钥管理这件事越晚做越麻烦。1.3 配置文件驱动的参数抽象litellm 在设计上有一个很关键的地方大量配置都集中在config.yaml里而不是散落在代码中。模型路由、API 密钥映射、预算额度、重试策略、fallback 顺序都在同一处管理。这样带来的好处很直接修改模型版本或调整某家服务的密钥时不需要重新发版。比如你发现某个模型近期不稳定想临时把流量切到备选模型改配置文件再 reload 代理服务即可。对于运维来说这也意味着可以把配置纳入版本管理方便回滚和审计。另外参数抽象意味着模型名称本身可以自定义。你完全可以把一个笨拙的模型路由名映射为my-chat-model业务方不必关心底层到底是哪家模型。业务代码只认这个名字底层怎么换都不影响它。2. 核心细节解析与实操要点2.1 安装与最简调用litellm 基于 Python依赖元比较多建议装在一个干净的虚拟环境里别往系统 Python 里硬塞。安装方式pip install litellm代理服务模式则多装一个包pip install litellm[proxy]最基础的调用是这样import litellm from litellm import completion response completion( modelopenai/gpt-4o, messages[{role: user, content: 你好请简单介绍一下自己}], ) print(response.choices[0].message.content)注意在模型名后面加了openai/前缀。这是 litellm 的一个重要规则前缀表示走哪家供应商的真实 API。你在代码里写modelanthropic/claude-3-5-sonnet-20241022时实际请求是用 Anthropic 的鉴权信息和接口地址发出的。如果没有前缀litellm 会按 OpenAI 默认处理。所以建议从一开始就写明前缀避免后面混淆。2.2 统一消息结构litellm 对外暴露的格式遵循 OpenAI 风格基础消息类型有四种system系统提示设置模型行为比如“你是一个严谨的翻译助手”。user人类输入请求内容。assistant模型历史回复多轮对话时回传。tool工具调用的结果回传。这套结构与各家内部原生结构当然不是一一对应的litellm 负责在翻译层做转换。比如 Anthropic 的系统提示词在原生 API 中是单独的system参数而 litellm 会把它融合进 OpenAI 风格的消息数组。你只写一套代码不用管后端是哪家模型。工具调用function calling也类似。OpenAI 的工具调用参数是tools和tool_choicelitellm 对主流模型做了适配。实际项目中只要供应商支持工具调用按 OpenAI 风格写一般都能正常工作个别模型能力差异导致的兼容问题我在第五节会给出排查思路。2.3 模型名映射规则与自定义别名litellm 内部维护了一张庞大的“模型名到真实服务地址”的映射表。你不需要知道某家模型的真实 endpoint 细节只要用 litellm 认识的名称即可。常用示例供应商完整调用名说明OpenAIopenai/gpt-4oOpenAI 官方 APIAzure OpenAIazure/gpt-4o需在配置中指定api_base等Anthropicanthropic/claude-3-5-sonnet-20241022Claude 新版本模型Googlegemini/gemini-1.5-proGemini 系列AWS Bedrockbedrock/anthropic.claude-3-5-sonnet-v2:0Bedrock 上的 ClaudeOllamaollama/llama3.1本地模型适合测试环境注意这个名字不总是固定的版本升级后旧名称也不会失效但新模型要按当时文档里的称呼来用。生产环境里比较稳妥的做法是在配置文件中自定义别名model_list: - model_name: my-chat litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY业务端请求时只写modelmy-chat。这样模型版本换代时业务代码一行不用动改配置即可。2.4 流式输出、超时与重试流式输出是聊天类产品的刚需。litellm 对流式的支持比较成熟用法与 OpenAI SDK 保持一致response completion( modelopenai/gpt-4o, messagesmessages, streamTrue, ) for chunk in response: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end)实际使用中我发现不同供应商的流式返回节奏差异挺大。有的模型会先吐 reasoning 内容再吐正式回复如果你在业务端直接拼接delta.content可能会把思维链过程也展示给用户。处理方式是留意delta.reasoning_content这类单独字段或者统一用 litellm 调用结果再封装一层只提取正文字段。超时与重试可以统一配置不必为每个请求单独处理litellm.timeout 30 litellm.num_retries 3重试逻辑有一点要提醒网络超时重试通常安全但如果超时发生在服务端已经接收到请求并且开始生成内容时重试可能会产生重复计费。关键业务最好在应用层做幂等控制而不是完全依赖客户端的自动重试。2.5 异步调用与并发控制服务端场景下异步 API 几乎是必选项因为同时有多个用户请求等待模型响应时同步调用会大量占用线程。litellm 提供acompletion异步方法import asyncio from litellm import acompletion async def main(): response await acompletion( modelopenai/gpt-4o, messages[{role: user, content: 用一句话总结异步调用}], ) print(response.choices[0].message.content) asyncio.run(main())并发控制也需要重视。各家模型 API 都有 RPM/TPM 限制不加控制时代理会在限流边缘疯狂重试反而加剧问题。litellm 支持max_parallel_requests、rpm、tpm配置可以在代理或客户端层面做限速。我建议至少在网关层设置一个总并发上限防止慢模型拖垮整个服务。3. 实操过程与核心环节实现3.1 部署代理网关代理网关是 litellm 在生产环境中的主力形态。以下是我常用的部署过程。先准备一个config.yaml最小可运行版本长这样model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY litellm_settings: drop_params: true num_retries: 2 request_timeout: 30 general_settings: master_key: sk-your-master-key database_url: os.environ/DATABASE_URL启动代理litellm --config config.yaml --port 4000general_settings.database_url建议一开始就配上。它负责持久化虚拟密钥、预算、调用日志。如果不配置代理也能跑但密钥和用量记录都只存在内存里服务一重启全部清空。生产环境里这个库非常关键。3.2 通过 OpenAI SDK 接入代理代理启动后业务端根本不需要安装 litellm直接使用 OpenAI Python SDK 即可from openai import OpenAI client OpenAI( api_keysk-your-virtual-key, base_urlhttp://localhost:4000 ) response client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 你好}], ) print(response.choices[0].message.content)这里的api_key不是真实模型供应商的密钥而是 litellm 代理生成的虚拟密钥。数据库里记录了这把虚拟密钥对应的真实密钥映射关系和预算限额。业务端即使把密钥泄露了攻击者也拿不到任何一家大模型厂商的真实 Key因为代理只认虚拟密钥虚拟密钥本身没有任何上游调用能力。3.3 虚拟密钥、预算管理与团队接入代理网关最有价值的操作是创建虚拟密钥并分配预算。用 master key 发起请求curl -X POST http://localhost:4000/key/generate \ -H Authorization: Bearer sk-your-master-key \ -H Content-Type: application/json \ -d { max_budget: 20, budget_duration: 30d, model_list: [gpt-4o], user: team-a }返回结果中会有一个key字段这就是给团队 A 的虚拟密钥。该密钥在 30 天内最多消费 20 美元且只能访问gpt-4o这个模型。这种做法的实际价值在于你把模型预算下放到团队而不是所有人都持有一个可能无限消费的真实密钥。有一次我给一个前端接入模型能力对方在调试时打了大量测试请求如果没有预算限制一个月账单可能直接爆掉。加上虚拟密钥预算后用完就停省心很多。3.4 多模型 fallback 与自动切换生产环境里单个模型偶尔会限流或者宕机litellm 支持通过fallbacks把请求自动切换到备选模型。litellm_settings: fallbacks: [ {model_name: gpt-4o, fallbacks: [claude]}, ]当gpt-4o因为 429、500 或超时失败时代理自动把这条请求转给claude处理。这个机制在关键业务中很实用但有一个经验要点两个模型的能力和成本差异可能很大无条件切换会导致用户得到完全不同的回答质量甚至部分依赖 model 特定参数的业务逻辑会失效。生产环境里最好只对“通用对话”这类请求启用 fallback特殊任务仍然锁定模型。3.5 用量统计与可观测性litellm 本身带有 cost tracking记录每次调用的 token 数和费用。配合数据库持久化可以通过管理接口查询curl -X GET http://localhost:4000/spend/logs \ -H Authorization: Bearer sk-your-master-key得到的是结构化 JSON我通常会把它接到内部日志系统每天跑一个汇总任务输出各团队、各模型的消费报表。这一步对预算管理和成本优化非常重要。很多团队用 litellm 半个月后才发现某个冷门模型虽然单价便宜但因为调用量大实际总费用远超预想。没有消费统计这种问题根本发现不了。另外 litellm 支持 Prometheus 监控指标让运维面板同时展示请求量、延迟、错误码分布。生产环境接入后可以快速定位是哪家模型拖慢了整体响应时间。3.6 实际项目的接入过程复盘我用一个模拟项目来串一下整个流程。项目代号叫“某跨平台系统”需求是让内部多个业务线都能调用 LLM 能力但各家真实验证方式完全由中台统一掌管。中台部署 litellm 代理网关配置三家模型OpenAI、Claude、本地 Ollama。为每条业务线各自生成虚拟密钥并设置月度预算。业务线接入时只需知道代理地址和自己的虚拟密钥代码里使用 OpenAI SDK 调用即可。某条业务线需要流式输出直接在 SDK 里传streamTrue网关自动转换为对应模型的流式格式。中台通过数据库记录和 Prometheus 指标跟进用量。整个过程里最耗时间的不在 litellm 本身而在梳理业务线的权限矩阵和预算模型。先把“谁可以用哪个模型、一个月最多花多少钱”定清楚部署配置反而是快事。4. 常见问题与排查技巧实录4.1 认证失败403 与 401这类错误几乎每个用 litellm 的人都会遇到。403 或者 401 的典型原因有几个。真实密钥手误。检查环境变量是否真的带上了例如echo $OPENAI_API_KEY如果为空就要看是否把密钥写进了.env文件而没有加载。litellm 不自动读取.env需要额外加from dotenv import load_dotenv; load_dotenv()。模型名前缀与密钥不匹配。比如配置里写的是anthropic/claude-3-5-sonnet但api_key设置的是openai/gpt-4o的密钥。此时 litellm 会用 OpenAI 密钥去请求 Anthropic必然认证失败。这种问题数据库日志里很容易看到请求发到了 Anthropic 的 endpoint但带的 key 是 sk- 开头的 OpenAI 格式。虚拟密钥过期。代理生成的虚拟密钥可以设置过期时间到期后请求会返回 401。排查时先确认虚拟密钥状态再检查数据库记录。4.2 模型名不识别与输入格式报错提示Model not found或者Invalid model name时多半是 litellm 的模型映射表里没有这个名字。两种解决方式使用 litellm 官网模型列表里能查到的准确名称。在代理配置的model_list中自定义一个别名把真实名映射过去。我在本地测试环境常用自定义别名把ollama/llama3.1映射为local-llama方便统一测试逻辑。4.3 上下文长度超限与 token 溢出提示上下文超限时第一反应不是调大模型的 max tokens而是检查请求里带了多大的历史上下文。很多问题来自业务代码不断地把聊天记录全量塞给模型堆积几轮后 token 数直接爆表。litellm 提供drop_params配置项可以把当前模型不支持的参数自动丢弃减少因参数过多导致的报错。但更根本的做法是在业务层维护消息压缩逻辑超过一定长度就把早期的对话摘要化或者只保留最近几轮。4.4 流式请求中途断连流式响应在长文本生成时容易断连尤其是跨供应商代理转发后任何一环的超时都可能导致客户端连接中断。我踩过的坑主要有三个代理层超时设置太短模型还没生成完代理自己先断开了。建议把request_timeout调大流式场景下更依赖的是 read timeout。客户端读取超时设置太短。OpenAI SDK 有默认超时对流式生成可能不够需要显式调大。网络中间层因为长时间没有数据包而断开。解决办法是确保代理层和客户端都启用了 keep-alive 机制或者把超时配置到一个能覆盖最慢模型生成时间的值。4.5 密钥管理混乱导致的权限失控很多团队一开始让所有人都用同一个真实密钥接入后来有人抱怨“为什么我的请求失败了”一查是某位同事把密钥泄露到了前端代码攻击者刷光了当月的额度。litellm 的虚拟密钥机制就是为了避免这种问题。每个接入方一把独立密钥能限制模型范围、预算额度和过期时间。即使一把泄露了影响面也被限定在可控范围内。你需要做的只是吊销这把虚拟密钥而不是重新申请真实密钥并影响所有人。我从实际使用中得到的一条重要经验是真实密钥在业务代码中出现的次数应该为零所有业务端请求都应该只掌握虚拟密钥并且尽量在代理后面再加一层内网访问控制。4.6 代理模式下数据库连接异常配置了database_url后代理启动时如果连不上数据库除了报错之外还可能导致虚拟密钥校验失败。检查以下几点数据库服务是否只允许特定 IP 访问而代理部署在别的机器上。数据库连接池是否过小请求高峰时连接被占满。表结构是否被旧版本 litellm 创建过升级后数据库迁移没执行。一旦发现连不上数据库代理通常会自动退回到内存模式。此时表面上还能用但虚拟密钥和预算信息全部丢失容易出现“密钥突然失效”的诡异现象。排查时记得看代理日志里有没有“falling back to in-memory”之类的警告。5. 一些值得留意的边界litellm 虽然方便但它终究是对着一百多个不断变化的 API 做适配的项目。上游 API 升级、字段废弃、模型参数变动都会影响它的翻译层。所以生产环境里不要盲目升级 litellm 版本最好先在测试环境跑一遍核心模型调用链路再放量。遇到版本升级后功能异常优先查看项目更新日志确认是否有对应后台模型的适配变更。另外litellm 的“统一”不代表“能力完全一致”。在 OpenAI 上支持的某个参数可能到了 Anthropic 模型上就直接忽略上下文窗口大小、默认温度策略也都各有差异。如果你在跨模型切换业务必须把“模型能力差异表”记录清楚避免某个请求在 A 模型表现正常、在 B 模型上因为不支持某些能力而静默降级。实际使用里很少有人一开始就把 litellm 所有功能都用上。个人建议的顺序是先跑通单模型调用再配置虚拟密钥和预算然后逐步加 fallback、监控、日志导出。别一上来就把所有模型都填进配置那样排查问题时会很痛苦。litellm 带给团队的核心价值不是省掉几行请求构造代码而是把“模型接入”这件事从研发手里抽出来变成中台可控、预算可管、日志可查的标准能力。接入一个新模型时后端只需要加一段配置业务方只需要知道自己拿到的虚拟密钥和模型别名。这套模式跑顺之后整个团队的模型使用成本和质量都会变得可视、可控。