1. 从一堆微服务开源项目里,我为什么盯上了 QuickBlue
这两年但凡在技术社区里泡过的人,应该都有一种感觉:微服务相关的开源项目多到看不过来。若依微服务Plus、Spring Cloud Alibaba 全家桶、各种电商中台脚手架,随便一搜就是几十个 star 过千的仓库。但真到企业里要落地一个“AI 应用底座”的时候,你会发现能直接拿来用的东西其实没几个——要么是纯业务脚手架,跟 AI 能力完全不搭边;要么是套了个大模型 API 的壳,底层架构经不起推敲。
QuickBlue 就是在这个背景下进入我视野的。简单说,它是一个面向企业级场景的AI 应用底座,底层基于 Spring Cloud 微服务体系搭建,同时把 AI 能力的接入、编排、治理做成了平台化的东西。你可以把它理解成一个“中间层”:往下对接各种模型服务、向量库、工具链,往上给业务系统提供统一的 AI 调用入口和治理能力。它解决的核心问题不是“怎么调一次大模型接口”,而是“当公司有二十个业务线都想用 AI 的时候,怎么统一管、统一控、统一迭代”。
这篇文章适合两类人看。一类是正在做技术选型的架构师或者技术负责人,手里有 AI 落地需求,但不想每个业务团队各搞一套;另一类是对微服务 + AI 结合感兴趣的开发者,想看看一个真实的“AI 应用底座”到底长什么样、里面有哪些坑。我会尽量把设计思路、关键实现、实操细节和踩过的坑都摊开讲,不玩虚的。
2. 拆解“AI 应用底座”这个说法,它到底要解决什么问题
2.1 没有底座的时候,企业 AI 落地是什么状态
我先描述一个特别典型的场景。某公司有三个业务团队同时要做 AI 功能:客服团队要做智能问答,运营团队要做文案生成,数据团队要做报表解读。如果没有统一底座,会发生什么?
客服团队自己申请了一个模型账号,写了一套调用代码,做了个简单的重试逻辑。运营团队用了另一个模型,因为觉得那个写文案效果更好,又写了一套。数据团队干脆在 Python 脚本里直接调,连服务化都没做。三个月后问题全来了:模型账号散落在各个人手里,费用没法归集;每个团队都在重复实现限流、重试、日志、鉴权;想换个模型,得改三个地方;出了线上问题,排查链路长得离谱。
这就是“没有底座”的典型症状。它不是某个技术点没做好,而是能力没有收敛。每个团队都在解决同样的问题,但解决方案互不兼容,最后形成一堆孤岛。
2.2 底座要收敛的四个核心能力
一个合格的 AI 应用底座,我认为至少要收敛四类能力。
第一类是接入收敛。不管底层用的是哪家模型、哪种向量库、哪个工具平台,业务侧只面对一套统一的接口。这层收敛的价值在于,模型可以换,业务代码不用动。
第二类是治理收敛。限流、熔断、降级、重试、超时、鉴权、审计,这些在传统微服务里已经玩得很熟的东西,在 AI 场景下同样需要,而且因为大模型调用又慢又贵,治理的重要性反而更高。
第三类是编排收敛。一个真实的 AI 应用往往不是“调一次模型”就完事,而是“检索 → 组装提示词 → 调模型 → 解析结果 → 调工具 → 再调模型”这样一条链路。这条链路如果每个团队自己写,维护成本极高。
第四类是观测收敛。Token 消耗、调用延迟、成功率、缓存命中率,这些指标必须统一采集、统一展示,否则你根本不知道钱花在哪、瓶颈在哪。
QuickBlue 的设计基本就是围绕这四个“收敛”展开的。下面我逐个拆。
2.3 为什么是微服务,而不是单体或者 Serverless
有人可能会问,一个 AI 底座,为什么非要用微服务?单体不是更简单吗?
这个问题我认真想过。如果你的公司只有一两个 AI 应用,单体确实够了。但底座的定位决定了它要服务多个业务线,而不同业务线的诉求差异很大:有的要求低延迟,有的要求高并发,有的要求强审计。这种差异用单体很难同时满足,因为一个模块的改动可能影响所有人。
微服务的好处在这里就体现出来了:接入层、编排层、治理层、观测层可以独立部署、独立扩容、独立迭代。比如编排层因为要处理复杂链路,资源消耗大,可以单独多给几个实例;接入层相对轻量,可以少给一点。这种弹性是单体给不了的。
至于 Serverless,它在 AI 场景下有个硬伤:大模型调用是长耗时操作,冷启动和超时限制会让体验很糟糕。所以底座这种常驻型的基础设施,微服务是更稳妥的选择。
3. QuickBlue 的整体架构与核心技术选型
3.1 分层架构:从接入到编排到治理
QuickBlue 的架构我习惯分成四层来看。
最底下是基础设施层,包括注册中心、配置中心、网关、消息队列这些微服务的标准件。这一层用的是 Spring Cloud 生态里比较成熟的组件,注册中心选的是 Nacos,配置中心也是 Nacos,网关用的是 Spring Cloud Gateway。
往上是能力接入层,负责对接各种外部能力:大模型服务、向量数据库、工具平台、缓存。这一层的关键设计是“适配器模式”,每种外部能力都有一个对应的适配器,业务侧不直接依赖具体实现。
再往上是编排与治理层,这是整个底座的核心。编排负责把多个能力串成一条链路,治理负责在这条链路上加限流、熔断、重试、缓存。这一层用到了 Spring Cloud Sentinel 做流量治理,用 Redis 集群做分布式缓存和限流数据存储。
最上面是应用接入层,对外暴露统一的 API,业务系统通过这一层来使用底座的 AI 能力。这一层还承担了鉴权、审计、计费等职责。
3.2 JDK 21 带来的实际收益
QuickBlue 明确要求 JDK 21,这个选择不是赶时髦。JDK 21 是 LTS 版本,里面有几个特性对 AI 底座特别有用。
第一个是虚拟线程。AI 场景下大量操作是 IO 密集型的——等模型返回、等向量库查询、等工具调用。传统线程模型下,一个请求占一个线程,并发一高线程池就爆了。虚拟线程让每个请求的线程开销大幅降低,同样的硬件能扛更高的并发。我实测过,在模型调用这种长耗时场景下,虚拟线程带来的吞吐提升相当明显。
第二个是模式匹配和记录类。编排层要处理各种结构化的请求和响应,用记录类定义数据结构,配合模式匹配做解析,代码比传统的 getter/setter 清爽太多,出错概率也低。
第三个是分代 ZGC。底座是常驻服务,对 GC 停顿敏感。分代 ZGC 在 JDK 21 里已经比较成熟,停顿时间控制在毫秒级,对延迟敏感的 AI 调用链路很友好。
提示:如果你的团队还在 JDK 8 或 11,升级到 21 之前一定要做充分的兼容性测试。虚拟线程虽然好用,但和某些依赖 ThreadLocal 的老库配合时会有坑,比如一些老版本的连接池。
3.3 Spring Cloud Alibaba 的现状与选型考量
这里必须说一个很多人关心的问题:Spring Cloud Alibaba 的维护状态。网上一直有“停更了”的说法,实际情况是核心组件(Nacos、Sentinel、Seata)仍在持续更新,只是节奏和以前不太一样。对于企业级项目来说,选型时更该关注的是组件是否稳定、社区是否活跃、出问题能不能找到人。
QuickBlue 选择 Spring Cloud Alibaba 体系,主要看中三点:Nacos 同时做注册和配置,省了一套组件;Sentinel 的流量治理能力开箱即用,规则可以动态下发;整套体系在国内的文档和案例足够多,团队上手成本低。
如果你的团队更倾向原生 Spring Cloud,也完全可行,只是注册配置中心可能要换成 Eureka + Config 或者 Consul,治理组件要自己搭。选型没有绝对对错,关键是和团队的技术栈匹配。
4. 核心模块的实操细节与关键实现
4.1 统一接入层:怎么做到换模型不改业务代码
接入层的核心是定义一套稳定的内部接口,把外部模型的差异屏蔽掉。我举个具体的例子。
假设业务侧要调用一个“对话补全”能力,它面对的是这样一个接口:
public interface ChatCompletionService { ChatCompletionResponse complete(ChatCompletionRequest request); }请求对象里包含消息列表、模型标识、温度参数这些通用字段。业务侧只管构造这个请求,不关心底层是哪个模型。
底层怎么实现呢?每个模型对应一个适配器,适配器实现同一个接口:
@Component public class ModelAAdapter implements ChatCompletionService { @Override public ChatCompletionResponse complete(ChatCompletionRequest request) { // 把内部请求转换成 ModelA 的 API 格式 // 调用 ModelA // 把响应转换回内部格式 } }路由逻辑放在一个工厂或者策略类里,根据请求里的模型标识选择对应的适配器。这样新增一个模型,只需要加一个适配器,业务代码一行不用改。
注意:适配器里一定要做好异常转换。不同模型返回的错误码和错误结构千差万别,如果直接把原始异常抛给业务侧,业务侧就得处理各种奇怪的错误类型。统一转换成底座自己的异常体系,业务侧才好写代码。
4.2 编排引擎:把多次调用串成一条链路
编排是底座里最复杂的部分。我拿一个 RAG(检索增强生成)场景举例,一条完整的链路是这样的:
- 接收用户问题
- 把问题向量化
- 去向量库检索相关文档
- 把检索结果和问题组装成提示词
- 调用大模型生成回答
- 解析回答,判断是否需要调用工具
- 如果需要,调用工具并把结果再喂给模型
- 返回最终结果
这条链路如果让业务侧自己写,代码会非常臃肿。QuickBlue 的做法是把每个步骤抽象成一个“节点”,链路用配置或者 DSL 来描述。
chain: name: rag-qa nodes: - type: embed input: ${question} output: ${vector} - type: retrieve input: ${vector} output: ${docs} - type: prompt template: rag-template input: [${question}, ${docs}] output: ${prompt} - type: llm input: ${prompt} output: ${answer}这种声明式编排的好处是,链路调整不用改代码,改配置就行。而且每个节点的执行情况可以被统一观测,哪个节点慢、哪个节点失败,一目了然。
4.3 治理层:Sentinel 在 AI 场景下的特殊配置
Sentinel 默认的限流熔断策略是为普通 HTTP 接口设计的,直接套到 AI 场景会有问题。最大的问题是大模型调用耗时太长,一个请求可能跑十几秒甚至几十秒,如果用默认的 RT(响应时间)阈值来熔断,几乎每次都会触发。
我的做法是调整熔断策略,把慢调用比例熔断的阈值放宽,同时把统计窗口拉长。具体配置大概是这样的:
DegradeRule rule = new DegradeRule(); rule.setResource("llm-invoke"); rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); rule.setCount(30000); // 30秒才算慢调用 rule.setTimeWindow(60); // 熔断后60秒再尝试 rule.setMinRequestAmount(10); // 至少10个请求才统计 rule.setSlowRatioThreshold(0.5); // 慢调用比例超过50%才熔断限流方面,AI 场景更该关注的是成本控制。可以按 Token 消耗来限流,而不是按请求数。这需要在调用后统计 Token 用量,然后反馈给限流器。Sentinel 本身不直接支持这种模式,需要自己扩展。
提示:Redis 集群做限流数据存储时,要注意集群模式下 Lua 脚本的 key 必须落在同一个 slot。如果限流的 key 设计得不好,跨 slot 操作会直接报错。我一般会在 key 前面加 hash tag,强制同一类限流数据落到同一个节点。
4.4 观测层:Token 消耗和延迟怎么采集
观测这块,底座需要采集的指标比普通微服务多。除了常规的 QPS、RT、错误率,还要采集 Token 消耗、缓存命中率、模型调用分布这些 AI 特有的指标。
采集方式上,我推荐用 Micrometer 做指标抽象,底层对接 Prometheus。每个模型适配器在调用完成后,把 Token 用量、耗时、是否命中缓存这些数据打到指标里。这样在 Grafana 上就能看到按模型、按业务线、按时间维度的消耗情况。
这里有个细节:Token 用量的统计要区分输入和输出,因为很多模型对输入和输出的计费标准不一样。如果只统计总量,成本核算会不准。
5. 实操过程中踩过的坑与排查经验
5.1 微服务拆分粒度:拆太细反而拖慢开发
我见过一个团队,把 AI 底座拆成了十几个微服务:模型接入一个、向量检索一个、提示词管理一个、编排一个、治理一个、观测一个……结果开发效率极低,改一个功能要动三四个服务,联调成本高得吓人。
我的经验是,底座初期拆成三到五个服务就够了:接入服务、编排服务、治理服务、观测服务。等业务量真的上来了,再把其中压力大的部分单独拆出去。过早拆分是微服务落地最常见的坑,没有之一。
5.2 配置中心的坑:动态刷新不是万能的
Nacos 的动态配置刷新很好用,但不是所有配置都能动态生效。比如数据源连接池的配置,改了之后需要重建连接池,光靠@RefreshScope是不够的。还有一些和线程池相关的配置,动态调整后需要重新初始化线程池。
我的做法是把配置分成两类:一类是真正需要动态调整的(比如限流阈值、模型权重),走 Nacos 动态刷新;另一类是启动时确定的(比如数据源、线程池核心参数),走本地配置或者启动参数。不要为了动态而动态。
5.3 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 |
|---|---|---|
| 模型调用频繁超时 | 网络抖动或模型侧限流 | 检查底座到模型服务的网络,查看模型侧返回的错误码 |
| 限流规则不生效 | Sentinel 规则未推送或资源名不匹配 | 检查 Nacos 里的规则配置,确认资源名和代码里一致 |
| Token 统计不准 | 流式响应未正确累计 | 检查流式调用的回调逻辑,确认每个 chunk 都被统计 |
| 缓存命中率低 | 缓存 key 设计不合理 | 检查 key 是否包含随机因子,确认相似请求能命中同一 key |
| 虚拟线程下 ThreadLocal 失效 | 老库依赖 ThreadLocal | 改用 ScopedValue 或显式传参 |
5.4 一个真实的排查案例
有次线上反馈说某个业务线的 AI 调用成功率突然掉到 60%。我先看观测面板,发现失败集中在某个模型上,其他模型正常。再看错误日志,大量超时。
第一反应是模型侧的问题,但联系模型服务方后对方说他们那边正常。于是我抓了一次完整的调用链路,发现请求在底座内部就卡了很久,根本没到模型侧。继续往下查,发现是编排层的一个节点在做向量检索时,Redis 集群有个节点响应特别慢,导致整个链路被拖住。
最后定位到是那个 Redis 节点的内存快满了,触发了频繁的淘汰。扩容之后问题解决。这个案例的教训是:AI 链路的瓶颈不一定在模型侧,底座内部的每个环节都可能是短板。观测要覆盖全链路,不能只盯着模型调用。
6. 这套底座适合什么样的团队,以及后续怎么扩展
QuickBlue 这种 AI 应用底座,最适合的是有多个业务线、有统一治理诉求、有一定微服务基础的团队。如果你的公司只有一个 AI 应用,或者团队里没人懂微服务,那上这套东西反而是负担,不如先用单体把业务跑通。
后续扩展上,我觉得有几个方向值得做。一是多模态能力的接入,现在底座主要处理文本,图片、音频、视频的接入可以复用同样的适配器模式。二是成本优化,比如做模型路由,简单问题走便宜的小模型,复杂问题才走大模型。三是评测体系,把 AI 应用的效果量化,这样才能持续迭代。
我自己在实际操作中的体会是,底座的价值不在于技术多先进,而在于把重复的事情收敛掉。当业务团队不再需要关心限流怎么写、日志怎么打、模型怎么换的时候,他们才能真正把精力放在业务创新上。这才是底座存在的意义。