Spring AI 企业级应用实战(1):Spring Boot 4.1+Spring AI 2.0 接入 DeepSeek V4 完整教程
摘要Spring AI 2.0 已经正式发布并以 Spring Boot 4 和 Spring Framework 7 为新基线。对 Java 开发者来说接入大模型已经不再只是手写一个HTTP POST模型配置、流式输出、工具调用、结构化输出、RAG、MCP、重试和可观测性都可以继续使用熟悉的 Spring 编程模型。本文使用 Spring Boot 4.1.0、Spring AI 2.0.0 与 DeepSeek V4从零搭建一个可运行的 AI 对话服务完整实现DeepSeek 专用 Starter 接入API Key 环境变量管理ChatClient同步调用SSE 流式输出请求参数校验统一异常处理模型参数与重试配置旧模型名迁移生产环境升级清单。本文将作为《Spring AI 企业级应用实战》系列的第1篇后续会继续深入 ChatClient、Advisor、Memory、RAG、Tool Calling、MCP 和生产级治理。一、Spring AI 解决的不是“如何发HTTP请求”直接调用 DeepSeek API 并不困难一段RestClient或WebClient代码就能完成。但真实企业项目很快会遇到以下问题不同模型厂商的接口字段并不完全一致System Prompt、历史消息和业务上下文散落在代码中流式输出、重试、限流和错误处理被重复实现模型切换时业务层需要跟着改动RAG、工具调用和结构化输出缺少统一抽象Token成本、调用链和运行指标无法统一观察AI能力难以融入现有Spring Security、Actuator和配置体系。Spring AI 的价值是把生成式 AI 应用开发重新放回 Spring 生态中。它提供统一的ChatModel、ChatClient、Advisor、Memory、VectorStore、Tool Calling 和 MCP 抽象让模型能力成为企业应用中的一个可管理基础组件。Spring AI 2.0 的几个关键变化包括以 Spring Boot 4.0/4.1 为基线将ChatClient作为主要用户接口工具执行循环进入 Advisor ChainDeepSeek 成为核心项目直接支持的模型提供商MCP Java SDK 与 Spring AI 深度整合选项对象统一使用不可变 Builder配置属性移除了旧版多余的.options层级。二、本文版本选择组件版本JDK21Spring Boot4.1.0Spring AI2.0.0Maven3.9DeepSeekdeepseek-v4-flashWeb框架Spring WebFluxSpring Boot 4.1.0 最低支持 Java 17本文推荐使用 Java 21原因是它是当前企业项目中更稳妥的长期支持版本。DeepSeek 当前提供deepseek-v4-flash速度快、成本低适合普通问答、摘要、抽取和高并发业务deepseek-v4-pro能力更强适合复杂分析、代码和长链路任务。需要特别注意deepseek-chat deepseek-reasoner这两个旧模型名将在北京时间2026年7月24日23:59停止服务。新项目应直接使用deepseek-v4-flash或deepseek-v4-pro。三、项目结构spring-ai-deepseek-demo ├── pom.xml └── src └── main ├── java │ └── com │ └── zyentor │ └── springai │ ├── SpringAiDeepSeekApplication.java │ ├── config │ │ └── AiConfig.java │ ├── controller │ │ ├── AiChatController.java │ │ └── GlobalExceptionHandler.java │ ├── dto │ │ ├── ChatRequest.java │ │ └── ChatResponse.java │ └── service │ └── AiChatService.java └── resources └── application.yml调用链如下浏览器/客户端 ↓ AiChatController ↓ 参数校验 ↓ AiChatService ↓ ChatClient ↓ DeepSeekChatModel ↓ DeepSeek API四、创建 Maven 项目完整pom.xml?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion4.1.0/versionrelativePath//parentgroupIdcom.zyentor/groupIdartifactIdspring-ai-deepseek-demo/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version21/java.versionspring-ai.version2.0.0/spring-ai.version/propertiesdependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion${spring-ai.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-deepseek/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-webflux/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdio.projectreactor/groupIdartifactIdreactor-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project最关键的依赖是artifactIdspring-ai-starter-model-deepseek/artifactIdSpring AI 2.0 已提供 DeepSeek 专用自动配置不需要再借用 OpenAI Starter 修改base-url。五、配置 API KeyLinux或macOSexportDEEPSEEK_API_KEYsk-xxxxxxxxWindows PowerShell$env:DEEPSEEK_API_KEYsk-xxxxxxxxIDEA运行配置在 Run/Debug Configurations 中增加DEEPSEEK_API_KEYsk-xxxxxxxx不要把真实密钥直接写进源码、application.yml、Git仓库、前端代码、Docker镜像或博客截图。六、编写 application.ymlspring:application:name:spring-ai-deepseek-demoai:model:chat:deepseekdeepseek:base-url:https://api.deepseek.comapi-key:${DEEPSEEK_API_KEY}chat:model:deepseek-v4-flashtemperature:0.3max-tokens:2048retry:max-attempts:3backoff:initial-interval:1smultiplier:2max-interval:10son-client-errors:falseserver:port:8080management:endpoints:web:exposure:include:health,info,metricsSpring AI 2.0 使用顶层模型选择属性spring.ai.model.chat:deepseek旧配置spring.ai.deepseek.chat.enabled:true已经移除不应继续使用。七、创建启动类packagecom.zyentor.springai;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassSpringAiDeepSeekApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SpringAiDeepSeekApplication.class,args);}}八、配置 ChatClientpackagecom.zyentor.springai.config;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassAiConfig{BeanChatClientdeepSeekChatClient(ChatClient.Builderbuilder){returnbuilder.defaultSystem( 你是企业级AI技术助手。 回答必须准确、清晰并优先给出可执行方案。 不确定的信息必须明确说明不得虚构。 提供代码时应给出必要的异常处理和使用说明。 ).build();}}Spring Boot 自动配置会创建一个原型作用域的ChatClient.Builder。开发者可以在不同注入点构建不同用途的ChatClient。九、定义请求与响应对象packagecom.zyentor.springai.dto;importjakarta.validation.constraints.NotBlank;importjakarta.validation.constraints.Size;publicrecordChatRequest(NotBlank(messagemessage不能为空)Size(max4000,messagemessage不能超过4000个字符)Stringmessage){}packagecom.zyentor.springai.dto;importjava.time.Instant;publicrecordChatResponse(Stringmodel,Stringcontent,Instanttimestamp){}十、实现业务服务packagecom.zyentor.springai.service;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.stereotype.Service;importreactor.core.publisher.Flux;ServicepublicclassAiChatService{privatefinalChatClientchatClient;publicAiChatService(ChatClientchatClient){this.chatClientchatClient;}publicStringchat(Stringmessage){returnchatClient.prompt().user(message).call().content();}publicFluxStringstream(Stringmessage){returnchatClient.prompt().user(message).stream().content();}}同步调用.call().content()流式调用.stream().content()十一、实现同步与SSE接口packagecom.zyentor.springai.controller;importcom.zyentor.springai.dto.ChatRequest;importcom.zyentor.springai.dto.ChatResponse;importcom.zyentor.springai.service.AiChatService;importjakarta.validation.Valid;importorg.springframework.http.MediaType;importorg.springframework.http.codec.ServerSentEvent;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importjava.time.Instant;RestControllerRequestMapping(/api/ai)publicclassAiChatController{privatestaticfinalStringMODELdeepseek-v4-flash;privatefinalAiChatServiceaiChatService;publicAiChatController(AiChatServiceaiChatService){this.aiChatServiceaiChatService;}PostMapping(/chat)publicChatResponsechat(ValidRequestBodyChatRequestrequest){StringcontentaiChatService.chat(request.message());returnnewChatResponse(MODEL,content,Instant.now());}PostMapping(value/chat/stream,producesMediaType.TEXT_EVENT_STREAM_VALUE)publicFluxServerSentEventStringstream(ValidRequestBodyChatRequestrequest){FluxServerSentEventStringchunksaiChatService.stream(request.message()).map(content-ServerSentEvent.Stringbuilder().event(message).data(content).build());ServerSentEventStringdoneServerSentEvent.Stringbuilder().event(done).data([DONE]).build();returnchunks.concatWithValues(done);}}十二、统一异常处理packagecom.zyentor.springai.controller;importorg.springframework.http.HttpStatus;importorg.springframework.http.ProblemDetail;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.RestControllerAdvice;RestControllerAdvicepublicclassGlobalExceptionHandler{ExceptionHandler(MethodArgumentNotValidException.class)ProblemDetailhandleValidation(MethodArgumentNotValidExceptionexception){Stringmessageexception.getBindingResult().getFieldErrors().stream().findFirst().map(error-error.getDefaultMessage()).orElse(请求参数错误);returnProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST,message);}ExceptionHandler(Exception.class)ProblemDetailhandleException(Exceptionexception){returnProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR,AI服务暂时不可用请稍后重试);}}十三、启动与测试mvn spring-boot:run健康检查curlhttp://localhost:8080/actuator/health同步调用curl-XPOSThttp://localhost:8080/api/ai/chat\-HContent-Type: application/json\-d{message:请用三个要点解释Spring AI的价值}流式调用curl-N-XPOSThttp://localhost:8080/api/ai/chat/stream\-HContent-Type: application/json\-d{message:请解释企业级RAG系统的完整链路}十四、Nginx代理后不流式怎么办location /api/ai/chat/stream { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_buffering off; proxy_cache off; proxy_read_timeout 300s; proxy_send_timeout 300s; }还应检查API网关是否缓冲CDN是否支持流式响应浏览器是否一次性调用response.text()服务端是否真正调用.stream()curl是否使用-N。十五、单次请求覆盖模型参数returnchatClient.prompt().user(message).options(DeepSeekChatOptions.builder().model(deepseek-v4-pro).temperature(0.2).build()).call().content();可形成任务路由普通问答 → deepseek-v4-flash 复杂分析 → deepseek-v4-pro十六、从Demo到生产还缺什么至少还需要Spring Security与JWT用户和租户级限流Chat Memory与消息持久化Token与费用统计首Token延迟和调用链监控敏感数据脱敏Prompt Injection防护模型故障降级用户反馈和自动化评测灰度发布与回滚。十七、总结本文完成了 Spring Boot 4.1.0、Spring AI 2.0.0 与 DeepSeek V4 的完整接入使用DeepSeek专用Starter使用环境变量管理API Key构建统一ChatClient提供同步和SSE流式接口增加参数校验与异常处理配置重试、模型参数与Actuator完成旧模型名迁移给出从Demo到生产的升级方向。下一篇Spring AI企业级应用实战2ChatClient、Advisor与Prompt Template——构建可复用的大模型调用层