1. 从一次深夜救火说起:为什么“AI 应用底座”突然成了刚需
去年冬天,一个做智能客服的朋友凌晨两点给我打电话,说他们的 AI 问答服务又挂了。不是模型的问题,而是模型前面那层业务系统扛不住了——会话状态丢失、限流规则失效、多个服务之间的调用链断得七零八落。他们团队之前把精力全砸在模型调优上,觉得“AI 应用”嘛,核心就是模型,结果上线三个月,真正拖后腿的全是那些看起来不起眼的基础设施。
这个场景我后来在好几个团队都遇到过。大家一窝蜂地接大模型、做 RAG、搞 Agent,但很少有人认真想过一个问题:AI 能力要真正变成企业里稳定运行的应用,中间那层“底座”到底该长什么样?QuickBlue 就是在这个背景下进入我视野的一个东西。它本质上是一个AI 应用底座,说白了就是给 AI 应用提供一套标准化的运行环境、服务治理能力和工程化支撑,让开发者不用每次都从零去搭微服务、配网关、接限流、管配置。
你可能会问,这不就是传统的微服务框架干的事吗?对,也不对。传统微服务解决的是“服务怎么拆、怎么调、怎么管”的问题,而 AI 应用底座要额外解决的是“模型调用怎么稳定、会话上下文怎么保持、推理请求怎么排队、多模型怎么路由”这些 AI 特有的问题。QuickBlue 的思路是把这两层揉在一起,用JDK 21和Spring Cloud这套成熟的技术栈做地基,在上面叠一层面向 AI 场景的抽象。
这篇文章适合谁看?如果你正在负责企业级 AI 应用的落地,或者你是一个后端工程师被拉来做 AI 项目,又或者你单纯好奇“AI 应用底座”这个词到底指什么,那接下来的内容应该能帮你把这件事想清楚。我会从设计思路、核心技术点、实操落地到踩坑经验,一层层拆开讲。
2. QuickBlue 到底解决了什么问题:AI 应用落地的四道坎
2.1 第一道坎:模型调用不是普通的 HTTP 请求
很多人第一次做 AI 应用,会觉得调模型就跟调一个普通接口一样,发个请求等结果就行了。实际跑起来才发现完全不是这么回事。模型推理的延迟波动极大,同一个 prompt 可能 800 毫秒返回,也可能 8 秒才返回;并发一上来,后端推理服务直接排队排到超时;更麻烦的是,很多模型服务是按 token 计费的,你没法像普通接口那样随便重试。
QuickBlue 在这块的处理思路是:把模型调用抽象成一种受治理的资源。它不是在业务代码里直接写 HTTP 调用,而是通过统一的模型网关层来管理。这一层会做几件事——请求排队与优先级调度、超时与重试策略的精细化控制、token 消耗的实时统计、多模型之间的路由与降级。我实测下来,光是“把模型调用从业务代码里抽出来”这一个动作,就能让后续的运维排查轻松一大截。
注意:模型调用的重试策略和普通接口完全不同。普通接口重试通常是无害的,但模型调用重试可能带来重复计费和重复推理。QuickBlue 默认对推理请求关闭自动重试,只对连接层失败做有限重试,这个设计我认为是对的。
2.2 第二道坎:会话状态和上下文管理
AI 应用和传统 Web 应用最大的区别之一,就是它高度依赖上下文。一个多轮对话的客服机器人,你得记住用户前面说了什么;一个 Agent 任务,你得维护它的执行状态和中间结果。传统微服务里,状态通常放在 Redis 或者数据库里,但 AI 场景下的上下文有它的特殊性——数据量大、生命周期短、访问频率高、结构灵活。
QuickBlue 在这块的方案是提供一个会话上下文服务,把上下文的存储、过期、压缩、检索都封装起来。它底层可以用 Redis 集群做热存储,用对象存储做冷归档,对上层业务暴露统一的 API。我比较欣赏的一点是它对上下文做了分级——最近几轮对话走内存缓存,稍早的走 Redis,更早的做摘要压缩后存储。这个分级策略在实际场景里非常实用,因为大部分对话的有效上下文其实就集中在最近几轮。
2.3 第三道坎:服务治理在 AI 场景下的变形
Spring Cloud 这套东西大家都很熟,服务注册发现、配置中心、熔断限流、链路追踪,该有的都有。但 AI 应用对服务治理提出了一些新要求。比如限流,传统接口按 QPS 限就够了,但 AI 接口你得按 token 数限、按并发推理数限、按用户等级限。再比如熔断,模型服务挂了之后,你是直接返回错误,还是降级到一个更小的模型,还是走缓存结果,这些策略都需要在底座层面支持。
QuickBlue 基于 Spring Cloud 做了不少针对 AI 场景的扩展。它把 Sentinel 的限流规则做了增强,支持按 token 消耗量做流控;在服务路由上,支持根据请求的模型类型、用户等级、当前负载做动态路由。这些能力如果让每个业务团队自己实现,工作量不小,而且很容易做得不一致。
2.4 第四道坎:工程化与可观测性
AI 应用的调试和排障比传统应用难得多。一个请求经过了多少个服务、在每个服务里花了多少时间、模型推理占了多大比例、上下文检索命中了哪些数据,这些信息如果散落在各个日志里,排查起来就是噩梦。QuickBlue 在可观测性上做了统一埋点,把一次 AI 请求的完整链路串起来,包括模型调用的输入输出摘要、token 消耗、各阶段耗时。这个能力在出问题的时候能救命。
3. 技术选型背后的逻辑:为什么是 JDK 21 加 Spring Cloud
3.1 JDK 21 带来的实际收益
QuickBlue 选择 JDK 21 作为基础运行时,这个决定我觉得挺有讲究。JDK 21 是 LTS 版本,虚拟线程(Virtual Threads)正式转正,这对 AI 应用来说是个大利好。AI 应用的典型特征是大量 IO 等待——等模型返回、等向量检索、等上下文读取。传统线程模型下,每个请求占一个线程,并发一高线程池就爆了。虚拟线程让每个请求可以低成本地阻塞等待,吞吐量提升非常明显。
我做过一个简单的对比测试,在一个模拟模型调用的场景下,同样的硬件配置,JDK 21 虚拟线程模式比 JDK 17 传统线程池模式的吞吐量高了将近三倍。当然这个数字会随场景变化,但方向是明确的。另外 JDK 21 在 ZGC 上的改进也让大内存场景下的 GC 停顿更可控,这对需要缓存大量上下文和向量的 AI 应用很重要。
3.2 Spring Cloud 生态的取舍
Spring Cloud 是个庞大的生态,QuickBlue 并没有全盘照搬,而是做了取舍。服务注册发现用的是 Nacos,配置中心也是 Nacos,网关用的是 Spring Cloud Gateway,熔断限流用的是 Sentinel。这套组合在国内的落地案例最多,社区资料也最丰富。
这里有个背景值得提一下——Spring Cloud Alibaba 前几年有过一段停更期,导致很多团队对这套技术栈的可持续性产生过疑虑。QuickBlue 的做法是把核心依赖锁定在稳定版本,同时对关键组件做了自研增强和封装,降低对上游更新节奏的依赖。这个策略我认为是务实的,企业级底座最怕的就是上游一变动自己就跟着抖。
3.3 微服务拆分粒度的考量
AI 应用底座本身也是个微服务系统,拆多细合适?QuickBlue 的拆分粒度大致是:模型网关一个服务、会话上下文一个服务、配置与治理一个服务、可观测性一个服务、业务编排一个服务。这个粒度不算细,但我觉得对底座类系统来说是对的。底座追求的是稳定和低耦合,拆得太细反而增加运维复杂度和调用链长度。
实操心得:底座类系统的微服务拆分,我建议按“变更频率”来拆,而不是按“功能模块”来拆。变更频率相近的放一起,变更频率差异大的分开。这样每次发版的影响面可控,不会因为改一个小功能导致整个底座重启。
4. 核心模块拆解与实操要点
4.1 模型网关层:统一入口与智能路由
模型网关是 QuickBlue 最核心的模块之一。所有对模型的调用都经过这一层,它负责协议适配、请求排队、路由决策、限流熔断、用量统计。协议适配这块,不同模型服务的接口格式不一样,有的走 OpenAI 兼容格式,有的走自定义格式,网关层做统一转换,上层业务只需要按一种格式调用。
路由决策是这里面最有意思的部分。QuickBlue 支持基于规则的路由,比如“VIP 用户的请求走高性能模型,普通用户走经济模型”,也支持基于负载的动态路由,比如“当前 A 模型集群负载超过 80%,自动切到 B 集群”。配置方式是在 Nacos 里写路由规则,支持热更新,不用重启服务。
# 路由规则示例(Nacos 配置) ai: gateway: routes: - id: vip-route predicate: user.level == 'VIP' target: model-cluster-high-performance - id: fallback-route predicate: cluster.load > 0.8 target: model-cluster-economy请求排队这块,QuickBlue 用的是基于优先级的队列。高优先级请求可以插队,低优先级请求在队列满时会被拒绝而不是无限等待。这个设计避免了慢请求拖垮整个系统。
4.2 会话上下文服务:分级存储与智能压缩
上下文服务的设计我前面提过分级存储的思路,这里展开讲一下具体实现。最近 N 轮对话(默认 5 轮)放在本地内存缓存,读写延迟在微秒级;N 到 M 轮(默认 5 到 20 轮)放在 Redis 集群,读写延迟在毫秒级;超过 M 轮的做摘要压缩后存到对象存储,需要时异步加载。
摘要压缩这块,QuickBlue 提供了一个可插拔的压缩策略接口。默认策略是用一个小模型对历史对话做摘要,保留关键信息。你也可以换成基于规则的压缩,比如只保留用户明确提到的实体和意图。这个设计的好处是,上下文长度可控,不会因为对话轮次多了就把 token 撑爆。
// 上下文压缩策略接口示例 public interface ContextCompressionStrategy { CompressedContext compress(List<DialogueTurn> turns); List<DialogueTurn> decompress(CompressedContext context); }4.3 治理与配置中心:Sentinel 的 AI 化增强
Sentinel 本身是个很成熟的限流熔断组件,但它的默认规则是面向 QPS 和线程数的。QuickBlue 在 Sentinel 之上做了一层封装,增加了 token 维度的流控。具体来说,它会在模型网关层统计每个请求的 token 消耗,然后把这个数据喂给 Sentinel 做规则判断。
配置中心用的是 Nacos,所有治理规则、路由规则、模型配置都放在 Nacos 里。这里有个细节值得注意——QuickBlue 对配置做了版本管理和灰度发布。你可以先把新规则推给 10% 的实例,观察一段时间没问题再全量。这个能力在生产环境里非常有用,避免了改错一个配置导致全站故障。
4.4 可观测性:把一次 AI 请求的完整链路串起来
可观测性模块是 QuickBlue 里我觉得最实用的部分。它基于 OpenTelemetry 做埋点,把一次 AI 请求经过的所有服务、每个阶段的耗时、模型调用的输入输出摘要、token 消耗、上下文命中情况都记录下来。这些数据可以在 Grafana 里看,也可以对接企业已有的监控系统。
我特别喜欢它的“请求回放”功能。出问题的时候,你可以根据 trace ID 把一次请求的完整过程回放出来,看到底是哪一步慢了、哪一步错了。这个功能在排查偶发问题时特别管用,因为 AI 应用的问题往往不是必现的。
5. 从零搭建一个 QuickBlue 环境的完整流程
5.1 环境准备与依赖检查
搭建 QuickBlue 环境之前,先把基础依赖确认一遍。JDK 21 是必须的,建议用 Eclipse Temurin 或者 Oracle 的官方版本。Nacos 建议用 2.x 版本,单机模式够开发用,生产环境至少三节点集群。Redis 建议 7.x,如果要用到向量检索能力,可以考虑 Redis Stack。
# 检查 JDK 版本 java -version # 应该输出类似:openjdk version "21.0.x" # 启动 Nacos(单机模式) sh startup.sh -m standalone # 启动 Redis redis-server /path/to/redis.conf内存方面,开发环境建议至少 16GB,因为要同时跑 Nacos、Redis、网关、上下文服务、治理服务好几个进程。生产环境按实际流量估算,模型网关层是资源消耗大户,建议单独部署。
5.2 核心服务启动顺序与配置要点
QuickBlue 的各个服务有启动依赖关系,顺序搞错了会报错。正确的顺序是:先起 Nacos 和 Redis,再起治理与配置服务,然后起模型网关和上下文服务,最后起业务编排服务。每个服务的配置都从 Nacos 拉取,所以 Nacos 必须先就绪。
# 模型网关核心配置示例 server: port: 8080 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 ai: gateway: model-clusters: - name: model-cluster-high-performance endpoint: http://model-a:9000 max-concurrency: 50 - name: model-cluster-economy endpoint: http://model-b:9000 max-concurrency: 100配置里有个参数max-concurrency需要根据实际模型服务的承载能力来设。设大了会把模型服务打挂,设小了浪费资源。我的经验是先从保守值开始,观察模型服务的 CPU 和显存使用率,逐步往上调。
5.3 验证底座是否正常工作的检查清单
环境搭好之后,别急着接业务,先做一轮基础验证。我整理了一个检查清单,按顺序过一遍基本能确认底座是健康的。
| 检查项 | 验证方法 | 预期结果 |
|---|---|---|
| 服务注册 | 访问 Nacos 控制台服务列表 | 所有 QuickBlue 服务都在列 |
| 配置拉取 | 查看各服务启动日志 | 无配置拉取失败报错 |
| 模型网关连通 | 调用网关健康检查接口 | 返回所有模型集群状态 |
| 上下文读写 | 调用上下文服务测试接口 | 写入后能正确读出 |
| 限流生效 | 压测工具打满 QPS | 超出阈值后返回限流错误 |
| 链路追踪 | 发起一次请求后查 trace | 完整链路可见 |
这套检查做完,底座基本就算跑起来了。接下来就是接业务、调参数、观察运行状态。
6. 实际落地中踩过的坑与排查技巧
6.1 模型网关超时设置的那些坑
超时设置看起来简单,实际很容易踩坑。我遇到过好几次因为超时设置不合理导致的问题。有一次是把网关的读超时设成了 5 秒,结果有些复杂推理请求需要 8 秒才返回,全被网关掐断了。后来改成 30 秒,又出现了慢请求堆积把连接池占满的问题。
最后的方案是分层设置超时:连接超时 2 秒,读超时按模型类型区分,轻量模型 10 秒,重量模型 60 秒,同时在网关层做并发隔离,不同模型集群用不同的连接池。这样既不会误杀正常请求,也不会让慢请求拖垮整个网关。
注意:超时时间不是越长越好。超时设长了,故障时请求堆积更严重;设短了,正常请求被误杀。关键是配合并发隔离和队列控制一起用。
6.2 上下文丢失问题的排查思路
上下文丢失是 AI 应用里比较常见的问题,表现是用户明明前面说过了,机器人却像失忆一样。排查这类问题,我一般按这个顺序走:先确认上下文有没有写进去,再确认有没有读出来,最后确认读出来的内容对不对。
写不进去的原因通常是 Redis 连接问题或者序列化失败。读不出来的原因可能是 key 过期了、被 LRU 淘汰了、或者读的是错误的 key。读出来内容不对的原因可能是压缩策略有问题,把关键信息压没了。QuickBlue 的上下文服务有详细的日志,每个操作都有记录,顺着日志查一般都能定位到。
6.3 限流规则配置不当引发的雪崩
限流规则配错了比不配还危险。我见过一个案例,限流阈值设得极低,正常流量都被限了,然后客户端疯狂重试,反而把系统打得更惨。还有一个案例是限流规则只配了总入口,没配下游服务,结果入口限住了,下游还是被内部调用打挂。
QuickBlue 的限流支持多层级配置,入口一层、网关一层、每个下游服务一层。我的建议是每层都配,而且阈值要有梯度,入口最宽,越往下越窄。另外一定要配 fallback 逻辑,被限流之后返回什么、怎么提示用户,这些都要提前想好。
6.4 常见问题速查表
| 现象 | 可能原因 | 排查方向 | 解决思路 |
|---|---|---|---|
| 请求全部超时 | 模型服务挂了或网络不通 | 检查模型服务健康状态 | 确认模型服务,检查网络策略 |
| 部分请求失败 | 限流触发或队列满 | 查看限流日志和队列深度 | 调整阈值或扩容 |
| 上下文丢失 | Redis 过期或 key 错误 | 查上下文服务日志 | 调整过期时间,检查 key 生成逻辑 |
| 响应变慢 | 模型负载高或 GC 停顿 | 看模型服务指标和 JVM 监控 | 扩容模型服务,调 GC 参数 |
| 配置不生效 | Nacos 推送失败或缓存 | 查 Nacos 推送日志 | 重启服务或手动刷新配置 |
7. 我对 AI 应用底座这件事的一些个人看法
做了一段时间的 AI 应用落地,我越来越觉得“底座”这个东西的价值被低估了。大家的目光都在模型上,觉得模型强则应用强,但实际决定一个 AI 应用能不能稳定跑起来的,往往是底座这一层。模型可以换,底座换起来就伤筋动骨了。
QuickBlue 这套东西给我的启发是,AI 应用底座的核心不是堆功能,而是把 AI 场景下的那些“特殊需求”用工程化的方式固化下来。模型调用要治理、上下文要管理、限流要按 token 算、链路要能追踪,这些需求每个做 AI 应用的团队都会遇到,与其各自造轮子,不如有一个统一的底座来承载。
当然,底座也不是越厚越好。我见过一些团队把底座做得极其复杂,结果业务团队用不起来,最后还是绕过底座自己干。底座的边界应该是:把通用的、稳定的、与业务无关的能力收进来,把变化的、个性化的留给业务层。这个边界怎么划,每个团队要根据自己的情况来定。
最后分享一个小技巧:如果你刚开始做 AI 应用底座,别一上来就追求大而全。先把模型网关和上下文服务这两个最核心的模块做扎实,让业务能跑起来,然后再逐步补治理、可观测性这些能力。底座是长出来的,不是设计出来的。