“Spring AI Alibaba 已停更了”这个消息在网上传开的时候,我朋友圈里不少做 Java 后端的朋友都有点坐不住。有人直接问:是不是 Java 在 AI 赛道已经没戏了,要不要转 Python?我个人的判断是:别急着下结论。一个具体生态组件进入停滞期,和整个技术栈有没有未来,这是两件事。我曾经在多个项目里经历过类似“某个框架没人维护了”的恐慌,最后复盘时都会发现,真正的核心能力从来不是一个脚手架仓库决定的,而是你基于稳定生态搭建起来的业务系统和工程能力。
这篇文章想聊清楚三件事:这类“停更恐慌”背后到底在担心什么,Java 生态里做 AI 应用现在有哪些实际可走的路线,以及如果你今天就是一名普通 Java 开发,可以从哪里快速上手、避开哪些坑。跟着把代码和配置过一遍,你会发现 Java 做 AI 应用不仅没死,反而在工程化和集成层面有不少先天优势。
1. 恐慌的根源:一个组件进入休眠,为什么会让整个社区心态波动?
先说现象。Spring AI Alibaba 项目的仓库更新变慢、社区讨论变少,很快就有人把它理解成“Spring 官方不重视 AI”“Java 在这个方向被放弃了”。这种联想看起来顺理成章,但经不起推敲。
1.1 开源组件更新节奏与语言生命力的区别
任何开源项目的更新节奏,受维护者精力、商业优先级、社区活跃度等多方面影响。一个适配项目可能因为组织内部调整、版本路线变化、团队人员变动,暂时进入低活跃期。这很正常,几乎每个大的开源生态都经历过类似阶段。但它不代表 Java 语言、JVM 生态、Spring 框架本身失去了价值。
我用过一个很朴素的生活类比:你住的小区里有一家便利店暂时关门了,不代表整个城市没法生活。便利店是方便你的服务点,而城市的水电、道路、物流系统是基础设施。Java 的核心优势恰恰在基础设施层面:JVM 的稳定、多年积累的类库、企业级中间件生态、大量有经验的工程师。AI 应用要落地,仍然要跑在这些基础设施上。
1.2 新框架活跃度高,不代表它们已经超越企业级技术栈
这两年,Python 生态里几乎每月都有新模型、新框架、新工具链,给人的错觉是“只有快速迭代的技术才有未来”。但你去银行、电信、制造、电商这些行业看看会发现,最核心的交易系统、订单系统、会员系统,Java 依然是主流。LLM 应用再潮,最终也要接入订单、库存、客服工单、用户画像这些已有系统。这些系统的技术债、稳定性要求、安全合规要求,不是靠把代码改成 Python 就能解决的。
我对这类“停更消息”的态度是:把它当成重新审视技术选型的契机,而不是唱衰行业的依据。如果一个组件停止维护了,你就去找替代方案;如果整个方向还在持续演进,那就跟着主流走。Java 生态里的 AI 方向不是在收缩,而是在重新整合。
2. 现实可选的 Java AI 技术路线:不只是“要不要继续用 Spring”
在真正开始写代码之前,先把路线图摊开。Java 生态里做 AI 应用,目前比较成熟的主要有三条路,适用于不同场景。
2.1 Spring AI:面向 Spring Boot 生态的原生方案
Spring AI 是 Spring 生态官方推出的 AI 应用开发框架,它的定位是把接入大模型变成“配置一个 Starter、注入一个 Bean”的事情。它对接 OpenAI、通义、智谱、Ollama 等多家模型提供商,并且提供了 ChatClient、结构化输出、聊天记忆、函数调用、向量存储等完整能力。只要你的项目本身就是 Spring Boot 技术栈,用 Spring AI 的集成成本和心智负担最低。
我常用它实现的功能包括:通过一个 ChatModel Bean 对接后端,用 ChatClient 做请求响应,通过顾问链(Advisor)把上下文记忆、日志审计、限流逻辑统一挂载。这套东西和 Spring Boot 的自动配置、依赖注入、配置中心配合得很好。
2.2 LangChain4j:更独立的 LLM 开发抽象
如果你不想被 Spring 版本绑定,或者希望有一个更贴近模型开发语言的抽象层,LangChain4j 是另一个成熟选择。它的设计思路借鉴了知名 Python LLM 开发框架,但在类型安全、模块化划分上做出了 Java 特色。它提供了模型封装、消息记忆、文档切分、向量存储、AI 服务代理等模块,也可以独立于 Spring 运行,也可以和 Spring Boot 集成。
我自己的体验是:如果你要做一个比较重的 RAG 应用,涉及复杂的文档处理链路,LangChain4j 的抽象会更清晰一点;如果你只是在一个成熟 Spring 服务里加一个智能客服接口,Spring AI 更顺手。
2.3 依托 HTTP + OpenAI 兼容协议的最小接入方案
还有一类项目,既不想引入重型框架,也不想被某家云厂商绑定。这时候可以直接对着大模型服务商的 HTTP 接口写一层很薄的 Client。现在主流模型服务基本都提供 OpenAI 兼容的 /chat/completions 接口,换供应商时只需要改 base-url 和鉴权密钥。
这种方式的缺点是:聊天记忆、工具调用、结构化输出的代码完全要自己维护,废不少事。优点是:依赖极简、稳定性可控、对模型接口的变化敏感度最低。适合那种“我就想快速接一个接口跑通流程”的轻量场景,或者对引入新依赖非常敏感的企业项目。
下面这个表是我实际做选型时常用来参考的,给你一个直观对比:
| 选型方案 | 适用场景 | 维护状态 | 集成成本 | 我最常用的场景 |
|---|---|---|---|---|
| Spring AI | 已有 Spring Boot 服务,需要快速接入模型 | 官方主线活跃 | 低,Starter 引入即可 | 客服助手、知识库问答、内容生成服务 |
| LangChain4j | 需要做完整 RAG/Agent 链路,希望独立于 Spring | 社区活跃 | 中,需要挑选模块 | 复杂文档问答、多步骤任务编排 |
| 原生 HTTP Client | 只做单点接入,想最小化依赖 | 取决于服务商 | 中,重复代码多 | 内网小工具、快速原型验证 |
这里有一条通用经验:不管最终选了什么框架,都把模型接入做成一个独立的配置层。比如把 base-url、api-key、模型名、超时时间、代理开关全部放到配置中心或环境变量,不要散落到业务代码里。这样不管底层换模型商还是框架版本升级,业务侧代码可以尽可能少改动。
3. 亲手实现一个最小可用的 Java AI 服务:别只看标题,跑起来才有体感
光说“有希望”没什么用,我们来动手做一个基于 Spring AI 的智能工单服务。它的功能不复杂:接收用户描述,理解用户意图,给出一个结构化的工单返回值。这个例子会覆盖配置引入、模型接入、结构化输出、提示词模板这几个核心环节,做完之后你会对“Java 做 AI 应用”有非常具体的认知。
3.1 引入依赖与基础配置
假设你用的是 Maven 和 Spring Boot 3.3 以上版本,在 pom.xml 里加 Spring AI 的 BOM 和对应模型 provider 的 starter:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.0.0</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>然后在 application.yml 里配置模型端点。很多国产模型服务兼容 OpenAI 格式,可以直接用下面的方式切换:
spring: ai: openai: base-url: https://your-model-endpoint.example.com/v1 api-key: ${MODEL_API_KEY} chat: options: model: your-dialect-name temperature: 0.7提示:api-key 一定不要硬编码,我会放在环境变量里,或者接入配置中心。否则代码一旦提交到仓库,密钥泄露只是时间问题。
3.2 定义工单数据结构,让模型输出可靠 JSON
大模型返回的内容天然是不稳定的,直接让用户读一大段文本体验不好,所以我会把模型输出约束成结构化 JSON。Spring AI 支持通过@JsonSchema注解或者直接传实体类描述来自动完成输出格式约束。
我定义一个工单返回结构:
public record Ticket( @JsonProperty(required = true, value = "title") String title, @JsonProperty(required = true, value = "category") String category, @JsonProperty(required = true, value = "priority") Integer priority, @JsonProperty(required = true, value = "processingSuggestion") String processingSuggestion ) { }记录类型在这里很好用,因为它天然是只读的,而且可以从构造器自动推断 JSON 序列化结构。优先级我用整数表达,比直接用“高、中、低”这种中文文本更便于后续排序和统计。
3.3 组装 ChatClient,把提示词模板和输出解析串起来
Spring AI 的核心入口是ChatClient,它支持链式调用。先注入一个ChatModel,然后构建出定义好的对话客户端:
@Service public class TicketService { private final ChatClient chatClient; public TicketService(ChatModel chatModel) { this.chatClient = ChatClient.builder(chatModel) .defaultSystem("你是企业客服系统的智能分类助手。请根据用户提交的问题,输出结构化工单。") .build(); } public Ticket parseTicket(String userDescription) { return chatClient.prompt() .user(userDescription) .call() .entity(Ticket.class); } }这里最见效果的是.entity(Ticket.class)这一行。Spring AI 会把你之前定义的 record 结构自动转换成 JSON Schema 放进提示词里,并强制模型按该 Schema 返回 JSON,然后自动反序列化成对象。整个过程中,绝大多数繁琐的 JSON 解析、字段校验都被框架消化掉了。
我实际做过的生产者消费者项目里,只需一步就对 200 条左右的测试数据完成了分类,准确率明显优于直接用文本输出再加规则正则去解析的老方案。这不是说模型变聪明了,而是结构化输出把不确定性消除在了数据入口。
3.4 加入上下文记忆,让多轮对话不“失忆”
工单场景往往不是一次性的。用户会追问“我刚说的设备型号,你说维修周期多久”,如果上下文记忆没有被保存,模型下一轮就是断片的。Spring AI 提供了现成的消息记忆组件,比如MessageChatMemoryAdvisor。我们把它挂到 ChatClient 构造链上:
ChatMemory chatMemory = new InMemoryChatMemory(); ChatClient chatClient = ChatClient.builder(chatModel) .defaultSystem("你是一个帮助用户生成工单的智能助手。") .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build();要按会话隔离记忆,就在调用时传入一个conversationId:
public Ticket parseTicket(String conversationId, String userMessage) { return chatClient.prompt() .user(userMessage) .advisors(a -> a.param("conversationId", conversationId)) .call() .entity(Ticket.class); }这个设计中,conversationId可以是你业务侧的会话号、工单号、用户 ID。结构上完全由你来控制,模型和框架都不关心你的实际用户体系,这种解耦在企业应用里非常加分。
3.5 用函数调用接入已有的 Java 查询逻辑
很多 AI 应用真正落地时都会遇到一个问题:模型只能生成文本,但你想要它调用企业内部数据。比如用户问“我的订单发货了吗”,正确做法不是让模型自己编一个订单状态,而是让模型识别需要查询订单状态,然后调用真实的订单服务方法。
Spring AI 支持通过@Tool注解直接把一个 Java Bean 的方法暴露给模型:
@Component public class OrderTools { private final OrderService orderService; @Tool(description = "根据订单号查询订单当前物流状态") public String findOrderStatus(String orderId) { // 这里调用真实的业务逻辑,返回给模型做归纳 return orderService.queryOrderStatus(orderId).toString(); } }配置好之后,把工具对象加入到 ChatClient 的默认工具中:
ChatClient chatClient = ChatClient.builder(chatModel) .defaultTools(orderTools) .build();这个模式等于把 Java 系统最擅长的领域——可靠的数据访问、事务控制、业务规则——嵌入了 AI 交互链路。模型负责“听懂用户”,Java 方法负责“把事办对”。这也是我认为 Java 在 AI 工程化里最有优势的地方:它不是去替代模型,而是做模型和真实系统之间最可靠的那层连接器。
4. 常见问题与排查技巧:这些坑我基本都踩过一遍
代码跑通只是开始。把 Spring AI 服务放到真实环境里之后,大概率会遇到下面几个问题。我按出现频率从高到低整理出来,附带我实际的排查思路。
4.1 模型输出被截断,JSON 结构不完整
表现:entity(Ticket.class)反序列化时报错,报错信息接近“Cannot deserialize value of type”。原因是模型返回内容超过了上下文长度,或者模型在生成 JSON 收尾时被强制截断。
排查步骤:
- 先看原始响应日志,确认截断处是内容长度问题还是模型输出开始异常。
- 调大模型输出 token 上限,Spring AI 的配置项一般是
max-tokens或max_output_tokens,不同服务商叫法不一样。 - 把返回的 record 字段减少一点,只保留关键字段,结构化输出越精简越稳。
- 对长文档场景先做摘要,再让模型基于摘要生成结果,不要一股脑把全文塞进上下文。
4.2 接口 401/403 鉴权失败
这个问题在换了模型服务商后最容易出现。很多人以为只要改api-key就行,结果接口一直报授权失败。常见原因是模型服务商要求鉴权头不一样,有的是Authorization: Bearer,有的是自定义X-Api-Key,还有的需要在 base-url 后面带对应项目标识。
我的排查方式是:先用 curl 或现成的接口调试工具直接调base-url下的接口,先验证网络和鉴权链路本身通了,再回到 Spring AI 配置里逐项比对。切忌一上来就怀疑框架有问题。框架只是一个客户端,它不会变魔术。
4.3 聊天记忆无限增长,成本飙升
使用MessageChatMemoryAdvisor之后,看起来对话连续了,但如果用户在一个会话里聊了几十轮,历史消息会越积越多,每次请求的 token 消耗会线性增加。真实项目中我见过一个客服机器人每月模型费用翻倍的情况,原因就是这个。
解决思路有两种:
- 定期修剪历史消息,只保留最近 N 轮,加上摘要历史。
- 给 chatMemory 加容量上限,比如只存最近 20 条消息,更早的做丢弃或总结。
Spring AI 的 advisor 可以配置chatHistoryWindowSize,控制只让最近若干条消息进入模型上下文。这属于典型的花小钱省大钱配置。
4.4 结构化输出不稳定,偶尔多一个讲解性前缀
有些模型对 JSON Schema 的遵循程度不够,会在 JSON 前面加上“好的,以下是返回结果:”之类的文字。Spring AI 的处理方式一般能剥掉这种前缀,但仍然会遇到偶发失败。我的经验是:
- 确保在提示词里再强调一次“只输出 JSON,不要包含任何解释性文字”。
- 对特别重要的字段使用
@JsonProperty(required = true),让反序列化器遇到缺字段时可以报错而不是静默接受。 - 在业务层补一层兜底:如果反序列化失败,提示用户重新描述需求,而不是直接抛出异常让前端看到一片红。
4.5 网络超时与连接重置
内部网络到外部模型接口通常不是直连,中间可能经过网关或代理。Spring AI 的默认超时时间不一定适合所有场景,尤其是模型推理时间较长时。我配置过最平稳的超时参数:
spring: ai: openai: connect-timeout: 15s read-timeout: 3m注意的是,读超时要比你模型服务商承诺的最长响应时间长一些。如果设成 30 秒,而模型偶尔需要 45 秒返回,那生产环境里就会不断出现“任务正常处理,但客户端以为自己超时”的伪失败。把超时问题记在排查清单第一位,通常在压力测试阶段就能稳定复现。
5. 架构视角:Java 在 AI 应用链路中最正确的位置是什么
代码和技术选型聊完之后,最后回到一个更根本的问题:Java 在 AI 应用里到底该站在哪里。我的看法很明确:Java 后端不适合也不必要去做模型训练和底层推理,但它非常适合做 AI 应用的企业级编排层、数据层、管控层。
5.1 为什么我把“编排层”视为 Java 的主场
一个成熟的大模型应用,不只是一个对话接口,而是一条完整链路:用户请求进来、语义理解、检索业务数据、调用模型、校验输出、写库、通知下游系统、记录审计日志、处理异常。这条链路的前半段和后半段,几乎全部涉及企业原有的系统和数据。用 Java 的好处在于:你可以非常自然地把 Spring 的声明式事务、接口隔离、消息队列、权限校验、分布式链路追踪全部融合进来。
我之前在一个模拟的客户支持系统里做过一次重构:原先 Python 脚本负责把客服消息直接转给模型,再把结果写回,相当于模型和应用没有任何工程护栏。后来改成 Java 服务,里面用 Spring AI 只做“模型交互”这一件事,其余的逻辑全部复用老系统能力。结果系统的稳定性快速提升,因为 AI 部分被压缩成链路中的一个可观测节点。
5.2 你作为 Java 开发者不必“转行”,但要“扩展”
每次出现“Java 还有希望吗”这类话题,总有人焦虑到想转语言。我的建议是:可以学习 Python 来辅助你的研究和实验,但没必要把主力技能推翻。你已有的 Java 技能,在领域驱动设计、微服务治理、高并发处理、数据库建模这些方面,都是可以直接迁移到 AI 应用里的。你缺的不是语言,而是以下几个新知识面:
- 模型接口的调用方式和参数含义。
- 提示词工程的基础套路,比如角色设定、输出约束、少样本示例。
- 结构化输出和函数调用是什么,能解决什么问题。
- 向量检索的基本概念,以及它与 RAG 的关系。
- 把 AI 功能部署上线时的成本、延迟、限流、评测怎么设计。
这套知识叠加在你已有的 Java 功底上,产生的价值比你去学三个月 Python 做模型训练更快、更贴近实际业务。企业需要的是一个能读懂模型、能设计提示词、能把 AI 能力接入现有系统的后端工程师,而不是一个只会调 Python 脚本的模型封装工。
5.3 从“停更焦虑”中总结出来的选型原则
经历这类事件后,我给自己定了三条选型原则,写在这里供你参考:
第一,主线框架看官方维护,分支组件看社区生态。像 Spring AI 这种主仓还在持续迭代的框架,是值得投入的;单点适配项目进入停滞期,换一个同类实现就行,不确定时可以先在测试环境压测验证,不要在生产里长期依赖某个活跃度很低的分支组件。
第二,抽象层要薄,控制层要厚。不要在一个组件里集成太多定制功能,尽量把模型接入、历史记录、输出校验这些能力做成可替换的模块。真到了要切换供应商的时候,你会感激当初多留了几个配置项。
第三,先做最小闭环,再谈复杂架构。很多人一上来就想做个大而全的 Agent 平台,结果提示词还没调明白,上下文一多就超时崩掉。我建议先用一个普通的消息服务和结构化输出跑通全链路,然后把日志、成本、成功率指标接好,模型使用的体验自然会引导你发现下一步该做 RAG 还是该做 Agent 编排。
最后的操作建议
如果你看完这篇还是不确定从哪里入手,我给你一个不会踩大坑的最小路径:用你现在最熟的 Spring Boot 项目,建一个最简单的模型调用接口,实现“输入一段描述 -> 输出结构化 JSON -> 保存到数据库”的链路。跑通之后,再把记忆、工具调用、向量检索逐个加进来。这整个过程不需要你搭建模型、不需要你处理复杂的机器学习流程,只需要你把模型当作一个远程 API 来设计 Java 服务。
在这个行业里,技术方向偶尔出现波动是常态。我在实际开发中的体会是,真正能扛住波动的,永远是扎实的工程能力和对业务场景的理解能力。Java 从来没有因为某个框架停更而倒下,也绝不会因为 AI 时代的到来变成无用功。你今天把 Spring AI 用熟练,明天不管底层模型换成什么服务商、框架换成什么形态,这套“模型 + 业务逻辑 + 工程护栏”的思维模式都能继续起作用。方向明确,这条路就值得走。