14. 如何设计一个支持多模型、多 Provider 的统一接入层?

整理多模型、多 Provider 统一接入层的架构设计与扩展策略。

简单回答

统一接入层的核心是定义一个标准化的内部 API 协议,然后为每个 Provider 实现一个适配器(Adapter),在适配器中处理请求/响应格式转换、认证、错误码映射和特性差异。关键挑战在于不同 Provider 的能力差异(工具调用格式、多模态支持、流式协议等)如何在统一接口中优雅处理。

详细解释

为什么需要统一接入层?

实际生产中,一个系统可能同时对接 OpenAI、Anthropic、Google、自建模型等多个 Provider。如果业务代码直接调用各家 SDK,代码中会充斥着 if provider == "openai" ... elif provider == "anthropic" ... 这种分支逻辑。新增或替换一个 Provider 需要改大量业务代码,维护成本很高。

统一接入层的目标是让业务层完全不感知底层 Provider 的差异,只和一个标准接口交互。

架构设计

核心是 Adapter 模式。定义一个内部标准协议(通常参考 OpenAI 的 Chat Completions API 格式,因为它已经成了事实标准),包括 messages 结构、tool 定义、response 格式等。然后为每个 Provider 写一个 Adapter,负责:

请求转换:把内部标准格式转成 Provider 的专有格式。比如 OpenAI 和 Anthropic 的 tool calling 格式不同、system message 的处理方式不同、多模态消息的图片编码方式不同。

响应转换:把 Provider 的响应转成内部标准格式。包括 content 字段提取、usage 统计映射、finish_reason 映射等。

流式适配:不同 Provider 的 SSE 数据格式不完全一样(字段名、事件格式、结束标记),Adapter 要做格式统一。

错误映射:不同 Provider 的错误码和错误信息各不相同,需要映射成统一的错误码体系。比如 OpenAI 返回 429 表示限流,Anthropic 返回 529 表示过载,都要映射成内部的"限流"错误。

认证管理:每个 Provider 的 API Key 管理方式不同(单 Key、组织 Key、OAuth 等),Adapter 统一处理。

能力差异处理

这是最难的部分。不同模型的能力不完全一致:有些支持 tool calling 有些不支持、有些支持多模态有些不支持、context window 长度不同、支持的参数不同(有些有 top_k 有些没有)。

处理方式通常是在模型注册表(Model Registry)中维护每个模型的能力矩阵:支持的功能列表、context window 大小、支持的参数列表、定价信息等。业务层在发请求前可以查询能力矩阵,确认目标模型是否支持需要的功能。如果不支持,可以选择降级处理(比如不支持 tool calling 的模型就不传 tools)或路由到其他模型。

SDK 设计

给业务层提供一个简洁的 SDK。使用方式类似:

from llm_gateway import LLMClient

client = LLMClient()
response = client.chat(
    model="gpt-4",  # 或 "claude-3-opus" 或 "deepseek-chat"
    messages=[...],
    tools=[...],
    stream=True
)

底层自动选择对应的 Adapter、处理格式转换、管理认证。对业务方来说完全透明。

实际考量

版本管理要注意。各 Provider 的 API 会升级,新版本可能改变格式或行为。Adapter 需要做版本适配,能同时支持新旧版本的平滑过渡。

测试策略上,每个 Adapter 都需要有完善的集成测试。可以用 mock server 做本地测试,定期跑真实 Provider 的 smoke test 确保 Adapter 没有因为 Provider 端的变更而 broken。

已有方案

LiteLLM 是这个领域最成熟的开源方案,支持 100+ 模型的统一接口,基本可以开箱即用。如果业务场景比较标准,直接用 LiteLLM 比自建省很多工作。自建的优势是可以做更深度的定制——比如自定义路由逻辑、集成内部的认证系统和计费系统、处理特殊的业务格式等。

面试时可以这样答

统一接入层的核心设计是 Adapter 模式。定义一套内部标准协议——通常参考 OpenAI 的格式因为它已经是事实标准,然后为每个 Provider 实现一个 Adapter 做请求响应格式转换、认证管理和错误码映射。业务层只和标准接口交互,完全不感知底层 Provider。

最难处理的是能力差异。不同模型支持的功能不一致——tool calling 格式不同、有些支持多模态有些不支持、context window 大小不同。解决方式是维护一个 Model Registry,记录每个模型的能力矩阵,业务层发请求前可以查询。

流式输出的适配也是一个坑,各家的 SSE 格式不完全一样,需要在 Adapter 层统一。

开源方案中 LiteLLM 比较成熟,如果场景标准可以直接用。自建的优势是能做更深度的定制,比如和内部的路由、计费、认证系统集成。实际工程中很多团队是先用 LiteLLM 快速搭起来,后续再根据需要自建。

常见追问

  1. 不同 Provider 的 tool calling 格式差异具体有哪些?怎么做统一抽象?
  2. Provider 的 API 升级导致 Adapter 失效怎么处理?怎么做到灵活升级?
  3. 如果要支持自建的 vLLM 模型,Adapter 需要额外处理什么?