老魏 · 折腾铺
民宿站监控台双色球点哪抠哪老照片修复Murdoku科学探险家
折腾铺/Java RAG 连载
Java RAG 连载2026-09-08老魏

Java RAG 合集②:版本选择的血泪史,Spring AI 2.0 从搭建到第一个流式调用

Spring AI 2.0.1 已经 GA 三个月,网上教程还在教 1.1。这篇把版本选型、BOM 钉版本、配置扁平化、国内模型接入的坑一次讲透,最后跑通第一个同步 + 流式调用。
Java RAG 合集②:版本选择的血泪史,Spring AI 2.0 从搭建到第一个流式调用

Java RAG 合集②:版本选择的血泪史,Spring AI 2.0 从搭建到第一个流式调用

写这篇的时候我去翻了一下网上还在教的 Spring AI 教程——90% 还在讲 1.1.x,配置属性还带 .options,模块名还是 spring-ai-advisors-vector-store。

但 Spring AI 2.0.0 已经在 2026 年 6 月 12 日 GA,2.0.1(2026-08-21)是当前稳定版。Spring Boot 3.5 / Spring Framework 6.2 2026-06-30 EOL——也就是说,照那些教程写出来的东西,三分之一的依赖已经没安全补丁了。

这篇是实操开篇:怎么选版本、怎么钉版本、第一个同步 + 流式调用、国内模型怎么接、还有 5 个 2.0 升级必踩的坑。全程 Spring AI 2.0.1 + Boot 4.1 + Java 21。


一、为什么版本选择是血泪史

2024 年底你立项的时候,选了 Spring AI 1.0.x。2025 年你照着教程升级到 1.1.x。2026 年初你想再升一档——打开官网一看,2.0 GA 了,1.1 只剩 1.1.7 一个维护版本,Boot 3.5 已经 EOL。

你面对的不是"升不升"的问题,而是升错了怎么办:

每一条都是调试一下午的级别。这篇把这五条一次讲透,抄作业就行。


二、技术栈怎么选:三种情况,三个答案

技术栈选型决策:三种情况三个答案

不是所有项目都该用最新版。新项目没包袱直接上 2.0.1,老项目要看能不能升 Boot,升级困难的才退守 1.1.7。

你的项目 怎么选
新项目 / 重构 Spring AI 2.0.1——官方主推,文档最全,跟 Spring 生态无缝
老项目,Boot 3.x 能升级 先升 Boot 4.1,再上 2.0——Boot 3.5 已 EOL(2026-06-30),无安全补丁
老项目,升不动 Spring AI 1.1.7——末版,只修 bug;用完赶紧排升级排期

不推荐 LangChain4j:抽象更薄、更灵活,但没有 Spring 官方背书。社区版图小、生产案例少、文档比 Spring AI 薄一半。本合集全程不采用。


三、钉版本:BOM 是底线

不管选哪一版,必须用 BOM 钉版本。散装版本 = 编译报 NoSuchMethodError,这个错在 Spring AI 2.0 出现概率比 1.x 高三倍——因为 2.0 模块切得更细,starter、advisor、rag、client-chat 都是独立 artifact,散装很容易配出"两个模块版本号不匹配"的组合。

pom.xml:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>2.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>4.1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
        <!-- 不写 version,由 BOM 统一钉 -->
    </dependency>
</dependencies>

BOM(Bill of Materials)= 一组依赖的"版本清单"。只要 import 进 dependencyManagement,所有 Spring AI 模块的版本就被统一钉死,你就不用一个一个写 <version>。这是 Spring AI 2.0 唯一推荐的依赖管理方式。

starter 命名规则:spring-ai-starter-model-{provider}。OpenAI 就是 spring-ai-starter-model-openai,要接 Anthropic 就换成 spring-ai-starter-model-anthropic,核心 API 完全一样,换 starter 不动业务代码。


四、第一个同步调用:Hello World

application.properties:

spring.ai.openai.api-key=${OPENAI_API_KEY:sk-local-placeholder}
spring.ai.openai.base-url=${OPENAI_BASE_URL:https://api.openai.com/v1}
spring.ai.openai.chat.model=${OPENAI_MODEL:gpt-4o-mini}

API Key 放环境变量,不要写死在 properties。${VAR:default} 写法允许给个本地默认值,CI/生产环境用真实值覆盖。

Java 代码——Spring Boot 自动注入 ChatClient.Builder,你只需要 build() 一下:

@RestController
class HelloController {
    private final ChatClient chatClient;

    HelloController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/ai")
    String hello(String q) {
        return chatClient.prompt()
                .user(q)
                .call()        // 同步调用
                .content();    // 拿 String
    }
}

启动 → 访问 http://localhost:8080/ai?q=讲个笑话 → 等 3-8 秒 → 一股脑返回全部。

.prompt().user(q).call().content() 是整个 Spring AI 的核心链式 API。记住这个形态,后面所有 RAG、工具调用、对话记忆都是在这个链上挂 Advisor。

但——用同步还是流式,看你的场景。下面见。


五、第一个流式调用:差一行代码,体验差一个时代

同步 vs 流式时序对比

同步:用户白屏 5 秒,最后一次性刷出来——用户以为页面卡了。 流式:0.3 秒出第一个字,边生成边看——用户以为你在"打字"给他。

差别只有一行:.call() → .stream(),返回类型从 String 变成 Flux<String>。

@GetMapping(value = "/ai/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<String> stream(String q) {
    return chatClient.prompt()
            .user(q)
            .stream()       // 流式调用
            .content();      // Flux<String>,每产生一个 token 就推一次
}

WebFlux 工程直接接 SSE / WebSocket。Spring MVC 工程需要先用 produces = MediaType.TEXT_EVENT_STREAM_VALUE 告诉 Spring "这流是 EventStream",否则浏览器拿不到。

坑:流式调用别忘了 .content()。不写 .content() 返回的是 Flux<ChatResponse>,每条 chunk 包了一层元数据,业务代码用 String 的话写 getResult().getOutput().getText()——能用但丑。


六、国内模型怎么接:OpenAI 兼容 + 1 个字符的坑

DeepSeek、通义千问、Kimi、智谱 GLM,几乎所有国产 LLM 都兼容 OpenAI 接口协议。也就是说,你用 spring-ai-starter-model-openai 这个 starter 就能接它们——根本不用换 starter。

application.properties 三行搞定切换:

# DeepSeek
spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com/v1
spring.ai.openai.chat.model=deepseek-chat

# 通义千问 DashScope(OpenAI 兼容模式)
spring.ai.openai.api-key=${DASHSCOPE_API_KEY}
spring.ai.openai.base-url=https://dashscope.aliyuncs.com/compatible-mode/v1
spring.ai.openai.chat.model=qwen-plus

# 智谱 GLM
spring.ai.openai.api-key=${ZHIPU_API_KEY}
spring.ai.openai.base-url=https://open.bigmodel.cn/api/paas/v4
spring.ai.openai.chat.model=glm-4-plus

业务代码完全不用改——换模型就是改 3 行配置。

⚠️ 1 个字符的坑(最容易踩):base-url 必须以 /v1 结尾。Spring AI 2.0 改用官方 openai-java SDK,SDK 只会在 base-url 后面拼 chat/completions,不会再帮你拼 /v1。你写 https://api.deepseek.com(少 /v1),SDK 会拼成 https://api.deepseek.com/chat/completions——直接 404,而且报错信息完全不说"路径不对"。

老代码抄过来的同学,第一步就是检查 base-url 是不是有 /v1。这条比 BOM 错误还常见,能查一下午。


七、配置扁平化的 5 个雷:抄这张表就够了

1.1 到 2.0 迁移对照表

2.0 的配置体系砍掉了 .options 这一层、把 ChatOptions 改成 Builder 模式、迁移到各厂商官方 SDK。这些是网上 90% 教程还教错的地方。下面这份清单你截图保存(配置项都省略了 spring.ai.openai 前缀):

① 模型名

② 温度

③ OpenAI 地址

④ Options 传参

⑤ 工具调用

最后两条特别反直觉:


八、老项目升级路径

如果你接手的是 1.1.x 老项目,按这五步走,能少踩一半坑:

  1. 先升 Spring Boot 到 4.1.x(不要 4.0,老版本 4.0.0 有几个 4.0.x 修了的关键 bug)
  2. 引入 spring-ai-bom 钉死 2.0.1(强烈建议先再动业务代码,依赖树先稳)
  3. application.properties 全量改造:.options 段全部去掉(用 IDE 全局搜索 \.options + 替换)
  4. base-url 加 /v1(最容易漏,老项目配里大概率没带)
  5. .options(xxx.build()) 改 .options(xxx)(全局搜索 + 替换,几秒钟)
  6. ToolCallAdvisor 改名 ToolCallingAdvisor(如果用了)

不要做的事:


写在最后

这一篇没碰 RAG 本身——先把"能跑起来"的环境搭好。

下一篇《向量到底是个啥》,我们讲 Embedding 和相似度。RAG 检索靠的就是相似度匹配——"猫坐在垫子上"和"猫科动物趴在地毯上"为什么能被匹配上?Embedding 是怎么把一句话变成一串数字的?这些不讲清楚,第五篇讲向量库选型时你只会跟着别人配,看不懂参数。

点个"在看"——RAG 这条路很长,咱们一篇一篇扎实推进。


作者:老魏 · 一个把公众号和代码当副业的散户投资者 系列:Java RAG 从零到上线(Spring AI 2.0.1) 下期:向量到底是个啥:Embedding 与相似度(人话版)