告别 LLM 供应商锁定 — SmartChat 的多模型 Provider 抽象层设计实践

0 阅读3分钟

前言

做 AI 应用最怕什么?供应商锁定。今天 OpenAI 涨价,明天某个国产模型效果更好,后天客户要求用私有化部署的模型……如果代码和某个 LLM 提供商深度耦合,每次切换都是一次重构。

SmartChat 通过一个 Provider 抽象层,实现了 7+ 个 LLM 提供商的无缝切换。来看看它是怎么设计的。

🔗 项目地址:smartchat.nofx.asia/

微信图片_20260212194717_45_236.png

一、问题:LLM 提供商的碎片化

目前主流的 LLM 提供商各有各的 SDK 和 API 格式:

  • OpenAIopenai SDK,/v1/chat/completions
  • Anthropic@anthropic-ai/sdk/v1/messages,完全不同的消息格式
  • 国产模型:大多兼容 OpenAI 格式,但 base URL 和模型名不同

如果每个提供商写一套调用逻辑,代码会变成这样:

// 反面教材:硬编码每个提供商
if (provider === 'openai') {
  // OpenAI 的调用逻辑
} else if (provider === 'anthropic') {
  // Anthropic 的调用逻辑
} else if (provider === 'deepseek') {
  // DeepSeek 的调用逻辑
} // ... 无限 if-else

二、SmartChat 的 Provider 抽象层

SmartChat 的核心思路是:将所有提供商归为两类 SDK(OpenAI 和 Anthropic),通过预设配置 + 统一接口消除差异

// Provider 预设配置
const PROVIDER_PRESETS = {
  openai: {
    baseURL: 'https://api.openai.com/v1',
    models: ['gpt-4o', 'gpt-4o-mini', 'gpt-3.5-turbo'],
    sdk: 'openai'
  },
  deepseek: {
    baseURL: 'https://api.deepseek.com/v1',
    models: ['deepseek-chat', 'deepseek-reasoner'],
    sdk: 'openai'  // DeepSeek 兼容 OpenAI 格式
  },
  qwen: {
    baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
    models: ['qwen-turbo', 'qwen-plus', 'qwen-max'],
    sdk: 'openai'  // 通义千问也兼容 OpenAI 格式
  },
  anthropic: {
    baseURL: 'https://api.anthropic.com',
    models: ['claude-3-5-sonnet', 'claude-3-haiku'],
    sdk: 'anthropic'
  },
  custom: {
    baseURL: '', // 用户自定义
    models: [],
    sdk: 'openai'  // 默认走 OpenAI 兼容协议
  }
};

关键洞察:绝大多数国产模型都兼容 OpenAI API 格式,所以只需要维护两套 SDK 调用逻辑(OpenAI 和 Anthropic),通过切换 baseURL 就能接入不同提供商。

三、统一的流式输出接口

不同 SDK 的流式输出格式差异很大,SmartChat 将其统一为一个 streamChat 函数:

async function streamChat(params: {
  provider: string;
  model: string;
  messages: Message[];
  apiKey: string;
  temperature?: number;
}) {
  const preset = PROVIDER_PRESETS[params.provider];

  if (preset.sdk === 'openai') {
    const client = new OpenAI({
      apiKey: params.apiKey,
      baseURL: preset.baseURL
    });

    return client.chat.completions.create({
      model: params.model,
      messages: params.messages,
      temperature: params.temperature,
      stream: true
    });
  } else if (preset.sdk === 'anthropic') {
    const client = new Anthropic({ apiKey: params.apiKey });

    return client.messages.stream({
      model: params.model,
      messages: convertToAnthropicFormat(params.messages),
      max_tokens: 4096,
      temperature: params.temperature
    });
  }
}

上层业务代码只需要调用 streamChat(),完全不关心底层用的是哪个提供商。

SmartChat 机器人设置转存失败,建议直接上传图片文件

四、自定义端点:终极灵活性

SmartChat 还支持用户配置自定义的 OpenAI 兼容端点,这意味着可以接入:

  • 本地部署的模型:Ollama、vLLM、LocalAI
  • 企业私有化部署:Azure OpenAI、AWS Bedrock(通过兼容层)
  • 任何 OpenAI 兼容的 API:各种代理、中转服务

用户只需在设置页面填入 base URL、API Key 和模型名称即可。

五、成本优化策略

多模型架构带来的一个隐藏好处是成本优化

简单问题 → 使用便宜的模型(DeepSeek、Qwen-Turbo)
复杂问题 → 使用强力模型(GPT-4o、Claude Sonnet)
嵌入向量 → 使用本地模型(零成本)

每个机器人可以独立配置模型和参数,运营者可以根据业务场景灵活调整。

六、这个设计模式的可复用性

SmartChat 的 Provider 抽象层设计模式可以直接复用到其他 AI 应用中。核心思路总结:

  1. 识别 SDK 家族:大多数提供商属于 OpenAI 兼容或 Anthropic 两个家族
  2. 预设配置驱动:用配置而非代码来区分提供商
  3. 统一接口:上层业务只依赖抽象接口
  4. 自定义端点兜底:覆盖所有长尾场景

总结

LLM 领域变化太快,今天的最优选择明天可能就不是了。SmartChat 的多模型架构不是过度设计,而是对现实的务实应对。如果你也在做 AI 应用,强烈建议从第一天就做好 Provider 抽象。

🔗 项目地址:smartchat.nofx.asia/,MIT 开源协议。