删不掉的 1.19.1:LangChain4j 发了个事故版本,升错的 Java 团队别乱降级

9 月 7 日,Maven Central 的目录里多了一个新制品:dev.langchain4j:langchain4j:1.19.1。官方同日在 GitHub 发布这个版本的 Release 页。别家发版本,Release 标题写的是"What's New",这一版的标题是一句警告:published in error, do not use (发布有误,请勿使用)。紧接着 1.19.2 的 Release 页也发了出来,两个页面的时间戳 12:47 和 12:49,相隔整两分钟。

两分钟双发,本身就是事故信号。这个"正常"的补丁版本号里,装着的是整个下一个大版本的全部内容------而且,它永远删不掉了。Maven Central 没有撤回键,这颗事故制品会在这个生态里流动很多年。

本文基于 LangChain4j 1.20.2 (主线最新)与 1.19.3(1.19.x 补丁线最新,均截至 2026-09-30)编写,事故信息核对自 GitHub Releases 与 Maven Central 制品目录,文中依赖树输出均为本地实跑结果。框架迭代快,请以官方 Releases 为准。

先把速查表放这------你现在处在哪个状态,比一切都重要:

你的现状 正确动作
还在 1.19.0 或更早 留守 1.19.x 用 1.19.2 / 1.19.3;要追新就直接上 1.20.x
已经升到 1.19.1 别降到 1.19.2------直升 1.20.0 或更高
用 langchain4j-bom 管版本 看一眼 BOM 版本号:只要不是 1.19.1,全家族模块都不会中招

下面按时间顺序拆:事故怎么发生的、我本地怎么复现的"物证"、为什么降级是最差选择、三分钟自查怎么做。

一个"补丁",怎么会装着整个大版本

官方在 1.19.1 的 Release 页里把事故说得很直白,原文值得逐句看:

This release was published by mistake. Do not use it.

It was cut from main instead of release/1.19.x. Despite the version number, it is not a patch on top of 1.19.0: it contains all of 1.20.0 plus three commits that landed after it --- 108 commits and 300 files ahead of 1.19.0.

事故机理一句话:切割分支切错了 。LangChain4j 的正常发布流程是从 release/1.19.x 维护分支上切补丁,这次却从 main 主干直接切------相当于本该从货架取一件包裹,结果连货架带整个仓库一起端走了。main 上早合入了 1.20.0 的全部内容(9 月 4 日刚发布的非阻塞支持、Jackson 3 可选支持,详见我后面要写的 1.20 实测篇)。于是版本号说是 1.19.1,代码实际比 1.19.0 超前 108 个提交、300 个文件。

发现事故后,官方两分钟内发布了本该发布的 1.19.2(内容是 1.19.0 + MCP 补丁回移,除此之外什么都没有),并且在事故页上写了那句每个用 Maven Central 的人都该记住的话:

Maven Central is immutable, so these artifacts cannot be withdrawn. This note is the only way we can flag them.

仓库不可变,制品撤不回,唯一能做的是把 Release 页改成事故公告。我实跑验证过这件事有多彻底:本地起了个空项目依赖 1.19.1,dependency:tree 一路绿灯,下载日志里这行字看得我愣了几秒------

csharp 复制代码
[INFO] Downloaded from aliyun-public: https://maven.aliyun.com/repository/public/dev/langchain4j/langchain4j/1.19.1/langchain4j-1.19.1.jar

一个被官方判了"请勿使用"的制品,正安安静静地从公共镜像流进我的本地仓库。通缉令都贴到 GitHub 门口了,仓库和各路镜像还在热情发货------Maven 不管好人坏人,只管打包递送。Central 删不掉,镜像就跟着删不掉------你的公司私服、云厂商镜像、CI 缓存,都是这颗制品的下一站。

给 1.19.1 做个亲子鉴定,依赖树不会说谎

官方说 1.19.1 里有 1.20.0 的全部内容,我不背数字,直接看树。同一个空项目,分别依赖四个版本各跑一遍 dependency:tree,结果摆在一起:

依赖 1.19.1 1.19.2 1.19.3 1.20.0
io.smallrye.reactive:mutiny-zero:1.3.1 有 无 无 有
org.jspecify:jspecify 1.0.1 1.0.0 1.0.0 1.0.1

1.19.1 的依赖树和 1.20.0 完全同构,跟 1.19.2、1.19.3 这俩"同门师弟"反而不是一家人。多出来的 mutiny-zero 是 SmallRye 的响应式互操作库,正对上 1.20.0 的非阻塞支持------这就是"误吞 1.20.0"留在依赖树上的指纹。

不用读 release notes,光看依赖树就能识破这个版本号的伪装。这一招后面自查时还会用到。

升错的团队,为什么反而不能降级

这是整件事最反直觉、也最容易做错的地方。

直觉说:升错了,退回去啊,1.19.1 挪到 1.19.2,版本号还在往前走,面子上根本不算降级。官方的警告偏偏对着这份体面来,原文如下:

If you are already on 1.19.1, do not "upgrade" to 1.19.2. 1.19.2 is numerically higher but contains less code --- it is the real 1.19.0 + backports, while 1.19.1 accidentally shipped everything up to and beyond 1.20.0. Moving 1.19.1 → 1.19.2 would silently remove ~108 commits of functionality from your build. Go to 1.20.0 or later instead.

数字更大的版本,内容反而更少------语义化版本的宇宙里,这近乎玄学:账面涨了一位,家底反而薄了。因为 1.19.2 才是那个"真正的 1.19.1"(1.19.0 + MCP 回移),而 1.19.1 早就越过它跑到了 1.20.0 前面。从 1.19.1 挪到 1.19.2,名义上是升级,实际是撤退,会静默丢掉大约 108 个提交的功能。

我原本以为这种"降级"最多回退几个 bugfix,树一对比才发现丢的是什么:对照表里 1.19.2 缺的那个 mutiny-zero,就是整个响应式栈的入口。假设你的代码已经用上了 1.20 线的类型(Flow.Publisher 相关),挪到 1.19.2 是编译期报错,还算能查;更阴险的是间接依赖------编译也过、测试也绿,直到某个运行时路径第一次摸到那个不存在的类。

两个连带坑一并交代:

  • beta 模块同坑 :langchain4j-spring 的 1.19.1-beta29 出自同一次故障发布,官方口径是改用 1.19.2-beta29 或 1.20.0-beta30。LangChain4j 的集成模块一直是 beta 双轨版本号(8 月底我在框架盘点里提醒过"升 beta 模块留意 API 变化"),这次连 beta 号都追加了事故。
  • API 对比工具会被骗 :官方在事故页末尾补了一条很细的提醒------revapi 这类"取 X 以下最新版当基线"的工具(oldVersion=RELEASE),会选中 1.19.1 当 1.19.x 的基线,然后对着它报一堆误导性的 API 差异。你的 CI 里如果挂着 revapi 报告,这阵子可能出现"看不懂的接口变动",根源就在这。

三分钟自查,顺手看清 BOM 为什么能防住

自查就一条命令,全树扫事故制品(Gradle 用户跑同名的 dependencies 任务):

csharp 复制代码
$ mvn dependency:tree | grep -C 3 "1.19.1"
[INFO] \- dev.langchain4j:langchain4j:jar:1.19.1:compile

有输出就说明树里有它------注意往上看几行,确认是哪个模块引的(自家 pom 还是三方集成模块传递进来的)。没输出,恭喜,这条你可以划掉了。

比自查更值得看的是 BOM 的表现。LangChain4j 官方文档推荐的引入方式就是 langchain4j-bom(下面以留守 1.19.x 线为例,追主线就把版本号换成 1.20.2):

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-bom</artifactId>
            <version>1.19.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

这里交代一个我自己的乌龙。写稿前我笃定 BOM 序列里不会有事故版本,理由充分到差点说服我------查了 Maven Central,有:langchain4j-bom:1.19.1 和 jar 同一分钟上传(09:37),内部 dependencyManagement 管理的正是 1.19.1 / 1.19.1-beta29。你看,事故从不挑制品类型。这次事故发布的波及面,连 BOM 本身都包括在内。

那 BOM 用户凭什么大概率没事?原因不在"没有事故 BOM",在决策收敛:引入 BOM 后,几十个 langchain4j 模块的版本都跟着 BOM 版本号走,你只需要在一个坐标上不写 1.19.1,全家族就都不会落到事故制品上。不引入 BOM 的团队反过来------每个模块各自声明版本号,每个坐标都是一次可以点错的机会,官方事故页那句"beta 模块改用 1.19.2-beta29 或 1.20.0-beta30"就是在替没收敛版本决策的团队挨个排雷。速查表第三行的底气在这。

官方处置链,值得单独学一遍

把 9 月的发布节奏排成表,能看到一条完整的事故处置链:

日期 版本 说明
9-04 1.20.0 非阻塞支持(#5527)+ Jackson 3 可选支持(#6184)
9-07 1.19.1 事故版,官方标记 do not use
9-07 1.19.2 替补补丁:1.19.0 + MCP 回移(#6329)
9-15 1.19.3 补丁线继续:ClassLoader 配置(#6409)+ MCP 回移(#6412)
9-25 1.20.1 @McpClientSupplier 修复(#6505)
9-28 1.20.2 A2A 修复(#6512),当前最新

两分钟响应、release 页改写成事故公告、beta 模块同步提示、连 revapi 这种边角工具都写了提醒------这套处置在开源项目里算得上范本。两分钟出替补什么概念?贵司生产事故的 MTTR 若有这个数,CTO 做梦都能笑醒------当然,前提是别出这档子事故。同时它也说明另一件事:对一个月更 6 次的框架,发布事故不是"会不会"的问题,是"何时"的问题。1.19.3 还在证明补丁线的存活,留守 1.19.x 的团队依然有安全落点,但每次升 patch 之前看一眼 Release 页标题,这个习惯从这次起得算标配------标题也可能是警告。

版本号不是语义承诺,是信任接口

最后给三档判断:

  • 没上 1.19.1 的团队 :BOM 锁版本打底,CI 里加一条 dependency:tree 全树审计(扫事故制品只是最粗的用法,更值钱的是版本漂移检测),升级前跑一遍你的评测集------这条我在 Agent Evals 那篇 里展开过,升级就是最该跑 Evals 的时刻。
  • 已经上了 1.19.1 的团队:直升 1.20.0 或更高,不要在 1.19.2 停留;升完跑全量回归,重点扫异步和流式路径------你身上已经带着 1.20 的依赖指纹了,退不回去。
  • 1.19.x 留守团队:1.19.3 是当前安全落点,补丁线在维护,可以留;但"三条维护线并行"意味着三条线都得有人盯,盯不过来的话,跟上主线比锁旧线的总成本更低。

我在 模型月抛那篇 里写过"别追新"的治理逻辑,框架月更时代要补上后半句:追新可以,但要追得可回滚。版本号本身不提供这个保证------1.19.1 就是活例子,数字在涨、内容在退。真正提供保证的是你自己的治理动作:锁版本、审依赖、升级前跑评测。

这颗删不掉的 1.19.1 会在 Maven Central 和各家镜像里存在很多年,等到某个新同事翻旧文档把版本号抄进 pom 里,它还能再咬人一次。你的依赖树,是唯一能替你挡住它的东西。

相关推荐
Yuhano1 小时前
W3. 实现Agent工具调用引擎
前端·aigc·ai编程
热爱2331 小时前
dsh里使用chatgpt plus或pro会员而不是apikey,其实很简单。
前端·openai
用户41716576618202 小时前
AI 写完的系统,挂在了 Redis 集群上
ai编程
AI创界者3 小时前
Python 进阶:重构经典设计模式(五)—— 状态模式与观察者模式在 Python 3.10+ 中的类型驱动与事件解耦
人工智能·aigc
四六的六3 小时前
让 Agent 点界面,比补接口贵 30 倍:computer use 成本实测
人工智能·agent·个人开发·ai编程·ai产品·computer use·agent api
zhangfeng11333 小时前
qjlDim 含义 TurboQuant QJL Quantized Johnson-Lindenstrauss,量化JL随机投影
人工智能·算法·ai编程·npu
Flynt4 小时前
Claude Code 103 秒删掉 4.8 万个文件之后,我把自己的仓库"删"了一遍:git 能救的比你想的少
git·ai编程·claude
时晴⁧⁧4 小时前
Skill和MCP推荐清单
ai编程
浅安的邂逅13 小时前
20929-OpenAI 一天踩三脚急刹:暂停前沿训练、叫停 Astra、披露越权访问澳政府网站
人工智能·大模型·ai编程·行业动态·ai日报