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.properties或application.yml中配置AI相关参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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; } public static class ChatResponse { private String response; public ChatResponse(String response) { this.response = response; } } }
|
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) { List<Document> relevantDocs = vectorStore .search(SearchQuery.query(question).withTopK(3)) .getMatches() .stream() .map(Document::get_content) .collect(Collectors.toList()); String context = String.join("\n", relevantDocs); String prompt = String.format( "基于以下上下文回答问题:\n\n%s\n\n问题:%s\n\n回答:", context, question ); 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; } public static class RagResponse { private String answer; public RagResponse(String answer) { this.answer = answer; } } }
|
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) { if (needsFunctionCall(request.getMessage())) { String functionResult = functionService.executeFunction(request.getMessage()); return new CustomerResponse(functionResult, "function_call"); } if (needsRAG(request.getMessage())) { String ragResult = ragService.ragQuery(request.getMessage()); return new CustomerResponse(ragResult, "rag"); } 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应用。通过本文的学习,你应该掌握了:
- Spring AI的基础概念:了解ChatClient、EmbeddingClient、VectorStore等核心组件
- 基础的对话功能:实现与AI模型的简单对话
- Function Calling:让AI调用Java方法,实现与外部系统的交互
- RAG技术:通过检索增强生成提高AI回答的准确性
- 多模型支持:同时使用多个AI模型
- 生产环境配置:重试、缓存、监控、异常处理等企业级特性
- 部署和运维:Docker部署、健康检查等
下一步学习建议
- 深入研究Prompt Engineering:学习如何设计更好的提示词
- 探索更多AI模型:尝试本地模型如Ollama、LLaMA等
- 集成其他AI能力:图像识别、语音处理等
- 性能优化:异步处理、批量操作等
- 安全考虑:提示词注入防护、数据安全等
Spring AI仍在快速发展中,建议关注官方文档和示例代码,获取最新的技术动态。作为Java开发者,Spring AI让我们能够充分利用现有的Spring生态知识,快速构建生产级的AI应用。
本文作者:小新,Spring AI实践者