1. Spring AI 入门指南:从零开始构建你的第一个 AI 应用
作为一名长期深耕 Java 生态的技术专家,我见证了 Spring 框架如何一步步改变企业级应用开发的方式。如今,随着 AI 技术的爆发式发展,Spring 官方推出的 Spring AI 框架正在为 Java 开发者打开通往智能应用的大门。本文将带你深入理解 Spring AI 的核心架构,并手把手教你构建第一个 AI 应用。
1.1 为什么选择 Spring AI?
在传统 AI 开发中,开发者面临诸多痛点:
- 不同 AI 提供商的 API 差异巨大,OpenAI、Claude、通义千问各有各的调用方式
- 切换模型需要重构大量代码,测试成本居高不下
- 向量数据库选型复杂,Milvus、Pinecone、PGVector 各有优劣难以抉择
- 缺乏与 Spring 生态的深度集成,需要自行处理配置、依赖管理等繁琐工作
Spring AI 的诞生完美解决了这些问题。它提供了统一的抽象层,让开发者可以用一致的 API 调用不同厂商的 AI 能力。就像 JDBC 统一了数据库访问一样,Spring AI 正在成为 Java 生态中 AI 应用开发的事实标准。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring AI 核心架构解析
2.1 整体设计理念
Spring AI 的核心设计遵循了 Spring 框架一贯的"约定优于配置"原则。其架构分为三个关键层次:
- 应用层:开发者编写的业务代码
- 抽象层:ChatClient、EmbeddingClient 等统一接口
- 实现层:对接具体 AI 提供商的后端实现
这种分层设计带来的最大优势是:业务代码与具体 AI 实现解耦。你可以通过修改配置轻松切换 AI 提供商,而无需改动任何业务逻辑。
2.2 核心组件详解
2.2.1 ChatClient:对话式交互的核心
ChatClient 是 Spring AI 中最常用的接口,它封装了与 AI 模型的对话能力。其核心方法包括:
prompt():构建对话请求call():执行对话并获取响应stream():支持流式响应(适用于长文本生成)
在实际开发中,我们通常通过 ChatClient.Builder 来创建实例,这样可以灵活配置各种参数:
java复制ChatClient client = ChatClient.builder()
.defaultSystem("你是一个专业的Java技术专家") // 默认系统角色
.defaultOptions(ChatOptions.builder()
.withTemperature(0.7f)
.withMaxTokens(1000)
.build())
.build();
2.2.2 EmbeddingClient:语义理解的关键
Embedding 是将文本转换为向量表示的核心技术。Spring AI 的 EmbeddingClient 提供了统一的接口:
java复制List<Double> embedding = embeddingClient.embed("Spring AI 简介");
这个向量可以用于:
- 语义搜索
- 文本分类
- 推荐系统
- RAG(检索增强生成)应用
2.2.3 VectorStore:向量数据库抽象
Spring AI 支持多种向量数据库,包括:
- Pinecone
- Redis
- PGVector
- Weaviate
- Chroma
统一的 VectorStore 接口让切换数据库变得非常简单:
java复制vectorStore.add(List.of(
new Document("Spring AI 文档", Map.of("category", "framework")),
new Document("Java 21 新特性", Map.of("category", "language"))
));
List<Document> results = vectorStore.similaritySearch("如何学习Spring");
3. 环境准备与项目搭建
3.1 开发环境要求
要顺利运行 Spring AI 项目,需要确保以下环境:
- JDK 17+:推荐使用最新的 LTS 版本 JDK 21
- Spring Boot 3.4+:这是支持 Spring AI 的最低版本
- 构建工具:Maven 3.8+ 或 Gradle 8+
提示:如果你使用 IntelliJ IDEA,建议安装最新版本以获得最佳的 Spring AI 支持。
3.2 项目初始化
3.2.1 使用 start.spring.io 创建项目
这是最快捷的方式:
- 访问 start.spring.io
- 选择:
- Project: Maven
- Language: Java
- Spring Boot: 3.4.0+
- 添加依赖:
- Spring Web
- Spring AI
- 点击生成并下载项目
3.2.2 手动配置 Maven 项目
如果你偏好手动配置,以下是关键配置:
xml复制<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.3</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>
</dependency>
</dependencies>
3.3 配置 API 密钥
在 application.properties 中配置你的 AI 提供商密钥:
properties复制# OpenAI 配置
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4
spring.ai.openai.chat.options.temperature=0.7
# 或者使用通义千问
# spring.ai.dashscope.api-key=${DASHSCOPE_API_KEY}
# spring.ai.dashscope.chat.options.model=qwen-turbo
安全提示:永远不要将 API 密钥直接提交到代码仓库。使用环境变量或配置中心管理敏感信息。
4. 核心功能实现
4.1 基础对话功能
创建一个简单的 REST 控制器来处理对话请求:
java复制@RestController
@RequestMapping("/api/ai")
public class AIController {
private final ChatClient chatClient;
public AIController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
测试这个端点:
bash复制curl "http://localhost:8080/api/ai/chat?message=用Java写一个快速排序算法"
4.2 高级提示工程
Spring AI 支持复杂的提示工程:
java复制@GetMapping("/expert-answer")
public String expertAnswer(@RequestParam String question) {
return chatClient.prompt()
.system("你是一位有10年经验的Java架构师,回答要专业且详细")
.user(question)
.call()
.content();
}
4.3 结构化输出
将 AI 响应映射为 Java 对象:
java复制public record CodeSnippet(String language, String code, String explanation) {}
@GetMapping("/generate-code")
public CodeSnippet generateCode(@RequestParam String requirement) {
String json = chatClient.prompt()
.user("根据以下需求生成代码,以JSON格式返回,包含language、code和explanation字段:" + requirement)
.call()
.content();
return new ObjectMapper().readValue(json, CodeSnippet.class);
}
5. 高级特性与最佳实践
5.1 流式响应处理
对于长文本生成,使用流式响应可以显著提升用户体验:
java复制@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.map(ChatResponse::getContent);
}
前端可以通过 SSE (Server-Sent Events) 来接收这些数据:
javascript复制const eventSource = new EventSource('/api/ai/stream?message=讲一个长故事');
eventSource.onmessage = (event) => {
console.log(event.data);
};
5.2 对话历史管理
实现多轮对话需要维护对话上下文:
java复制@PostMapping("/conversation")
public String conversation(@RequestBody List<Message> messages) {
return chatClient.prompt()
.messages(messages)
.call()
.content();
}
其中 Message 可以是这样的结构:
java复制public record Message(String role, String content) {}
5.3 异常处理与重试
AI 服务可能不稳定,需要合理的错误处理:
java复制@RestControllerAdvice
public class AIExceptionHandler {
@ExceptionHandler(ApiException.class)
public ResponseEntity<String> handleAIException(ApiException ex) {
return ResponseEntity.status(502)
.body("AI服务暂时不可用: " + ex.getMessage());
}
@Bean
public RetryTemplate aiRetryTemplate() {
return RetryTemplate.builder()
.maxAttempts(3)
.fixedBackoff(1000)
.retryOn(ApiException.class)
.build();
}
}
6. 性能优化技巧
6.1 缓存策略
对常见查询结果进行缓存:
java复制@Cacheable("aiResponses")
@GetMapping("/cached-chat")
public String cachedChat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
6.2 批量处理
对于大量文本的 Embedding 操作,使用批量接口:
java复制@GetMapping("/batch-embed")
public List<List<Double>> batchEmbed(@RequestParam List<String> texts) {
return embeddingClient.embedBatch(texts);
}
6.3 连接池配置
优化 HTTP 连接池以提高性能:
properties复制# 适用于 OpenAI 的连接池配置
spring.ai.openai.rest-template.max-connections=50
spring.ai.openai.rest-template.connection-timeout=5000
spring.ai.openai.rest-template.read-timeout=30000
7. 安全注意事项
7.1 输入验证
永远不要信任用户输入:
java复制@GetMapping("/safe-chat")
public String safeChat(@RequestParam @Size(max=500) String message) {
// 清理可能的恶意输入
String sanitized = HtmlUtils.htmlEscape(message);
return chatClient.prompt()
.user(sanitized)
.call()
.content();
}
7.2 敏感信息过滤
防止 AI 泄露敏感信息:
java复制public class SensitiveFilter implements PromptTransformer {
@Override
public Prompt transform(Prompt prompt) {
String filtered = prompt.getContents().replaceAll("password|token|密钥", "[REDACTED]");
return new Prompt(filtered, prompt.getOptions());
}
}
7.3 访问控制
限制 AI 接口的访问:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/ai/**").hasRole("AI_USER")
.anyRequest().permitAll()
)
.httpBasic();
return http.build();
}
}
8. 部署与监控
8.1 健康检查
添加 AI 服务的健康指示器:
java复制@Bean
HealthIndicator aiHealthIndicator(ChatClient chatClient) {
return () -> {
try {
String response = chatClient.prompt()
.user("简单回复'OK'")
.call()
.content();
return "OK".equals(response)
? Health.up().build()
: Health.down().build();
} catch (Exception e) {
return Health.down(e).build();
}
};
}
8.2 指标监控
跟踪 AI 使用情况:
java复制@Bean
MeterRegistryCustomizer<MeterRegistry> aiMetrics() {
return registry -> {
Timer.builder("ai.chat.duration")
.description("AI聊天响应时间")
.register(registry);
Counter.builder("ai.requests.count")
.description("AI请求总数")
.register(registry);
};
}
8.3 容器化部署
创建 Dockerfile:
dockerfile复制FROM eclipse-temurin:21-jre
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar
ENV OPENAI_API_KEY=${API_KEY}
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
构建并运行:
bash复制docker build -t spring-ai-demo .
docker run -e API_KEY=your_key -p 8080:8080 spring-ai-demo
9. 常见问题解决
9.1 依赖冲突解决
Spring AI 可能会与其他库产生冲突。使用 Maven 的依赖树分析:
bash复制mvn dependency:tree
常见的冲突包括:
- 不同版本的 Spring Boot
- 冲突的 JSON 处理器(Jackson vs Gson)
- HTTP 客户端版本不一致
9.2 性能调优
如果响应缓慢,考虑:
- 降低 temperature 值以获得更快的确定性响应
- 设置合理的 maxTokens 限制
- 使用更轻量级的模型(如 gpt-3.5-turbo 替代 gpt-4)
9.3 本地模型集成
对于不想使用云服务的场景,可以集成本地模型:
properties复制# 使用 Ollama 运行本地模型
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.options.model=llama3
启动 Ollama 服务:
bash复制ollama pull llama3
ollama serve
10. 扩展学习路径
掌握了基础之后,建议按照以下路径深入学习:
- 工具调用:让 AI 调用外部 API 和函数
- RAG 架构:构建企业级知识库系统
- 智能体开发:创建自主决策的 AI Agent
- 多模态应用:集成图像和语音处理能力
- 微调与蒸馏:定制专属的 AI 模型
每个主题都可以展开为一个完整的学习模块。在实际项目中,我通常会先从小功能开始验证概念,然后逐步扩展为完整的 AI 增强型应用。
