“Spring AI Alibaba 停更了”这个消息年初在好几个技术群里传开的时候,我第一反应不是恐慌,而是先看了一眼自己手头几个项目里到底用了多少那个组件的代码。真正让我觉得值得聊的,不是某个具体项目背后的团队怎么调整,而是这件事把不少Java开发者心里那个一直没摆上台面的问题彻底炸出来了:这两年AI应用开发几乎被Python生态包圆了,Java到底还有没有资格坐在这张牌桌边上?我自己做了好几年Java后端,2024年之后又开始接触LLM应用开发,今天这篇就把我踩过的坑、验证过的方案、以及对“Java + AI”这条路的真实判断一次性说清楚。
1. 停更传言刷屏那天,Java开发者真正担心的是什么
1.1 所谓“停更”指的是什么
先说清楚一个基本事实:这次传出来的“停更”,说的是某个阿里系开源的Spring AI适配组件,项目主页进入归档或者提交频率骤降的状态。这类组件的定位,是让Spring Boot开发者能更快地对接各家模型API,省掉自己封装HTTP客户端、管理对话上下文的功夫。它和Spring官方主推的Spring AI主线项目是两个东西,很多人一看到“停更”两个字,第一反应以为Spring官方放弃AI了,这其实是误会。
但我也理解为什么大家会慌。一个由大厂开源出来的、看起来很“官方血统”的组件说停就停,打击的是Java开发者对生态的信心,不是某一行代码。尤其2024年Spring AI官方项目更新节奏一直很快,大家刚觉得“Java在AI时代站稳了”,突然来了这么一出,谁都会多想一想。
1.2 大家慌的点其实不是停更本身
我观察群里的讨论,发现真正让大家不安的不是“少一个开源库”,而是下面这几个朴素的质疑:
- Java在后端存量系统里的地位还在,但AI应用普遍是Python在写,这轮技术红利Java还能不能分到?
- Spring AI官方主线还年轻,社区其他可选方案要么成熟度存疑,要么绑定了特定云厂商,谁敢放心上生产?
- 就算聊到RAG、Agent,Java社区能用的组件是不是还是比Python那边差一大截?
这些问题每一个都成立,但它们全都可以用实践去验证。这篇内容我不打算写鸡汤式安慰,而是把我自己从2024年下半年到现在,在Java项目里接模型、跑RAG、做AB测试的真实过程和结论拿出来,供你参考。
2. LLM应用开发不是Python专属:Java缺的不是能力而是组件生态
2.1 LLM应用开发的骨架:不是只有Python才能跑
先说一个最容易让Java开发者产生自我怀疑的点。总感觉AI应用开发一定要开个Notebook,用 Python 一把梭。实际情况完全不是这样。LLM应用,尤其是ToB系统里的LLM应用,绝大部分做的事情本质上是:
- 编排模型调用,把用户输入、系统提示词、历史记录拼成一次上下文;
- 调用模型API,拿到流式输出的结果,再逐段推给前端;
- 处理工具调用,让模型吐出结构化参数,然后按参数去查数据库或调用内部服务;
- 做RAG,把用户问题和知识库里的片段做相似度检索,把可用上下文拼进提示词;
- 加各种保护,比如敏感信息过滤、结果校验、超时重试、token消耗统计。
你仔细看这套骨架,它和传统的 Java Web 服务几乎没有本质区别。需要的不是高性能数值计算,而是可靠的HTTP调用、灵活的数据结构、完善的流处理、清晰的监控链路。这些都是Java后端的老本行。Python强在模型训练和调研验证,Java强在把这些能力工程化、产品化、稳定地跑在线上。
2.2 Java的存量系统优势恰恰是AI落地的Key
再想一个问题:今天企业里真正想用AI改造的业务,是老板临时打开网页问ChatGPT两句,还是希望已有的订单系统、售后系统、知识库里沉淀的数据能被AI用起来?答案明显是后者。而这些数据,绝大多数都埋在用Java写的、可能已经运行了七八年的系统里。
我在某制造企业做集成项目的时候,客户最想要的是让一线售后人员用自然语言查历史工单处理方案。知识数据全部存在MySQL里,查询接口是Java写的,总不能因为这个需求,就推翻整套系统去搞Python微服务。我们最后就是在原Java服务里加了一个AI问答模块,把知识库定时同步到向量库,再用检索增强生成回答。这个过程中,Java不是“勉强能用”,反而是最合适的。
所以Java在AI时代的核心位置不是“训练模型”,而是做模型和业务系统之间的那座桥。Python想直接对接老系统的内部服务、事务、权限体系,其实绕路得很。
2.3 语言层面的弱点需要正视,但不能以偏概全
当然要说句公道话,Java在AI生态里确实有短板。科学计算生态比Python弱是事实;NumPy、PyTorch这一类库,Java这边体验确实差一些;模型推理时如果有GPU上的定制算子,Java很难直接接管。再一个就是迭代节奏,开源社区新玩法通常是 Python 先跑通,Java 版本慢半拍。
但对我们绝大多数写业务系统的开发者来说,用不到这些底层能力。我们接触模型是通过API,跑本地模型是通过一个独立进程,Java要做的只是当那个“发请求、收结果、做编排”的客户端。用这个角度看,Java 的短板根本没有想象中那么致命。
3. 目前Java侧真正称得上路线的事情:Spring AI主线与社区替代
3.1 Spring AI官方主线到底能做什么
先放下那个停更的组件,我们来看真正应该关注的东西。Spring AI官方主线项目从2024年发布第一个稳定版本开始,到现在已经在往相对成熟的方向走。我自己的使用体验,它目前比较能打的几块能力是这样的:
| Spring AI能力 | 解决的实际问题 | 我的使用感受 |
|---|---|---|
| ChatClient统一API | 不管是接OpenAI风格接口,还是接本地模型服务,都同一套调用方式 | 切换模型供应商时改动很小 |
| Advisors机制 | 把RAG、日志记录、上下文压缩这类横切逻辑插进对话链路 | 类似Spring MVC里的拦截器概念,上手快 |
| 向量存储抽象 | 对上屏蔽不同向量库的差异好在对接多个检索源 | 目前实现还在变,但思路清晰 |
| Observation链路 | 和Micrometer对接,统计调用耗时、token消耗 | 生产监控必备,别再自己写日志埋点 |
Spring AI目前最大的好处不是你多了一个“官方库”,而是它把LLM应用开发在Java世界里规范化了。如果你以前做过Spring Boot,你会发现它的设计思路跟Spring MVC一脉相承:抽象接口、依赖注入、约定优于配置。学习成本比想象中低很多。
3.2 社区替代方案:成熟度参差,但有得选
除了Spring AI,Java社区也有其他思路。比如LangChain的Java版移植类项目、一些国产大厂出的适配封装,以及不少围绕特定向量库和模型供应商的轻量组件。它们各有优势,有的更贴近Python生态的写法,有的集成特定云厂商服务更顺手。但我的建议是,新项目优先选择与Spring生态深度绑定的方向,理由其实不复杂:组件停更的概率和项目的“血统”直接相关,官方主线项目的维护动力更稳定。
那么那个停更的阿里系组件到底还能不能继续用?我的判断是:已经在生产环境稳定跑着的,不必急着删库改架构;但如果是新项目,建议直接切到Spring AI官方主线,或者干脆自己封装一个薄薄的Client。把核心逻辑依赖在一个随时可能停更多组件上,对团队来讲是风险,不是便利。
3.3 自己做薄封装,永远比押宝某个组件重要
这里我想重点展开一个观点:Java开发者在AI时代最该练的不是会哪个AI库,而是“薄封装能力”。所谓薄封装,就是自己写一层极简的接口,把模型调用、上下文管理、重试降级这些事定义清楚,底层具体用哪个官方库,可以随时替换。
我们团队在做AI客服模块时,一开始也想依赖某个库的全部功能,后来发现很多API我们根本用不上。干脆自己写了一个AiClient接口,定义complet()和stream()两个方法,剩下的事全部由实现类去对接具体模型。这样换模型、换SDK,对业务代码的侵入都小很多。这个思路强烈推荐给所有准备在Java项目里引入AI能力的朋友。
4. 从零搭一个Java版RAG问答服务:我的最小可运行方案
4.1 需求与选型:为什么我用这套组合
接下来给一套可以直接抄作业的方案。假设现在要在Spring Boot项目里做一个最简单的知识库问答服务:支持用户传一个问题,系统先检索本地知识片段,再带着片段让模型生成答案。我最终选择的组合是:Spring Boot 3.x + Spring AI主线 + 本地向量库 + 本地模型运行时。选这组,是因为它不依赖任何远端云服务,在公司内网环境也能完整跑起来,便于初学的人在自己电脑上复现。
关键思路是:所有组件都抽象成接口,具体实现可替换。比如今天是本地模型运行时,明天想换成云端大模型,只需要换一个实现类,不需要改Controller和Service层的逻辑。
4.2 核心流程拆解
整个RAG问答服务分成两个阶段:索引构建阶段和问答检索阶段。索引构建阶段,我们把知识库文档切片、向量化、写入向量库;问答检索阶段,我们把用户问题向量化,从向量库找回相似片段,拼进提示词,再交给模型生成回答。
阶段一:索引构建
@Configuration public class EmbeddingConfig { @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { return new SimpleVectorStore(embeddingModel); // SimpleVectorStore适合本地小规模实验,生产可替换为独立向量数据库 } @Bean public ApplicationRunner indexKnowledge(VectorStore vectorStore, EmbeddingModel embeddingModel) { return args -> { // 读取知识库文档目录,按固定长度切块 List<String> chunks = TextSplitter.splitByTokenCount(500); vectorStore.add(List.of( new Document("售后工单模板规范", chunks.get(0)), new Document("售后工单模板规范", chunks.get(1)) // 实际场景应从数据库中加载 )); System.out.println("知识库索引完成"); }; } }阶段二:问答检索
@Service public class RagQuestionService { private final ChatClient chatClient; private final VectorStore vectorStore; public RagQuestionService(ChatClient.Builder builder, VectorStore vectorStore) { this.chatClient = builder.build(); this.vectorStore = vectorStore; } public String answer(String question) { List<Document> similarDocs = vectorStore.similaritySearch( SearchRequest.query(question).withTopK(3) ); String context = similarDocs.stream() .map(Document::getContent) .reduce("", (a, b) -> a + "\n" + b); return chatClient.prompt() .system("你是一名售后知识库助手,只能基于提供的资料回答。资料中没有的内容,明确说不知道。") .user("已知资料:\n" + context + "\n\n用户问题:" + question) .call() .content(); } }4.3 这段代码里藏着的几个关键点
第一,切块长度直接影响回答质量。我踩过的坑是切块太小导致语义不完整,太大导致token浪费且检索精度下降。按token数切块而不是按字符切,在中文场景下差异非常明显。第二,system提示词里写“资料中没有的内容明确说不知道”,能在很大程度上抑制模型胡编。第三,相似度检索TopK不用贪,3条左右对大多数知识库场景足够,TopK太大反而引入不相关内容干扰回答。
向量库的选择也值得聊一下。简单实验可以直接用本地内存向量库,但数据量到十万级别以上,还是得换独立的向量数据库。接法上记得依赖抽象接口,而不是具体库的API。这样以后迁移只是换一个实现Bean的事。
5. 老系统接入AI的务实策略:叠加、兜底、可观测
5.1 老Spring Boot服务如何平稳叠加AI能力
很多Java开发者关心的场景不是“从零写一个新项目”,而是“手上跑着的老系统怎么办”。我在一个库存查询系统上做过真实改造,那个系统的核心流程是:用户在内部IM里发一条自然语言消息,后端解析意图,生成查询条件,去数据库执行查询,返回结果。整个系统没有微服务,单体应用跑了五年。
改造思路就一条:不替换,只叠加。不动老代码,只新增一个AI解析服务。用户消息先走AI意图解析,解析出结构化的查询参数后,仍然调用原来的查询Service。这样AI能力变成了一组新接口,老系统完全感知不到模型的存在。
实现上要注意:解析模型返回的JSON,不要用“正则+胡乱截取”的方式,要用框架自带的严格输出格式校验能力。先声明一个查询参数类,再让模型按这个schema输出。集成后,我们顺手就把“模型输出解析失败”当异常分支处理,触发兜底逻辑,让用户走原来的手工查询界面。
5.2 熔断、降级和成本控制要像做支付一样认真
AI接口也是外部依赖,这一点很多人下意识会忽略。模型服务挂了、慢了、返回了乱格式,如果代码里没有任何防御,故障就会直接传导给用户。我见过最夸张的例子是群里有人吐槽大模型API超时把整个线程池占满了,最后业务系统跟着崩。本质上还是没把模型调用当成慢外部IO去处理。
我的建议是给所有模型调用加上超时、限流和降级三件套。超时时间从判断不要拍脑袋取一个固定值,要看接口的P99耗时,我这边本地模型常见P99在2到4秒,远端模型有时候要到10秒以上,超时给到接口P99的1.5倍比较合理。限流方面,用最基本的测试发现超过并发量时,不是加机器而是直接降级返回缓存答案。成本控制方面,每次调用记录输入输出token数,按月按业务线汇总,这个数据比任何花哨报表都实在。
5.3 可观测性:AI调用链路的四个指标
Java后端最擅长的可观测性,在AI功能上依然有效,只是指标换了一些。我在项目里只盯四个数:
- 请求耗时(区分模型响应时间和整体链路时间)
- Token消耗(输入+输出的分项统计)
- 模型返回的成功率(200和异常分开算)
- 命中兜底的比例(降级次数占比,这个数最能暴露问题)
这四个指标都打进原有的监控面板,每天看一遍,基本能掌握AI模块的健康度。别一上来就追求什么全链路根因分析,先把基础观测落在实处更重要。
6. 我的踩坑清单:关于延迟、上下文管理和本地模型
6.1 三个值得单独拿出来讲的坑
第一个坑是流式输出的前端适配。后端的流式响应很容易写,但前端如果在网关层配置了全局响应缓冲,流式效果会直接变成最后一次性吐出来,用户感觉“慢到爆炸”。排查到最后不是后端问题,是网关关闭缓冲的配置没生效。建议所有做流式输出的项目,提前确认网关和代理层的缓冲策略,别让前端同学白等。
第二个坑是上下文管理。最开始把整段历史消息全部拼给模型,token很快爆掉,回答也开始漂移。后来改成只保留最近N轮消息,并做摘要压缩,效果立竿见影。上下文压缩这步,看起来简单,实际是实现中最需要拿捏的部分:压缩太狠丢信息,压缩太少费token。
第三个坑是本地模型的并发表现。本机跑的大模型看起来挺快,但并发一上来,推理排队会让响应时间直线上升。我们做过一个测试,单卡跑7B模型,并发从1路升到5路,P95延迟从3秒翻到15秒。后来在生产上限制并发数为2,其余请求排队,用户体验反而比放开并发更稳定。关于并发度,Java侧我记得用信号量控制并发调用数,效果很好。
6.2 普通Java开发者的调整:换位思考比换语言更重要
绕了一大圈,再回到最初的那个问题:Java在AI时代还有没有希望?我的观点非常明确:希望不在某个具体开源组件身上,而在于Java本身在软件工程领域的积累。LLM应用开发走到深水区,大家比的不是谁写模型写得快,而是谁能把模型稳定地嵌进复杂业务系统里。
Java的优势在于,你懂事务、懂并发、懂分布式、懂可观测性,这些都是AI应用落地绕不开的工程设计问题。这几年最抢手的人才画像,已经从“会调模型API”变成了“能把模型能力和现有系统无缝融合,还能保证稳定性”的人。这恰恰是Java后端工程师一直积累的核心能力。
所以我建议所有Java开发者,不要把时间花在纠结“要不要转行Python ”上,而是把AI当成一类新的后端依赖,用你熟悉的那套工程方法论去驾驭它。该学的学:RAG、Agent、提示词工程、向量库选型、调用链路的可靠性设计。不该扔的别扔:你现有的架构能力、领域建模能力、排查故障的能力,在AI时代一点都不会贬值,反而会因为稀缺而升值。
最后分享一个我最近一直坚持的土办法:每周抽半天时间,用Java写一个和AI相关的小玩具,可能是一个可以本地跑的语音转文字助手,也可能是一个把团队周报做成知识库的问答Bot。做得多了就会发现,Java和AI并不是什么二选一的关系,它们只是同一个工具箱里相邻的两把锤子。工具再多,最后决定活干得好不好的,还是拿锤子的人。