团队里同时在用GPT-4o、Claude、Qwen三个模型,每个模型的API格式都不一样,代码里一堆if-else判断用哪个SDK。后来发现一个更好的方案:所有模型都通过OpenAI兼容API格式暴露,代码只维护一套,换模型只改一个参数。这篇文章分享这个方案的实现思路和实际经验。

为什么是OpenAI格式

大模型领域的API格式目前是"OpenAI一家独大"的局面。虽然各家的API细节不同,但核心接口(chat completions)的结构惊人地一致:system/user/assistant角色、messages数组、model参数、stream开关。这意味着只要一个服务把内部格式转换成OpenAI格式,所有OpenAI SDK的代码都能直接用。

统一API格式的好处:

  • 代码维护成本低:一套SDK代码,不用适配每个模型的API差异;
  • 切换模型方便:改一个model参数就能换模型,不需要改业务逻辑;
  • A/B测试简单:同一个接口不同model参数就能对比不同模型的效果;
  • 供应商锁定风险低:随时可以从OpenAI切换到其他模型提供商;

开源方案对比

LiteLLM是最成熟的方案,支持100+模型提供商,一个Python包搞定所有适配。它的核心功能是把各种模型的API格式统一转换成OpenAI格式,你只需要配置API Key和模型映射关系;

Ollama内置了OpenAI兼容API,专门针对本地部署的模型。访问/v1/chat/completions就能用OpenAI SDK调用本地模型;

vLLM的OpenAI兼容服务适合高并发场景。它在底层做了PagedAttention等优化,推理性能比Ollama高一个量级,但部署也更复杂;

One API是国内开发者做的,支持Azure、国内各家大模型(文心一言、通义千问、智谱等),有Web管理界面,适合团队使用;

切换后端只需改两行

from openai import OpenAI

# 切换OpenAI
client = OpenAI(api_key="sk-xxx")

# 切换Ollama —— 改两行
client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"
)

# 切换vLLM
client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="dummy"
)

# 切换LiteLLM网关
client = OpenAI(
    base_url="http://localhost:4000/v1",
    api_key="anything"
)

# 调用代码完全一样,不需要改任何东西
response = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[{"role": "user", "content": "你好"}]
)

这套代码在OpenAI、Ollama、vLLM、LiteLLM上都能跑,只需要改base_urlapi_key。这就是OpenAI兼容API的核心价值——业务代码和模型提供商解耦。

用LiteLLM搭建统一网关

安装和配置

pip install litellm

配置文件config.yaml

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_API_KEY}
  - model_name: claude
    litellm_params:
      model: anthropic/claude-sonnet-4-20250514
      api_key: ${ANTHROPIC_API_KEY}
  - model_name: qwen
    litellm_params:
      model: openai/qwen-turbo
      api_base: https://dashscope.aliyuncs.com/compatible-mode/v1
      api_key: ${DASHSCOPE_API_KEY}

启动服务

litellm --config config.yaml --port 4000

负载均衡和故障转移

LiteLLM支持多API Key轮询和故障转移——配置两个Key后自动轮询,一个Key触发rate limit自动切换到另一个:

model_list:
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_KEY_1}
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_KEY_2}

流式输出兼容性

流式输出是各家API差异最大的地方。好消息是OpenAI兼容格式的SSE(Server-Sent Events)基本一致:

stream = client.chat.completions.create(
    model="qwen2.5-7b",
    messages=[{"role": "user", "content": "写一首诗"}],
    stream=True
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

这段代码在所有OpenAI兼容的后端上都能正常流式输出。唯一的差异是各家模型的生成速度不同——本地7B模型可能比GPT-4o慢,但数据格式完全兼容。

注意事项和踩坑

模型参数不完全兼容。比如Claude不支持response_format参数,Gemini的stop_sequences和OpenAI的stop参数格式不同。LiteLLM做了大部分适配,但偶尔还是会遇到不支持的参数,需要在请求里过滤掉;

Token计数方式不同。OpenAI用tiktoken计数,其他模型各有各的分词器。统一网关的成本追踪可能和实际计费有出入,重要场景以模型提供商的实际计费为准;

Function Calling格式差异。虽然都是function calling,但各家对tool schema的支持程度不同。有些模型不支持嵌套的JSON Schema,有些对enum字段的处理有差异。在统一网关里做tool schema的兼容性检查很重要;

错误码不统一。OpenAI返回429表示rate limit,但有些模型返回503或自定义错误码。统一网关需要做错误码映射,让业务代码能统一处理;

写在最后

OpenAI兼容API已经是事实上的行业标准。与其为每个模型写适配代码,不如在API层做一次格式统一。LiteLLM、Ollama、vLLM这些开源方案让这件事变得非常简单。如果你的团队同时使用多个模型,强烈建议搭一个统一API网关。