我把 Spring Boot 升级到 4.0.2 后,顺手重构了整个 AI 脚手架:删模块、加 Skills Agent、补 Resume RAG

很多人以为升级 Spring Boot,只是改几个版本号。
真正升级过一次大版本的人都知道:版本号只是开始,架构清算才是正戏。
Git 仓库: langchain4j-spring-agent/langchain4j-spring-ai

最近,我把自己的 AI 工程脚手架做了一次跨度很大的升级:

  • Spring Boot 升级到 4.0.2
  • Spring Cloud 升级到 2025.1.1
  • Spring AI 升级到 1.1.3
  • LangChain4j 升级到 1.12.2
  • MCP 升级到 0.17.2

本来我以为,这会是一场"改依赖、修编译、跑测试"的常规升级。

结果一动手,我就发现:

这根本不是一次升级。
这是一场针对整个 AI 工程结构的"大体检"。

因为一旦主框架跨代,你迟早都要面对这些问题:

  • 哪些模块已经沦为历史包袱?
  • 哪些服务还值得继续作为主线维护?
  • 旧的设计是不是已经不适合现在的 AI 工程演进了?
  • 文档是不是早就跟代码脱节了?
  • 你到底是在维护一个"能持续进化的工程",还是一堆功能堆出来的 demo?

于是这次我没有停留在"把项目升到 Boot 4"这一步。

我顺手把整个仓库做了一轮 模块收敛 + 主线重构 + 文档重写 + 前端同步修正

一句话总结这次升级:

升级 Spring Boot 4.0.2,只是导火索。真正发生的,是整个 AI 项目开始从"试验场"走向"主线工程"。


一、为什么说 Spring Boot 4.0.2 这次升级,不是"改版本号"那么简单?

很多人看到升级日志,第一反应是:

"不就是把 spring-boot.version 改成 4.0.2 吗?"

如果只是一个小 demo,这么说没毛病。

但如果你维护的是一个多模块 AI 工程,里面同时有:

  • 对话服务
  • RAG 检索
  • MCP 工具服务
  • 安全权限模块
  • 日志模块
  • 前端多套 UI
  • 技能 Agent
  • 简历 RAG
  • 智能分割流程

那升级的影响,就绝不只是 pom.xml 里那一行版本号。

这次我最明显的感受有 3 个。

1)Starter 体系真的变了

尤其是和 Spring Boot 生态深绑定的组件,比如 MyBatis-Plus,这次就不是原来那套惯性写法了。

我最终统一切换到了 Boot 4 对应的 starter

这件事表面看只是依赖替换,实际上影响的是一整套东西:

  • 数据源配置
  • 自动装配行为
  • 多模块依赖一致性
  • 后续新模块的基线写法

也就是说,升级不只是"修能跑",而是要重新确定:

以后整个工程应该按哪套基线继续演进。

2)很多旧模块必须重新判断生死

以前做项目时,很容易出现这种情况:

  • 先搞一个 chat
  • 然后做一个 chat-v1
  • 再做一个 chat-v2
  • 安全模块也会有历史版本
  • 某些 RAG 分块实验也单独留成模块

刚开始看,这像是在"保留探索痕迹"。

但升级时你会突然发现:

这些历史模块会持续制造认知噪音。

比如:

  • 新人不知道该看哪个模块
  • 文档不知道该写哪个模块
  • 前端不知道应该对接哪个版本
  • 你自己后面都不想维护多个平行宇宙

于是这次我决定不再模糊处理,而是直接做结构收敛。

3)最危险的不是代码报错,而是文档早就错了

这次还有一个非常深的感受:

代码报错不可怕,可怕的是代码已经变了,README 还在讲旧世界。

代码错了你很快能发现。

文档错了,通常要等别人被误导之后你才意识到它的杀伤力。

所以这次我同步重写了:

  • 根目录 README.md
  • 后端聚合工程 README.md
  • TECH_WHITEPAPER.md

因为升级完成后,如果文档不重写,那这次升级就只完成了一半。


二、这次升级里,我做的最重要决定不是"加模块",而是"删模块"

很多人做架构升级,会本能地想:

"先别删,先兼容着,留着以后再说。"

但真实情况往往是:

你今天不删,明天它就会继续制造维护成本。

这次我非常明确地把项目主线重新收敛了。

我保留下来并继续强化的主线模块

  • langchain4j-spring-ai-chat-v2
  • langchain4j-spring-ai-security-v1
  • langchain4j-spring-ai-seg-flow
  • langchain4j-spring-ai-skills
  • langchain4j-spring-ai-resume-rag
  • langchain4j-spring-ai-swagger-mcp

我不再把它们当主线维护的模块

  • langchain4j-spring-ai-chat
  • langchain4j-spring-ai-chat-v1
  • langchain4j-spring-ai-security
  • langchain4j-spring-ai-rag-chunk

这一步其实非常关键。

因为一旦主线不明确,后面所有事情都会变得混乱:

  • 文档很难写
  • 代码 review 很难统一标准
  • 新功能不知道放哪
  • 分支管理会越来越乱

所以这次我给自己定了一个原则:

升级窗口,就是做架构减法的最佳窗口。

这句话我非常建议做项目的人记住。


三、这次升级后,项目里最值得说的两个新增主线:Skills Agent 和 Resume RAG

很多项目升级后,只会留下一个"版本升级完成"的提交记录。

但我这次不想只做"升级成功",我更想让项目升级之后 更有方向感

所以这次我重点扶正了两个模块。


1. Skills Agent:终于把"技能目录"做成一个真正能跑的服务了

这是这次升级里我最满意的变化之一。

过去很多人做 skills / prompt / agent 能力时,容易停留在:

  • 读取本地文件
  • 简单拼 prompt
  • 调一下模型
  • 打印个结果

这种做法能验证想法,但很难长期演进。

所以这次我把它正式做成了一个 独立 Skills Agent 服务

它现在已经不仅仅是"会读 skill 文件",而是具备完整的服务能力:

  • health / info / refresh
  • 同步对话 chat
  • 流式对话 chat/stream
  • 会话创建、列表、归档
  • 历史消息分页回放
  • 模型管理
  • 会话级 modelCode
  • Redis 记忆窗口
  • 摘要压缩
  • MySQL 落库

也就是说,现在的 Skills 已经具备这种能力:

不只是"读技能",而是"围绕技能做完整对话闭环"。

这意味着它可以往更多方向继续演进:

  • 本地技能助手
  • 命令型 Agent
  • 团队共享技能平台
  • 与 Swagger MCP / 外部工具服务联动
  • 个人工作流编排

更重要的是,我还顺手给它配了一套新前端:

  • langchain4j-spring-ai-ui-skills

这个前端现在已经支持:

  • 概览页
  • 会话管理
  • 历史消息查看
  • 模型管理
  • 同步 / 流式对话

从"能调用"到"能管理",它已经从一个实验能力变成了一个正式主线。

一句话总结:

Skills Agent 的真正价值,不在于能对话,而在于它已经具备了工程化落地的骨架。


2. Resume RAG:终于不再只谈"通用 RAG",而是做成了业务化 RAG

另一个我这次重点新增和强化的模块,是:

  • langchain4j-spring-ai-resume-rag

我越来越觉得,AI 工程里最容易陷入的一种空转是:

天天讲 RAG、讲向量、讲知识库,但始终没有一个真正贴业务的闭环场景。

所以这次我直接把一个比较真实的业务域拉出来做:简历 RAG

这个模块现在已经打通了完整链路:

  • 简历文件上传
  • 文本内容抽取
  • LLM 语义切窗
  • Elasticsearch 主文档写入
  • Qdrant 向量写入
  • RustFS 文件存储
  • 下载 / 分页 / 检索 / 向量详情查看

这就和"做一个通用聊天页"完全不是一个层次的事了。

因为它真正落到一个更贴近业务的链路里:

文件 → 解析 → 结构化 → 切窗 → 向量化 → 检索 → 返回结果

这类模块的价值是非常高的,因为它更容易让项目往真实场景里落:

  • 人才库检索
  • 候选人画像分析
  • 简历向量召回
  • JD 与简历匹配
  • 招聘侧 AI 能力中台

如果说 Skills Agent 是这次升级里"Agent 主线"的代表,

那 Resume RAG 就是"业务化 RAG 主线"的代表。


四、升级过程中,那些看起来像小 bug 的问题,其实都在暴露架构问题

这次升级里我还修了一些表面很小的问题,但我后来发现,很多小问题其实都在提醒我:

真正该修的,往往不是表象,而是状态设计和工程边界。


1. Skills 对话页的历史消息为什么会"消失又出现"?

我在做 ui-skills 时,遇到一个很典型的问题:

  • 第一次提问,大模型正常回答
  • 第二次提问时,第一次 AI 的回答在页面里不见了
  • 刷新页面后,它又从历史记录里出来了

这个现象非常迷惑。

但顺着查下去,问题本质就很清楚了:

  • 流式输出时,AI 回复先存在临时状态里
  • 临时状态没有及时落到正式消息数组
  • 下一次发送前又触发了一次历史覆盖
  • 后端历史与前端内存状态的同步时机没处理好

最后修复的核心思路是:

  • 流式结束后立刻把 AI 内容写进正式消息列表
  • 不要在下一次发送前随手整体覆盖本地消息
  • 切换会话、清理流式状态、加载历史这些动作要拆清楚

这个问题让我再次确认了一件事:

前端很多"看起来是显示问题"的 bug,本质都是状态模型设计问题。


2. rustfs-data 运行时目录被 git 管住了,分支切换直接卡死

我后来还遇到了一个很典型的工程化问题:

resume-rag 的 RustFS 运行时目录被提交进了 git,结果导致切分支时直接报错:

  • 本地有改动
  • checkout 会覆盖这些文件
  • Git 阻止切换分支

这种问题表面不大,但它非常能说明工程边界是否清楚。

因为 docker/rustfs-data/ 这种目录,本质上属于:

  • 运行时数据
  • 容器挂载数据
  • 本地缓存 / 元信息

它天然就不应该进入版本管理。

后面我把它补进了 .gitignore,这件事虽然小,但它其实提醒了我一个很重要的点:

真正成熟的工程,不只是代码干净,运行时边界也必须干净。


五、这次升级后,我终于觉得这个项目不像"功能堆砌仓库"了

这是我这次升级后的最大感受。

以前这个项目虽然功能不少,但会有一种很明显的感觉:

  • 方向很多
  • 模块很多
  • 试验也很多
  • 但主线感不够强

升级之后,这种感觉明显变了。

现在整个项目最值得继续投入的主线已经很清楚:

  • chat-v2
  • skills
  • resume-rag
  • swagger-mcp
  • seg-flow
  • security-v1

把这些模块放在一起看,会发现这个仓库已经能拼出一个相当完整的企业 AI 工程底座:

现在这套工程能覆盖什么能力?

  • 多轮聊天
  • 流式输出
  • Redis / MySQL 上下文链路
  • 检索增强
  • Swagger 转 MCP Tool
  • Elasticsearch MCP 检索工具
  • Skills Agent 技能服务
  • Resume RAG 业务化检索
  • 智能分割
  • JWT / RBAC 安全治理
  • 日志与测试脚本

换句话说,现在它不再像"做过很多功能的仓库",而更像:

一个边界更清晰、主线更明确、后续更容易继续扩展的 AI 工程框架。


六、为什么我说这次升级最大的收获,不是"升成功了",而是"终于敢做减法了"

做工程时间长了会发现一个特别真实的现象:

加东西,永远很容易。

删东西,永远最难。

因为删除一个模块,意味着你要承认:

  • 它已经完成历史使命
  • 它不值得继续当主线维护
  • 它会干扰后续判断
  • 它继续存在的成本,已经高于它的价值

这件事比改代码难多了。

但一旦你做了,收益也特别明显:

  • 文档更容易统一
  • 新人更容易理解
  • 模块边界更清晰
  • 分支策略更容易管理
  • 下一次升级成本更低

所以如果要我用一句话总结这次升级最大的收获,那我会说:

真正让工程变强的,不是你加了多少能力,而是你有没有勇气趁升级时把不该留下的东西清掉。

这是我这次最深的体会。


七、如果你也准备升级到 Spring Boot 4,我给你 5 条很实在的建议

建议 1:不要把升级理解成"改依赖版本"

版本号只是入口。

真正要重看的,是模块边界、依赖基线、运行时边界和文档口径。

建议 2:趁升级窗口做模块收敛

平时你舍不得删的东西,升级时反而最适合删。

因为升级本身就是一次天然的"全局检查"。

建议 3:一定要同步重写 README 和白皮书

否则你最后得到的,只是一个"代码升级了、文档过时了"的半成品工程。

建议 4:明确哪些目录属于源码,哪些目录属于运行时

像日志、缓存、对象存储、docker 挂载目录,一定要尽早 ignore。

建议 5:把"主线模块"写清楚

这是给后来的人看的,也是给未来的自己看的。

你今天不明确主线,半年后你自己都未必看得懂当时为什么这样拆。


八、最后:这次升级表面在升框架,本质上是在重建项目秩序

回头看这次升级,我觉得最有意思的地方在于:

表面上,我只是把项目升级到了 Spring Boot 4.0.2

但本质上,我其实做的是一件更重要的事:

借一次大版本升级,重新建立了整个 AI 工程的主线秩序。

现在这个项目里,哪些模块是主线、哪些模块只是历史、哪些能力值得继续投入,终于比以前清楚了很多。

我最终得到的,不只是一个"能编译通过的新版本",而是一个更像样的 AI 工程底座:

  • 更少的历史包袱
  • 更清晰的模块边界
  • 更明确的能力主线
  • 更贴近业务的 Skills 与 Resume RAG 能力
  • 更一致的文档体系

如果你现在也在维护一个 AI 项目,或者正准备把老项目升级到新基线,我特别建议你别只盯着版本号。

你真正该问自己的问题是:

这次升级,我只是把依赖升上去了,还是顺手把整个项目真正整理了一遍?

很多时候,真正拉开差距的,不是你升级得多快。

而是你有没有借这次机会,把架构做得更干净。


相关推荐
满腹的小不甘2 小时前
YOLO11改进:注意力魔改 | 微小目标检测 | 上下文增强和特征细化网络ContextAggregation,暴力涨点
人工智能·目标检测·计算机视觉
洒满阳光的午后2 小时前
我做了一个“能理解业务语义”的可观测性 MCP Server:统一接入 Prometheus、OpenObserve 和 SkyWalking
人工智能·ai·prometheus·skywalking·openobserve·mcp
小鱼~~2 小时前
集成学习简介
人工智能·机器学习·集成学习
半兽先生2 小时前
03阶段:机器学习
人工智能·机器学习
.柒宇.2 小时前
LLM大模型认识
人工智能·深度学习·神经网络·阿里云·ai
泉城嵌入式2 小时前
AI工程概念解析:从提示词工程到驾驭工程
人工智能
ModelWhale2 小时前
和鲸科技CEO范向伟亮相“AI极客夜话”:畅谈智能体时代的人才培养与创业路径
人工智能·科技
这张生成的图像能检测吗2 小时前
(论文速读)ControlNet-XS: 从反馈控制系统视角重新思考图像生成的控制机制
人工智能·计算机视觉·controlnet·扩散模型·条件控制扩散模型
Ztop2 小时前
一文说清ChatGPT Pro 5x 和 20x 区别,以及国内如何升级ChatGPT Pro 最新教程
人工智能·gpt·chatgpt