存量系统AI升级:统一能力网关与适配层架构设计实践

发布时间:2026/9/5 12:15:28
存量系统AI升级:统一能力网关与适配层架构设计实践 1. 先聊几句存量培训系统搞 AI 升级最该动的不是模型是入口先说个背景。我最近接到一个很典型的改造需求一套跑了七八年的企业培训系统后端是 Java 单体架构业务表几十张API 文档老到发黄前端还在用 jQuery 混着 Vue2。老板看完几场大模型发布会拍板要做“AI 升级”——要能智能问答、要能自动生成课程摘要、要能做个性化的学习路径推荐。听起来挺美好。但真到了动手阶段问题全冒出来了这套系统里根本没有“AI能力”这个概念业务流程里也没有预留任何模型调用的位置。最要命的是一线业务方已经等不及了有人偷偷在某个后台页面里接了一个大模型的 API写死了 Key还把密钥提交到了 Git 仓库里。过了两周模型厂商调价那个页面的回答质量骤降没人知道去哪里改配置也没人敢动那段代码。这种场景其实特别普遍存量系统做 AI 升级最大的坑往往不是模型选型而是“接入方式”。你今天选了大模型 A拍脑袋把接口写死在业务代码里明天想换模型 B、想加一个行业小模型、想过一个安全审核网关那就要改所有调用方。更离谱的是每个业务模块都自己接一个 Key靠口头约定“这个 Key 谁申请的谁负责”最后账单出来财务直接找上门问为什么一个月花了十几万。所以我在做这个培训系统的 AI 升级方案时定了一个核心原则所有的 AI 能力调用必须经过一个统一入口业务代码不许直接碰任何模型厂商的 API。这就是题目里说的“统一 AI 能力网关”加上“适配层”。这篇文章不聊那些高深的理论就讲我实际是怎么设计这套接入方案的以及中间踩过的坑、想明白的一些道理希望对正在折腾存量系统 AI 化的朋友有帮助。这个方案适合谁看手里维护着老系统、又想用上大模型能力的技术负责人和开发人员。不管你的老系统是培训类、内容管理类还是企业内部工具类只要你想让存量业务优雅地接入 AI而不是把系统推倒重来这篇文章的思路都可以直接参考。2. 统一 AI 能力网关与适配层的整体设计思路2.1 为什么不能直接在业务代码里调大模型 API先聊一个很基础但经常被忽略的问题。很多团队接入大模型第一反应是“找个 SDK 装上把 Prompt 填进去调接口拿结果”。对于 demo、原型验证这么做完全没问题因为它快。但对于一个还要活很多年的存量系统直接在业务代码里调大模型 API后续会面临一堆麻烦。模型厂商的 API 改动影响面大。 大模型的接口版本升级、参数调整、返回格式变化在厂商那边可能就是一次普通发版但对你来说意味着所有调用方都要跟着改。如果你有十个业务模块调了同一个模型每个模块的调用代码还写得不一样那这个版本升级就是一次事故。密钥管理失控。 每个模块各申请各的 KeyKey 散布在代码、配置文件、运维脚本里泄漏了都不知道。我见过最夸张的是一个测试环境的 Key 被刷了十几万次因为有人把这个 Key 写死在前端代码里等于把钱包密码公开了。成本无法统计和管控。 每个业务方说自己“就调了一点点”月底的账单让你们直接傻眼。没有统一的计量和配额管理AI 成本就是一个黑盒。模型切换和灰度发布做不了。 你不可能因为换了模型厂商就把所有业务模块都停掉一起改。更现实的情况是某个新模型在某个场景明显更好但你只能“整个系统”切过去没法针对单个功能做灰度。说白了业务代码直接调大模型短期内是“最省事”长期看是“最债”。统一网关的本质就是把**“模型厂商 API 的复杂性”和“业务调用方”隔离开来**让业务方像调用内部服务一样调用 AI 能力。用个生活类比以前是每家公司自己跑去菜市场买菜、自己洗菜、自己切菜、自己开火做饭流程重复、口味不可控、卫生没保障。统一网关相当于建了一个中央厨房——菜统一采购、统一洗切、统一做熟前端餐厅只管点菜和上菜。餐厅不用关心今天的菜是从哪进的、谁做的、做得干不干净只管拿到成品、摆盘上桌。2.2 三层架构接入层、核心服务层、适配层这套方案的整体架构我拆成了三层每一层只干一件事边界清晰方便独立升级和扩展。接入层Open API面向所有业务模块提供统一的调用入口。我在这里定义了一套只属于本公司/本系统的 AI 能力 API 规范包括统一的鉴权方式、统一的请求响应格式、统一的能力标识。业务方只需要对接这一套规范不需要知道背后是哪个大模型。核心服务层AI 能力网关负责路由、融合、管控。请求进来之后网关根据业务方申请的“能力编码”找到对应的路由策略决定把流量转发给哪个模型同时做限流、降级、熔断、审计和计量。这一层是大脑各种管控策略都在这里执行。适配层Adapter Layer负责跟外部模型厂商的 API 打交道。每个模型厂商对应一个适配器适配器做的事情包括把内部统一请求格式转换成厂商要求的格式、调用厂商 API、把返回结果再转换成内部统一格式、处理不同厂商的异常和限流逻辑。这三层的依赖关系是单向的接入层依赖核心服务层核心服务层依赖适配层适配层依赖外部模型 API。业务方永远只跟接入层打交道不会绕过网关直接触达适配层和外部模型。为什么要强调三层而不是两层因为“核心服务层”和“适配层”的职责真的不一样。核心服务层关心的是“请求怎么路由、怎么管控”适配层关心的是“具体如何跟某个厂商对话”。如果把它们混在一起比如在路由逻辑里写死“某厂商要求 temperature 必须传 0~2而我们统一规范是 0~1”这个路由代码就变得特别脆弱——换一个模型厂商你不仅得改适配代码还得小心别动到路由逻辑。分层之后每层各改各的出问题好排查。2.3 核心概念能力Capability与路由Route在设计这套方案时我重点定义了“能力”这个概念。在业务方眼里AI 能力是一个个业务语义化的名字比如“课程内容问答”“试题智能生成”“学习路径推荐”而不是“调用某个文本生成模型的 chat/completions 接口”。这么做的好处在于业务方和底层模型之间彻底解耦。你有一个“课程内容问答”的能力管理员在管理后台配置这个能力背后的模型参数可以配为模型 A system prompt 模板一也可以配为模型 B system prompt 模板二。业务方每次调用都是按“能力编码”来请求网关负责翻译和分发。路由策略我设计了三种按需使用固定路由一个能力绑定一个模型。用于模型效果稳定、不需要调整的场景。权重路由一个能力绑定多个模型按比例分发流量。用于新模型上线灰度验证的场景。条件路由根据请求上下文如用户等级、内容类型、业务线选择不同模型。用于精细化管控场景比如高付费用户走效果更好的贵模型普通用户走便宜的模型。这套设计的核心思想就一句话业务只需要关心“我有什么能力”不需要关心“这个能力是谁提供的”。所有的模型选型、切换、灰度、降级都沉淀在网关层。3. 适配层的核心细节与实现要点3.1 适配层到底在适配什么很多人听到“适配层”三个字以为就是写个类、封装一下 API 调用而已。但实际上适配层要处理的问题比想象中繁琐得多。我在这个项目里把适配层的职责归纳为四个层面。协议差异适配。 不同模型厂商的 API 风格天差地别。有的走 RESTful有的走 gRPC有的要求messages数组有的要求prompt字符串有的返回content字段有的返回choices[0].message.content。适配层的第一个职责就是把外部千奇百怪的格式“磨平”成内部统一格式。行为和约束适配。 有的模型最大输入只有 4K token有的是 128K有的模型必须传用户 ID用于合规审计有的模型对特殊字符敏感需要在 prompt 里做转义。这些差异如果不统一处理业务方对接每一个模型都要踩一遍坑。异常和重试语义适配。 不同厂商的限流策略不一样有的返回 429 带Retry-After头有的返回rate_limit_exceeded错误码。如果内部网关有一个统一的“重试多久、退避策略怎么样”的规范适配层就必须把厂商的各种错误转化为内部统一的异常类型再由网关决定是否重试。计费和用量字段的归一化。 模型厂商返回的 token 使用量字段有的是prompt_tokens completion_tokens有的是input_tokens output_tokens还有的干脆不返回。适配层需要统一换算成内部标准的计费字段否则后续做成本分析、配额计算都会变成一团乱麻。我在设计时为每个适配器定义了一个统一接口大概长下面这个样子public interface ModelAdapter { /** * 返回当前适配器支持的模型类型标识 */ String supportedModelType(); /** * 统一的模型调用入口 */ UnifiedAiResponse invoke(UnifiedAiRequest request); }UnifiedAiRequest和UnifiedAiResponse是内部统一的请求/响应对象字段由我们自己定义与任何厂商无关。这样业务方和网关永远只跟这两个对象打交道。3.2 流式输出与非流式输出的统一处理这是个很容易被忽略但特别重要的细节。大模型最常见的交互方式是打字机式流式输出但不同厂商的流式协议格式差异极大。有的厂商走 SSEServer-Sent Events每一行是一个data: {...}结构以data: [DONE]结尾。有的厂商走 WebSocket自己定义了一个消息帧格式。有的厂商虽然底层是流式但返回的是一个 chunk 数组。更麻烦的是有的厂商在流式过程中还会发 ping/heartbeat 消息处理不好就会出现“解析异常”假象。我在这套适配层里设计了“统一输出流”概念把不同厂商的流式输出转换成统一的事件流。简单来说适配器在底层跟厂商“对话”但在面向网关的接口上只暴露一个标准的事件回调接口onStart、onTokenDelta、onFinish、onError。四个事件覆盖了整个生成过程网关也好、业务方也好不需要关心底层是 SSE 还是 WebSocket统一消费就行。这样做还有一个额外好处可以对流式输出做额外的后处理。比如关键词过滤、敏感信息屏蔽、格式校正都可以在适配层的“事件转换”环节插入处理器而不需要改动业务代码。这一点在培训系统里特别有用因为企业内容有合规要求你肯定不希望大模型生成的内容里带出不该出现的内容。3.3 适配层与厂商 SDK 的边界很多适配器实现的时候会直接引入模型厂商提供的官方 SDK。这个我倒不反对只要 SDK 没有过度依赖云厂商的扩展组件就行。但有一个关键点要拎清楚SDK 只是一个工具绝不能让它污染内部的核心模型。比如厂商 SDK 抛出异常你直接在适配层里 catch 住抛出一个自定义的内部异常SDK 返回的对象你不要直接往外传而是提取关键字段塞进UnifiedAiResponse里。有的团队图省事直接把 SDK 返回的对象序列化成 JSON 交出去结果业务方写代码的时候发现字段名跟着厂商走以后厂商一改字段名业务方全挂。适配层存在的意义就是在这里扛住这些变化。我当时是这么约束团队的适配器可以依赖厂商 SDK但 SDK 类型禁止出现在适配器的 public 方法签名里。所有对外暴露的类型都必须是内部统一类型。代码评审时检验这一条很快就能发现设计上的问题。3.4 适配层扩展新模型到底要改多少代码这套方案还有一个很实用的收益新增一个模型厂商基本上只写一个 ModelAdapter 实现类然后注册到网关的适配器工厂里。我不需要改动任何业务代码也不需要修改网关的路由逻辑和管控逻辑。因为网关只知道“能力编码”和“模型类型”它不关心这个模型类型具体调的是哪家 API。适配层就像电源插头的转换器你从中国带了个两脚插头到欧洲不需要拆墙壁重新走线只需要换一个转换头。这个收益在后来的实际业务中体现得很明显有一周时间培训系统要临时加一个“多模态课程内容转文字描述”的能力我们需要接入一个与公司原先合作厂商不同的外部视觉模型。整个过程中我只写了一个新的 Adapter 类约两百行代码然后在管理后台配置了一个新能力的路由规则配好对应的 Prompt 模板和模型参数就上线了。全程没有碰业务系统的任何其他代码。4. 实操过程网关主流程、运维管理与灰度切换4.1 网关请求主流程我把一次完整的请求链路整理了一下大致步骤如下业务方调用统一 API 接口请求头里带着内部应用 ID 和签名。网关收到请求后先做鉴权和权限校验确认该业务方有权限调用对应“能力编码”。网关根据能力编码从路由配置中心读取路由策略确定本次请求该转发到哪个模型以及对应的适配器。请求进入通用处理管线内容长度检查、敏感词检查、Prompt 模板渲染。网关组装UnifiedAiRequest交给对应适配器的invoke方法。适配器将内部请求转换为厂商格式调用外部 API处理重试、异常、限流等。适配器拿到结果后转换成UnifiedAiResponse返回给网关。网关记录审计日志和计量数据把响应返回给业务方。这个流程看起来不复杂但每一步都有很多细节。我挑几个最容易出问题的环节展开讲讲。4.2 鉴权与密钥管理的实操做法统一网关的价值之一就是把“密钥散落一地”的问题收口。具体操作上我们的做法是内部业务方只使用“应用 ID 应用密钥”的方式访问网关应用密钥由网关管理后台统一生成和轮换。业务方申请新应用时后台生成一对密钥密钥可以设置有效期到期自动失效。网关与模型厂商之间的密钥全部加密存储在独立的配置中心里只有网关服务在启动时能读取。开发人员本地开发环境里没有真实密钥只有测试环境的 mock Key。网关支持“密钥池”管理。当某个模型厂商因单 Key 限流时网关可以自动切换到密钥池里的另一个 Key。这个功能在业务高峰期非常有用。刚开始我们用的是“一个业务方一个 Key、业务方自己去厂商平台申请”的模式后来发现根本无法管理有人把 Key 放在前端代码里、有人把 Key 写在配置文件的明文里、有人把 Key 直接发给外部供应商。统一收口之后至少能保证全系统只有网关一个地方跟外部模型厂商打交道其他任何地方出现模型厂商的密钥都属于异常情况可以第一时间告警。4.3 审计日志与成本核算的可观测设计存量系统最难搞的是可观测性以前没有 AI 调用不需要管“这个页面为什么回答慢”“这笔账是谁花的”。有了统一网关这些问题都有了落点。我在网关里为每个请求生成一个唯一的请求 ID同时要求业务方在调用时传入“业务追踪 ID”。网关的审计日志会记录请求时间、应用 ID、能力编码、模型类型、输入 token 数、输出 token 数、响应耗时、响应状态码。这些日志两路输出一路写入 Elasticsearch 用于日常查询一路以原始日志形式存档用于对账和分析。有了这些数据成本核算就变得特别简单。比如培训系统里“课程内容问答”这个能力一个月花了 8000 元我们可以直接拆到每个业务模块甚至拆到具体的请求。财务再也不会拿着厂商账单来问“这钱是哪花的”我们在后台把账单明细导出来即可。审计日志的另一个重要作用是合规留痕。企业内部系统使用大模型时往往需要记录用户问了什么、模型回答了什么。如果所有请求都绕过网关、直接对接厂商这个留痕根本无从谈起。统一网关做这一层拦截留痕成了顺理成章的事情。4.4 模型切换与灰度发布的一个示例再分享一个实际操作中的例子。培训系统里原本的“课程内容问答”能力用的是厂商 A 的通用对话模型。有一天厂商 B 推出一个新的行业知识增强模型在培训领域上表现明显更好。但直接切换有风险如果新模型在某些 prompt 上表现不稳定整个问答功能就崩了。我的操作流程是在管理后台给“课程内容问答”能力添加一个路由策略设置为“权重路由”。把厂商 B 的适配器准备好注册到适配器工厂并配置好模型参数。线上先设置 5% 的流量走厂商 B95% 继续走厂商 A。观察两周对比响应质量、延迟、人工评分。效果稳定后把权重调整为 30% 对 70%继续观察一周。最终确认没问题把权重调整为 100% 走厂商 B。整个切换过程业务方无感知没有发版没有停服。如果不做统一网关这种灰度切换是无法想象的。业务代码一旦写死模型 A你要换 B就得改代码、发版、全量更新。而有了统一网关和适配层模型切换变成一个配置动作而不是一个开发动作。4.5 管理后台功能的“三个必须”网关的管理后台看起来只是配置界面但实际上它是这套方案的“驾驶舱”。我做了三个必须的功能缺一不可必须能查看实时流量和运行状态。 每个月/每个能力/每个模型的调用量、成功率、平均延迟、token 消耗都要一眼看清。这样出问题时可以快速定位到是哪个模型、哪个环节的问题。必须能配置路由和降级策略。 运维人员不需要写代码就能改变某个能力的模型路由或者为某个能力配置降级规则比如模型 A 挂了自动降级到模型 B甚至返回一个静态兜底答案。必须能管理和审核 Prompt 模板。 业务方可以提交 Prompt 模板的修改申请管理员审核后发布。这样可以避免业务方在系统里乱改 Prompt 导致输出质量失控。培训系统里不同课程可能对应不同的 Prompt 风格这个功能尤其有用。5. 落地过程中的常见问题与排查技巧5.1 问题一业务方绕过网关直接用模型厂商的 SDK这是我在项目中遇到最典型的问题。道理讲了一堆但总有人贪图省事想在新功能 demo 里直接调用厂商 API绕过网关。这种做法的后果很严重密钥泄漏、成本失控、审计缺失而且新功能一旦跑起来后续就很难再迁回网关。排查技巧在网关层面能做的有限我们当时靠的是月末对账。把厂商账单里所有 API Key 拉出来跟系统中登记的 API Key 比对发现一个不明 Key马上定位到人追究来源。后来我在公司内部定了一条铁律**接入任何大模型能力必须走网关否则不予上线。**对于绕过网关的行为采用技术制度双重手段约束。这里也提醒一下技术方案再完善也抵不过“人心涣散”。网关的本质是“收口”它的效果高度依赖团队的执行力。没有制度配合网关会沦为摆设。5.2 问题二不同模型返回的 token 口径不一致成本统计对不上这个坑我踩得比较惨。之前某个月的成本报表显示厂商 A 的计费 token 数和网关日志里记录的消耗 token 数差了 30%。排查半天发现厂商 A 的“token”统计里包含了系统提示词和上下文历史内容而我们内部日志只记录了“当次请求新增的 prompt token”没把上下文算进去。解决方案是在适配层做 token 口径的归一化。我定义了一个内部 token 统计模型total_tokens prompt_tokens completion_tokens其中prompt_tokens包含系统提示词 历史消息 本次输入。适配器拿到厂商返回的数据后按照内部口径重新计算并覆盖原始值。这样后续所有成本分析都基于同一套口径再也不会出现对不上的情况。5.3 问题三流式输出的连接经常莫名断开培训系统里“课程内容问答”功能上线后运维反馈部分用户遇到回答到一半就断开的情况。看了半天发现是网关层没有正确设置超时和重连策略。厂商的流式接口通常没有固定总超时但如果一段时间没有收到任何数据连接会被中间的网络设备掐断。解决方案分两层网关层设置“空闲超时”和“总超时”两个参数空闲超时比如 30 秒超过 30 秒没有新数据则认为连接已死总超时比如 300 秒最长只允许一个流式输出持续 5 分钟。适配层做“自动重连”处理如果连接断开但模型还没有生成完毕适配器能尝试恢复上下文并重新请求。这里用到了大模型的“续写”能力但不同厂商的续写参数不一样我把这个逻辑收敛在适配器内部对网关和业务方透明。5.4 问题四Prompt 模板管理与版本控制培训系统里不同课程、不同讲师可能想要不同的回答风格所以 Prompt 模板不能写死在业务代码里。我在网关里做了一个轻量级的模板管理功能支持版本号、内容、变量占位符、生效状态等字段。业务方提交新模板时需要关联到特定的能力和路由策略管理员审核后才能在线上生效。这里有一个重要的技术点模板和具体的模型、参数是分开管理的。比如业务方写了一个模板但它可以选择用“便宜的快速模型”或“高质量大模型”来执行。这个解耦让业务方的灵活性和平台的可控性都兼顾了。5.5 常见问题速查表症状可能原因排查方向调用模型报 401密钥配置错误或过期检查配置中心密钥是否轮换, 确认网关是否成功读取请求响应 429触达模型厂商限流检查密钥池设置, 开启自动换 Key 或降级策略输出内容全部为系统兜底答案模型厂商故障或被熔断查看网关告警, 检查降级规则是否被触发成本报表 token 数与厂商账单不符token 口径不一致检查适配层的 token 归一化逻辑流式回答频繁中断网关超时配置不合理调整空闲超时和重连策略部分业务方调用无权限应用未申请对应的能力编码在管理后台检查应用-能力绑定关系6. 踩过坑之后的几点运营建议技术方案讲完之后我想再补充几条运营层面的经验因为单靠技术架构解决不了所有问题。第一别急着把所有 AI 能力都接到网关里。我建议先接一个场景比如“课程内容问答”跑通整个流程接入适配器、配置路由、上线灰度、可观测、成本核算。把这一条链路打磨好再逐步扩展其他能力。“先窄后宽”远比“一上来接十个场景”稳得多。第二统一网关上线初期一定要双轨运行一段时间。老的直连调用可以保留但只做只读观察不再新增。等网关链路跑稳了、业务方习惯了再把老的直连方式下线。不要“一刀切”否则业务方会有强烈的抵触情绪。第三网关的调优是持续性的。大模型厂商的模型版本更新很快新的模型可能效果更好、价格更低。如果网关层没有定期的模型评估机制很容易守着旧模型白白多花成本。我们在网关里做了一个“模型评估任务”每周自动用一组固定的测试题跑所有可用模型输出质量得分和价格对比辅助管理员做模型选型决策。这个机制非常实用。第四别忘了给业务方提供清晰的接入文档和示例代码。比如调用网关的 SDK demo、常见报错说明、沙箱环境等等。技术人员往往喜欢不停做架构却忽略了“让使用者好上手”才是落地的关键。我在这个项目里专门花了三天时间写了一份《AI 网关接入指南》把从申请应用到发出第一个请求的完整过程写清楚配上代码片段。这份指南上线后业务方的自助接入率明显提升不再动不动就拉着我们问“这个接口到底怎么调”。7. 最后分享一个最实用的技巧说了这么多最后分享一个我认为最值得保留的小技巧网关层一定要保留“请求-响应”的回放能力。什么意思就是网关在审计日志里除了记录请求和响应的摘要还要把完整的请求体、响应体、Prompt 模板的渲染结果、模型名称和参数配置全部存下来。当线上出现一个“回答很奇怪”的情况时你可以直接通过请求 ID把当时的完整上下文还原出来看到底是 Prompt 的问题、模型的问题还是业务方输入的问题。这个能力一开始我们没做后来被业务方在群里三次之后才补上的。补上之后排查问题的效率提升至少一倍。因为 AI 应用的特点就是“输出不确定性”一旦出问题光靠抽象的日志字段完全不够必须回到当时的那次具体对话里看。我这个方案的完整代码自然是不能全部贴在这里的但上面讲到的核心思路、实现要点和踩坑记录应该足够你在自己的项目里搭一个可运行的雏形了。存量系统做 AI 升级最重要的是保持系统可演进。统一能力网关加适配层本质上就是用一个小而稳的中间层把 AI 的不确定性和业务的稳定性隔离开来。有了这个底座后续不管增加多少个模型、多少个能力都只是适配器和配置的增量而不是系统结构的伤筋动骨。