避免切换 LLM 时代码重写的架构方案
实战指南展示如何设计 LLM 无关的代码架构,降低供应商更换成本,避免重复工程投入。
实战指南展示如何设计 LLM 无关的代码架构,降低供应商更换成本,避免重复工程投入。
你知道那种感觉吗——当你刚刚完成把整个代码库从 GPT-4 迁移到 Claude 时,重新编写 API 调用,修复响应解析,更新流式逻辑——突然 Google 发布了一个新的 Gemini,基准测试让其他所有东西看起来都像 1995 年的计算器?
是的。我经历过。多次。
在半年内经历第三次迁移后,我坐下来想:为什么我要重写集成代码,当唯一改变的是我请求的 HTTP 端点?请求是 JSON。响应是 JSON。所有模型都是输入消息、输出文本。为什么切换提供商感觉像是在行驶中的汽车上更换引擎?
这就是我开始关注 LM-Proxy 的原因——它改变了我架构由 LLM 驱动的应用程序的方式。让我带你了解它是什么、为什么重要,以及如何在 5 分钟内设置它。
以下是由 LLM 驱动的项目的典型演变过程:
第 1 个月:"我们就用 OpenAI。一个提供商,一个 SDK,很简单。"
第 3 个月:"Claude 对我们的摘要任务实际上更好。让我们也加上 Anthropic。" 现在你有两个不同的 SDK、两个身份验证流程、两种响应格式,以及一个困扰你梦境的 if/else。
第 5 个月:"Gemini Flash 对于简单查询便宜得多。让我们把简单的东西路由到那里。" 你的路由逻辑现在分散在三个不同的文件中,你到处都有特定于提供商的错误处理,新开发人员花了两天时间才弄清楚哪个 API 密钥放在哪里。
第 7 个月:有人问"我们能为敏感数据添加本地模型吗?"你开始更新你的 LinkedIn。
根本原因很简单:每个 LLM 提供商都决定发明自己的 API 格式,尽管它们在根本上都做相同的事情。OpenAI 的格式成为了事实上的标准,但 Anthropic、Google 和其他公司各有各的怪癖、身份验证方案和流式协议。
你真正需要的是一个反向代理——一个单一的端点,在外部使用 OpenAI 的 API 格式,但在内部可以与任何提供商交互。
LM-Proxy 是一个轻量级的、与 OpenAI 兼容的 HTTP 代理/网关,用 Python 和 FastAPI 构建。一句话总结:
你的应用与一个 API(OpenAI 格式)交互。LM-Proxy 与其他所有人交互。
它支持 OpenAI、Anthropic、Google(AI Studio 和 Vertex AI)、本地 PyTorch 模型以及任何使用 OpenAI API 格式的系统——全部通过单一的 /v1/chat/completions 端点。需要 Python 3.11+。
但"另一个 LLM 网关"并不是让它有趣的地方。这才是:
无 Kubernetes。无 Redis。无 Kafka。无 47 个微服务架构。它就是一个 Python 包:
pip install lm-proxy
一个 TOML 配置文件。一个命令启动:
lm-proxy
就这样。你可以在月费 5 美元的 VPS、Docker 容器内运行它,甚至直接将其嵌入到你的 Python 应用中作为库(因为它基于 FastAPI 构建,你可以导入它并将其作为子应用挂载)。整个核心设计极其简洁——无臃肿、无企业级复杂性用于一个不需要的问题。
这是一个完整的、可工作的配置,将 GPT 请求路由到 OpenAI,Claude 到 Anthropic,Gemini 到 Google:
host = "0.0.0.0"
port = 8000
[connections.openai]
api_type = "open_ai"
api_base = "https://api.openai.com/v1/"
api_key = "env:OPENAI_API_KEY"
[connections.anthropic]
api_type = "anthropic"
api_key = "env:ANTHROPIC_API_KEY"
[connections.google]
api_type = "google_ai_studio"
api_key = "env:GOOGLE_API_KEY"
[routing]
"gpt*" = "openai.*"
"claude*" = "anthropic.*"
"gemini*" = "google.*"
"*" = "openai.gpt-4o-mini" # fallback
[groups.default]
api_keys = ["my-team-api-key-1", "my-team-api-key-2"]
从头到尾读这个配置。你在 30 秒内理解了它,对吧?无 YAML 缩进噩梦,无 200 行的 JSON 数据块——只是清晰的 TOML,语义明显。(顺便说一下,也支持 YAML、JSON 和 Python 配置格式。)
env: 前缀从环境变量(或 .env 文件)中提取秘密,所以你的 API 密钥永远不会进入版本控制。
[routing] 部分是魔法发生的地方。键是与客户端发送的模型名称匹配的 glob 模式。.* 后缀意味着"按原样将模型名称传递给提供商。" 所以当你的客户端请求 claude-sonnet-4-5-20250929 时,LM-Proxy 将其完全转发到 Anthropic 的 API。无映射表、无模型 ID 转换文件——它就可以工作。
你也可以将模式固定到特定的模型:
[routing]
"custom*" = "local.llama-7b" # Any "custom*" request → local Llama
"gpt-3.5*" = "openai.gpt-3.5-turbo" # Pin to a specific model
"*" = "openai.gpt-4o-mini" # Everything else → cheap fallback
这意味着你的客户端代码永远不会改变。想尝试新模型?更新配置中的一行。想 A/B 测试两个提供商?添加一个路由规则。想废弃一个模型?将模式重定向到其他东西。零代码更改。
这是使 LM-Proxy 生产就绪而不仅仅是玩具的功能。
LM-Proxy 维护两层 API 密钥:
虚拟(客户端)API 密钥 ——你的用户/服务用来与代理进行身份验证的密钥
提供商(上游)API 密钥 ——OpenAI、Anthropic 等的真实 API 密钥,保持隐藏
# Premium users get everything
[groups.premium]
api_keys = ["premium-key-1", "premium-key-2"]
allowed_connections = "*"
# Free tier gets OpenAI only
[groups.free]
api_keys = ["free-key-1"]
allowed_connections = "openai"
# Internal tools get local models only
[groups.internal]
api_keys = ["internal-key-1"]
allowed_connections = "local"
你的上游 API 密钥永远不会暴露给客户端。你可以轮换它们而无需更新任何客户端配置。你可以创建细粒度的访问层——高级用户获得 Claude Opus,免费用户获得 GPT-4o-mini,内部工具使用本地模型。全部在一个配置文件中管理。
它甚至支持外部身份验证——你可以针对 Keycloak、Auth0 或任何 OIDC 提供商验证虚拟 API 密钥:
[api_key_check]
class = "lm_proxy.api_key_check.CheckAPIKeyWithRequest"
method = "POST"
url = "http://keycloak:8080/realms/master/protocol/openid-connect/userinfo"
response_as_user_info = true
use_cache = true
cache_ttl = 60
[api_key_check.headers]
Authorization = "Bearer {api_key}"
你现有的 OAuth 令牌自动变成 LLM API 密钥。如果内置验证器不适配,你可以编写一个自定义的——只需一个 Python 函数,接受 API 密钥字符串并返回组名。
SSE 流式处理开箱即用。无论哪个提供商实际生成它们,你的客户端都会得到实时的逐令牌响应。代理以透明的方式处理格式转换——Anthropic 的流式格式在到达你的客户端之前变成了 OpenAI 兼容的 SSE 事件。
LM-Proxy 不仅仅是一个独立的服务——它也是一个可导入的 Python 包。由于它基于 FastAPI 构建,你可以将其挂载在你现有的应用内,在集成测试中使用它,或与其他 ASGI 中间件组合。如果你不想要,无需运行单独的进程。
让我走过一个具体的场景。你在构建一个使用 LLM 的 SaaS 产品。你想要 GPT-4o 进行复杂推理,Claude Sonnet 进行长文档处理,Gemini Flash 进行廉价分类。
步骤 1:安装
pip install lm-proxy
步骤 2:设置环境变量
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=AI...
步骤 3:创建 config.toml
host = "0.0.0.0"
port = 8000
[connections.openai]
api_type = "open_ai"
api_base = "https://api.openai.com/v1/"
api_key = "env:OPENAI_API_KEY"
[connections.anthropic]
api_type = "anthropic"
api_key = "env:ANTHROPIC_API_KEY"
[connections.google]
api_type = "google_ai_studio"
api_key = "env:GOOGLE_API_KEY"
[routing]
"gpt*" = "openai.*"
"claude*" = "anthropic.*"
"gemini*" = "google.*"
"*" = "google.gemini-2.0-flash"
[groups.backend]
api_keys = ["backend-service-key"]
allowed_connections = "*"
[groups.frontend]
api_keys = ["frontend-widget-key"]
allowed_connections = "google" # cheap models only
步骤 4:启动
lm-proxy
步骤 5:从你的应用使用
from openai import OpenAI
client = OpenAI(
api_key="backend-service-key",
base_url="http://localhost:8000/v1"
)
# Complex reasoning → GPT-4o
response = client.chat.completions.create(
model="gpt-5.2",
messages=[{"role": "user", "content": "Analyze this contract..."}]
)
# Long document → Claude
response = client.chat.completions.create(
model="claude-opus-4-6",
messages=[{"role": "user", "content": "Summarize this 100-page report..."}]
)
# Quick classification → Gemini Flash (cheap)
response = client.chat.completions.create(
model="gemini-2.0-flash",
messages=[{"role": "user", "content": "Is this email spam? ..."}]
)
一个客户端。一个基础 URL。三个提供商。明天,当有人发布一个便宜 50% 的模型时,你在 config.toml 中更改一行并重启服务器。你的应用代码保持不变。
显而易见的问题:"这与 LiteLLM 有什么不同?"
坦白说——LiteLLM 是这个领域的 800 磅大猩猩。拥有 33k+ 的 GitHub stars、2000+ 个支持的 LLM、AWS Marketplace 列表以及花费跟踪仪表板、护栏、缓存、速率限制、SSO 和 MCP 集成等功能,它是一个成熟的企业平台。它也同时提供 Python SDK 和 HTTP 代理服务器,所以从架构上看它覆盖类似的领域。
那么为什么你会选择 LM-Proxy 呢?
理由和你选择 Flask 而不是 Django,或 SQLite 而不是 PostgreSQL 的理由一样。并不是所有东西都需要完整的企业堆栈。
选择 LM-Proxy 当: 你想要一个轻量级的、易于嵌入的代理,占用空间小、Python 配置可扩展,并且你不需要 90% 的企业功能。它适合小团队、个人项目,或当你想要一个可以通过在下午读完源代码而完全理解的网关。
选择 LiteLLM 当: 你需要企业级的花费跟踪、管理 UI、几十个集成、护栏、缓存以及开箱即用的 100+ 个提供商和集成的支持。
Portkey 等其他替代品甚至更加企业化。LM-Proxy 有意占据"刚好够用的网关"利基——足够强大用于生产,足够简单使得你的配置文件成为文档。
应当指出——LM-Proxy 已经覆盖了比你从"轻量级"工具所期望的更多地面:
结构化日志 ——一个可插拔的日志系统,拥有 JsonLogWriter 和 LogEntryTransformer(跟踪令牌、持续时间、组、连接、远程地址),加上 lm-proxy-db-connector 附加组件,用于通过 SQLAlchemy 写入日志到 PostgreSQL、MySQL、SQLite 和其他数据库
负载均衡 ——有一个示例配置,使用 Python 配置格式在多个 LLM 服务器间随机分发请求
请求处理程序 ——一个类似中间件的系统,用于在请求到达上游提供商之前拦截它们,启用审计和头部操作等横切关注点
Vertex AI 支持 ——Google Cloud 的 Vertex AI 在更简单的 AI Studio API 之外得到支持,拥有专用的配置示例
话虽如此,该项目仍在演进中(最新发布:v3.0.0),少数几件事仍在我个人的愿望清单上:
使用分析仪表板 ——日志和数据库基础设施是坚实的,但一个内置 UI 用于可视化花费和使用将是锦上添花
通配符模型扩展 ——/v1/models 的 expand_wildcards 模式已计划但尚未实现——现在你需要在路由配置中显式列出模型
自动提供商故障转移 ——如果 OpenAI 返回 5xx,自动重新路由到 Anthropic。同一提供商的实例间负载均衡已经存在,但跨提供商故障转移将完成画面
按设计的可扩展性哲学意味着大多数这些可以作为附加组件添加而无需接触核心——数据库连接器已经很好地演示了这种模式。代码库是 MIT 许可的,足够小可以在下午内读完。
如果你与多个 LLM 提供商合作(或认为将来可能会),停止编写特定于提供商的集成代码。将 LM-Proxy 设置为网关,将所有服务指向它,永远不用再想 API 格式差异。
pip install lm-proxy
你试过 LM-Proxy 或类似的 LLM 网关吗?你对多提供商 LLM 集成的方法是什么?在评论中分享你的经验。
某些评论可能仅对登录的访客可见。登录以查看所有评论。
如需更多操作,你可以考虑阻止此人和/或举报滥用。