一、Spring AI 是什么
Spring AI 是 Spring 官方推出的AI应用开发框架,核心做了三件事:
用一张图理解Spring AI的核心架构:

关键洞察:这跟当年Spring Data JPA统一各种数据库的操作是一模一样的思路。Spring最擅长的事情就是——在混乱的API之上建立统一的抽象。
二、项目初始化:3分钟跑起来
2.1 创建项目
使用 Spring Initializr(https://start.spring.io)创建项目,选择以下依赖:
- Spring Boot 3.3.x(最低要求3.2+)
- Spring Web
- Spring AI DashScope Starter(通义千问)或 Spring AI OpenAI Starter
如果你用Maven手动创建,核心POM配置如下:
<!– 父POM:锁定Spring Boot版本 –>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<properties>
<java.version>17</java.version>
<!– Spring AI版本(截至2024年底稳定版) –>
<spring-ai.version>1.0.0-M4</spring-ai.version>
</properties>
<dependencies>
<!– Spring Boot Web –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!– Spring AI BOM:统一管理所有AI相关依赖版本 –>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!– 接入通义千问(DashScope) –>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M3.2</version>
</dependency>
<!– 或者接入DeepSeek(兼容OpenAI协议) –>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<!– Spring AI的Milestone仓库(必须加,否则拉不到包) –>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
2.2 配置API Key
在 application.yml 中配置:
方式一:接入通义千问(DashScope)
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY} # 从环境变量读取,别硬编码到代码里
chat:
options:
model: qwen-plus # 模型名称:qwen-plus / qwen-turbo / qwen-max
temperature: 0.7 # 温度:0~1,越高越发散
方式二:接入DeepSeek(兼容OpenAI协议)
spring:
ai:
openai:
api-key: ${AI_DEEPSEEK_API_KEY}
base-url: https://api.deepseek.com # DeepSeek的API地址
chat:
options:
model: deepseek-chat # 或 deepseek-reasoner(R1推理模型)
temperature: 0.7
为什么DeepSeek用OpenAI的starter? 因为DeepSeek的API完全兼容OpenAI协议,只需要改 base-url 和 api-key 就行。这也是Spring AI统一抽象的威力——兼容OpenAI协议的模型,统统用同一个starter。
三、5行代码接入大模型:ChatClient初体验
3.1 最简版本
@RestController
public class ChatController {
private final ChatClient chatClient;
// 构造器注入,Spring AI自动配置已经帮你创建好了ChatClient.Builder
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt(message).call().content();
}
}
就这5行核心代码(构造器注入 + 一行调用),启动项目后访问:
http://localhost:8080/chat?message=用一句话解释什么是依赖注入
你会收到类似这样的回复:
依赖注入是一种设计模式,对象不自己创建依赖项,而是由外部容器将所需依赖"注入"进来,从而实现松耦合。
一个GET请求,接入了大模型。 这就是Spring AI的入门体验。
3.2 理解调用链路
别急着往下走,我们先搞懂这行代码背后发生了什么:
chatClient.prompt(message) // 1. 构建Prompt
.call() // 2. 发起同步HTTP请求到模型API
.content(); // 3. 提取文本内容(忽略token使用量等元数据)
完整链路是这样的:
你的代码 → ChatClient → ChatModel → 模型API(通义千问/DeepSeek)
↓
返回 ChatResponse
↓
.content() 提取纯文本
ChatClient 是面向开发者的高级API(类似Spring Data的Repository),ChatModel 是底层模型接口。你日常开发90%的场景用 ChatClient 就够了。
3.3 带系统提示词的对话
实际业务中,你通常需要设定AI的角色和行为规则。Spring AI用链式API优雅地处理这个:
@GetMapping("/assistant")
public String assistant(@RequestParam String question) {
return chatClient.prompt()
// system消息:设定AI角色和行为约束
.system("你是一个资深的Java技术顾问,回答简洁专业," +
"每次回答不超过200字,代码示例用Java语言。")
// user消息:用户实际输入
.user(question)
// 调用配置
.call()
// 获取结构化结果(包含内容、token用量等)
.chatResponse()
.getResult()
.getOutput()
.getContent();
}
对比一下如果你自己拼接OpenAI的JSON请求体,需要手动构造 messages 数组、区分 system 和 user 角色、解析返回的JSON……Spring AI把这些全封装了。
3.4 多模型切换:只改配置不改代码
这是Spring AI最值钱的设计。你写好的ChatController代码,切换模型只需要改配置:
# 开发环境用通义千问(便宜)
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
chat:
options:
model: qwen-turbo
# 生产环境切到DeepSeek(性价比高)
# spring:
# ai:
# openai:
# api-key: ${AI_DEEPSEEK_API_KEY}
# base-url: https://api.deepseek.com
# chat:
# options:
# model: deepseek-chat
当然,如果你想在运行时动态切换模型(比如简单问题用turbo、复杂问题用max),可以通过注入多个 ChatModel 实现:
@Service
public class SmartChatService {
private final ChatClient qwenClient; // 通义千问
private final ChatClient deepseekClient; // DeepSeek
public SmartChatService(
@Qualifier("dashScopeChatModel") ChatModel qwenModel,
@Qualifier("openAiChatModel") ChatModel deepseekModel) {
this.qwenClient = ChatClient.builder(qwenModel).build();
this.deepseekClient = ChatClient.builder(deepseekModel).build();
}
public String chat(String question, String model) {
ChatClient client = "deepseek".equalsIgnoreCase(model)
? deepseekClient : qwenClient;
return client.prompt(question).call().content();
}
}
这种模型路由的思路在后面Day 89的综合项目里会详细展开,这里先埋个种子。
四、进阶:结构化输出——让AI返回Java对象
大模型默认返回的是自然语言文本,但在工程中,我们经常需要AI返回结构化数据(比如JSON),直接映射成Java对象。
4.1 场景:智能情感分析
假设你有一个用户评论分析系统,需要AI判断评论的情感倾向并返回结构化结果:
// 定义输出结构(Java Record,JDK 16+)
public record SentimentResult(
String sentiment, // POSITIVE / NEGATIVE / NEUTRAL
double confidence, // 置信度 0~1
String summary // 一句话摘要
) {}
@RestController
public class SentimentController {
private final ChatClient chatClient;
public SentimentController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@PostMapping("/analyze")
public SentimentResult analyze(@RequestBody Map<String, String> body) {
String review = body.get("review");
return chatClient.prompt()
.system("你是一个情感分析专家。分析用户评论的情感倾向," +
"返回POSITIVE/NEGATIVE/NEUTRAL,给出置信度和摘要。")
.user("请分析以下评论:\\n" + review)
.call()
// 核心魔法:entity()方法自动将AI输出转换为指定类型的Java对象
.entity(SentimentResult.class);
}
}
调用示例:
curl -X POST http://localhost:8080/analyze \\
-H "Content-Type: application/json" \\
-d '{"review": "这个ERP系统太好用了,库存管理清晰,报表功能强大,强烈推荐!"}'
返回结果:
{
"sentiment": "POSITIVE",
"confidence": 0.95,
"summary": "用户对ERP系统的库存管理和报表功能给予高度评价。"
}
原理:entity() 方法底层使用了 BeanOutputConverter,它做了三件事:
这意味着你不需要写任何JSON解析代码,Spring AI帮你全搞定了。
4.2 对比传统方案的痛点
如果没有Spring AI,你需要:
// 传统做法:手动拼接 + 手动解析
String prompt = "分析以下评论的情感,返回JSON格式:" +
"{\\"sentiment\\":\\"POSITIVE/NEGATIVE/NEUTRAL\\"," +
"\\"confidence\\":0.0,\\"summary\\":\\"\\"}\\n" + review;
String response = callLlmApi(prompt); // 自己封装HTTP调用
// 手动解析JSON(还可能遇到模型不按格式返回的问题)
ObjectMapper mapper = new ObjectMapper();
SentimentResult result = mapper.readValue(response, SentimentResult.class);
痛点很明显:Prompt和代码耦合、JSON格式不稳定、没有类型安全、换模型要改HTTP调用代码。Spring AI把这些问题全解决了。
五、模型选型与成本对比
很多开发者问我"该选哪个模型",我的建议是根据业务场景和预算来:
| 中文能力 | 优秀 | 优秀 | 良好 |
| 代码能力 | 良好 | 优秀(性价比之王) | 优秀 |
| 输入价格 | ¥0.008/1K tokens | ¥0.001/1K tokens | ¥0.035/1K tokens |
| 输出价格 | ¥0.02/1K tokens | ¥0.002/1K tokens | ¥0.07/1K tokens |
| 免费额度 | 有(新用户) | 有(限时) | 无 |
| 上下文窗口 | 128K | 128K | 128K |
| 合规性 | 国内合规 | 国内合规 | 需评估 |
价格数据为2024年底公开价格,实际以官方为准。
我的选型建议:
- 内部工具/原型验证:DeepSeek,便宜到几乎不花钱
- 面向用户的中文场景:通义千问,中文表达自然
- 复杂代码推理:DeepSeek-R1(推理模型)或GPT-4o
- 数据敏感场景:后面Day 61会讲Ollama本地部署
六、建议
建议1:API Key永远不要硬编码
// ❌ 错误:硬编码到代码里,一旦提交到Git就完蛋
@Value("${spring.ai.dashscope.api-key}")
private String apiKey = "sk-xxxxxxx";
// ✅ 正确:用环境变量注入
// application.yml中写 ${AI_DASHSCOPE_API_KEY}
// 启动时:export AI_DASHSCOPE_API_KEY=sk-xxxxxxx
更进一步,生产环境用Nacos配置中心或Vault管理密钥,不要放在代码仓库里。
建议2:永远设置超时和重试
大模型API的延迟远高于传统接口(通常2~10秒),不设超时会拖垮你的线程池:
yaml
复制
spring:
ai:
dashscope:
chat:
options:
model: qwen-plus
# Spring AI的retry配置(M4+版本支持)
retry:
max-attempts: 3 # 最多重试3次
backoff:
initial-interval: 1000 # 首次重试等待1秒
multiplier: 2 # 指数退避:1s → 2s → 4s
同时,你的HTTP客户端(Tomcat/Undertow)也要确保超时时间大于模型的最大响应时间:
server:
tomcat:
connection-timeout: 30000 # 30秒超时
threads:
max: 200 # 根据并发量调整
建议3:从简单场景开始,不要一上来就RAG
我见过太多团队一上来就搞RAG知识库,结果文档切分、向量检索、重排序一堆问题,项目延期两个月。
正确的节奏是:
第一步:ChatClient跑通基础对话(今天这篇)
↓
第二步:Prompt工程,让AI按你的规则输出(Day 27)
↓
第三步:结构化输出 + Function Calling,让AI调你的业务接口
↓
第四步:RAG,给AI喂你的私有知识(Day 71+)
每一步都要确保上一步能稳定运行。AI应用开发的坑不在框架,而在调优和边界处理。
下篇预告:Day 27 —— 《Spring AI Prompt工程:PromptTemplate/FewShot/角色系统》,我们将深入Prompt模板化管理,把"调教AI"这件事工程化、可版本管理地做起来。




