AI应用底座工程化实践:微服务架构与JDK 21虚拟线程

发布时间:2026/10/7 13:39:16
AI应用底座工程化实践:微服务架构与JDK 21虚拟线程 1. 从一个尴尬的现场说起为什么“能跑的AI Demo”到了生产环境就趴窝我见过太多团队在AI落地这件事上栽跟头。场景几乎一模一样某个业务部门提了个需求说想用大模型做智能客服、做文档问答、做合同审查。团队里两三个工程师花两周时间用Python写了个脚本调一下模型接口套个Gradio或者Streamlit的界面演示的时候效果惊艳领导拍板说“就这个方向赶紧上线”。然后真正的噩梦开始了。演示环境里只有一个用户、一份文档、一个模型接口。生产环境里是几百个并发、几十个业务系统、十几种模型供应商、还有审计合规部门天天追着你要调用日志。原来那个脚本里硬编码的API Key要换成密钥管理原来同步阻塞的调用要改成异步队列原来一个文件搞定的事情现在要拆成网关、鉴权、限流、路由、缓存、监控、计费七八个模块。更要命的是每个业务线都想接AI能力如果每个团队都自己搭一套公司里会冒出十几个互不相通的“AI烟囱”。这就是AI应用底座要解决的问题。而QuickBlue就是我在这个背景下重点关注的一个项目。它不是一个具体的AI应用而是一套让企业能够快速、规范、可治理地构建和运行AI应用的底层平台。你可以把它理解成AI时代的“操作系统中间层”——上面跑着各种智能应用下面接着各种模型和数据源中间负责调度、治理和安全。这篇文章我会从实际工程角度拆解QuickBlue这类AI应用底座到底包含哪些核心能力为什么微服务架构是它的必然选择Spring Cloud技术栈在其中扮演什么角色JDK 21又带来了哪些实质性的改变以及企业在选型和落地时最容易踩的坑。适合正在做AI平台规划的技术负责人、架构师以及想理解企业级AI工程化的开发者阅读。2. QuickBlue的定位拆解它到底是不是又一个“中台”2.1 从“模型调用”到“应用生命周期管理”的认知升级很多人第一次听到“AI应用底座”这个词第一反应是“这不就是个API网关吗把模型接口包一层”。这个理解不能说错但太窄了。如果只是包一层接口用Nginx加个转发规则就够了犯不上搞一个平台。QuickBlue这类底座真正管的是AI应用的完整生命周期。我把它拆成四个阶段来看。第一阶段是接入业务系统怎么发现有哪些AI能力可用怎么申请权限怎么拿到调用凭证。第二阶段是编排一个AI应用往往不是单次模型调用而是“检索知识库→组装提示词→调用模型→后处理→格式化返回”这样一条链路底座要提供编排能力。第三阶段是运行并发来了怎么限流模型响应慢了怎么降级某个供应商挂了怎么自动切换。第四阶段是治理谁在什么时候调了什么模型、消耗了多少Token、产生了什么内容、有没有违规这些都要可追溯。把这四件事都做扎实才配叫“底座”。只做第一件事的那叫接口代理。2.2 企业为什么不能每个团队自己造轮子我参与过一次内部技术评审某大型企业有七个业务部门同时在做AI相关的项目。结果发现七个部门用了五种不同的模型供应商、四套不同的提示词管理方式、三套完全独立的计费统计逻辑。到了年底财务要核算AI成本发现根本算不清楚因为有的部门按调用次数算有的按Token算有的干脆没统计。这就是典型的“AI烟囱”问题。每个团队单独看都在推进创新合在一起看就是资源浪费和治理灾难。AI应用底座的核心价值之一就是把重复建设的基础能力收敛到一处。模型接入、密钥管理、限流熔断、日志审计、计费统计这些东西做一次就够了所有业务线复用。业务团队只需要关注自己的业务逻辑和提示词工程不用关心底层怎么调通模型。这里有个常见的误区有些架构师觉得“收敛”就是“集权”会把底座做得很重什么都要管。实际上好的底座应该是“薄而硬”的——接口薄但底层能力硬。业务团队接入成本要低但底座提供的能力要可靠。2.3 QuickBlue与通用微服务框架的本质区别有人会问既然QuickBlue是基于Spring Cloud生态的那它和一个普通的Spring Cloud微服务项目有什么区别区别在于领域模型的差异。普通微服务项目里核心领域对象是“订单”“用户”“商品”这类业务实体。而AI应用底座里核心领域对象是“模型”“提示词模板”“知识库”“会话”“调用配额”。这些对象的生命周期、状态流转、依赖关系完全不同。比如一个模型实例会有“健康”“降级”“熔断”“下线”这些状态一个提示词模板会有“草稿”“测试”“发布”“灰度”“回滚”这些版本状态。这些领域逻辑是通用微服务框架不提供的必须由底座自己实现。所以QuickBlue的价值不在于它用了Spring Cloud而在于它在Spring Cloud之上构建了一套面向AI场景的领域模型和治理策略。技术栈是手段领域能力才是目的。3. 微服务架构在AI底座中的必然性不是赶时髦是被逼的3.1 模型调用的异构性决定了不能单体我见过一个团队试图用一个单体应用来承载所有AI能力结果遇到了几个绕不过去的坎。第一个坎是依赖冲突。调用某家模型供应商的Java SDK需要Jackson 2.13另一个供应商的SDK依赖Jackson 2.9两个版本在同一个JVM里打架序列化行为不一致排查了三天才发现是依赖冲突。第二个坎是资源隔离。图像生成类模型调用是CPU和内存密集型文本对话类模型调用是IO密集型。放在同一个进程里图像任务一跑起来文本对话的响应时间从200毫秒飙到3秒。你没法给同一个JVM里的不同线程组分配不同的资源配额。第三个坎是独立伸缩。文本对话的QPS可能是图像生成的100倍单体应用只能整体扩容造成大量资源浪费。拆成微服务之后对话服务可以部署20个实例图像服务部署2个实例按需分配。这三个问题在AI场景里是常态不是例外。所以微服务架构对AI底座来说不是“可选项”而是“必选项”。3.2 服务拆分的粒度按“能力域”而非“技术层”切微服务拆分最容易犯的错误是按技术层切——网关一个服务、业务逻辑一个服务、数据访问一个服务。这种切法在AI底座里是灾难因为一次AI调用要横跨所有层网络开销大得离谱而且任何一层出问题整个链路都断。正确的切法是按能力域切。我在设计QuickBlue类系统时通常这样划分服务名称职责典型接口接入网关服务统一入口、鉴权、路由、协议转换/api/v1/chat/completions模型路由服务模型选择、负载均衡、故障转移内部RPC调用提示词管理服务模板CRUD、版本管理、变量渲染/api/v1/prompts知识库检索服务向量检索、混合检索、重排序/api/v1/retrieval会话管理服务多轮对话上下文、会话状态/api/v1/sessions配额计费服务Token统计、配额扣减、账单生成内部RPC调用审计日志服务调用记录、内容留存、合规检查异步消息消费每个服务对应一个明确的业务能力服务之间通过定义良好的接口通信。这样拆分之后每个服务可以独立开发、独立部署、独立扩容团队协作的边界也清晰了。3.3 服务间通信同步RPC与异步消息的取舍AI底座里的服务通信有个特点调用链路上既有强实时要求又有大量可异步化的环节。用户发一条消息等待模型回复这个链路必须同步用户不能等三秒才看到“正在处理”。但调用日志记录、Token计费、内容审计这些环节完全可以异步。我的经验是主链路同步旁路异步。用户请求进来网关→路由→模型调用→返回结果这条链路用同步RPCSpring Cloud OpenFeign或者gRPC。而日志、计费、审计这些旁路操作通过消息队列异步处理。这样既保证了用户体验又避免了旁路操作拖慢主链路。有个细节要注意异步旁路操作如果失败了不能影响主链路。比如计费服务挂了用户对话不能报错。这时候需要本地消息表或者事务消息来保证最终一致性而不是让主链路回滚。4. Spring Cloud技术栈选型哪些组件是刚需哪些是锦上添花4.1 注册中心与配置中心Nacos还是ConsulSpring Cloud生态里注册中心的选择主要有Nacos、Consul、Eureka。Eureka已经停止维护了新项目不建议用。Consul功能强大但运维复杂度高需要单独维护一套集群。Nacos在国内社区活跃度高同时提供注册和配置两个功能运维成本相对低。对于AI底座这种场景我倾向于选Nacos。原因有三个第一AI底座的配置项特别多——模型参数、限流阈值、提示词模板、路由规则这些都需要动态配置能力Nacos的配置中心能很好地支撑。第二Nacos支持命名空间隔离可以按环境开发/测试/生产或者按业务线隔离配置。第三Nacos的临时实例和永久实例机制能很好地处理AI服务实例的上下线。4.2 流量治理Sentinel在AI场景下的特殊配置Sentinel是Spring Cloud Alibaba体系里的流量治理组件做限流、熔断、降级。在AI底座里Sentinel的配置和普通业务系统有很大不同。普通业务系统的限流通常是QPS限流比如某个接口每秒最多100次调用。但AI场景下Token消耗才是真正的瓶颈。一个请求可能只调用一次模型但消耗了8000个Token另一个请求也调用一次只消耗50个Token。如果只按QPS限流前者会把配额瞬间打满。所以AI底座的限流策略需要QPS限流和Token限流双管齐下。Sentinel本身不直接支持Token维度的限流需要结合Redis来做。常见做法是Sentinel做QPS维度的粗粒度限流然后在业务代码里用Redis的原子操作做Token维度的细粒度配额扣减。两者配合既能防止突发流量打垮系统又能精确控制成本。# Sentinel限流规则示例QPS维度 spring: cloud: sentinel: datasource: flow: nacos: server-addr: ${nacos.address} >// Token配额扣减示例Redis Lua保证原子性 public boolean deductTokenQuota(String tenantId, int tokenCount) { String key ai:quota: tenantId : LocalDate.now(); String luaScript local current redis.call(GET, KEYS[1]) if current false then current ARGV[2] end if tonumber(current) tonumber(ARGV[1]) then return 0 end redis.call(DECRBY, KEYS[1], ARGV[1]) return 1; Long result redisTemplate.execute( new DefaultRedisScript(luaScript, Long.class), Collections.singletonList(key), String.valueOf(tokenCount), String.valueOf(dailyLimit) ); return result ! null result 1; }4.3 网关选型Spring Cloud Gateway的定制化改造Spring Cloud Gateway是响应式网关基于WebFlux吞吐量比传统的Servlet网关高。但AI底座对网关有特殊要求需要做定制化改造。第一个改造点是协议适配。不同模型供应商的接口协议不一样有的用OpenAI兼容格式有的用自定义格式。网关需要做协议转换把内部统一格式转成各供应商的格式。第二个改造点是流式响应。大模型对话通常是流式返回SSE网关要支持流式转发不能等模型全部返回再一次性发给客户端。第三个改造点是请求体缓存。审计和计费需要读取请求体内容但请求体在网关层默认只能读一次需要做缓存处理。// 网关全局过滤器请求体缓存 流式响应支持 Component public class AiGatewayFilter implements GlobalFilter, Ordered { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request exchange.getRequest(); // 缓存请求体用于审计 return DataBufferUtils.join(request.getBody()) .flatMap(dataBuffer - { byte[] bytes new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String body new String(bytes, StandardCharsets.UTF_8); // 存入上下文供后续过滤器使用 exchange.getAttributes().put(cachedBody, body); ServerHttpRequest mutatedRequest request.mutate() .body(Flux.just(exchange.getResponse().bufferFactory().wrap(bytes))) .build(); return chain.filter(exchange.mutate().request(mutatedRequest).build()); }); } Override public int getOrder() { return -100; } }4.4 分布式事务AI调用链里哪些环节真的需要微服务架构下分布式事务是个绕不开的话题。但在AI底座里我的观点是能不用分布式事务就不用。原因很简单AI调用的主链路是“请求-响应”模式不涉及多服务的数据写入。真正需要保证一致性的只有计费扣减和配额管理。对于计费场景我通常用最终一致性方案而不是强一致性。用户调用模型先生成一条计费流水记录状态为“待确认”然后异步扣减配额。如果扣减失败流水记录标记为“异常”由定时任务补偿。这样主链路不受影响计费准确性通过补偿机制保证。强一致性方案如Seata在AI底座里往往得不偿失。因为AI调用本身就是高延迟操作再叠加分布式事务的协调开销用户体验会很差。而且计费场景对实时一致性要求没那么高秒级延迟完全可以接受。5. JDK 21带来的实质改变虚拟线程不是噱头5.1 虚拟线程如何解决AI底座的IO瓶颈AI底座是典型的IO密集型系统。一次模型调用大部分时间花在等待模型响应上CPU基本闲着。传统的线程池模型下每个请求占用一个平台线程线程池大小受限于操作系统线程数通常几千个。当并发请求超过线程池大小时请求排队等待响应时间急剧上升。JDK 21引入的虚拟线程改变了这个局面。虚拟线程由JVM管理不直接映射到操作系统线程可以创建数百万个。当虚拟线程遇到IO阻塞时JVM会自动把它挂起让出底层平台线程去执行其他虚拟线程。这意味着AI底座可以用很少的平台线程支撑极高的并发。我做过一个压测对比同样的模型调用逻辑用传统线程池200个线程和虚拟线程无限制分别跑1000并发。传统线程池的P99响应时间是8.2秒虚拟线程是2.1秒。差距主要来自排队等待时间。// JDK 21虚拟线程在AI调用中的应用 Configuration public class VirtualThreadConfig { Bean(aiTaskExecutor) public ExecutorService aiTaskExecutor() { // 为AI调用创建虚拟线程执行器 return Executors.newVirtualThreadPerTaskExecutor(); } } // 在模型调用服务中使用 Service public class ModelInvokeService { Autowired Qualifier(aiTaskExecutor) private ExecutorService executor; public CompletableFutureString invokeModelAsync(String prompt) { return CompletableFuture.supplyAsync(() - { // 这里执行阻塞的模型调用 // 虚拟线程会自动处理IO阻塞 return modelClient.call(prompt); }, executor); } }5.2 结构化并发让多模型并行调用不再混乱AI底座里有个常见场景一个请求需要同时调用多个模型比如一个用于生成一个用于审核然后合并结果。传统做法是用CompletableFuture或者ExecutorService但异常处理和资源清理很容易出问题。比如一个模型调用失败了另一个还在跑怎么取消线程池里的任务怎么保证都结束了JDK 21的结构化并发StructuredTaskScope解决了这个问题。它把一组并发任务看作一个整体要么全部成功要么全部失败异常传播和资源清理都由框架处理。// 结构化并发并行调用多个模型并合并结果 public String multiModelInvoke(String prompt) throws Exception { try (var scope new StructuredTaskScope.ShutdownOnFailure()) { SubtaskString generateTask scope.fork(() - generateModel.call(prompt)); SubtaskString reviewTask scope.fork(() - reviewModel.call(prompt)); scope.join(); // 等待所有任务完成 scope.throwIfFailed(); // 如果有任务失败抛出异常 String generated generateTask.get(); String reviewed reviewTask.get(); return mergeResults(generated, reviewed); } }这段代码比CompletableFuture版本清晰太多。如果generateTask失败了reviewTask会被自动取消不会留下孤儿任务。5.3 从JDK 8升级到21的迁移成本评估很多企业的AI底座项目还在用JDK 8或者JDK 11升级到21需要评估成本。我的经验是新项目直接用21老项目分阶段升级。新项目没有历史包袱直接用JDK 21享受虚拟线程和结构化并发带来的好处。老项目升级要关注几个点第一依赖库兼容性有些老库用了反射访问JDK内部API在21上会报错需要升级或替换。第二GC行为变化JDK 21默认用G1如果原来用的是CMS需要调优。第三模块化系统如果项目用了JPMS升级时要检查模块描述符。实际迁移中大部分Spring Cloud项目升级到JDK 21不会遇到太大阻力因为Spring Boot 3.x已经全面支持JDK 21。主要工作量在依赖库升级和回归测试上。6. 落地AI底座时最容易踩的五个坑6.1 坑一把底座做成了“模型代理”业务团队不买账我见过一个团队花了半年做AI底座结果上线后业务团队根本不用。原因很简单底座只提供了模型调用的代理接口业务团队自己也能调模型为什么要多绕一层底座没有提供业务团队真正需要的东西——提示词版本管理、效果评估、A/B测试、成本分析。教训底座的价值不在于“能调模型”而在于“让调模型这件事变得可管理、可优化、可度量”。如果底座只是多了一层转发那它就没有存在意义。6.2 坑二限流策略只考虑QPS忽略了Token消耗前面提过AI场景下Token消耗才是成本大头。我见过一个系统QPS限流设了100看起来没问题。结果某个用户用长文本反复调用一次消耗几万Token一天下来把月度配额用光了。其他用户全部被限流投诉不断。正确做法QPS限流和Token限流同时配置并且Token限流要按租户、按用户、按模型多个维度设置。还要有实时监控和告警当某个租户的Token消耗异常时及时通知。6.3 坑三日志审计只记了“谁调了什么”没记“调了什么内容”合规审计要求AI调用可追溯。很多系统只记录了调用时间、调用者、模型名称但没有记录具体的输入输出内容。出了合规问题根本查不到当时用户问了什么、模型答了什么。正确做法审计日志要记录完整的请求和响应内容但要注意脱敏和加密。敏感信息如个人身份信息在入库前要脱敏日志存储要加密访问要有严格的权限控制。6.4 坑四模型路由只做了轮询没有健康检查和故障转移模型供应商的服务不是100%可用的。我遇到过某供应商突然返回大量超时但路由层还在往那个供应商转发请求导致大量用户请求失败。正确做法路由层要集成健康检查定期探测各供应商的可用性。当某个供应商的错误率超过阈值时自动将其从可用列表中移除请求转发到备用供应商。同时要有半开机制定期尝试恢复被熔断的供应商。6.5 坑五忽视了提示词的管理和版本控制提示词是AI应用的核心资产但很多团队把提示词硬编码在代码里改一个词就要重新部署。更糟糕的是没有版本管理改错了没法回滚也不知道哪个版本效果更好。正确做法提示词要作为独立资产管理支持版本、灰度、回滚。每次修改都要记录变更人和变更原因。线上运行的提示词版本要可追溯出了问题能快速定位和回滚。7. 我对AI应用底座这件事的真实看法做了几个AI底座项目之后我最大的体会是技术选型不是最难的部分最难的是想清楚底座和业务团队的边界在哪里。底座管得太多业务团队觉得束手束脚管得太少又变成了一个没有价值的空壳。我的经验是底座应该管三件事接入规范、运行治理、成本度量。接入规范保证所有AI应用用统一的方式接入运行治理保证系统稳定可靠成本度量让每一分AI开销都有迹可循。至于业务逻辑、提示词设计、效果优化这些交给业务团队自己负责。QuickBlue这类项目的价值不在于它用了多先进的技术栈而在于它把AI工程化这件事的最佳实践沉淀成了可复用的平台能力。对于正在从“AI Demo”走向“AI生产系统”的企业来说一个设计良好的底座能省下大量的重复建设成本也能避免很多只有踩过坑才知道的教训。如果你正在规划AI底座我的建议是先别急着写代码花两周时间把公司内部所有AI相关的需求梳理一遍看看哪些能力是共性的、哪些是个性的。共性能力优先做个性能力先放一放。底座的第一版不需要大而全但一定要解决最痛的那个问题。