摘要:Java 程序员想接大模型,别自己写 HTTP 请求了——Spring AI 2.0 让这一切像写 CRUD 一样简单,还能让 AI 用上你的业务工具


前阵子朋友问我:

“我想在项目里接个大模型做个智能客服,是不是得自己用 HttpClient 调 OpenAI 的 API?还要处理流式响应、JSON 解析、多轮对话上下文……想想就头大。”

说实话,去年我也是这么想的,还真的手写过一段。JSON 解析、重试、token 计数、上下文拼接,写了两天,bug 一堆。

直到我用了 Spring AI——Spring 官方出的 AI 框架。20 分钟,从零到一个能对话的 AI 接口。

这篇写给 Java 程序员,不扯原理,直接上手。文中的内容都对照了 Spring AI 官方文档(spring.io/projects/spring-ai),当前版本 2.0.0


Spring AI 是什么

Spring AI 是 Spring 生态官方的 AI 应用框架,专门解决"Java 怎么接大模型"这个问题。

你可以这么理解:

  • JDBC 之于数据库 = Spring AI 之于大模型

  • 以前你连 MySQL 不会自己写 TCP 协议,现在你接 GPT 也不用自己写 HTTP 请求

官方文档的说法是:它提供跨模型提供商的 Portable API(可移植 API),同步、流式都支持;还内置了结构化输出、Function Calling、向量数据库、可观测性、RAG 等一整套能力。

换模型供应商,改一行配置就行,代码一行不用动。

2.0 版本的核心就是 ChatClient——一个链式调用的 Fluent API,官方文档说它"惯用法上跟 WebClient 类似",写起来跟 Stream 流一样顺。


Spring AI 2.0 到底能干什么

按官方文档的功能清单,Spring AI 2.0 主要解决这几件事:

1. 一套 API 接所有模型

官方原生支持 OpenAI、Anthropic、Amazon Bedrock、Mistral、Ollama 等模型提供商,能力覆盖对话补全、向量 Embedding、文生图、语音转文字、文字转语音、内容审核六大类。

注意:DeepSeek、通义千问这类国内模型,官方没有独立 starter,但它们大多提供 OpenAI 兼容接口,配置 base-url 就能接入(后面 Ollama 章节会演示类似做法)。

2. 结构化输出——AI 返回直接变对象

Structured Outputs 是官方明确列出的能力:把模型输出映射成 POJO。.entity(News.class) 一行搞定,不用自己写 JSON 解析。

3. Function Calling——让 AI 调用你的代码

官方定义是"允许模型请求执行客户端侧的工具和函数"。AI 说"我要查天气",你写的 getWeather() 方法就被调起来了。2.0 里这块的 API 从 FunctionCallback 迁移到了 ToolCallback。

4. 可观测性——出问题知道去哪查

官方文档明确写了 Observability:对 AI 相关操作提供洞察。请求耗时、token 消耗、错误原因都能上监控,不用靠猜。

5. 对 MCP 的支持——让 AI 用上你的工具

MCP(Model Context Protocol)你可以理解成"AI 世界的 USB 接口"——一个标准协议,让 AI 能调用外部的工具和数据源。官方文档有专门的 MCP 章节。

6. 记忆和 RAG

官方支持 Chat Conversation Memory(对话记忆) 和 RAG(检索增强生成)。多轮对话、让 AI 读你的文档,都是官方能力,不是野路子插件。

小提示:以上全部出自官方文档的 Features 清单和参考指南。技术文章怕写错,建议收藏官方地址随时核对。


准备工作

三样东西:

1. JDK 17+(Spring Boot 3.x 的要求)

<span leaf="">java -version</span><span leaf=""><br></span><span leaf=""># 确认版本 &gt;= 17</span><span leaf=""><br></span>

2. 一个模型 API Key

想花钱省事的:OpenAI 注册拿 Key。

一分钱不想花的:装 Ollama 本地跑模型(后面有专门一节)。

3. 一个 IDE(IDEA 用着顺手)


第一步:建项目

打开 start.spring.io,按这样选:

  • Project

    :Maven

  • Language

    :Java

  • Spring Boot

    :3.4 或更高版本(Spring AI 2.0 官方基于 3.4.2 做依赖管理)

  • Dependencies

    :Spring Web + Spring AI(OpenAI 或 Ollama,看你用哪个)

依赖选完之后,点 Generate 下载,解压,用 IDEA 打开。

如果你已经有一个 Spring Boot 项目,直接加依赖也行。官方推荐用 BOM 管理 Spring AI 的版本(因为它的发布节奏比 Spring Boot 快):

pom.xml

<span leaf="">&lt;!-- 1. 加 Spring AI BOM,统一管理版本 --&gt;</span><span leaf=""><br></span><span leaf="">&lt;dependencyManagement&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;dependencies&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &lt;dependency&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;artifactId&gt;spring-ai-bom&lt;/artifactId&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;version&gt;2.0.0&lt;/version&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;type&gt;pom&lt;/type&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;scope&gt;import&lt;/scope&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &lt;/dependency&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;/dependencies&gt;</span><span leaf=""><br></span><span leaf="">&lt;/dependencyManagement&gt;</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&lt;!-- 2. 加 OpenAI starter,版本不用写,BOM 管 --&gt;</span><span leaf=""><br></span><span leaf="">&lt;dependency&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;artifactId&gt;spring-ai-starter-model-openai&lt;/artifactId&gt;</span><span leaf=""><br></span><span leaf="">&lt;/dependency&gt;</span><span leaf=""><br></span>

如果项目不是通过 start.spring.io 建的,BOM 管理能避免"版本对不上"的坑。具体版本号以 Spring AI 官网 当前稳定版为准。


第二步:配置 application.yml

在 src/main/resources/application.yml 里写:

<span leaf="">spring:</span><span leaf=""><br></span><span leaf="">&nbsp; application:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; name: spring-ai-demo</span><span leaf=""><br></span><span leaf="">&nbsp; ai:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; openai:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; api-key: ${OPENAI_API_KEY} &nbsp; &nbsp; &nbsp;# 你的 Key,用环境变量传,别硬编码</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; chat:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; options:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; model: gpt-4o-mini &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 模型名,性价比之选</span><span leaf=""><br></span>

注意: 如果你的 API 走代理或者用国内中转,还需要配 base-url:

<span leaf="">spring:</span><span leaf=""><br></span><span leaf="">&nbsp; ai:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; openai:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; base-url: https://你的中转地址/v1</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; api-key: ${OPENAI_API_KEY}</span><span leaf=""><br></span>

第三步:写代码

Spring AI 2.0 最爽的地方来了——ChatClient 自动注入,一行配置都不用写。

ChatController.java

<span leaf="">@RestController</span><span leaf=""><br></span><span leaf="">public class ChatController {</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; // ChatClient 由 Spring 自动装配,直接用</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; private final ChatClient chatClient;</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; public ChatController(ChatClient.Builder builder) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; this.chatClient = builder.build();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; // GET /chat?msg=你好</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; @GetMapping("/chat")</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; public String chat(@RequestParam String msg) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; // 链式调用:prompt → user → call → content</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; return chatClient.prompt()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .user(msg)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .call()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .content();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span>

就这么多。没有 HTTP 客户端、没有 JSON 解析、没有重试逻辑。

官方文档里的 ChatClient 关键 API:

| 方法

|

作用

call().content()

返回 String

| | call().entity(Class) |

返回指定类型的对象

| | call().chatResponse() |

返回完整的 ChatResponse(含 token 消耗等元数据)

| | stream().content() |

流式返回 Flux

|


第四步:跑起来

<span leaf="">mvn spring-boot:run</span><span leaf=""><br></span>

启动成功后在浏览器访问:

<span leaf="">http://localhost:8080/chat?msg=用一句话介绍你自己</span><span leaf=""><br></span>

几秒钟后返回模型的回答。

20 分钟不到,你的第一个 AI 应用已经能跑了。

跟手动写 HttpClient 的版本比一下,代码量大概缩了 90%。


进阶一:结构化输出

默认返回的是字符串。但真实项目里,你想让 AI 返回 JSON 直接塞进对象——比如让 AI 提取一条新闻的时间、地点、人物。

News.java

<span leaf="">public record News(</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; String title, &nbsp; &nbsp; &nbsp; // 标题</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; String location, &nbsp; &nbsp;// 地点</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; String date &nbsp; &nbsp; &nbsp; &nbsp; // 日期</span><span leaf=""><br></span><span leaf="">) {}</span><span leaf=""><br></span>

Controller 里

<span leaf="">@GetMapping("/extract")</span><span leaf=""><br></span><span leaf="">public News extract(@RequestParam String text) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; return chatClient.prompt()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .user("从下面的新闻中提取:标题、地点、日期。\n" + text)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .call()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .entity(News.class); &nbsp; // 直接转成对象!</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span>

.entity(News.class) 这一行,AI 返回的 JSON 自动帮你解析成对象。 官方文档还支持 entity(ParameterizedTypeReference<T>)——比如要返回 List<News> 这种集合类型,用这个就行。


进阶二:流式输出

ChatGPT 那种一个字一个字往外蹦的效果,用 stream:

<span leaf="">@GetMapping(value = "/chat/stream", produces = "text/plain")</span><span leaf=""><br></span><span leaf="">public Flux&lt;String&gt; chatStream(@RequestParam String msg) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; return chatClient.prompt()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .user(msg)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .stream()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .content(); &nbsp; // 返回 Flux&lt;String&gt;,逐字推送</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span>

前端配合 SSE(Server-Sent Events)就能实现打字机效果。

官方实现说明里有个细节:流式输出只在响应式栈(Reactive)下支持,同步调用走 Servlet 栈。如果报"streaming not supported",检查是不是用了非响应式的环境。


进阶三:带上下文的多轮对话

默认情况下,每次调用都是"失忆"的——AI 不记得你上一句说了什么。

官方提供了 Chat Memory 机制(支持 In-Memory、JDBC、Redis、MongoDB 等 6 种存储),用 advisor 挂到 ChatClient 上:

<span leaf="">@RestController</span><span leaf=""><br></span><span leaf="">public class ChatController {</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; private final ChatClient chatClient;</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; public ChatController(ChatClient.Builder builder) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; this.chatClient = builder</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .defaultSystem("你是一个耐心的 Java 老师")</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .build();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; @GetMapping("/chat")</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; public String chat(@RequestParam String msg,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@RequestParam String userId) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; return chatClient.prompt()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .user(msg)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 把 userId 作为会话 ID,同一用户的对话共享上下文</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .advisors(a -&gt; a.param(ChatMemory.CONVERSATION_ID, userId))</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .call()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .content();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span>

同一 userId 的用户,AI 记得他说过的每一句话。智能客服就是这么做的。

官方示例里会话 ID 的常量是 ChatMemory.CONVERSATION_ID(旧版写法是 CHAT_MEMORY_CONVERSATION_ID_KEY,2.0 已简化)。要控制记忆窗口大小,用 MessageWindowChatMemory.builder().maxMessages(10).build() 这样限制最多记 10 条。


一分钱不花:用 Ollama 本地跑

不想注册 OpenAI、不想花钱、甚至不想把数据发给第三方——用 Ollama 在本地跑开源模型。官方原生支持 Ollama(streaming、多模态、function-calling 都支持)。

第一步:装 Ollama

去 ollama.com 下载安装,然后拉一个模型:

<span leaf=""># 拉一个 7B 的 Qwen 模型(中文效果好)</span><span leaf=""><br></span><span leaf="">ollama pull qwen2.5:7b</span><span leaf=""><br></span>

第二步:改依赖和配置

<span leaf="">&lt;dependency&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &lt;artifactId&gt;spring-ai-starter-model-ollama&lt;/artifactId&gt;</span><span leaf=""><br></span><span leaf="">&lt;/dependency&gt;</span><span leaf=""><br></span>
<span leaf="">spring:</span><span leaf=""><br></span><span leaf="">&nbsp; ai:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; ollama:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; base-url: http://localhost:11434</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; chat:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; options:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; model: qwen2.5:7b</span><span leaf=""><br></span>

第三步:代码一行不用改

ChatClient 的用法完全一样:

<span leaf="">chatClient.prompt().user("你好").call().content();</span><span leaf=""><br></span>

换模型供应商 = 换一个 starter + 改配置。代码零改动。 这就是 Spring AI 最值钱的地方。


踩坑记录

坑 1:ChatClient 注入失败

报错 No qualifying bean of type ChatClient

原因:少了 starter 依赖,或者 Spring AI 的自动配置没生效。

解决:确认 pom.xml 里有 spring-ai-starter-model-xxx,且通过 BOM 或显式版本指定了版本;Spring Boot 版本 >= 3.4。

坑 2:报 401 认证失败

<span leaf=""># 报错:401 Unauthorized</span><span leaf=""><br></span>

原因:API Key 没配或配错了。

解决:确认 application.yml 里的 api-key 正确;用环境变量的话,确认启动时真的传了:

<span leaf="">export OPENAI_API_KEY=sk-xxxx</span><span leaf=""><br></span><span leaf="">mvn spring-boot:run</span><span leaf=""><br></span>

坑 3:国内网络访问 OpenAI 超时

<span leaf=""># 报错:connect timed out</span><span leaf=""><br></span>

原因:OpenAI 官方地址在国内访问不稳定。

解决:配 base-url 走中转;或者直接换 DeepSeek / 通义千问(OpenAI 兼容接口) / Ollama。

坑 4:Ollama 启动很慢 / 内存不够

7B 模型大概要吃 4-8GB 内存。如果电脑内存小:

<span leaf=""># 换小一点的模型</span><span leaf=""><br></span><span leaf="">ollama pull qwen2.5:3b</span><span leaf=""><br></span>

总结

Spring AI 2.0 给 Java 程序员带来的核心价值:

| 以前手动写

|

现在 Spring AI

HttpClient 调 API

| chatClient.prompt().call() | |

Jackson 解析 JSON

| .entity(News.class) | |

自己拼上下文

|

ChatMemory + advisor

| |

自己写流式解析

| .stream().content() | |

换模型改代码

|

换 starter + 改配置

| |

自己实现函数回调

|

ToolCallback(Function Calling)

|

说白了,Spring AI 就是 Java 世界的"大模型 JDBC"。 你不需要懂大模型的底层协议,跟写 CRUD 一样,声明式地调用就行。

20 分钟跑通第一个应用,剩下的功能(Function Calling 让 AI 调你的方法、RAG 让 AI 读你的文档)都是在这个基础上加。