同时接入多个国内大模型 API 的统一网关方案

发布时间:2026/6/28 5:28:02
同时接入多个国内大模型 API 的统一网关方案 做 AI 应用开发最头疼的不是调哪个模型而是怎么同时调 10 个模型还不乱。每个厂商 API 格式不同、鉴权方式不同、计费规则不同、SSE 流式协议也各写各的。你写了 10 套适配代码之后光是维护就已经筋疲力尽。这篇文章给出一个完整的统一网关方案让你用一套协议、一个 Key、一份账单同时接入国内所有主流大模型。一、问题场景你的代码是不是也长这样如果你同时接入了 DeepSeek、通义千问、豆包、文心一言四个模型你的代码大概率是这样的# 现状每接一个模型就写一套逻辑# DeepSeek —— OpenAI 兼容resprequests.post(https://api.deepseek.com/chat/completions,headers{Authorization:fBearer{deepseek_key}},json{model:deepseek-chat,messages:[{role:user,content:prompt}]})# 通义千问 —— DashScope 协议resprequests.post(https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation,headers{Authorization:fBearer{qwen_key}},json{model:qwen-plus,input:{messages:[{role:user,content:prompt}]}})# 豆包 —— OpenAI 兼容但有差异max_tokens 字段名不同resprequests.post(https://ark.cn-beijing.volces.com/api/v3/chat/completions,headers{Authorization:fBearer{doubao_key}},json{model:ep-20240601,messages:[{role:user,content:prompt}]})# 文心一言 —— 需要先拿 access_token再调用token_resprequests.post(fhttps://aip.baidubce.com/oauth/2.0/token?grant_typeclient_credentialsclient_id{ak}client_secret{sk})access_tokentoken_resp.json()[access_token]resprequests.post(fhttps://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token{access_token},json{messages:[{role:user,content:prompt}]})四个模型四种鉴权方式静态 Key / OAuth2 / AKSK四种请求格式四种响应格式。这还只是文字对话场景算上视频生成、图片生成、向量 Embedding复杂度更高。业务代码和模型厂商耦合致死。换一个模型改代码厂商 API 升级改代码新增一个模型又是一套适配逻辑。二、统一网关方案核心思想解决思路一句话在业务代码和模型厂商之间插入一个网关层由网关来做协议翻译和路由分发。┌──────────────────────┐ │ 你的业务代码 │ │ │ │ POST /v1/chat/completions │ Authorization: Bearer 平台Key │ {model: deepseek-v4,messages:[...]} └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ 统一网关层 │ │ │ │ ① 鉴权校验平台 Key │ │ ② 路由模型→通道→上游│ │ ③ 适配OpenAI→厂商原生│ │ ④ 计费实时扣 Token │ │ ⑤ 转发SSE 流式透传 │ └──────────┬───────────┘ │ ┌────────────────┼────────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ DeepSeek │ │ 通义千问 │ │ 豆包 │ │ (OpenAI) │ │(DashScope)│ │ (OpenAI) │ └──────────┘ └──────────┘ └──────────┘对业务代码来说它只需要知道调用的模型名和输入的消息完全不用关心这个模型背后是哪个厂商、用的什么协议、Key 是什么。所有复杂度被网关收敛。三、方案一自建网关的五个核心模块如果你有专门的工程团队、需要高度定制可以选择自建。以下是五个核心模块的实现要点。3.1 协议适配器这是工作量最大的模块。核心思路是适配器模式每个厂商一个 Adapter实现三个方法。// Adapter 接口定义publicinterfaceModelAdapter{// ① 把 OpenAI 格式请求转为厂商原生请求ObjecttoProviderRequest(ChatRequestopenaiRequest,ChannelConfigchannel);// ② 把厂商响应转回 OpenAI 格式ChatResponsetoOpenAIResponse(ObjectproviderResponse);// ③ 把厂商 SSE 事件转成 OpenAI 兼容的 SSE chunkStringtoOpenAISSEChunk(StringproviderSSELine);}以通义千问 DashScope 适配器为例publicclassDashScopeAdapterimplementsModelAdapter{OverridepublicObjecttoProviderRequest(ChatRequestreq,ChannelConfigchannel){// OpenAI 格式 → DashScope 格式MapString,ObjectdashscopeReqnewHashMap();dashscopeReq.put(model,channel.getProviderModelName());dashscopeReq.put(input,Map.of(messages,req.getMessages()));MapString,ObjectparamsnewHashMap();params.put(result_format,message);dashscopeReq.put(parameters,params);returndashscopeReq;}OverridepublicChatResponsetoOpenAIResponse(ObjectproviderResponse){// DashScope 响应 → OpenAI 格式MapString,Objectresp(MapString,Object)providerResponse;MapString,Objectoutput(MapString,Object)resp.get(output);ListMapString,Objectchoices(ListMapString,Object)output.get(choices);MapString,Objectchoicechoices.get(0);MapString,Objectmessage(MapString,Object)choice.get(message);ChatResponsechatRespnewChatResponse();chatResp.setChoices(List.of(newChoice(0,newMessage(message.get(role).toString(),message.get(content).toString()),stop)));MapString,Objectusage(MapString,Object)resp.get(usage);chatResp.setUsage(newUsage(((Number)usage.get(input_tokens)).intValue(),((Number)usage.get(output_tokens)).intValue(),((Number)usage.get(total_tokens)).intValue()));returnchatResp;}OverridepublicStringtoOpenAISSEChunk(StringproviderSSELine){// DashScope SSE 格式 → OpenAI SSE 格式if(providerSSELine.startsWith(data:)){// 解析 DashScope 的 output.text 转为 OpenAI 的 delta.contentreturnproviderSSELine;// 简化处理实际需要 JSON 转换}returnproviderSSELine;}}适配器注册表用工厂模式管理所有适配器。publicclassAdapterRegistry{privateMapString,ModelAdapteradaptersnewHashMap();publicAdapterRegistry(){adapters.put(openai_compatible,newOpenAICompatAdapter());adapters.put(dashscope,newDashScopeAdapter());adapters.put(anthropic,newAnthropicAdapter());adapters.put(baidu_qianfan,newQianfanAdapter());adapters.put(zhipu,newZhipuAdapter());// 新厂商只需要在这里注册一个 Adapter}publicModelAdaptergetAdapter(StringprotocolType){returnadapters.getOrDefault(protocolType,adapters.get(openai_compatible));}}新增一个厂商只需要写一个 Adapter 类不改动主流程代码。3.2 模型路由表路由是网关的大脑。核心数据结构模型 → 通道 → 上游地址。数据库设计简化版-- 模型定义表CREATETABLElx_model_label(idINTPRIMARYKEY,label_nameVARCHAR(64),-- 暴露给业务方的模型名如 deepseek-v4model_typeVARCHAR(32),-- chat / embedding / image / videostatusTINYINTDEFAULT1);-- 通道表连接模型和上游CREATETABLElx_channel(idINTPRIMARYKEY,channel_nameVARCHAR(64),-- 通道名称model_label_idINT,-- 关联模型endpointVARCHAR(255),-- 上游 API 地址protocol_typeVARCHAR(32),-- openai_compatible / dashscope / anthropic / qianfanapi_keyVARCHAR(255),-- 厂商 API Key加密存储weightINTDEFAULT1,-- 负载权重statusTINYINTDEFAULT1);路由逻辑① 业务方请求 modeldeepseek-v4 ② 查 lx_model_label → 得到 model_label_id ③ 查 lx_channel WHERE model_label_id ? AND status 1 ④ 按 weight 加权随机选一条通道 ⑤ 拿到 endpoint protocol_type api_key ⑥ 根据 protocol_type 获取对应 Adapter ⑦ Adapter 转换请求格式 → 发送到 endpoint这样模型和通道完全解耦——一个模型可以配多个上游通道负载、容灾、灰度切换通道不影响业务方看到的模型名。3.3 流式 SSE 代理AI 对话的核心体验是低首字延迟。网关不能等上游全返回完了再发给业务方必须边收边转。// 响应式 SSE 代理核心逻辑基于 Spring WebFluxpublicMonoVoidproxySSE(ServerWebExchangeexchange,ChannelConfigchannel,StringrequestBody){// ① Adapter 转换请求体ModelAdapteradapteradapterRegistry.getAdapter(channel.getProtocolType());ObjectproviderRequestadapter.toProviderRequest(parseRequest(requestBody),channel);// ② 构建上游请求WebClientclientWebClient.create(channel.getEndpoint());returnclient.post().uri(channel.getPath()).header(Authorization,Bearer channel.getApiKey()).bodyValue(providerRequest).retrieve().bodyToFlux(String.class)// 获取响应式流.map(chunk-adapter.toOpenAISSEChunk(chunk))// 逐块转换.flatMap(chunk-exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(chunk.getBytes(StandardCharsets.UTF_8))))).then();}关键点用WebClientbodyToFlux获取响应式流不能用RestTemplate阻塞式每拿到一个 SSE chunk立即调用 Adapter 转换立即 flush 给业务方不做任何 buffer 和聚合网关增加的延迟 1ms3.4 统一鉴权体系业务方不应该持有任何模型厂商的 API Key。网关提供自己的密钥体系方案AK/SK JWT ① 业务方在平台控制台创建 AccessKeyAK SK ② 调用时携带 JWT由 SK 签发 ③ 网关 Filter 校验 JWT → 从 JWT 中读 agencyId、可用模型列表、QPS 上限 ④ 校验通过后放行给路由层 ⑤ 网关内部持有各模型厂商的 API Key业务方完全不知道这样两个价值安全厂商 API Key 只有平台知道不会泄露可控可以按 AK 维度限流、按机构维度计费、按模型维度做权限管控3.5 Token 计费引擎统一网关的另一个核心价值是一份账单——所有模型的消费都统一核算。计费流程 ① 请求进来时解析模型名 → 查计费规则表 → 预估费用 → 检查余额预扣 ② 请求返回后从响应中提取 usage.prompt_tokens 和 usage.completion_tokens ③ 计算费用input_tokens × 输入单价 output_tokens × 输出单价 ④ 扣减余额Redis 原子操作→ 写入流水表MySQL ⑤ 如果上游返回 cached_tokens这部分不计费-- 计费规则表CREATETABLElx_model_price(idINTPRIMARYKEY,model_label_idINT,input_priceDECIMAL(10,6),-- 输入价格元/1K tokensoutput_priceDECIMAL(10,6),-- 输出价格元/1K tokenscache_read_priceDECIMAL(10,6)DEFAULT0,-- 缓存命中价格effective_timeDATETIME-- 价格生效时间支持调价);四、方案二使用成熟的 AI API 聚合平台自建网关的开发周期 2-4 个月维护成本也高。如果你的团队没有专职基础架构人员可以考虑使用成熟的聚合平台。以星枢无极为例它已经把上述五个模块全部做了标准化接入方式业务代码零改造只需把base_url和api_key换成平台提供的地址。# 之前直连 DeepSeekclientOpenAI(api_keysk-xxxx,base_urlhttps://api.deepseek.com)# 使用聚合平台后一行改动调所有模型clientOpenAI(api_keyak-xxxx,# 平台密钥base_urlhttps://api.591ll.com/v1# 平台统一入口)# 调 DeepSeekresponseclient.chat.completions.create(modeldeepseek-v4,messages[{role:user,content:你好}])# 调通义千问 —— 只改 model 名responseclient.chat.completions.create(modelqwen-plus,messages[{role:user,content:你好}])# 调豆包 —— 还是只改 model 名responseclient.chat.completions.create(modeldoubao-pro,messages[{role:user,content:你好}])核心能力对比能力自建网关成熟聚合平台模型接入数量需要逐个写 Adapter40平台持续接入协议适配需自研开箱即用流式 SSE需自建响应式代理原生支持延迟 50msToken 计费需自研计费引擎 Redis MySQL开箱即用支持套餐和按量密钥管理需自建 AK/SK 体系平台提供完整密钥管理厂商 API 变动自行跟进适配平台统一维护开发周期2-4 个月0 天运维成本需要专人零运维适用场景有专职基础架构团队的大企业中小企业、创业团队、快速验证五、关键决策自建还是用平台做这个决策问自己三个问题1. 模型数量有多少如果只接 1-2 个模型比如 DeepSeek Claude自建适配器的工作量很小用平台反而多了一层中转延迟。但如果接了 5 个以上维护成本会指数级增长。2. 计费逻辑复杂吗如果你只是自己用、看看总 Token 数就行不需要完整的计费引擎。但如果有多个业务方需要按项目核算成本计费系统就变成了刚需。3. 有没有人维护这是最关键的问题。模型厂商 API 经常变动——改字段名、改鉴权方式、改 SSE 格式。这些变动的适配和回归测试是持续的隐性成本。如果没有人持续维护三个月后网关可能一半模型都调不通。一个简单的判断标准如果你需要同时接入 ≥5 个模型 有多个业务方共用 → 用聚合平台 如果只接 1-2 个模型 单人使用 → 直连或简单自建代理即可六、实战用聚合平台搭建一个多模型路由 Demo下面是一个完整的前端示例展示如何通过统一网关同时调用 DeepSeek 和通义千问并做模型级 fallback// 多模型路由 降级策略importOpenAIfromopenai;constclientnewOpenAI({apiKey:ak-xxxx,baseURL:https://api.591ll.com/v1,defaultHeaders:{Content-Type:application/json}});// 模型优先级链优先用主模型失败自动降级constMODEL_CHAIN[deepseek-v4,qwen-plus];asyncfunctionchatWithFallback(messages,modelChainMODEL_CHAIN){for(constmodelofmodelChain){try{constresponseawaitclient.chat.completions.create({model,messages,stream:false,});console.log([成功] 模型:${model}, 消耗 Token:${response.usage.total_tokens});returnresponse.choices[0].message.content;}catch(error){console.warn([降级] 模型${model}失败:${error.message});// 自动尝试下一个模型}}thrownewError(所有模型均调用失败);}// 使用constanswerawaitchatWithFallback([{role:system,content:你是一个技术专家},{role:user,content:解释一下适配器模式}]);console.log(answer);这段代码的特点只用一个baseURL和一个apiKey调所有模型业务代码只关心model名称不关心背后是哪个厂商Fallback 逻辑自动生效主模型失败自动切备用七、总结统一网关解决的不是一个能不能调的问题而是能不能高效地管理和维护多个模型的接入。核心思路就三层统一入业务方只认 OpenAI 兼容协议 平台密钥中间转网关做协议适配 路由分发 计费核算多路出网关持有各厂商 API Key按需路由到对应上游不管你是选择自建还是使用成熟平台不要让业务代码和模型厂商直接耦合。把适配复杂度收敛到一个地方是处理多模型接入的第一原则。本文基于 2026 年 6 月的国内大模型 API 生态撰写。模型厂商和 API 格式持续变化中具体接入细节请参考各厂商最新文档。