怎么用一套代码调用 GPT、Claude、Gemini 等多个模型?3 种方案实测避坑

5 阅读1分钟

上个月我接了个活儿,甲方要做一个文档智能处理平台,核心逻辑是:简单的摘要任务走便宜模型,复杂的合同走 Claude Opus 4.7,多模态识别走 Gemini 3.1 Pro。听起来很合理对吧?但真写起来我人傻了——三家 API 的 SDK 初始化方式不一样,请求参数名不一样,错误码体系也不一样,光是写适配层就折腾了两天半。

直接回答标题问题:要用一套代码统一调用多个大模型 API,2026 年主流有三种方案——自己封装适配层、用 LiteLLM 这类开源库、或者直接走 OpenAI 兼容协议的 API 聚合平台。 我三种都试过,下面把踩的坑和实测结果全写出来。

为什么会出现这个问题

根源很简单:各家大模型厂商的 API 规范不统一。

OpenAI 用 messages 数组 + role/content 结构,Anthropic 的 Claude 原生 API 用的是 anthropic.messages.create(),参数名叫 max_tokens 但行为和 OpenAI 的不完全一致。Google 的 Gemini 更离谱,原生 SDK 是 google.generativeai,连鉴权方式都不一样(API Key vs OAuth)。

你要是只用一个模型,随便写。但项目里要根据任务类型动态切换模型,代码就会变成这样:

if model.startswith("gpt"):
 # OpenAI 的逻辑
 client = OpenAI(api_key=os.getenv("OPENAI_KEY"))
 resp = client.chat.completions.create(...)
elif model.startswith("claude"):
 # Anthropic 的逻辑
 client = Anthropic(api_key=os.getenv("ANTHROPIC_KEY"))
 resp = client.messages.create(...)
elif model.startswith("gemini"):
 # Google 的逻辑,又是另一套
 ...

三个 if 分支,三套错误处理,三套 retry 逻辑。后面再加 DeepSeek V4、Qwen3、GLM-5?这个 if-elif 能写到天荒地老。

graph TD
 A[你的业务代码] -->|OpenAI SDK| B[OpenAI API]
 A -->|Anthropic SDK| C[Claude API]
 A -->|Google SDK| D[Gemini API]
 A -->|各家SDK| E[DeepSeek / Qwen / GLM ...]
 
 style A fill:#ff6b6b,color:#fff
 B -.->|不同鉴权| F[维护 N 套 Key]
 C -.->|不同参数| G[维护 N 套适配逻辑]
 D -.->|不同错误码| H[维护 N 套 retry]

方案一:自己封装统一适配层

最"正统"的做法。我一开始就是这么干的,写了个 UnifiedLLMClient 类,内部用策略模式分发。

class UnifiedLLMClient:
 def __init__(self):
 self.openai_client = OpenAI(api_key=os.getenv("OPENAI_KEY"))
 self.anthropic_client = Anthropic(api_key=os.getenv("ANTHROPIC_KEY"))
 # ... 还有 Google、DeepSeek 的
 
 def chat(self, model: str, messages: list, **kwargs):
 if "gpt" in model or "o3" in model:
 return self._call_openai(model, messages, **kwargs)
 elif "claude" in model:
 return self._call_anthropic(model, messages, **kwargs)
 # ... 继续 elif

优点:完全可控,想怎么处理错误就怎么处理。

缺点:维护成本太高了。4 月 22 号 DeepSeek V4 预览版上线,我得去看他们新 API 有没有改参数。上周 Anthropic 更新了一版 SDK,tool_use 的返回格式微调了,又得改。这活儿干了两周我就不想干了。

还有个坑:Anthropic 的 messages API 不接受 system 作为 messages 数组里的 role,要单独传 system 参数。我一开始没注意,直接把 OpenAI 格式的 messages 透传过去,返回了这个:

anthropic.BadRequestError: 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages: roles must alternate between \"user\" and \"assistant\", but found \"system\" role"}}

修是修好了,但每个模型都有这种小差异,防不胜防。

方案二:用 LiteLLM 开源库

LiteLLM 是个 Python 库,号称一个 completion() 函数搞定 100+ 模型。试了一下,确实省事不少:

from litellm import completion

# 调 GPT-5.5
response = completion(
 model="gpt-5.5",
 messages=[{"role": "user", "content": "你好"}]
)

# 调 Claude Opus 4.7,只改 model 名
response = completion(
 model="claude-opus-4.7",
 messages=[{"role": "user", "content": "你好"}]
)

代码层面确实统一了,但实际跑起来问题不少。

第一个坑:你还是得管理 N 个 API Key。LiteLLM 只是帮你做了参数转换,底层还是分别调各家的 API。环境变量要配 OPENAI_API_KEYANTHROPIC_API_KEYGEMINI_API_KEY……我数了一下项目里有 7 个不同的 Key。

第二个坑:版本兼容。4 月初我升级 LiteLLM 到最新版,结果 DeepSeek 的调用挂了,报了个:

litellm.exceptions.BadRequestError: DeepSeekException - {"error":{"message":"Unrecognized request argument supplied: tool_choice","type":"invalid_request_error"}}

查了半天发现是 LiteLLM 给 DeepSeek V3.2 透传了 tool_choice 参数,但 DeepSeek 那个版本还不支持。得手动在调用时加 drop_params=True

第三,LiteLLM 的 proxy server 模式(自建网关)倒是能解决 Key 管理问题,但你得自己部署、自己运维。我试着用 Docker 跑了一个,内存占用 400MB 起步,对于我这种小项目有点杀鸡用牛刀。

总结一句话:适合个人项目快速验证,团队生产环境用的话运维成本不低。

方案三:走 OpenAI 兼容协议的聚合平台

这是我目前在用的方案。原理很简单:很多 API 聚合平台都实现了 OpenAI 兼容协议,你只需要用 OpenAI SDK,改一下 base_urlapi_key,就能调用各家模型。

from openai import OpenAI

# 一个 client 搞定所有模型
client = OpenAI(
 api_key="your-key",
 base_url="https://api.ofox.ai/v1"
)

# 调 Claude Opus 4.7
response = client.chat.completions.create(
 model="claude-opus-4.7",
 messages=[{"role": "user", "content": "分析这份合同的风险点"}],
 max_tokens=4096
)

# 调 GPT-5.5,同一个 client,只改 model
response = client.chat.completions.create(
 model="gpt-5.5",
 messages=[{"role": "user", "content": "总结这段文字"}],
 max_tokens=1024
)

这类平台有好几家,OpenRouter 收 5.5% 手续费,Together AI 主要做开源模型推理,ofox.ai 是 0% 加价直接对齐各厂商官方价格。我选了 ofox 主要是因为团队管理后台能看到每个人调了哪些模型、花了多少钱,月底对账不用翻 N 个平台。

graph LR
 A[你的业务代码] -->|OpenAI SDK| B[聚合平台网关]
 B -->|官方通道| C[GPT-5.5]
 B -->|官方通道| D[Claude Opus 4.7]
 B -->|官方通道| E[Gemini 3.1 Pro]
 B -->|官方通道| F[DeepSeek V4]
 
 style B fill:#4ecdc4,color:#fff

优点:代码最简洁,一个 Key 一个 SDK,模型随便切。新模型上线平台那边适配好了你直接改 model 名就行。

缺点:多了一层网关,理论上会增加延迟。实测下来 P95 大概多 15-30ms,对于大模型动辄几百毫秒到几秒的响应时间来说基本可以忽略。还有就是你得信任这个平台——API Key、请求内容都经过它。

一个我没预料到的好处:错误处理统一了。不管底层是哪个模型,返回的错误格式都是 OpenAI 兼容的,429 就是 429,不用针对每家写不同的 catch 逻辑。

三种方案对比

维度自己封装LiteLLM聚合平台
代码改动量大,每加一个模型都要写适配中,换 model 名就行但要配 Key小,改 base_url 一次搞定
Key 管理N 个 KeyN 个 Key1 个 Key
新模型接入速度自己写,看心情等库更新,通常 3-7 天平台适配,通常 1-2 天
额外延迟00(本地库)15-30ms
运维成本低(但代码维护高)中(proxy 模式要自己部署)
适合场景只用 1-2 个模型个人项目快速验证团队生产环境

我的最终选择

三种方案我都用过一段时间。结论是:如果你的项目只用一个模型,别折腾,直接用官方 SDK。要切换 2 个以上的模型,方案三最省心。

我现在的项目架构是:开发阶段用 LiteLLM 快速试各种模型的效果,确定模型组合之后,生产环境走聚合平台的 OpenAI 兼容接口。开发灵活,上线稳定。

有一点我也不确定是不是最佳实践:我在代码里把 base_url 放在环境变量里,这样万一某天要换平台或者切回官方直连,改个环境变量就行,不用动代码。目前跑了一个多月没出过问题,长期稳定性还要再观察。

核心思路就一个:别让 API 差异污染你的业务逻辑。不管用哪种方案,把模型调用抽象成一层,业务代码只关心"我要用什么模型、传什么 prompt、拿什么结果",怎么调、怎么鉴权、怎么处理错误,都封在下面。这个道理说起来简单,但我见过太多项目把 if model == "gpt" 写满了业务层,后面换模型的时候痛不欲生。