如何设计一个通用的大模型对接框架

基于企业级 RAG 项目实战,设计一个支持多供应商、自动容错、易扩展的 LLM 对接架构


一、背景与挑战

在企业级 AI 应用开发中,我们经常面临以下挑战:

  1. 多供应商接入:需要同时支持阿里云百炼、硅基流动、Ollama 本地模型等多种 LLM 供应商

  2. 稳定性要求:单个模型故障不能影响整体服务

  3. 成本控制:需要根据场景智能选择不同价位的模型

  4. 快速扩展:新增供应商时不应修改现有业务代码

  5. 统一体验:业务层无需关心底层调用细节

本文基于一个生产级 RAG(检索增强生成)项目,详细介绍如何设计一个通用的大模型对接框架。


二、架构设计概览

2.1 整体架构图

┌─────────────────────────────────────────────────────────────┐
│                     业务层 (Business Layer)                  │
│                    ChatController / Service                  │
└─────────────────────────────┬───────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   RoutingLLMService (路由服务)                │
│   • 统一入口  • 故障转移  • 健康检查  • 流式首包探测           │
└─────────────────────────────┬───────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ ModelSelector    │ │ ModelRouting     │ │ ModelHealth      │
│ (模型选择器)      │ │ Executor (执行器) │ │ Store (健康存储)  │
└──────────────────┘ └──────────────────┘ └──────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  ChatClient 接口 (策略模式)                   │
├──────────────────┬──────────────────┬──────────────────────┤
│ BaiLianChatClient│ SiliconFlowClient│ OllamaChatClient     │
│ (阿里云百炼)      │ (硅基流动)        │ (本地模型)            │
└──────────────────┴──────────────────┴──────────────────────┘

2.2 核心设计原则

原则 说明
接口隔离 业务代码只依赖抽象接口,不感知具体实现
配置驱动 所有供应商和模型通过配置管理,零代码修改
自动容错 故障自动转移,无需业务层处理
健康感知 熔断机制避免连续请求故障模型
开闭原则 对扩展开放,对修改关闭

三、核心组件实现

3.1 定义统一接口

/**
 * 聊天客户端接口 - 所有 LLM 供应商的统一抽象
 */
public interface ChatClient {
​
    /**
     * 获取服务提供商名称
     */
    String provider();
​
    /**
     * 同步聊天方法
     */
    String chat(ChatRequest request, ModelTarget target);
​
    /**
     * 流式聊天方法
     */
    StreamCancellationHandle streamChat(
        ChatRequest request,
        StreamCallback callback,
        ModelTarget target
    );
}

设计要点

  • provider() 方法用于标识供应商,支持路由分发

  • 同步和流式两种调用方式,覆盖不同场景

  • ModelTarget 封装目标模型信息,实现参数透传


3.2 路由服务:统一入口

@Slf4j
@Service
@Primary  // 标记为主要实现,注入时优先使用
public class RoutingLLMService implements LLMService {
​
    private final ModelSelector selector;
    private final ModelRoutingExecutor executor;
    private final Map<String, ChatClient> clientsByProvider;
​
    // Spring 自动注入所有 ChatClient 实现
    public RoutingLLMService(
            ModelSelector selector,
            ModelRoutingExecutor executor,
            List<ChatClient> clients) {
        this.selector = selector;
        this.executor = executor;
        this.clientsByProvider = clients.stream()
                .collect(Collectors.toMap(ChatClient::provider, Function.identity()));
    }
​
    @Override
    public String chat(ChatRequest request) {
        return executor.executeWithFallback(
                ModelCapability.CHAT,
                selector.selectChatCandidates(request.getThinking()),
                target -> clientsByProvider.get(target.candidate().getProvider()),
                (client, target) -> client.chat(request, target)
        );
    }
​
    @Override
    public StreamCancellationHandle streamChat(ChatRequest request, StreamCallback callback) {
        List<ModelTarget> targets = selector.selectChatCandidates(request.getThinking());
        // ... 流式调用逻辑
    }
}

核心能力

  1. 通过构造函数自动收集所有 ChatClient 实现

  2. 委托给 ModelSelector 选择候选模型列表

  3. 委托给 ModelRoutingExecutor 执行故障转移


3.3 模型选择器:智能调度

@Component
public class ModelSelector {
​
    private final AIModelProperties properties;
    private final ModelHealthStore healthStore;
​
    public List<ModelTarget> selectChatCandidates(Boolean deepThinking) {
        AIModelProperties.ModelGroup group = properties.getChat();
​
        // 1. 根据是否深度思考选择首选模型
        String firstChoiceModelId = resolveFirstChoiceModel(group, deepThinking);
​
        // 2. 过滤并排序候选列表
        List<AIModelProperties.ModelCandidate> enabled = candidates.stream()
                .filter(c -> c != null && !Boolean.FALSE.equals(c.getEnabled()))
                .filter(c -> !Boolean.TRUE.equals(deepThinking)
                          || Boolean.TRUE.equals(c.getSupportsThinking()))
                .sorted(Comparator.comparing(AIModelProperties.ModelCandidate::getPriority)
                        .thenComparing(AIModelProperties.ModelCandidate::getId))
                .collect(Collectors.toList());
​
        // 3. 将首选模型提升到第一位
        promoteFirstChoiceModel(enabled, firstChoiceModelId);
​
        // 4. 构建目标列表,过滤熔断状态的模型
        return buildAvailableTargets(enabled);
    }
}

调度策略

  • 支持深度思考模式智能匹配

  • 按优先级排序

  • 自动过滤熔断中的模型


3.4 路由执行器:故障转移

@Component
public class ModelRoutingExecutor {
​
    private final ModelHealthStore healthStore;
​
    public <C, T> T executeWithFallback(
            ModelCapability capability,
            List<ModelTarget> targets,
            Function<ModelTarget, C> clientResolver,
            ModelCaller<C, T> caller) {
​
        Throwable last = null;
        for (ModelTarget target : targets) {
            C client = clientResolver.apply(target);
            if (client == null) {
                continue;
            }
​
            // 检查熔断状态
            if (!healthStore.allowCall(target.id())) {
                continue;
            }
​
            try {
                T response = caller.call(client, target);
                healthStore.markSuccess(target.id());  // 标记成功
                return response;
            } catch (Exception e) {
                last = e;
                healthStore.markFailure(target.id());  // 标记失败
                log.warn("模型调用失败,切换下一个:modelId={}", target.id(), e);
            }
        }
​
        throw new RemoteException("所有候选模型均调用失败", last);
    }
}

容错机制

  • 遍历候选列表,逐个尝试

  • 成功则立即返回,失败则切换下一个

  • 实时更新健康状态


3.5 健康存储:熔断器

@Component
public class ModelHealthStore {
​
    private final ConcurrentHashMap<String, CircuitBreaker> breakers = new ConcurrentHashMap<>();
    private final int failureThreshold;
    private final long openDurationMs;
​
    public boolean allowCall(String modelId) {
        CircuitBreaker breaker = getOrCreate(modelId);
        return breaker.allowCall();
    }
​
    public void markSuccess(String modelId) {
        getOrCreate(modelId).markSuccess();
    }
​
    public void markFailure(String modelId) {
        getOrCreate(modelId).markFailure();
    }
​
    private static class CircuitBreaker {
        private int failureCount = 0;
        private long openUntil = 0;
​
        synchronized boolean allowCall() {
            if (openUntil > System.currentTimeMillis()) {
                return false;  // 熔断开启中
            }
            if (openUntil > 0) {
                // 半开状态,允许一次探测
                openUntil = 0;
                failureCount = 0;
            }
            return true;
        }
​
        synchronized void markSuccess() {
            failureCount = 0;
        }
​
        synchronized void markFailure() {
            failureCount++;
            if (failureCount >= failureThreshold) {
                openUntil = System.currentTimeMillis() + openDurationMs;
            }
        }
    }
}

熔断策略

  • 连续失败 N 次触发熔断

  • 熔断期间拒绝请求

  • 超时后进入半开状态探测


四、供应商实现示例

4.1 阿里云百炼实现

@Slf4j
@Service
@RequiredArgsConstructor
public class BaiLianChatClient implements ChatClient {
​
    private final OkHttpClient httpClient;
    private final Executor modelStreamExecutor;
    private final Gson gson = new Gson();
​
    @Override
    public String provider() {
        return ModelProvider.BAI_LIAN.getId();
    }
​
    @Override
    public String chat(ChatRequest request, ModelTarget target) {
        // 1. 获取提供商配置
        AIModelProperties.ProviderConfig provider = requireProvider(target);
​
        // 2. 构建请求体
        JsonObject reqBody = buildRequestBody(request, target, false);
​
        // 3. 发送 HTTP 请求
        Request httpRequest = new Request.Builder()
                .url(resolveUrl(provider, target))
                .post(RequestBody.create(reqBody.toString(), HttpMediaTypes.JSON))
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer " + provider.getApiKey())
                .build();
​
        try (Response response = httpClient.newCall(httpRequest).execute()) {
            if (!response.isSuccessful()) {
                throw new ModelClientException("请求失败", response.code());
            }
            return extractChatContent(parseJsonBody(response.body()));
        }
    }
​
    @Override
    public StreamCancellationHandle streamChat(
            ChatRequest request,
            StreamCallback callback,
            ModelTarget target) {
​
        Call call = httpClient.newCall(buildStreamRequest(request, target));
        return StreamAsyncExecutor.submit(
            modelStreamExecutor,
            call,
            callback,
            cancelled -> doStream(call, callback, cancelled)
        );
    }
}

4.2 硅基流动实现(OpenAI 兼容接口)

@Slf4j
@Service
@RequiredArgsConstructor
public class SiliconFlowChatClient implements ChatClient {
​
    // 结构与 BaiLianChatClient 几乎一致
    // 主要差异在于 API 端点和响应解析格式
​
    @Override
    public String provider() {
        return ModelProvider.SILICON_FLOW.getId();
    }
​
    // ... 实现细节类似
}

五、配置管理

5.1 配置类设计

@Data
@Configuration
@ConfigurationProperties(prefix = "ai")
public class AIModelProperties {
​
    /** 提供商配置 */
    private Map<String, ProviderConfig> providers = new HashMap<>();
​
    /** 聊天模型组 */
    private ModelGroup chat = new ModelGroup();
​
    /** Embedding 模型组 */
    private ModelGroup embedding = new ModelGroup();
​
    @Data
    public static class ProviderConfig {
        private String url;
        private String apiKey;
        private Map<String, String> endpoints = new HashMap<>();
    }
​
    @Data
    public static class ModelGroup {
        private String defaultModel;
        private String deepThinkingModel;
        private List<ModelCandidate> candidates = new ArrayList<>();
    }
​
    @Data
    public static class ModelCandidate {
        private String id;              // 模型标识
        private String provider;        // 对应 providers 的 key
        private String model;           // 实际 API 模型名
        private Integer priority = 100; // 优先级
        private Boolean enabled = true; // 是否启用
        private Boolean supportsThinking = false; // 是否支持思考链
    }
}

5.2 配置文件示例

ai:
  # 提供商配置
  providers:
    bailian:
      url: https://dashscope.aliyuncs.com
      api-key: sk-your-api-key
      endpoints:
        chat: /compatible-mode/v1/chat/completions
​
    siliconflow:
      url: https://api.siliconflow.cn
      api-key: sk-your-api-key
      endpoints:
        chat: /v1/chat/completions
​
    ollama:
      url: http://localhost:11434
      endpoints:
        chat: /api/chat
​
  # 路由策略
  selection:
    failure-threshold: 2        # 失败阈值
    open-duration-ms: 30000     # 熔断时长
​
  # 聊天模型配置
  chat:
    default-model: qwen3-max
    deep-thinking-model: qwen3-max
    candidates:
      - id: glm-4.7
        provider: siliconflow
        model: Pro/zai-org/GLM-4.7
        supports-thinking: true
        priority: 0             # 最高优先级
​
      - id: qwen-plus
        provider: bailian
        model: qwen-plus-latest
        priority: 1
​
      - id: qwen3-local
        provider: ollama
        model: qwen3:8b-fp16
        priority: 2

六、如何扩展新供应商

6.1 三步接入新供应商

步骤 1:在 ModelProvider 枚举中添加

public enum ModelProvider {
    BAI_LIAN("bailian"),
    SILICON_FLOW("siliconflow"),
    OLLAMA("ollama"),
    OPENAI("openai");  // 新增
​
    private final String id;
    // ...
}

步骤 2:实现 ChatClient 接口

@Slf4j
@Service
@RequiredArgsConstructor
public class OpenAIChatClient implements ChatClient {
​
    private final OkHttpClient httpClient;
    @Qualifier("modelStreamExecutor")
    private final Executor modelStreamExecutor;
​
    @Override
    public String provider() {
        return ModelProvider.OPENAI.getId();
    }
​
    @Override
    public String chat(ChatRequest request, ModelTarget target) {
        // 实现 HTTP 调用逻辑
    }
​
    @Override
    public StreamCancellationHandle streamChat(
            ChatRequest request,
            StreamCallback callback,
            ModelTarget target) {
        // 实现流式调用逻辑
    }
}

步骤 3:添加配置

ai:
  providers:
    openai:
      url: https://api.openai.com
      api-key: sk-your-key
      endpoints:
        chat: /v1/chat/completions
​
  chat:
    candidates:
      - id: gpt-4o
        provider: openai
        model: gpt-4o
        priority: 1

七、架构亮点总结

特性 实现方式 收益
统一接口 ChatClient 接口 业务层零感知
自动容错 ModelRoutingExecutor 服务高可用
智能路由 ModelSelector + 优先级 成本最优化
熔断保护 ModelHealthStore 避免雪崩
配置驱动 AIModelProperties 零代码变更
快速扩展 Spring 自动发现 新增供应商仅需 3 步

八、适用场景

本架构适用于以下场景:

  1. 企业级 AI 应用:需要同时对接多个 LLM 供应商

  2. RAG 系统:需要智能选择 Embedding、Rerank、Chat 模型

  3. 成本敏感场景:需要根据优先级自动选择性价比最优的模型

  4. 高可用要求:单点故障不能影响整体服务

  5. 快速迭代:需要频繁接入新的 LLM 供


九、总结

本文介绍了一种通用的大模型对接框架设计,核心思想是:

  1. 接口抽象:用统一的接口屏蔽供应商差异

  2. 配置驱动:用配置代替硬编码,实现灵活调度

  3. 自动容错:内置故障转移和熔断机制

  4. 开闭原则:扩展新供应商无需修改现有代码

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐