Spring AI是Spring官方推出的AI框架,为Java开发者提供了原生的AI开发体验。本文将带你从零开始,掌握Spring AI的核心概念和Spring Boot集成技巧,打造属于自己的AI应用。
Spring AI简介 Spring AI是Spring官方推出的AI框架,专门为Java和Spring开发者设计,提供了一套简洁、直观且符合Spring生态的AI开发API。它集成了多种主流的AI模型和服务,让开发者能够轻松构建AI驱动的应用。
为什么选择Spring AI?
Spring生态完美集成 :无缝集成Spring Boot、Spring Cloud等
官方维护 :Spring官方项目,质量保证
简洁的API :直观的编程模型,学习成本低
企业级支持 :完整的生产环境特性支持
多模型支持 :支持OpenAI、Azure OpenAI、Ollama等多种模型
工具集成 :内置丰富的工具和增强器
社区活跃 :Spring社区强大的支持
核心组件详解 1. ChatClient(聊天客户端) ChatClient是Spring AI的核心组件,提供简洁的聊天交互API。
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 @Configuration public class AiConfig { @Bean public ChatClient chatClient (ChatClient.Builder builder) { return builder .defaultAdvisors(new SimpleLoggerAdvisor ()) .build(); } } @Service public class ChatService { private final ChatClient chatClient; public ChatService (ChatClient chatClient) { this .chatClient = chatClient; } public String chat (String message) { return chatClient.prompt() .user(message) .call() .content(); } public String chatWithSystem (String systemMessage, String userMessage) { return chatClient.prompt() .system(systemMessage) .user(userMessage) .call() .content(); } }
2. Prompt Templates(提示词模板) Spring AI提供了丰富的提示词模板支持。
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 @Service public class PromptService { public String generatePrompt (String role, String question, String language) { return """ 你是一个专业的%s,请回答以下问题: %s 请用%s回答。 """ .formatted(role, question, language); } public String chatWithTemplate (String role, String question) { PromptTemplate template = new PromptTemplate (""" 你是一个专业的{role},请详细解释: {question} 请提供具体示例和最佳实践。 """ ); return chatClient.prompt(template) .user(Map.of("role" , role, "question" , question)) .call() .content(); } }
3. Advisors(增强器) Advisor是Spring AI中用于增强AI响应的机制。
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 @Configuration public class AdvisorConfig { @Bean public Advisor loggingAdvisor () { return new SimpleLoggerAdvisor (); } @Bean public Advisor customAdvisor () { return new DefaultPromptAugmentor () { @Override public AdvisedRequest adviseRequest (AdvisedRequest request, Map<String, Object> context) { String enhancedUserMessage = "请详细回答以下问题,并提供示例:\n" + request.user().text(); return AdvisedRequest.from(request) .withUser(enhancedUserMessage) .build(); } }; } @Bean public Advisor rateLimitAdvisor () { return new RateLimitChatMemoryAdvisor (Duration.ofMinutes(10 ), 50 ); } }
4. Function Callbacks(函数调用) Spring AI支持工具调用,让AI能够执行特定任务。
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 50 51 52 53 54 55 56 57 58 59 public class SearchTools { @Tool(description = "搜索互联网信息") public String searchWeb (String query) { return "搜索 '" + query + "' 的结果..." ; } @Tool(description = "计算数学表达式") public double calculate (String expression) { try { ScriptEngineManager manager = new ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName("JavaScript" ); return ((Number) engine.eval(expression)).doubleValue(); } catch (Exception e) { return 0.0 ; } } @Tool(description = "获取当前时间") public String getCurrentTime () { return LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } } @Configuration public class FunctionConfig { @Bean public FunctionCallbackContext functionCallbackContext () { FunctionCallbackContext context = new FunctionCallbackContext (); context.addCallback("searchWeb" , new FunctionCallback () { @Override public String call (String input) { return new SearchTools ().searchWeb(input); } }); return context; } } @Service public class FunctionCallService { public String chatWithTools (String message) { return chatClient.prompt() .user(message) .functions("searchWeb" , "calculate" , "getCurrentTime" ) .call() .content(); } }
5. Vector Store(向量存储) Spring AI支持多种向量存储,用于实现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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Configuration public class VectorStoreConfig { @Bean public VectorStore vectorStore (EmbeddingModel embeddingModel) { return new SimpleVectorStore (embeddingModel); } @Bean public EmbeddingModel embeddingModel () { return new OpenAiEmbeddingModel (OpenAiApi.builder() .apiKey(System.getenv("OPENAI_API_KEY" )) .build()); } } @Service public class RagService { private final VectorStore vectorStore; private final EmbeddingModel embeddingModel; private final ChatClient chatClient; public RagService (VectorStore vectorStore, EmbeddingModel embeddingModel, ChatClient chatClient) { this .vectorStore = vectorStore; this .embeddingModel = embeddingModel; this .chatClient = chatClient; } public void storeDocument (String content, String metadata) { TextSegment segment = TextSegment.from(content); Embedding embedding = embeddingModel.embed(segment).content(); Document document = new Document (segment, Map.of("source" , metadata)); vectorStore.add(List.of(document)); } public String askWithContext (String question) { List<Document> relevantDocs = vectorStore.similaritySearch( SearchRequest.builder() .query(question) .topK(3 ) .build() ); String context = relevantDocs.stream() .map(doc -> doc.getText()) .collect(Collectors.joining("\n\n" )); return chatClient.prompt() .system("基于以下文档内容回答问题:\n" + context) .user(question) .call() .content(); } }
实战案例:智能问答系统 项目结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 spring-ai-qa-system/ ├── src/main/java/com/example/springai/ │ ├── config/ # 配置类 │ │ ├── AiConfig.java # AI配置 │ │ ├── VectorStoreConfig.java # 向量存储配置 │ │ └── AdvisorConfig.java # 增强器配置 │ ├── controller/ # 控制器 │ │ └── QaController.java # 问答接口 │ ├── service/ # 业务服务 │ │ ├── ChatService.java # 聊天服务 │ │ ├── RagService.java # RAG服务 │ │ └── PromptService.java # 提示词服务 │ ├── model/ # 数据模型 │ │ ├── ChatRequest.java # 请求模型 │ │ └── ChatResponse.java # 响应模型 │ └── tools/ # 工具类 │ └── SearchTools.java # 搜索工具 ├── src/main/resources/ │ ├── application.yml # 应用配置 └── pom.xml # Maven依赖
Maven依赖配置 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 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.ai</groupId > <artifactId > spring-ai-openai-spring-boot-starter</artifactId > <version > 1.0.0-M3</version > </dependency > <dependency > <groupId > org.springframework.ai</groupId > <artifactId > spring-ai-pgvector-store-spring-boot-starter</artifactId > <version > 1.0.0-M3</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-validation</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > </dependencies >
核心服务实现 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 50 51 52 @Service @Slf4j public class ChatService { private final ChatClient chatClient; private final PromptService promptService; public ChatService (ChatClient chatClient, PromptService promptService) { this .chatClient = chatClient; this .promptService = promptService; } public ChatResponse chat (ChatRequest request) { try { String prompt = promptService.generatePrompt(request); String response = chatClient.prompt() .system(prompt) .user(request.getMessage()) .call() .content(); return ChatResponse.builder() .response(response) .timestamp(System.currentTimeMillis()) .success(true ) .build(); } catch (Exception e) { log.error("聊天服务调用失败" , e); return ChatResponse.builder() .success(false ) .errorMessage(e.getMessage()) .timestamp(System.currentTimeMillis()) .build(); } } public Flux<String> streamChat (ChatRequest request) { String prompt = promptService.generatePrompt(request); return chatClient.prompt() .system(prompt) .user(request.getMessage()) .stream() .content(); } }
REST控制器 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 @RestController @RequestMapping("/api/chat") @RequiredArgsConstructor @Slf4j public class ChatController { private final ChatService chatService; private final RagService ragService; @PostMapping("/simple") public ResponseEntity<ChatResponse> simpleChat (@Valid @RequestBody ChatRequest request) { log.info("收到简单聊天请求:{}" , request.getMessage()); ChatResponse response = chatService.chat(request); return ResponseEntity.ok(response); } @PostMapping("/rag") public ResponseEntity<ChatResponse> ragChat (@Valid @RequestBody ChatRequest request) { log.info("收到RAG聊天请求:{}" , request.getMessage()); String answer = ragService.askWithContext(request.getMessage()); ChatResponse response = ChatResponse.builder() .response(answer) .timestamp(System.currentTimeMillis()) .success(true ) .build(); return ResponseEntity.ok(response); } @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamChat (@Valid @RequestBody ChatRequest request) { log.info("收到流式聊天请求:{}" , request.getMessage()); return chatService.streamChat(request); } @PostMapping("/tools") public ResponseEntity<ChatResponse> chatWithTools (@Valid @RequestBody ChatRequest request) { log.info("收到工具聊天请求:{}" , request.getMessage()); ChatResponse response = chatService.chat(request); return ResponseEntity.ok(response); } }
应用配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 spring: application: name: spring-ai-qa-system ai: openai: api-key: ${OPENAI_API_KEY:your-api-key-here} chat: model: gpt-3.5-turbo temperature: 0.3 max-tokens: 1000 embedding: model: text-embedding-ada-002 server: port: 8080 logging: level: org.springframework.ai: DEBUG com.example.springai: INFO
高级功能扩展 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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Configuration public class MultiModelConfig { @Bean @Qualifier("gpt4ChatClient") public ChatClient gpt4ChatClient (ChatClient.Builder builder) { return builder .defaultOptions(ChatOptions.builder() .model("gpt-4" ) .temperature(0.1 ) .build()) .build(); } @Bean @Qualifier("gpt35ChatClient") public ChatClient gpt35ChatClient (ChatClient.Builder builder) { return builder .defaultOptions(ChatOptions.builder() .model("gpt-3.5-turbo" ) .temperature(0.7 ) .build()) .build(); } } @Service public class MultiModelService { private final ChatClient gpt4Client; private final ChatClient gpt35Client; public MultiModelService ( @Qualifier("gpt4ChatClient") ChatClient gpt4Client, @Qualifier("gpt35ChatClient") ChatClient gpt35Client) { this .gpt4Client = gpt4Client; this .gpt35Client = gpt35Client; } public String chatWithModel (String message, String model) { ChatClient client = "gpt4" .equals(model) ? gpt4Client : gpt35Client; return client.prompt() .user(message) .call() .content(); } }
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 @Component public class CustomLoggingAdvisor implements Advisor { private static final Logger log = LoggerFactory.getLogger(CustomLoggingAdvisor.class); @Override public AdvisedRequest adviseRequest (AdvisedRequest request, Map<String, Object> context) { log.info("AI请求 - 用户: {}, 系统: {}, 消息长度: {}" , request.user().text(), request.system().text(), request.user().text().length()); return request; } @Override public ChatResponse adviseResponse (ChatResponse response, Map<String, Object> context) { log.info("AI响应 - 成功: {}, 响应长度: {}, Token使用: {}" , response != null , response != null ? response.getResult().getOutput().getContent().length() : 0 , response != null ? response.getMetadata().getUsage().getTotalTokens() : 0 ); return response; } }
部署和优化 Docker部署 1 2 3 4 5 6 7 8 9 10 FROM openjdk:17 -jdk-slimWORKDIR /app COPY target/*.jar app.jar EXPOSE 8080 CMD ["java" , "-jar" , "app.jar" ]
1 2 3 4 5 6 7 8 9 10 version: '3.8' services: spring-ai-app: build: . ports: - "8080:8080" environment: - OPENAI_API_KEY=${OPENAI_API_KEY} restart: unless-stopped
性能优化策略
缓存机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Configuration public class CacheConfig { @Bean public CacheManager cacheManager () { CaffeineCacheManager cacheManager = new CaffeineCacheManager (); cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000 ) .expireAfterWrite(Duration.ofMinutes(30 ))); return cacheManager; } } @Service @Cacheable("ai-responses") public String cachedChat (String message) { return chatClient.prompt() .user(message) .call() .content(); }
异步处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Service public class AsyncChatService { @Async public CompletableFuture<String> asyncChat (String message) { return CompletableFuture.supplyAsync(() -> chatClient.prompt() .user(message) .call() .content() ); } public List<String> batchChat (List<String> messages) { return messages.stream() .map(message -> chatClient.prompt() .user(message) .call() .content()) .collect(Collectors.toList()); } }
最佳实践 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 25 26 @Service public class ResilientChatService { @Retryable( value = {AiException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2) ) public String resilientChat (String message) { try { return chatClient.prompt() .user(message) .call() .content(); } catch (AiException e) { log.error("AI服务调用失败,重试中..." , e); throw e; } } @Recover public String recover (AiException e, String message) { log.error("AI服务调用失败,使用降级方案" , e); return "抱歉,AI服务暂时不可用,请稍后再试。" ; } }
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 @Configuration public class MetricsConfig { @Bean public MeterRegistryCustomizer<MeterRegistry> metricsCustomizer () { return registry -> { registry.config() .commonTags("application" , "spring-ai-qa-system" ); }; } } @Service public class MonitoredChatService { private final Counter chatRequests; private final Counter chatErrors; private final Timer chatDuration; public MonitoredChatService (MeterRegistry registry) { this .chatRequests = Counter.builder("ai.chat.requests" ) .description("Number of chat requests" ) .register(registry); this .chatErrors = Counter.builder("ai.chat.errors" ) .description("Number of chat errors" ) .register(registry); this .chatDuration = Timer.builder("ai.chat.duration" ) .description("Chat request duration" ) .register(registry); } public String monitoredChat (String message) { chatRequests.increment(); return chatDuration.recordCallable(() -> { try { return chatClient.prompt() .user(message) .call() .content(); } catch (Exception e) { chatErrors.increment(); throw e; } }); } }
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain (HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(authz -> authz .requestMatchers("/api/chat/**" ).authenticated() .anyRequest().permitAll() ) .httpBasic(); return http.build(); } @Bean public RateLimiter rateLimiter () { return RateLimiter.create(10.0 ); } } @Service public class SecureChatService { private final RateLimiter rateLimiter; public SecureChatService (RateLimiter rateLimiter) { this .rateLimiter = rateLimiter; } public String secureChat (String message, Authentication auth) { if (!rateLimiter.tryAcquire()) { throw new RuntimeException ("请求过于频繁,请稍后再试" ); } String sanitizedMessage = sanitizeInput(message); String response = chatClient.prompt() .user(sanitizedMessage) .call() .content(); return sanitizeOutput(response); } private String sanitizeInput (String input) { return input.trim(); } private String sanitizeOutput (String output) { return output.trim(); } }
总结与注意事项 技术要点总结
Spring AI 是Spring官方推出的AI框架,提供了原生的Spring集成体验
核心组件 包括ChatClient、Advisor、Function Callbacks、Vector Store等
Spring Boot集成 提供了完整的应用开发体验
多模型支持 可以灵活选择不同的AI模型
企业级特性 包括监控、安全、缓存等生产环境必需功能
使用注意事项
合理管理API密钥,避免泄露
注意速率限制和成本控制
在生产环境中使用适当的缓存和监控
定期更新Spring AI版本,获取最新功能
遵守相关法律法规,确保内容合规
扩展阅读建议
深入学习Spring AI官方文档
了解Spring生态的其他AI相关项目
学习Spring Boot最佳实践
关注AI技术的最新发展趋势
研究向量数据库和RAG技术
通过本文的介绍,你已经掌握了使用Spring AI构建LLM应用的基本技能。Spring AI以其简洁的API设计和强大的Spring生态集成,为Java开发者提供了一条快速构建AI应用的捷径。
参考资料
Spring AI官方文档
Spring AI GitHub仓库
OpenAI API文档
Spring Boot官方文档
Spring WebFlux文档
Resilience4j文档
Micrometer文档
Docker最佳实践
Spring Security文档
向量数据库比较