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——构建可复用的大模型调用层

相关新闻

LLaVA-1.5

LLaVA-1.5

第一章 为什么会有 LLaVA-1.5?作者真正想回答的问题其实是:到底应该怎样训练一个优秀的 Large Multimodal Model(LMM)?这听起来很普通,但实际上,这是2023年多模态领域最核心的问题。1.1 当时的大…

2026/10/17 1:30:52 阅读更多 →
深入解析C2000 ePWM高级功能:Trip-Zone、Event-Trigger与Digital Compare

深入解析C2000 ePWM高级功能:Trip-Zone、Event-Trigger与Digital Compare

1. 项目概述与核心价值 在电机驱动、数字电源或者任何需要高可靠性功率控制的嵌入式系统里,PWM信号的生成只是基础,如何确保它在异常情况下能“安全停车”,以及如何精准地“抓住”特定时刻来触发采样或计算,才是真正考验设计功力的…

2026/10/16 13:55:48 阅读更多 →
海南FTP项目:构建高效跨境数据交换枢纽的技术实践

海南FTP项目:构建高效跨境数据交换枢纽的技术实践

1. 海南FTP项目背景解析 在全球贸易格局重构的背景下,区域经济一体化进程面临新的挑战与机遇。海南自由贸易港(FTP)作为新型跨境贸易服务平台,其核心定位在于构建高效便捷的国际数据交换枢纽。这个项目本质上是通过技术创新重构跨…

2026/10/15 12:05:06 阅读更多 →

最新新闻

深度学习第二章自救指南:概率论与数值计算如何落地

深度学习第二章自救指南:概率论与数值计算如何落地

说实话,当我在学习笔记目录里看到deeplearningbook_002-2这个编号时,第一反应是有点头皮发麻的。002 指的是那本经典深度学习教材的第二章,而 -2 则意味着这一章被我拆成了两个部分来处理。前半部分线性代数还能靠矩阵乘法硬撑下去&#xff0…

2026/10/17 4:53:15 阅读更多 →
MySQL基本应用与性能调优:从建表、SQL优化到索引实战

MySQL基本应用与性能调优:从建表、SQL优化到索引实战

1. MySQL到底是什么,为什么大家都在用它先别急着敲命令,把概念搞清楚比什么都重要。MySQL本质是一个关系型数据库管理系统,它帮你把数据按照“表”的形式组织起来,一张表里有行有列,行是一条记录,列是一个字…

2026/10/17 4:53:15 阅读更多 →
海风域名查询工具v1.0:纯PHP轻量模块,无需API快速集成

海风域名查询工具v1.0:纯PHP轻量模块,无需API快速集成

简介:海风域名查询工具v1.0是一款基于PHP开发的轻量级域名查询系统,面向需要在Linux主机上快速搭建域名信息查询服务的站长与开发者,尤其适合具备基础PHP环境配置能力的技术人员使用。资源包为rar压缩格式,整体约372KB&#xff0c…

2026/10/17 4:53:15 阅读更多 →
claude-code-templates 模板化配置与 MCP 接入实战指南

claude-code-templates 模板化配置与 MCP 接入实战指南

1. 从一条命令说起:claude-code-templates 到底解决了谁的痛点第一次接触 Claude Code 的人,十有八九会卡在同一个地方:装是装上了,但打开终端之后不知道下一步该干什么。官方文档给了一堆命令,可真到项目里&#xff0…

2026/10/17 4:53:15 阅读更多 →
群晖NAS上用Docker部署memos:自托管备忘录从零到日常使用全攻略

群晖NAS上用Docker部署memos:自托管备忘录从零到日常使用全攻略

我的NAS上装了不下二十个容器,但用得最频繁的偏偏是最不起眼的一个——memos。说它不起眼,是因为界面干干净净,没有花哨的仪表盘;说它高颜值,是因为每次打开都想多记两笔。这篇文章就聊聊在群晖上把memos从零部署到日常…

2026/10/17 4:53:15 阅读更多 →
Mac 上 Hadoop 集成 Snappy 压缩:从编译到验证全流程

Mac 上 Hadoop 集成 Snappy 压缩:从编译到验证全流程

1. 为什么要在本地折腾 Hadoop 与 Snappy 的集成大数据生态里,压缩算法的选择从来不是一件小事。存储成本、网络传输开销、CPU 占用这三者之间的平衡,直接决定了集群的吞吐表现。Snappy 是 Google 开源的一套压缩库,主打的是极快的压缩与解压…

2026/10/17 4:52:15 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →