1. 从一次技术选型争论说起:QuickBlue 到底想解决什么问题
去年年底,我参与了一个中型企业的技术架构评审会。会议室里两拨人吵得不可开交:一拨是做了七八年 Spring Cloud 微服务的老兵,坚持要把新上的 AI 能力拆成独立的推理服务、向量服务、编排服务,走标准的注册中心加网关那一套;另一拨是刚做完几个大模型应用落地的算法团队,觉得微服务那套太重了,一个 Python 脚本加个 FastAPI 就能跑起来的东西,何必套那么多层。
吵到最后,CTO 问了一个很朴素的问题:我们明年要上至少五个 AI 场景,客服、文档问答、代码助手、报表生成、智能巡检,每个场景都要接模型、管提示词、做权限、记日志、控成本。如果每个团队各搞一套,一年之后谁来维护?
这个问题一出来,会议室安静了。因为大家都清楚,真正的问题不是"微服务好不好",而是"AI 应用这件事,有没有一个统一的底座"。
QuickBlue 就是在这个背景下进入我视野的。简单说,它是一个面向企业的AI 应用底座——把 AI 应用开发中那些重复、琐碎、但又绕不开的公共能力(模型接入、提示词管理、会话编排、权限、审计、限流、成本统计)沉淀成一层平台,让业务团队只关心自己的场景逻辑,而不是每次都从零搭一遍轮子。它本身构建在Spring Cloud微服务体系之上,基于JDK 21这样的现代运行时,把传统微服务的治理能力和 AI 应用的特性结合起来。
这篇文章我想聊的不是"QuickBlue 有多好",而是把它拆开来看:一个企业级的 AI 应用底座,为什么需要微服务?微服务在这里到底承担了什么角色?JDK 21 带来了哪些实际收益?以及在真实落地时,哪些坑是文档里不会写、但一定会踩的。如果你正在负责企业 AI 平台的选型或建设,或者你是一个想理解"AI 工程化"到底在工程化什么的开发者,这篇内容应该能给你一些可以直接参考的东西。
2. AI 应用底座的核心设计思路拆解
2.1 为什么"底座"这个词比"框架"更准确
很多人第一反应会把 QuickBlue 这类东西理解成一个"AI 开发框架",就像 LangChain 那样。但框架和底座是两回事,这个区别很关键。
框架解决的是"我怎么把代码写出来",它是一组库、一套 API,你引入到自己的项目里,按它的方式组织逻辑。底座解决的是"我怎么让一堆应用长期稳定地跑起来",它是一个运行环境、一套治理体系,你的应用部署在它上面,享受它提供的公共能力。
打个比方:框架像是给你一套好用的厨具,底座像是给你一个配好水电燃气、有排烟系统、有消防设施的中央厨房。你当然可以拿一套好厨具在自家阳台上做饭,但如果你要同时给几百人供餐,厨具再好也不够,你需要的是那个厨房。
企业为什么需要底座?因为 AI 应用一旦从"demo"走向"生产",问题就从"能不能跑通"变成了"能不能管住"。管住什么?管住模型调用的成本、管住提示词的版本、管住数据的流向、管住谁能用哪个模型、管住出问题时的排查路径。这些事情,框架帮不了你,只有底座能兜住。
2.2 微服务架构在这里扮演的真实角色
热搜词里"微服务架构""微服务拆分""Spring Cloud"反复出现,说明大家最关心的还是这块。我想先泼一盆冷水:不是所有 AI 应用都需要微服务。如果你只是做一个内部小工具,日调用量几千次,单体应用加个模型 SDK 完全够用,硬上微服务是自找麻烦。
那什么时候微服务才真正有价值?我的判断标准是三条:能力需要被多个场景复用、各组件的伸缩需求差异巨大、团队边界和部署边界需要对齐。AI 应用底座恰好三条全中。
先说复用。模型接入层、向量检索层、提示词管理层、审计日志层,这些能力会被客服、问答、代码助手等所有场景共用。如果做成单体,每个场景要么重复实现,要么强耦合在一个大应用里,改一处动全身。拆成服务之后,每个能力有清晰的接口,场景方按需调用。
再说伸缩差异。模型推理是典型的计算密集型,需要 GPU 资源,扩容慢、成本高;而提示词管理、权限校验是 IO 密集型,CPU 就能扛,扩容快。把这两类东西塞在一个进程里,你要么为推理的峰值给整个应用配 GPU,要么让推理被 IO 拖累。拆开之后,各自按自己的节奏伸缩,资源利用率能差出好几倍。
最后说团队边界。AI 平台团队维护底座,业务团队开发场景,这是两个节奏完全不同的团队。底座要稳定、要向后兼容,场景要快速迭代、要频繁发布。如果代码在一个仓库、一个部署单元里,业务团队每次发版都要拉着平台团队一起,效率会被拖死。微服务的独立部署能力,本质上是把组织边界映射成了技术边界。
2.3 技术选型背后的取舍逻辑
QuickBlue 选择 Spring Cloud 而不是别的微服务方案,这个选择本身值得说道。Spring Cloud 生态成熟、组件齐全、Java 开发者基数大,这是优势。但热搜里有一条很扎眼——"spring cloud alibaba 停更了"。这提醒我们,选型不能只看"现在有什么",还要看"三年后还在不在"。
我的经验是,底座类项目选型要遵循"核心依赖求稳、边缘能力求活"的原则。核心的注册发现、配置中心、网关、熔断限流,尽量选社区活跃、有商业支持或者大厂背书的方案,比如 Spring Cloud 官方体系里的组件,或者经过大规模验证的开源实现。边缘的、实验性的能力,可以大胆用新的,坏了换掉成本也低。
JDK 21 的选择也是同理。它是一个长期支持版本,虚拟线程、结构化并发、模式匹配这些特性对 AI 应用这种高并发、大量 IO 等待的场景特别友好。后面我会专门讲虚拟线程在模型调用场景下的实际收益,这里先记住一点:运行时版本的选择,决定了你未来几年能用到哪些语言级能力,选低了会被迫用各种 workaround 绕路。
3. 核心能力模块与实操要点解析
3.1 模型接入层:把"多模型"这件事做扎实
AI 应用底座最基础也最容易做砸的,就是模型接入层。看起来很简单——封装一个统一的调用接口,底下适配不同厂商的模型。但真做起来,坑非常多。
第一个坑是接口语义不统一。不同模型的输入输出格式、参数命名、错误码、流式返回方式都不一样。有的用messages数组,有的用prompt字符串;有的流式返回是 SSE,有的是 WebSocket;有的超时返回 504,有的返回自定义错误体。如果接入层只是简单转发,上层业务就要写一堆 if-else 来适配,那这个底座就白做了。
正确的做法是定义一套内部标准协议,所有模型适配器都往这个协议上靠。我一般会定义这么几个核心字段:model_id(逻辑模型标识)、messages(统一的消息数组)、stream(是否流式)、params(温度、最大长度等采样参数)、metadata(业务透传信息)。适配器负责把标准协议翻译成各家模型的私有格式,再把返回翻译回来。
第二个坑是模型路由和降级。企业通常不会只用一个模型,可能是"主力用 A,A 挂了切 B,敏感数据走私有化部署的 C"。这套路由逻辑如果散落在业务代码里,维护起来是灾难。放在接入层统一做,业务方只需要传一个逻辑模型名,具体走哪个物理模型由底座决定。
这里有个实操细节:路由策略要支持运行时热更新。我见过一个项目,模型切换要改配置文件重启服务,结果线上主力模型限流了,运维手忙脚乱改配置重启,中间停了十几分钟。后来改成从配置中心动态拉取路由规则,秒级生效,这类事故就再没发生过。
提示:模型接入层的错误处理一定要做"错误归一化"。把各家的超时、限流、内容审核拒绝、参数错误统一映射成底座自己的错误码,上层才能写出一致的重试和降级逻辑。否则你会陷入"每个模型一套异常处理"的泥潭。
3.2 提示词管理:被严重低估的工程问题
提示词管理是很多团队一开始不当回事、后来追悔莫及的地方。早期大家都是把提示词硬编码在代码里,改一个词就要发一次版。等到提示词积累到几十上百个,产品、运营都想调,代码仓库变成了文案仓库,就彻底乱了。
一个像样的提示词管理模块,至少要解决四件事:版本化、变量化、灰度、审计。
版本化是说每次修改都留痕,能回滚。这听起来简单,但很多团队就是直接覆盖,出了问题想找回上一版都找不到。变量化是说提示词里的动态部分(用户输入、检索到的文档、历史对话)要用占位符抽出来,而不是字符串拼接,这样提示词模板可以独立于代码维护。灰度是说新版本提示词可以先给一小部分流量用,观察效果再全量。审计是记录谁在什么时候改了什么,出了问题能追溯。
我踩过的一个坑是提示词和代码的耦合。早期我们把提示词模板放在 Java 代码的常量里,结果产品经理想改个措辞,得提需求、排期、等发版,一个字的改动走了一周流程。后来把提示词抽到独立的配置存储里,配合一个简单的管理界面,产品自己就能改,效率天差地别。
具体实现上,我建议提示词模板用类似这样的结构存储:
{ "prompt_id": "customer_service_reply", "version": "v3", "template": "你是一名客服助手。用户问题是:{{question}}。参考资料:{{context}}。请用简洁友好的语气回答。", "variables": ["question", "context"], "model_hint": "general_chat", "created_by": "product_team", "created_at": "2025-01-15T10:30:00Z" }这样业务代码只需要传prompt_id和变量值,具体模板内容由底座管理。改文案不用发版,灰度发布也有据可依。
3.3 会话编排:从"单次调用"到"多步流程"
真实的 AI 应用很少是"一问一答"这么简单。客服场景可能要"意图识别 → 知识检索 → 生成回答 → 敏感词过滤";文档问答要"问题改写 → 向量检索 → 重排 → 生成";代码助手要"上下文收集 → 补全 → 校验"。这些都是多步流程,需要一个编排引擎来串起来。
编排引擎的设计有两种主流思路:代码编排和声明式编排。代码编排就是用编程语言直接写流程,灵活但门槛高;声明式编排是用配置(YAML、JSON 或者可视化拖拽)描述流程,易用但复杂逻辑表达受限。
我的建议是两者结合:简单流程用声明式,复杂流程允许嵌入代码节点。QuickBlue 这类底座通常会提供声明式的编排能力,让业务方用配置就能搭出常见流程,遇到特殊需求再写自定义节点。
编排里最容易出问题的是状态管理和错误恢复。一个五步流程走到第三步失败了,是整体回滚还是从第三步重试?中间产生的临时数据怎么处理?这些如果没设计好,线上会出现各种"半成品"状态。我的做法是给每个流程实例一个明确的状态机,每一步的输入输出都持久化,失败时可以从任意检查点恢复。
3.4 权限、审计与成本控制:企业真正买单的部分
前面几个模块偏技术,权限、审计、成本这三块才是企业客户真正愿意掏钱的地方。因为这三块直接对应着合规、安全和财务三个硬需求。
权限要解决"谁能用哪个模型、哪个提示词、哪个知识库"。企业里不同部门、不同角色的权限差异很大,财务部门的数据不能让研发随便调,外部合作方的应用不能访问内部知识库。这套权限模型要和企业的账号体系打通,通常走 OAuth2 或者对接内部 SSO。
审计要记录"谁在什么时候调用了什么、输入输出是什么、花了多少 token"。这既是合规要求,也是排查问题的依据。我见过一个案例,某业务方反馈 AI 回答质量下降,一查审计日志,发现是他们自己偷偷换了提示词版本,没有走灰度流程。如果没有审计,这种问题能查一整天。
成本控制是最容易被忽视、但最烧钱的一块。模型调用是按 token 计费的,一个没控制好的应用,一个月烧掉几十万很正常。底座要提供按应用、按部门、按模型的成本统计,还要支持配额和告警。比如给每个应用设一个月度 token 上限,快到了就告警,超了就限流。这套机制能让成本从"月底看账单吓一跳"变成"实时可控"。
| 能力模块 | 解决的核心问题 | 关键设计点 | 常见踩坑 |
|---|---|---|---|
| 模型接入 | 多模型统一调用 | 标准协议、路由降级、错误归一化 | 各家格式差异导致上层适配爆炸 |
| 提示词管理 | 提示词可维护可追溯 | 版本化、变量化、灰度、审计 | 硬编码在代码里,改一个字发一次版 |
| 会话编排 | 多步流程自动化 | 状态机、检查点、错误恢复 | 失败后状态不一致,产生脏数据 |
| 权限审计 | 合规与安全 | 对接 SSO、全链路留痕 | 权限模型太粗,无法满足部门隔离 |
| 成本控制 | 费用可控 | 配额、告警、按维度统计 | 没有上限,月底账单失控 |
4. 基于 Spring Cloud 与 JDK 21 的实操落地
4.1 服务拆分:拆到什么粒度才合适
微服务拆分是永恒的话题,热搜里"微服务拆分"反复出现,说明大家是真的纠结。我的经验是,AI 应用底座的拆分要遵循"按能力边界拆,不按技术分层拆"。
什么意思?不要拆成"controller 服务、service 服务、dao 服务"这种按技术分层的,那是分布式单体,比单体还糟。要按业务能力拆:模型接入服务、提示词服务、编排服务、权限服务、审计服务、成本服务。每个服务有自己清晰的职责,对外暴露的是业务能力,不是技术层次。
粒度上,我倾向于中等粒度。太粗了失去微服务的意义,太细了运维成本爆炸。一个判断标准是:如果一个服务的代码量少于两千行,且没有独立的伸缩需求,那它可能不该单独拆出来。另一个标准是团队边界——一个服务最好由一个小组负责,跨组维护的服务迟早会变成没人管的孤儿。
具体到 QuickBlue 这类底座,我见过比较合理的拆分是这样的:网关服务负责统一入口和鉴权;模型接入服务负责所有模型适配和路由;编排服务负责流程执行;管理服务负责提示词、配置、权限的 CRUD;审计和成本可以合并成一个可观测服务。这样五六个核心服务,职责清晰,运维可控。
4.2 JDK 21 虚拟线程在模型调用场景的真实收益
JDK 21 的虚拟线程是这几年 Java 生态最实在的进步之一,尤其对 AI 应用这种"大量 IO 等待"的场景。我拿实际数据说话。
传统平台线程模型下,一个模型调用要占用一个线程,等待模型返回的几秒钟里,这个线程啥也干不了。假设单机线程池配 200,那并发上限就是 200,再多请求就得排队。要提升并发,只能加机器或者加线程数,但线程数一高,上下文切换开销就上来了,得不偿失。
虚拟线程改变了这个模型。它由 JVM 调度,阻塞时自动让出底层载体线程,一个载体线程可以承载成千上万个虚拟线程。同样是等待模型返回,虚拟线程几乎不占资源。实测下来,同样的硬件,用虚拟线程处理模型调用,吞吐量能提升三到五倍,而且代码写法几乎不用改——把线程池换成虚拟线程执行器就行。
// 传统方式:固定线程池,并发受限于池大小 ExecutorService pool = Executors.newFixedThreadPool(200); // JDK 21 方式:虚拟线程,并发能力大幅提升 ExecutorService virtualExecutor = Executors.newVirtualThreadPerTaskExecutor(); // 调用模型 CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return modelClient.call(prompt); }, virtualExecutor);但虚拟线程不是银弹,有两个坑要注意。第一,不要在虚拟线程里做 CPU 密集计算,那会阻塞载体线程,反而更慢。第二,注意 synchronized 块,早期版本里在 synchronized 里阻塞会钉住载体线程,虽然新版本改善了,但能用 ReentrantLock 就用它。第三,连接池要重新评估,虚拟线程能开很多,但下游数据库、模型服务的连接是有限的,别把压力全转嫁过去。
4.3 配置中心与动态治理的落地细节
微服务离不开配置中心,AI 应用底座对配置的动态性要求更高——模型路由、限流阈值、提示词版本、配额上限,这些都可能需要在不重启的情况下调整。
我推荐的做法是分层配置:全局默认配置、环境级配置、应用级配置、实例级配置,优先级从低到高。这样既能统一管理,又能针对特定应用做覆盖。配置变更要有审批和回滚机制,不能谁都能改生产配置。
限流这块,热搜里出现了"spring cloud sentinel datasource redis 集群",说明大家在用 Sentinel 做限流并且把规则持久化到 Redis。这个组合是可行的,但要注意 Redis 集群模式下的一致性。我的经验是,限流规则这种数据,允许短暂不一致,用最终一致就够了,不要为了强一致牺牲性能。规则变更后各实例拉取有延迟是正常的,只要延迟在秒级以内,业务上完全能接受。
注意:配置中心本身是高可用单点,它挂了整个体系都会受影响。生产环境一定要做配置中心的高可用部署,并且客户端要有本地缓存兜底——配置中心不可用时,用最后一次拉到的配置继续运行,而不是直接启动失败。
4.4 可观测性:没有它,微服务就是黑盒
微服务最大的代价就是排查难度上升。一个请求穿过五六个服务,出了问题不知道卡在哪。所以可观测性不是可选项,是必选项。
三件套:日志、指标、链路追踪。日志要结构化,带 traceId,能按请求串起来。指标要覆盖 QPS、延迟、错误率、token 消耗这些关键维度。链路追踪要能画出完整的调用链,看到每个环节的耗时。
AI 应用还有特殊的地方:要记录模型调用的输入输出。这既是审计需求,也是调试需求。但要注意脱敏和存储成本,不能把所有原始数据都无脑存下来。我的做法是,正常调用只存摘要和 token 数,出错的调用存完整内容,并且设置保留期限。
5. 常见问题与排查技巧实录
5.1 模型调用超时与重试的正确姿势
模型调用超时是最常见的问题。很多人第一反应是加大超时时间,但这是治标不治本。超时时间设太长,用户等不起;设太短,正常的长回答会被误杀。
我的经验是分级超时加智能重试。首字节超时(TTFB)设短一点,比如 5 秒,因为模型开始返回通常很快;整体超时设长一点,比如 60 秒,给长回答留空间。重试要区分错误类型:网络抖动、限流可以重试,参数错误、内容审核拒绝重试也没用。重试要加退避,别一失败就立刻重试,那会把下游打垮。
还有一个坑是重试导致的重复计费。模型调用是按 token 收费的,重试一次就多花一次钱。所以重试策略要谨慎,能通过幂等避免的重复调用要避免。
5.2 流式返回中断的处理
流式返回体验好,但中断处理麻烦。用户看到一半,连接断了,是重新生成还是续传?如果重新生成,前面的 token 白花了;如果续传,模型不一定支持。
我的做法是服务端缓存已生成内容。流式返回的同时,把内容按块缓存起来。连接断了,客户端带上已收到的位置重新请求,服务端从缓存里补发缺失部分,必要时再让模型续写。这样既省 token 又体验好。当然,这要求服务端有状态,对架构有额外要求,简单场景可以不做,直接重新生成。
5.3 微服务拆分过细导致的性能问题
前面说拆分要中等粒度,就是因为拆太细会出问题。我见过一个项目,把权限校验拆成了独立服务,结果每个请求都要跨网络调一次权限服务,延迟凭空多了几十毫秒,QPS 一高权限服务先扛不住。
解决办法有两个:一是本地缓存加失效通知,权限数据变化不频繁,可以缓存在本地,变更时通过消息通知各实例刷新;二是合并过细的服务,把调用频繁、耦合紧密的服务合回去。微服务不是越细越好,是要在复用和性能之间找平衡。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决建议 |
|---|---|---|---|
| 模型调用偶发超时 | 下游限流或网络抖动 | 看下游错误码和延迟分布 | 分级超时+退避重试 |
| 流式返回中断 | 连接不稳定或服务端异常 | 查网关和服务端日志 | 服务端缓存+断点续传 |
| 提示词改动不生效 | 缓存未刷新或版本未切换 | 查配置中心和缓存 | 加缓存失效通知 |
| 成本突然飙升 | 某应用调用量异常或重试过多 | 按应用维度看 token 统计 | 配额告警+重试收敛 |
| 服务间调用延迟高 | 拆分过细或网络问题 | 看链路追踪耗时分布 | 合并服务或加本地缓存 |
| 配置中心不可用 | 单点故障 | 查配置中心健康状态 | 高可用部署+本地兜底 |
5.5 几个文档里不会写的实操心得
第一个心得:上线前一定要做压测,而且要压到模型限流为止。很多团队压测只压到自己的服务扛不住,但真实瓶颈往往在模型侧。提前知道模型能扛多少并发,才能合理设置限流阈值。
第二个心得:给每个模型调用打上业务标签。这样成本统计能按业务维度拆开,出问题也能快速定位是哪个业务在异常调用。标签要轻量,别影响性能。
第三个心得:保留一份"降级预案"。主力模型不可用时,切备用模型;所有模型都不可用时,返回兜底话术。这套预案要定期演练,别等真出事才发现预案是坏的。
第四个心得:提示词变更要走灰度,哪怕产品经理催得再急。我见过太多"改一个词导致线上回答质量暴跌"的事故,灰度能救命。
6. 我对企业 AI 应用底座这件事的真实看法
做了几个 AI 平台项目之后,我越来越觉得,AI 应用底座的价值不在于技术多先进,而在于把混乱收敛成秩序。企业里 AI 应用最容易失控的地方,从来不是模型不够强,而是没人管、没标准、没边界。每个团队各搞一套,短期看是灵活,长期看是负债。
QuickBlue 这类底座的意义,就是给企业一个"统一入口"——模型从这里接、提示词从这里管、权限从这里控、成本从这里看。它不一定能让你做出最惊艳的 AI 应用,但能让你做出一堆可维护、可治理、可扩展的 AI 应用。对于要长期投入 AI 的企业来说,后者比前者重要得多。
至于微服务和 Spring Cloud,我的态度是:它们是手段不是目的。用得好,它们让底座具备弹性、可复用、可独立演进的能力;用得不好,它们就是一堆分布式单体加运维噩梦。判断标准始终是那三条——复用需求、伸缩差异、团队边界。三条都满足,微服务值得;只满足一条,再想想。
JDK 21 的虚拟线程是我这两年最愿意推荐的技术升级之一,尤其在 AI 这种 IO 密集场景,投入产出比很高,迁移成本却很低。如果你的底座还跑在 JDK 8 或 11 上,认真评估一下升级,收益会比想象中大。
最后分享一个我自己的习惯:每次设计一个底座模块,我都会问自己一个问题——"如果这个模块三年后要换掉,换的成本有多大?"如果答案是"要动所有业务代码",那这个模块的边界就没设计好。好的底座,每个模块都应该是可替换的,业务方感知不到底层的更替。这个标准帮我避开了很多"看起来很美、实际很脆"的设计。