ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI应用底座实战:基于JDK 21与Spring Cloud的微服务架构设计

AI应用底座实战:基于JDK 21与Spring Cloud的微服务架构设计 1. 从一个真实困境说起为什么能跑起来的AI Demo和能上线的AI应用之间隔着一道鸿沟过去一年多我参与过好几个企业内部的AI落地项目从智能客服、文档问答到工单自动分类几乎每一个项目都经历过同样的剧本第一周搭出一个Demo效果惊艳老板拍板就按这个方向做第二周开始接入真实业务系统问题像潮水一样涌出来——模型调用超时怎么重试、多租户的会话上下文怎么隔离、Prompt模板改了要不要重新发版、某个模型供应商限流了怎么自动切换、调用量突然暴涨怎么限流降级、审计日志怎么留痕、成本怎么按部门分摊……原本一个调API的活儿硬生生变成了一整套分布式系统的工程问题。这就是AI应用底座这个概念出现的现实土壤。QuickBlue 正是围绕这个痛点设计的一套AI应用底座方案它的核心思路不是再做一个大模型也不是再做一个聊天界面而是把AI能力当作一种基础设施来对待用成熟的微服务工程体系去承载它。关键词里出现的微服务、Spring Cloud、JDK 21以及热搜词里的微服务架构、微服务拆分、Spring Cloud Alibaba、Sentinel、Redis集群其实已经点明了它的技术底色这是一套用Java微服务生态搭建的、面向企业级AI应用的支撑平台。先把这个概念说清楚。所谓AI应用底座你可以把它类比成当年电商兴起时的中台或者更早的应用服务器。企业不需要每个业务团队都从零去处理模型接入、鉴权、限流、计费、日志、灰度这些横切关注点而是把这些能力下沉到一个统一的平台层业务团队只关心自己的业务逻辑和Prompt设计。QuickBlue 要解决的就是让AI应用从Demo走向生产这段最难走的路。这篇文章适合三类人看一是正在做企业AI落地的后端工程师和架构师你们会关心它怎么和现有微服务体系融合二是技术负责人你们会关心为什么值得单独搞一个底座而不是各做各的三是对微服务架构感兴趣但还没接触过AI工程的开发者你们可以把它当成一个微服务如何服务新场景的完整案例来读。下面我会从需求本质、架构拆解、技术选型、落地步骤到踩坑经验一层层讲透。2. 拆解AI应用底座的真实需求它到底要替业务团队扛下哪些事2.1 模型接入的多供应商抽象是第一道坎企业用AI几乎不可能只绑一家模型。原因很现实不同任务对模型能力要求不同成本敏感度不同合规要求也不同。有的场景要用能力最强的模型有的场景用便宜的小模型就够了还有的场景必须用私有化部署的模型。如果每个业务团队各自去对接代码里到处散落着各家SDK的调用一旦要换供应商改动量巨大。AI应用底座要做的第一件事就是提供一层统一的模型接入抽象。业务代码只面向一个统一的接口编程比如ChatService.complete(request)底层到底是哪家模型、走什么协议由底座根据配置和路由策略决定。这层抽象的价值在于换模型不改业务代码加模型不改业务代码甚至可以做A/B测试——同一批请求按比例分流到两个模型对比效果和成本。这里有个容易被忽略的细节不同模型的输入输出格式、Token计算方式、错误码体系都不一样。底座必须把这些差异抹平对外暴露统一的语义。比如统一用一套错误码表示限流超时内容被拦截额度不足业务层才能写出稳定的重试和降级逻辑。2.2 会话上下文与多租户隔离比想象中复杂聊天类AI应用天然是有状态的——多轮对话需要携带历史上下文。但在企业环境里状态这个词立刻变得敏感A部门的对话历史绝不能被B部门看到同一个用户在不同业务线之间的上下文要隔离会话还要能过期清理、能持久化、能在服务重启后恢复。这就引出了底座必须解决的会话管理问题。常见做法是把会话上下文存到Redis里用租户ID用户ID会话ID做三级key。但这里有个坑上下文是有长度限制的模型能吃的Token有限历史对话不能无限追加。底座需要实现上下文窗口管理——超出长度时怎么截断、怎么摘要、怎么保留关键信息这是一套策略不是简单存个list就行。多租户隔离还涉及配额和计费。每个租户每月能用多少Token、超了怎么办、成本怎么归集到具体部门这些都需要底座在请求链路上埋点统计。热搜词里出现的Redis集群在这里就派上用场了——高并发下的会话读写和计数单机Redis扛不住必须上集群。2.3 限流、降级、熔断AI调用比普通接口更需要这套机制普通业务接口的QPS相对可预测但AI调用有几个特殊性一是贵每次调用都是真金白银被恶意刷或者程序bug导致循环调用账单会很难看二是慢一次生成可能几秒到几十秒线程和连接占用时间长三是依赖外部模型供应商随时可能限流或抖动。所以底座必须内置限流、熔断、降级能力。热搜词里的Spring Cloud Sentinel正是干这个的。限流可以按租户、按接口、按模型维度配置熔断可以在某个模型供应商连续失败时快速切断避免请求堆积拖垮整个服务降级则是在模型不可用时返回兜底结果比如当前繁忙请稍后再试或者走一个规则引擎的简单回复。提示限流阈值不能拍脑袋定。要先统计正常业务峰值再留出合理余量。设太松起不到保护作用设太紧会误伤正常用户这个值需要在压测中反复调。2.4 可观测性AI应用的黑盒问题必须被打开传统接口出问题看日志基本能定位。AI应用出问题往往更隐蔽用户说回答得不对但你不知道是Prompt的问题、模型的问题、还是上下文拼接的问题。底座需要提供完整的可观测性——每次调用的输入、输出、耗时、Token消耗、命中的模型版本、使用的Prompt模板版本都要能追溯。这不仅是排错需要也是合规需要。企业环境里AI生成的内容可能需要审计谁在什么时候问了什么、模型答了什么都得留痕。这就要求底座在设计之初就把日志和追踪做进去而不是事后补。3. QuickBlue 的架构骨架微服务如何承载AI能力3.1 为什么选微服务而不是单体有人会问一个AI底座搞成单体应用不行吗早期确实可以但企业级场景下微服务的优势会逐渐显现。第一能力可以独立伸缩。模型调用网关是IO密集型会话管理是内存密集型计费统计是计算密集型它们的资源需求不同混在一个进程里没法分别扩容。第二故障可以隔离。计费模块出问题不应该拖垮对话服务。第三团队可以并行开发。大企业里不同团队负责不同模块微服务的边界就是团队的边界。QuickBlue 采用微服务架构本质上是把前面说的那些需求拆成一个个独立的服务每个服务职责单一通过明确定义的接口通信。热搜词里的微服务拆分说的就是这个过程——拆得好系统清晰拆得不好分布式事务和调用链会让人痛不欲生。3.2 核心服务划分基于常见的企业AI底座实践QuickBlue 这类系统通常会拆成以下几个核心服务我按职责说明服务名称核心职责典型技术要点接入网关服务统一入口、鉴权、路由、协议转换Spring Cloud Gateway、JWT鉴权模型路由服务多模型抽象、路由策略、故障切换策略模式、负载均衡、健康检查会话管理服务上下文存储、窗口管理、多租户隔离Redis集群、过期策略Prompt管理服务模板版本管理、变量渲染、灰度发布配置中心、版本快照计量计费服务Token统计、配额管理、成本归集异步消息、聚合计算治理服务限流、熔断、降级规则管理Sentinel、规则动态推送可观测服务日志采集、链路追踪、审计留痕链路追踪、结构化日志这张表不是让你照抄而是帮你理解一个AI底座到底由哪些零件组成。实际项目中小团队可以把几个服务合并比如把Prompt管理并入模型路由把计量计费并入会话管理。拆分的粒度应该匹配团队规模和运维能力盲目追求细粒度只会增加复杂度。3.3 服务之间的通信与数据一致性微服务拆开之后通信方式的选择很关键。同步调用用HTTP或者RPC异步场景用消息队列。QuickBlue 这类系统里模型调用链路是同步的用户等着结果但计量计费、日志采集是异步的不需要阻塞用户。这种同步主链路异步旁路的设计是常见做法既保证响应速度又保证数据最终一致。这里有个经典问题计量数据如果异步丢了怎么办答案是不能丢。计费相关的消息要用可靠投递消费端做幂等必要时加对账补偿。我见过有项目因为计费消息丢失导致月底账单对不上排查了整整一周。所以涉及钱的链路可靠性优先级要拉到最高。4. 技术选型背后的取舍JDK 21、Spring Cloud 与那些热搜词里的坑4.1 JDK 21 带来的实际收益QuickBlue 选择 JDK 21 作为基础运行时这不是赶时髦。JDK 21 是LTS版本长期支持有保障而且它带来的几个特性对AI底座这种高并发IO密集型系统特别友好。虚拟线程是最大的亮点。AI调用是典型的阻塞式IO等待——发一个请求出去等几秒才回来。传统线程模型下每个请求占一个平台线程线程池很快被占满吞吐上不去。虚拟线程让一个请求一个线程的写法重新变得可行几万并发不再是问题代码还保持同步阻塞的简单写法不用被迫改成复杂的响应式编程。对于团队里大部分是普通业务开发的情况这一点极大降低了心智负担。记录模式Record Patterns和模式匹配让处理各种模型响应结构时更简洁。分代ZGC在JDK 21里已经成熟大堆内存下的停顿时间大幅降低对会话管理这种内存密集服务很友好。当然升级JDK不是零成本依赖库兼容性要提前验证这个后面踩坑部分会细说。4.2 Spring Cloud 生态的现状与选择热搜词里有一条很扎眼spring cloud alibaba停更了。这反映了很多人的焦虑。实际情况是开源项目的维护节奏会变化但Spring Cloud本身作为一套规范其核心组件Gateway、OpenFeign、LoadBalancer、Config等依然活跃。企业在选型时关键不是用不用Spring Cloud而是具体用哪些组件、哪些组件需要自己兜底。我的建议是核心链路尽量用Spring Cloud官方维护良好的组件比如网关用Spring Cloud Gateway服务调用用OpenFeign配置用Spring Cloud Config或者直接对接Nacos。对于治理能力Sentinel依然是成熟选择即使某个具体项目维护节奏变化其核心的限流熔断能力是稳定的而且规则模型清晰团队容易掌握。注意不要因为某个组件停更的传言就全盘推翻技术栈。要区分停止新特性开发和停止维护前者在稳定期项目里未必是坏事。真正要警惕的是安全漏洞无人修复这个要定期关注依赖扫描结果。4.3 注册中心、配置中心与网关的组合一套典型的QuickBlue微服务组合是这样的Nacos同时承担注册中心和配置中心服务启动时注册自己同时拉取配置Spring Cloud Gateway作为统一入口做鉴权和路由OpenFeign做服务间调用Sentinel做流量治理。这套组合在国内企业里非常常见资料多、踩坑记录多遇到问题容易找到答案。选Nacos而不是EurekaConfig的组合主要原因是它把注册和配置合二为一运维成本低而且支持配置的动态推送——Prompt模板改了不用重启服务就能生效这对AI应用迭代速度很重要。4.4 Redis集群在会话与计数场景的用法会话管理和计量计数都高度依赖Redis。单机Redis在并发高时是瓶颈所以要用集群。但集群带来一个限制跨slot的多key操作不支持。这意味着你不能用事务一次性操作分布在多个节点上的key。设计key的时候要用心尽量让相关的数据落在同一个slot比如用租户ID做hash tag。会话数据的存储结构也有讲究。用Hash存会话元信息用List或者ZSet存消息序列设置合理的过期时间。上下文窗口管理时读取最近N条消息超长时做摘要压缩。这些操作都要考虑Redis的原子性避免并发读写导致上下文错乱。5. 从零搭建一个最小可用AI底座的实操路径5.1 环境准备与依赖版本锁定动手之前先把版本定死这是血泪教训。JDK 21、Spring Boot 3.x、Spring Cloud 2023.x、Spring Cloud Alibaba 2023.x这几个版本之间有严格的兼容矩阵不能随便组合。我建议在项目根pom里用dependencyManagement统一管理版本避免子模块各自引入导致冲突。properties java.version21/java.version spring-boot.version3.2.x/spring-boot.version spring-cloud.version2023.0.x/spring-cloud.version spring-cloud-alibaba.version2023.0.x.x/spring-cloud-alibaba.version /properties版本号具体填哪个一定要去官方兼容性说明里核对不要凭记忆。我踩过一次坑Spring Boot升了个小版本结果Nacos客户端不兼容服务注册不上排查了半天才发现是版本问题。5.2 搭建注册中心与配置中心先起一个Nacos。开发环境用单机模式生产环境必须集群部署至少三个节点否则注册中心挂了整个系统就瘫了。Nacos的配置要持久化到数据库不要用内置存储否则重启数据就没了。服务接入Nacos很简单加依赖、写配置spring: application: name: quickblue-model-router cloud: nacos: discovery: server-addr: ${NACOS_ADDR:127.0.0.1:8848} config: server-addr: ${NACOS_ADDR:127.0.0.1:8848} file-extension: yaml配置里把地址做成环境变量方便不同环境切换。这一步看似简单但很多团队把地址硬编码在代码里上线时手忙脚乱。5.3 实现统一模型接入层这是底座的核心。定义一个统一的请求和响应模型然后为每家模型供应商写一个适配器实现同一个接口。public interface ModelProvider { ChatResponse chat(ChatRequest request); String name(); boolean healthy(); }路由服务根据配置决定用哪个Provider。配置可以放在Nacos里支持动态调整。故障切换的逻辑是调用失败达到阈值标记该Provider不健康后续请求路由到备用Provider同时后台定时探活恢复后重新纳入。这里的关键设计是把选择哪个模型和怎么调用模型解耦。路由策略可以很复杂——按租户、按场景、按成本、按负载但Provider只负责给定请求返回结果。这样加新策略不影响Provider加新Provider不影响策略。5.4 接入Sentinel做流量治理Sentinel的接入分两步引入依赖配置规则。规则可以硬编码也可以放在Nacos里动态推送生产环境强烈建议后者。PostConstruct public void initFlowRules() { ListFlowRule rules new ArrayList(); FlowRule rule new FlowRule(); rule.setResource(chat-api); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); rules.add(rule); FlowRuleManager.loadRules(rules); }限流资源要按维度细分比如租户A的chat接口和租户B的chat接口分开限流避免一个租户把额度占满影响其他人。熔断规则则针对具体的模型Provider某个Provider连续失败就熔断它。5.5 会话存储与上下文窗口管理会话存Redis结构设计如下// key: session:{tenantId}:{userId}:{sessionId} // field: messages - ListMessage // field: meta - Hash(创建时间、最后活跃时间、模型偏好)上下文窗口管理用一个简单策略起步保留最近N轮对话超出时从最老的开始丢弃。进阶做法是做摘要——把被丢弃的历史压缩成一段摘要作为系统消息带上。摘要本身也要调模型所以要有成本控制不能每轮都摘要。提示会话过期时间要合理。太短用户觉得它怎么忘了太长占内存且可能泄露旧信息。常见做法是30分钟无活动过期同时设置绝对过期时间比如24小时。5.6 计量计费的埋点与聚合每次模型调用完成后异步发一条计量消息包含租户、用户、模型、输入Token、输出Token、耗时。消费端聚合到分钟级或小时级写入数据库。配额检查在请求入口做超配额直接拒绝避免先用后付导致账单失控。// 伪代码请求入口检查配额 if (quotaService.isExceeded(tenantId)) { throw new QuotaExceededException(本月额度已用完); }配额数据要缓存不能每次都查数据库否则入口就成了瓶颈。用Redis计数定期同步到数据库做持久化。6. 上线后才会暴露的坑几个真实场景的排查与修复6.1 虚拟线程下的ThreadLocal陷阱升级到JDK 21用虚拟线程后一个隐蔽的问题出现了原来用ThreadLocal存的租户上下文在某些异步场景下取不到了。原因是虚拟线程的调度和平台线程不同ThreadLocal的继承行为在跨线程传递时不可靠。修复方案是改用ScopedValueJDK 21的预览特性或者显式传递上下文对象。如果暂时不想用预览特性就确保上下文在同一个线程内使用跨线程时手动传递。这个坑很典型——新特性带来便利的同时也改变了原有的隐式约定团队必须重新审视那些约定俗成的写法。6.2 模型供应商限流导致的雪崩有一次线上突然大量超时排查发现是某个模型供应商侧限流了我们的请求全部排队等待线程池被占满进而拖垮了其他正常接口。这就是典型的故障扩散。修复分三层第一给每个Provider设置独立的线程池或信号量隔离资源第二Sentinel熔断规则生效连续失败快速切断第三降级逻辑返回兜底响应。改完之后再遇到供应商抖动影响范围被控制在单个Provider内其他功能不受影响。6.3 上下文拼接顺序引发的答非所问用户反馈模型经常答非所问排查发现是上下文拼接顺序错了——系统Prompt被放在了历史消息后面模型把系统指令当成了用户输入的一部分。这类问题在日志里很难直接看出来因为每次调用的输入看起来都有内容。解决办法是在可观测服务里把每次调用的完整Prompt记录下来包括角色标注。排查时一看便知。这也说明为什么可观测性要在设计之初就做事后补会非常痛苦。6.4 配置动态刷新不生效Nacos改了配置服务却没生效。常见原因有三个一是没加RefreshScope注解二是配置的dataId或group对不上三是本地缓存了配置。排查顺序就是从注解到配置坐标再到缓存一层层确认。这个坑几乎每个用配置中心的团队都会踩一次。7. 我对AI应用底座这件事的个人判断做了几个项目之后我越来越确信一件事AI应用的竞争力长期看不在模型本身而在工程能力。模型是大家都能调用的公共资源但谁能把模型稳定、可控、可计量、可审计地集成进业务谁才能真正把AI用起来。QuickBlue 这类底座的价值恰恰在于它把工程能力沉淀下来让业务团队不用重复造轮子。如果你正在考虑要不要做这样一个底座我的建议是先别急着追求大而全。从最痛的那个点切入——通常是模型接入抽象和限流——先解决一个真实业务团队的痛点跑通了再逐步扩展。底座是长出来的不是设计出来的。一上来就规划七八个微服务大概率会陷入过度设计的泥潭。技术选型上JDK 21 值得上虚拟线程对IO密集型场景的收益是实打实的Spring Cloud 生态依然可用但要盯紧依赖的安全更新Sentinel、Nacos、Redis集群这套组合成熟稳定资料丰富适合大多数团队。真正要花心思的是边界划分和可观测性这两件事决定了你的底座是能用还是好用。最后分享一个我自己的习惯每次上线新功能前先问自己三个问题——出问题了怎么发现、怎么定位、怎么回滚。这三个问题答不上来就别急着上线。AI应用的不确定性比传统系统更高这套自检习惯帮我避开了不少深夜救火的夜晚。
返回列表