Spring AI 入门到实战:Java开发者的AI应用开发指南

字数:约3800字 | 阅读时间:12分钟


随着大语言模型(LLM)的快速发展,越来越多的Java开发者开始探索如何在Spring生态中集成AI能力。Spring AI作为Spring官方推出的AI开发框架,为Java开发者提供了一套统一、简洁的API来与各种AI模型进行交互。

本文将从Spring AI的核心概念开始,带你逐步构建一个完整的AI应用,包括基础的对话功能、RAG(检索增强生成)、函数调用等高级特性。

1. Spring AI是什么?

Spring AI是Spring Framework生态中的一个新项目,旨在为Java开发者提供统一的AI编程模型。它的核心目标包括:

  • 统一的API:通过统一的接口支持多种AI模型(OpenAI、Anthropic、Azure、Ollama等)
  • Spring集成:充分利用Spring生态的优势,如依赖注入、配置管理等
  • 生产就绪:提供重试、缓存、监控等企业级特性
  • 简化开发:降低AI应用的开发门槛,让更多Java开发者能够快速上手

Spring AI的核心组件

Spring AI的主要组件包括:

  • ChatClient:对话客户端,用于与大语言模型进行对话
  • EmbeddingClient:嵌入客户端,用于将文本转换为向量
  • VectorStore:向量存储,用于存储和管理向量数据
  • FunctionCallback:函数回调机制,实现AI调用Java方法
  • PromptTemplate:提示词模板,用于构建复杂的提示

2. 环境搭建

2.1 项目初始化

使用Spring Initializr创建一个Spring Boot项目:

1
2
3
4
5
6
7
8
9
10
curl https://start.spring.io/starter.zip \
-d dependencies=web,ai,spring-ai-openai-spring-boot-starter,spring-ai-postgres-store-spring-boot-starter \
-d type=maven-project \
-d language=java \
-d bootVersion=3.2.0 \
-d javaVersion=17 \
-d name=spring-ai-demo \
-d groupId=com.example \
-d artifactId=spring-ai-demo \
-o spring-ai-demo.zip

或者在IDE中选择以下依赖:

  • Spring Boot Web Starter
  • Spring AI OpenAI Starter
  • Spring AI PostgreSQL Vector Store Starter
  • Spring AI Core

2.2 配置文件

application.propertiesapplication.yml中配置AI相关参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY:your-api-key-here}
base-url: ${OPENAI_BASE_URL:https://api.openai.com}
chat:
options:
model: gpt-4
temperature: 0.7
embedding:
options:
model: text-embedding-ada-002
vectorstore:
pgvector:
initialize-schema: true

3. 基础对话功能

3.1 创建简单的对话服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class ChatService {

private final ChatClient chatClient;

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

public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}

3.2 控制器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestController
@RequestMapping("/api/chat")
public class ChatController {

private final ChatService chatService;

public ChatController(ChatService chatService) {
this.chatService = chatService;
}

@PostMapping
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
String response = chatService.chat(request.getMessage());
return ResponseEntity.ok(new ChatResponse(response));
}

// 请求和响应对象
public static class ChatRequest {
private String message;
// getters and setters
}

public static class ChatResponse {
private String response;

public ChatResponse(String response) {
this.response = response;
}
// getter
}
}

3.3 测试对话功能

启动应用后,你可以通过curl或Postman测试:

1
2
3
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "你好,请介绍一下Spring AI"}'

4. 高级特性:Function Calling

4.1 定义可调用的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class WeatherService {

public String getWeather(String city) {
// 模拟天气查询
Map<String, String> weatherData = Map.of(
"北京", "晴天,温度25°C",
"上海", "多云,温度22°C",
"广州", "小雨,温度28°C"
);
return weatherData.getOrDefault(city, "未知城市");
}
}

4.2 配置Function Callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class ChatWithFunctionService {

private final ChatClient chatClient;

public ChatWithFunctionService(ChatClient.Builder builder, WeatherService weatherService) {
this.chatClient = builder
.defaultFunctions("weatherService")
.build();
}

public String chatWithFunction(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}

4.3 函数注册

在配置类中注册函数:

1
2
3
4
5
6
7
8
@Configuration
public class FunctionConfig {

@Bean
public Functions functions(WeatherService weatherService) {
return Functions.of(weatherService);
}
}

5. RAG实现:知识库问答

5.1 文档处理和向量化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Service
public class DocumentProcessingService {

private final VectorStore vectorStore;
private final EmbeddingClient embeddingClient;

public DocumentProcessingService(VectorStore vectorStore, EmbeddingClient embeddingClient) {
this.vectorStore = vectorStore;
this.embeddingClient = embeddingClient;
}

@PostConstruct
public void initializeDocuments() {
// 示例文档
List<Document> documents = List.of(
new Document("Spring AI是一个为Java开发者设计的AI开发框架,支持多种AI模型。", Set.of("Spring AI", "AI框架")),
new Document("RAG技术结合了检索和生成,可以提高AI回答的准确性。", Set.of("RAG", "检索增强生成")),
new Document("Function Calling允许AI调用Java方法,实现与外部系统的交互。", Set.of("Function Calling", "Java方法"))
);

// 向量化并存储
vectorStore.add(documents);
}
}

5.2 RAG服务实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Service
public class RagService {

private final VectorStore vectorStore;
private final ChatClient chatClient;

public RagService(VectorStore vectorStore, ChatClient.Builder builder) {
this.vectorStore = vectorStore;
this.chatClient = builder.build();
}

public String ragQuery(String question) {
// 1. 检索相关文档
List<Document> relevantDocs = vectorStore
.search(SearchQuery.query(question).withTopK(3))
.getMatches()
.stream()
.map(Document::get_content)
.collect(Collectors.toList());

// 2. 构建提示词
String context = String.join("\n", relevantDocs);
String prompt = String.format(
"基于以下上下文回答问题:\n\n%s\n\n问题:%s\n\n回答:",
context, question
);

// 3. 调用AI模型生成回答
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
}

5.3 RAG控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@RestController
@RequestMapping("/api/rag")
public class RagController {

private final RagService ragService;

public RagController(RagService ragService) {
this.ragService = ragService;
}

@PostMapping
public ResponseEntity<RagResponse> ragQuery(@RequestBody RagRequest request) {
String response = ragService.ragQuery(request.getQuestion());
return ResponseEntity.ok(new RagResponse(response));
}

public static class RagRequest {
private String question;
// getter
}

public static class RagResponse {
private String answer;
public RagResponse(String answer) {
this.answer = answer;
}
// getter
}
}

6. 多模型支持

6.1 配置多个模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4
azure:
openai:
api-key: ${AZURE_API_KEY}
endpoint: ${AZURE_ENDPOINT}
chat:
options:
model: gpt-35-turbo

6.2 动态模型选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class MultiModelService {

private final ChatClient openaiClient;
private final ChatClient azureClient;

public MultiModelService(
@Named("openai") ChatClient openaiClient,
@Named("azure") ChatClient azureClient) {
this.openaiClient = openaiClient;
this.azureClient = azureClient;
}

public String chat(String message, String model) {
return switch (model) {
case "openai" -> openaiClient.prompt().user(message).call().content();
case "azure" -> azureClient.prompt().user(message).call().content();
default -> "不支持的模型";
};
}
}

7. 生产环境配置

7.1 重试和熔断

1
2
3
4
5
6
7
8
9
10
11
12
spring:
ai:
openai:
chat:
options:
model: gpt-4
retry:
max-attempts: 3
backoff:
initial-interval: 1000
multiplier: 2
max-interval: 10000

7.2 缓存配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
@EnableCaching
public class CacheConfig {

@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("chat-responses"),
new ConcurrentMapCache("embeddings")
));
return cacheManager;
}
}

7.3 监控和日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
@RequestMapping("/api/ai")
public class AiMetricsController {

private final ChatService chatService;

public AiMetricsController(ChatService chatService) {
this.chatService = chatService;
}

@PostMapping("/chat")
@Timed(value = "ai.chat.time", description = "Time spent processing AI chat")
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
long startTime = System.currentTimeMillis();
String response = chatService.chat(request.getMessage());
long duration = System.currentTimeMillis() - startTime;

log.info("Chat request took {} ms", duration);

return ResponseEntity.ok(new ChatResponse(response));
}
}

8. 完整示例:智能客服系统

8.1 系统架构

1
2
3
用户请求 → API网关 → Spring AI服务 → 向量检索 → LLM生成 → 响应返回

监控日志 ← 缓存层 ← 函数调用 ← 外部API

8.2 核心服务实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@Service
public class CustomerService {

private final RagService ragService;
private final FunctionService functionService;
private final ChatClient chatClient;

public CustomerService(RagService ragService, FunctionService functionService,
ChatClient.Builder builder) {
this.ragService = ragService;
this.functionService = functionService;
this.chatClient = builder
.defaultFunctions("functionService")
.build();
}

public CustomerResponse handleCustomerRequest(CustomerRequest request) {
// 1. 检查是否需要调用函数
if (needsFunctionCall(request.getMessage())) {
String functionResult = functionService.executeFunction(request.getMessage());
return new CustomerResponse(functionResult, "function_call");
}

// 2. 使用RAG检索知识库
if (needsRAG(request.getMessage())) {
String ragResult = ragService.ragQuery(request.getMessage());
return new CustomerResponse(ragResult, "rag");
}

// 3. 普通对话
String chatResult = chatClient.prompt()
.user(request.getMessage())
.call()
.content();

return new CustomerResponse(chatResult, "chat");
}

private boolean needsFunctionCall(String message) {
return message.toLowerCase().contains("天气") ||
message.toLowerCase().contains("查询");
}

private boolean needsRAG(String message) {
return message.toLowerCase().contains("产品") ||
message.toLowerCase().contains("服务") ||
message.toLowerCase().contains("教程");
}
}

8.3 异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ControllerAdvice
public class AiExceptionHandler {

@ExceptionHandler(AiException.class)
public ResponseEntity<ErrorResponse> handleAiException(AiException e) {
ErrorResponse error = new ErrorResponse(
"AI_ERROR",
e.getMessage(),
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(error);
}

@ExceptionHandler(VectorStoreException.class)
public ResponseEntity<ErrorResponse> handleVectorStoreException(VectorStoreException e) {
ErrorResponse error = new ErrorResponse(
"VECTOR_STORE_ERROR",
"向量存储服务不可用",
System.currentTimeMillis()
);
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(error);
}
}

9. 部署和运维

9.1 Docker部署

1
2
3
4
5
6
7
8
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app
COPY target/spring-ai-demo-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

9.2 Docker Compose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: '3.8'
services:
spring-ai-app:
build: .
ports:
- "8080:8080"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- AZURE_API_KEY=${AZURE_API_KEY}
depends_on:
- postgres
restart: unless-stopped

postgres:
image: pgvector/pgvector:latest
environment:
POSTGRES_DB: spring_ai_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:

9.3 健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@RestController
@RequestMapping("/actuator/health")
public class HealthController {

private final VectorStore vectorStore;
private final ChatClient chatClient;

public HealthController(VectorStore vectorStore, ChatClient chatClient) {
this.vectorStore = vectorStore;
this.chatClient = chatClient;
}

@GetMapping
public ResponseEntity<Health> health() {
Health health = Health.up()
.withDetail("vectorStore", checkVectorStore())
.withDetail("aiService", checkAiService())
.build();

return ResponseEntity.ok(health);
}

private String checkVectorStore() {
try {
int count = vectorStore.search(SearchQuery.query("test")).getMatches().size();
return "OK";
} catch (Exception e) {
return "ERROR: " + e.getMessage();
}
}

private String checkAiService() {
try {
String response = chatClient.prompt().user("ping").call().content();
return "OK";
} catch (Exception e) {
return "ERROR: " + e.getMessage();
}
}
}

10. 总结

Spring AI为Java开发者提供了一个强大而简洁的工具来构建AI应用。通过本文的学习,你应该掌握了:

  1. Spring AI的基础概念:了解ChatClient、EmbeddingClient、VectorStore等核心组件
  2. 基础的对话功能:实现与AI模型的简单对话
  3. Function Calling:让AI调用Java方法,实现与外部系统的交互
  4. RAG技术:通过检索增强生成提高AI回答的准确性
  5. 多模型支持:同时使用多个AI模型
  6. 生产环境配置:重试、缓存、监控、异常处理等企业级特性
  7. 部署和运维:Docker部署、健康检查等

下一步学习建议

  1. 深入研究Prompt Engineering:学习如何设计更好的提示词
  2. 探索更多AI模型:尝试本地模型如Ollama、LLaMA等
  3. 集成其他AI能力:图像识别、语音处理等
  4. 性能优化:异步处理、批量操作等
  5. 安全考虑:提示词注入防护、数据安全等

Spring AI仍在快速发展中,建议关注官方文档和示例代码,获取最新的技术动态。作为Java开发者,Spring AI让我们能够充分利用现有的Spring生态知识,快速构建生产级的AI应用。


本文作者:小新,Spring AI实践者