1. 引言
Spring AI 1.0 GA 版本于 2025 年 5 月 20 日正式发布,标志着 Spring 生态系统全面拥抱人工智能技术。作为 Spring 官方推出的 AI 集成框架,Spring AI 提供了统一的 API 来连接各种 AI 模型和向量数据库,显著降低了 Java 开发者构建 AI 应用的门槛。本文将详细介绍 Spring AI 的环境搭建步骤,并通过实战案例演示如何构建智能助手应用。
2. 核心概念
Spring AI 的设计理念是通过抽象层简化 AI 集成,其核心组件包括:
- ChatClient:统一的 AI 模型交互接口,支持 20+ 主流模型(如 OpenAI、DeepSeek、Anthropic 等),提供同步/流式调用和结构化 JSON 响应。
- 多模态支持:处理文本、图像、音频等多种数据类型,API 设计保持一致性。
- RAG 框架:检索增强生成,结合向量数据库实现外部知识集成,提升回答准确性。
- 向量存储抽象:支持 20+ 向量数据库(Pinecone、Milvus、Weaviate 等),提供类 SQL 查询语法。
- 工具调用:通过 @Tool 注解将外部功能(如天气查询、数据库操作)暴露给 AI 模型。
- 可观测性:集成 Micrometer 监控模型性能指标,如响应延迟、Token 使用量等。
3. 环境搭建
3.1 开发环境要求
- JDK 17 或更高版本(推荐 JDK 21,支持 ZGC 优化)
- Spring Boot 3.2+
- Maven/Gradle 构建工具
3.2 依赖配置
在 Maven 项目中添加以下依赖(以 OpenAI 为例):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
国内镜像配置(解决依赖下载慢问题): 在 settings.xml
中添加阿里云镜像:
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
3.3 API 密钥配置
在 application.yml
中配置 AI 模型信息:
OpenAI 配置:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0.7
DeepSeek 配置(阿里云百炼平台):
spring:
ai:
openai: # DeepSeek 兼容 OpenAI API 规范
api-key: ${DEEPSEEK_API_KEY}
base-url: https://dashscope.aliyuncs.com/compatible-mode
chat:
options:
model: deepseek-r1
temperature: 0.8
安全提示:API 密钥应通过环境变量或配置服务器管理,避免硬编码在代码中。
4. AI 助手实践
4.1 基础案例:智能对话接口
实现一个支持同步响应和流式响应的对话接口。
Step 1: 创建 Controller
import org.springframework.ai.chat.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatController {
private final ChatClient chatClient;
// 构造函数注入 ChatClient
public ChatController(ChatClient chatClient) {
this.chatClient = chatClient;
}
/**
* 同步响应接口
*/
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
/**
* 流式响应接口
*/
@GetMapping(value = "/stream-chat", produces = "text/event-stream")
public Flux<String> streamChat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.map(response -> response.getResult().getOutput().getContent());
}
}
Step 2: 测试接口
- 同步调用:
curl "http://localhost:8080/chat?message=Spring AI 是什么?"
- 流式调用:
curl "http://localhost:8080/stream-chat?message=介绍 Spring AI 的核心功能"
4.2 高级案例:RAG 知识库问答
结合向量数据库实现基于本地文档的智能问答。
Step 1: 添加向量存储依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
Step 2: 配置 Pinecone 向量数据库
spring:
ai:
pinecone:
api-key: ${PINECONE_API_KEY}
environment: gcp-starter
index-name: spring-ai-demo
Step 3: 实现文档加载与问答服务
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentReader;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class KnowledgeService {
private final VectorStore vectorStore;
private final ChatClient chatClient;
public KnowledgeService(VectorStore vectorStore, ChatClient chatClient) {
this.vectorStore = vectorStore;
this.chatClient = chatClient;
// 初始化时加载文档
loadDocuments();
}
// 加载本地 PDF 文档并存储到向量数据库
public void loadDocuments() {
DocumentReader reader = new TikaDocumentReader(new FileSystemResource("docs/spring-ai-docs.pdf"));
List<Document> documents = reader.read();
vectorStore.add(documents);
}
// 检索相关文档并生成回答
public String queryKnowledge(String question) {
List<Document> relevantDocs = vectorStore.similaritySearch(question, 3);
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));
String prompt = String.format("基于以下上下文回答问题:\n%s\n问题:%s", context, question);
return chatClient.prompt().user(prompt).call().content();
}
}
5. 高级特性探索
5.1 多模态处理
Spring AI 1.0 支持图像输入,以下是生成图像描述的示例:
import org.springframework.ai.image.ImageClient;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class ImageController {
private final ImageClient imageClient;
public ImageController(ImageClient imageClient) {
this.imageClient = imageClient;
}
@PostMapping("/describe-image")
public String describeImage(@RequestParam MultipartFile image) throws IOException {
ImagePrompt prompt = new ImagePrompt("描述图片内容",
ImagePrompt.Options.builder().withN(1).build());
ImageResponse response = imageClient.call(prompt);
return response.getResult().getOutput().getUrl();
}
}
5.2 工具调用
通过 @Tool 注解让 AI 模型调用外部工具:
import org.springframework.ai.core.Tool;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@Component
public class WeatherTool {
@Tool(description = "查询指定城市的天气")
public String getWeather(String city) {
// 实际应用中调用天气API
return String.format("%s的天气:晴朗,25°C", city);
}
@Tool(description = "创建会议日程")
public String createMeeting(String title, String participant) {
String time = Instant.now().plus(2, ChronoUnit.DAYS).toString();
return String.format("会议[%s]已创建,参与者:%s,时间:%s", title, participant, time);
}
}
6. 常见问题与解决方案
问题 | 解决方案 |
---|---|
依赖版本冲突 | 使用 spring-ai-bom 统一管理版本 |
模型响应慢 | 调整超时配置:spring.ai.openai.chat.options.timeout=60s |
中文乱码 | 在 prompt 中明确指定:用中文回答,确保编码正确 |
向量数据库连接失败 | 检查 API 密钥和环境配置,启用 DEBUG 日志:logging.level.org.springframework.ai=DEBUG |