1. 为什么从Spring AI到MLOps是一堂必修课先交代一下背景。我最近一年多主要在做一件事把企业内部那些老旧的后端系统逐步改造成能用上大模型能力的“AI 2.0”应用。这个改造过程踩了不少坑也沉淀了不少方法。很多团队现在还在“调API、拼Prompt”的阶段觉得能接上ChatGPT就万事大吉了。但真正把应用放到生产环境里面对的是另一套完全不同的逻辑模型怎么管理、数据怎么隔离、效果怎么评估、流量怎么兜底、成本怎么控制这些都不是简单调库能解决的。所以有了这篇文章的标题——“从Spring AI到MLOps”。这个跨度看起来很跳但其实是一条完整的全栈技术链路。前半段解决“怎么让业务代码优雅地接入大模型”后半段解决“怎么让接入大模型的应用稳定、可控、可迭代地跑在线上”。如果你正在做AI应用开发或者准备把现有Java服务升级成AI能力服务这篇文章就是我对这条链路的一份实操笔记。我默认读者是有一定Java后端基础的。你用Spring Boot写过接口知道Bean、配置、依赖注入这些概念那你就能跟上大部分内容。不懂机器学习内部原理没关系MLOps层面更讲究工程化反而是业务开发转过来的人优势更大。要是你只会Python那一套AI生态这篇文章也能帮你理解在Java生态里做AI应用体验没有想象中那么差。2. 从“调模型API”到“AI应用工程”先想清楚要做哪一层2.1 AI 2.0 到底新在哪里“AI 2.0”这个词这两年被喊得很多。但落到工程上我觉得真正的变化在于大模型从“一个可以调用的接口”变成了“一个需要参与架构设计的核心组件”。以前做AI比如图像识别模型是固定的你训练完一个模型部署上去不做大更新基本不动。现在做大模型应用模型本身在快速迭代业务场景也千变万化你需要不断调整提示词、换模型版本、改上下文策略甚至在线评估模型输出质量。这就让AI应用变成一个“运行时还在持续变化”的系统。Spring AI这个框架解决的就是这个问题它把大模型接入变成Spring生态的标准动作。你不需要一个个去对接不同厂商的SDK不需要自己封装API调用、Token统计这些脏活。它采用类似Spring Data那种“统一抽象多实现”的思路——你对着ChatClient写业务代码底层接的是OpenAI、Ollama还是国产模型切换起来是配置的事。2.2 从零搭一个AI后端服务需要拆成几个模块我自己做这类项目的时候习惯先把架构拆成四层。这四层不复杂但想清楚之后再写代码后面做MLOps会省很多事。第一层是应用接入层就是正常的Controller、Service那一套负责处理HTTP请求、权限验证、异常兜底。第二层是AI编排层这一层是Spring AI的主场负责调模型、组装提示词、处理流式输出、做函数调用。第三层是数据与知识层包括向量数据库、文档加载、Embedding计算用来支撑RAG之类的能力。第四层是运维治理层对应就是MLOps里的模型管理、监控、评估这些。很多团队失败的原因就是跳过第二层和第四层直接在Controller里调模型API。刚开始demo跑得很欢一旦业务逻辑复杂起来提示词散落得到处都是模型一换接口全废线上效果出问题也不知道是模型的事还是数据的事。Spring AI的定位是解决第二层的编排问题。但要注意它不替你解决第四层那是MLOps要处理的范畴。这也是为什么我把两件事放在一起讲——它们是先后关系不是替代关系。2.3 Spring AI和其他AI框架相比凭什么值得学现在Java生态里也有不少AI框架比如LangChain4j、Semantic Kernel都能对接大模型。Spring AI的优势在于它背靠整个Spring生态和Spring Boot、Spring Cloud的集成是天然顺滑的。举个例子你在Spring Security里已经把用户体系做好了要做AI对话就必须知道“当前是哪个用户在调用模型”。Spring AI的ChatClient可以直接在调用链路里透传上下文而不用自己在拦截器里额外做一套。再比如你公司已经有Spring Cloud Gateway做统一网关现在要给AI接口加限流你可以直接在网关层配置不用专门为AI服务引入另一套流量治理组件。这不是说Spring AI一定优于其他框架而是说如果你的技术栈本来就在Spring生态里选它的学习成本和后期维护成本是最低的。LangChain4j在某些功能上更激进Semantic Kernel对.NET更友好这些都要结合团队实际情况判断。3. Spring AI核心实践ChatClient、提示词模板与模型管理3.1 先跑通一个最小可用的对话接口我不会一上来就贴一堆POJO和工具类先用最简单的例子说明Spring AI的编程模型长什么样。在Spring Boot 3.x项目中引入Spring AI的依赖后你只需要在application.yml里配置模型供应商的信息。比如用Ollama本地模型配置长这样spring: ai: ollama: base-url: http://localhost:11434 chat: model: qwen2.5:7b然后定义一个Service注入Spring AI提供的ChatClientService public class AIChatService { private final ChatClient chatClient; public AIChatService(ChatClient.Builder builder) { this.chatClient builder .defaultSystem(你是一个专业的技术助手请用简洁的中文回答问题。) .build(); } public String chat(String userMessage) { return chatClient.prompt() .user(userMessage) .call() .content(); } }代码不长但它背后做的事情很多ChatClient封装了与Ollama的HTTP通信、Token计算、错误重试、模型参数传递。你不用关心它底层是REST调用还是流式解析只关心业务层的输入输出。这个示例能跑通你就已经完成“从零到一”的接入。但你还要理解一件事ChatClient.Builder是整个链路的核心入口后面做流式输出、多轮对话、结构化输出都是在这个Builder和Prompt上叠加能力。3.2 Prompt模板不是字符串拼接很多从其他语言转过来的朋友第一次用Spring AI写Prompt第一反应是搞一个StringBuilder去拼提示词。这个习惯在简单Demo里没问题生产环境就是灾难。Spring AI提供了PromptTemplate类似Spring的MessageSource把提示词和参数分离。比如你要做一个“产品描述生成器”模板可以单独放文件你是一位电商文案专家。请根据以下产品信息生成一段不超过80字的商品描述。 产品名称{name} 核心卖点{features} 目标人群{audience} 语气要求{tone}代码里这样调用PromptTemplate template new PromptTemplate(classpath:prompts/product-description.st); Message message template.createMessage(Map.of( name, 智能保温杯, features, 316不锈钢48小时保温智能温显, audience, 年轻上班族, tone, 轻松活泼 ));这么做的好处第一是提示词可以独立维护产品同学也能快速看懂第二是每次模型改动只动模板文件不用重新编译Java代码。这在MLOps里很重要后面讲提示词版本管理的时候我会再提。3.3 流式输出体验和实现之间的平衡ChatGPT那种一个字一个字蹦出来的效果在Java端要做到也不难。Spring AI的ChatClient提供stream方法配合WebFlux或者Servlet异步接口能实现SSE推送。GetMapping(/chat/stream) public FluxString streamChat(RequestParam String message) { return chatClient.prompt() .user(message) .stream() .content(); }Controller返回Flux前端用EventSource就能直接接收。但这里有个坑Spring MVC默认是同步阻塞模型你用Flux做返回类型必须确保底层不是传统Servlet容器阻塞线程。要么引入WebFlux要么用Spring MVC的异步返回包装一下否则流量一上来连接就拖垮。我实际项目里更推荐用Spring MVC SSEManager之类的封装后端用线程池处理流式响应前端看到的效果和原版对话一样。去掉流式直接等全部Token回来再一次性输出在长文本场景下用户等待时间会变得难以接受。3.4 多模型接入的策略生产环境最大的变量是模型本身。OpenAI可能调整版本国产模型可能在特定场景下效果更好企业内部甚至可能部署私有化模型。Spring AI的抽象层让你切换模型时业务代码基本不用改。我常用的做法是定义枚举标记业务场景和模型对应的关系public enum ModelScene { CHAT(chat-model), RAG_EMBEDDING(embedding-model), STRUCTURED_EXTRACT(extract-model); }然后在配置中心维护每个Scene对应的具体模型名、供应商、参数。每次模型升级先灰度一个小比例流量观察评估指标确认没问题再全量切换。这里要额外提醒Spring AI的API在不同版本之间有过比较大的调整比如早期版本还有AiClient后来换成了ChatClient。你在看教程的时候要确认代码和文档版本一致否则容易出现“照着写但编译不过”的尴尬情况我因为这个浪费过不少时间。4. 从Spring AI到MLOps把AI应用当成产品而不是脚本4.1 MLOps不是CI/CD换个名字很多人觉得MLOps就是给AI项目加个自动化部署流程。我在学习初期也是这么理解的后来做完整套项目才明白MLOps的核心矛盾是“模型和数据都是持续在变的”传统软件工程里的版本管理、测试、监控在模型驱动的系统里都要重新设计。传统代码出Bug修代码再发布就行。AI应用出问题可能是代码的Bug也可能是提示词写得不合适可能是模型换版本了可能是检索到的上下文质量太差还可能是用户输入本身就有歧义。你没法靠单元测试全覆盖只能靠建立一套围绕“模型输出质量”的观测和评估体系。Spring AI解决的是开发期的问题MLOps解决的是运行期和迭代期的问题。两者结合在一起才是完整的产品闭环。4.2 模型生命周期管理从实验到上线的四个阶段模型在我们项目里像代码一样走一套生命周期实验、评估、注册、部署。实验阶段数据工程师和算法工程师用MLflow或者本地脚本跑各种Prompt版本和模型组合。评估阶段把测试结果记录下来看准确率、相关性、Token消耗这些指标。注册阶段把效果达标的模型和Prompt版本传到模型注册表生成一个唯一版本号。部署阶段配置中心把版本号下发到Spring AI服务通过ChatClient里的模型参数指定到具体版本。这套流程看起来复杂其实基础工具可以很轻量。我在小团队里面用一套组合MySQL存评估记录注册表就用配置中心的KV列表没有刻意上重型MLflow平台。等到团队规模和模型数量真的上来了再切换到正式平台也不迟。选型的关键在于不要让流程制约迭代速度。AI应用的一个特点就是胜败在于迭代快不快如果你增加一个管理环节要卡两天审批那还不如不做。4.3 数据和提示词都是需要版本管理的资产这里分享一个真实踩过的坑。我们有次做客服助手早上的时候效果还很好下午用户反馈输出质量下降。查了很久最后发现是数据同步任务在凌晨更新了向量库但新数据里混了一大批没清洗的脏数据导致RAG检索到的上下文质量变差。模型没换、代码没动问题出在数据。从那以后我要求每一个数据集在写入向量库之前必须有版本标签和字段说明。类似Git的commit你要能说清楚这批数据是什么时候、由谁、通过什么脚本生成的。提示词同样要做版本记录。Spring AI的PromptTemplate文件建议直接纳入Git管理每次修改都走Commit记录。更进一步的团队会把提示词和模型版本绑定起来形成一个“运行时物料清单”哪天线上发生了什么效果变化你能回溯出当时的模型版本、知识库版本、提示词版本。有了这套历史追踪能力MLOps里的“模型回滚”才不是一句空话。否则你想回滚根本不知道要滚到哪个版本、配套哪些物料。4.4 可观测性AI服务的黑盒必须被照亮我在做监控体系时会从三个维度收集信息业务指标、模型指标、基础设施指标。业务指标比较好理解用户提问数、回答采纳率、会话时长、用户反馈的点赞点踩数量。模型指标包括Token消耗、响应延迟、上下文长度、拒绝服务次数。基础设施指标就是常规的CPU、内存、QPS、错误率。代码层面Spring AI预留了一些可扩展的拦截点。你可以通过实现ChatClient的调用链来记录输入输出日志。我推荐在Service层统一做日志埋点每次请求记录用户ID、场景、模型、Token数、耗时、返回状态和返回内容摘要。注意不要整段记录用户输入和模型输出一是隐私合规问题二是日志量会爆炸。摘要化、脱敏化是必须的。监控采集上来之后要有配套的告警规则。最简单的做法是当模型接口错误率超过2%或者P95延迟超过设定的阈值立刻通知到值班群。再有经验的团队还会加一层“输出质量抽检”每天随机抽取一定比例的问答记录人工或者用大模型评测的方式打分防止指标正常但体验变差的情况发生。5. 生产环境实战评估、部署、监控和成本控制5.1 没有评估体系的模型切换都是赌运气我在切换模型供应商的时候踩过一次很痛的跟头。线上本来用的商业模型因为成本原因想把一部分流量分流到本地开源模型。换之前只做了几个固定用例的评测感觉效果差不多就直接改了配置。结果上线一周用户投诉率明显上升很多深度推理类问题开源模型回答得漏洞百出。从那以后我建立了一套最小可用的评测集。几百条覆盖典型业务场景的输入问题配上预期答案要点每次要换模型或者改提示词先把评测集跑一遍用“通过率”作为准入门槛。更高级的做法是用大模型当裁判把新旧模型的输出同时给一个评判模型打分但那个成本比较高适合最终定夺阶段用日常迭代还是跑固定评测集更效率。Spring AI支持在运行时动态指定模型参数所以灰度切换在架构上不困难。难的是你敢不敢在评估数据不足的情况下按下那个切换开关。5.2 部署拓扑AI服务也是普通的云原生应用部署层面Spring Boot的AI服务和其他微服务没有本质区别。镜像打包、Kubernetes部署、水平扩容这套流程成熟稳定。唯一要注意的是流式请求对长连接和内存的压力。普通接口几毫秒就返回了AI流式接口可能要持续几十秒每个连接占用的线程和缓冲都不能按普通接口的思路估算。配置Tomcat的线程池时要预留更多线程给流式请求否则其他短请求容易饿死。另外一个细节是超时控制。模型供应商的服务不一定稳定第三方接口可能挂起很久。我在网关层和Service层都要配超时时间而且是分级超时。网关层超时稍微长一点比如90秒Service层超时短一点比如60秒。一旦模型响应超时就返回一个预设的兜底文案而不是让用户一直转圈。对于成本控制我习惯给不同的API Key或者模型场景设置配额。比如普通聊天用便宜模型法律咨询用高质量模型。Spring AI允许你定义多个ChatClient实例分别绑定不同模型。这样做的好处是业务与模型资源直接挂钩成本归属清晰。5.3 线上反馈闭环用户点踩是最好的训练信号MLOps的最后一环是把线上反馈变成下一次模型迭代的输入。我们系统里接入了用户点踩逻辑。用户点踩之后会把当时的前后文对话快照、检索到的知识片段、模型输出内容统一归档形成一个待分析的负反馈样本。每周我们都会review这批样本挑出高频问题类型补充进评测集再驱动Prompt或知识库优化。这其实就是一种在线学习循环。模型本身可能没有更新但你的知识库和提示词一直在变系统的智能水平也跟着在变。做这个闭环的时候要注意节奏。用户点踩样本往往噪音很大有可能是用户操作失误也有可能是前一轮回答没问题但后一轮跑偏了。人工review的速度跟不上就要靠规则初筛相似问题自动聚类只挑代表性的给人工看。我见过团队因为不筛选直接拿所有负反馈去调Prompt结果被少量异常样本带偏方向的案例教训很深刻。5.4 成本治理Token账单里的经济学大模型应用和传统应用不同成本不是线性增长的。你多一个用户不只是多一份服务器开销而是每次用户交互都伴随着Token消耗。这个消耗和会话长度、检索上下文大小、模型价格直接相关。我的经验是接到账单之后先按场景拆解搞清楚钱花在哪些环节。常见的大头有三个一是长上下文的重复计费每次对话都把大量历史记录塞给模型Token飞速涨二是Embedding调用频繁尤其是知识同步和查询的Embedding没有做缓存三是模型选型过度小任务用了大模型。针对这三件事省钱策略也清晰。会话上下文要做滑动窗口只保留最近几轮关键信息文档切分和Embedding结果要做缓存内容没变就直接复用不同复杂度任务拆到不同模型。Spring AI里可以通过调整Prompt的上下文策略和设置多个ChatClient实例来实现。成本治理不是一次性的我建议每个月做一次回顾看Token消耗趋势、评估模型性价比、调整场景和模型的匹配关系。把成本当成工程指标来对待而不是等月底账单回来再焦虑。6. 这些坑我替你踩过常见问题速查与避坑清单6.1 Spring AI版本演进带来的兼容性烦恼Spring AI的版本更新节奏非常快而且没有完全稳定下来。度量和包名都会在版本之间变动。应对这个问题的办法一是锁定具体版本号不要用Spring Boot的BOM无脑升级。二是多留意当前使用版本对应的文档不要在搜索引擎里找最新版教程然后直接往旧项目里套。我自己的做法是给每个项目建立一个spring-ai.version属性所有依赖和代码都基于这个固定版本验证过。升级的时候单独拉分支重点回归几个核心链路普通对话、流式输出、结构化解析、向量检索。6.2 向量库检索质量不佳不一定是数据库的锅RAG效果差很多人第一个怀疑向量数据库选型有问题。但以我的经验绝大多数情况问题出在文档切分策略。切得太小语义不完整切得太大检索噪音多。不同文档类型甚至不同章节结构最优切分方式都不一样。我的做法是按标题层级切分保留上下文标题信息。切分后的文本块带上文档ID和章节路径作为元数据。检索的时候先按业务场景过滤比如只搜技术文档或者只搜公告可以做混合检索。用关键词检索兜底很多专业名词在向量检索里效果不稳定混合检索能把这部分补回来。6.3 流式响应中断和前端状态不一致流式输出最烦人的问题是响应中途断掉。用户看了一半内容突然没了前端还不知道。我碰到之后主动给流式接口加了结束标记。前端必须收到结束标记才认为整轮回答完成要是连接断开但没有结束标记就自动触发一次重新请求或者降级提示。后端则要做好幂等控制同一个用户短时间内重复发起同样请求要有去重机制。不然用户一着急多点几遍模型那边会多扣好几倍Token账单白涨。6.4 单元测试不是不能写而是要分层写很多人觉得AI应用没法测试一问到测试就摆烂。其实能测的环节很多。Prompt模板可以测Java单元测试里验证模板渲染后的字符串是否符合预期。模型对接那一层可以做契约测试Mock掉大模型响应确保业务逻辑不依赖模型具体输出格式。结构化输出解析可以用固定JSON样本测试。真正难测的是“模型输出质量好坏”。这确实不是传统单元测试的范畴要交给评估集和灰度反馈。但把能测的都测好线上出问题时定位范围会小很多。7. 落地这套体系的最低配置小团队也可以循序渐进我经常被问你讲的这套东西很完整但我们团队就五六个人也要一开始就全套上吗我的回答是不必但方向要早一点明确。如果你的业务还在验证期连用户都没有那最重要的就是速度和体验。用Spring AI搭好一个能用的对话服务日志简单记录足够用了。没必要现在就上复杂的评估和监控平台。当你的工具开始有真实用户用户反馈和线上指标开始影响你们的产品决策时就轮到MLOps这套体系登场了。先加上请求日志、加上简单评估集、加上基础告警渐进式地搭建。我见过最理想的小团队配置是一个Git仓库管代码和提示词一个配置中心管模型版本和场景映射一Table的评估记录一套Grafana看板。这三个仓库加起来可能一个月就能搭完但带来的收益是从“感觉能用”变成“知道为什么能用、什么时候可能不能用”。这就是工程化的意义。8. 讲讲我对未来趋势的个人判断如果你现在开始学习Spring AI加MLOps时间点其实很好。Spring AI还在快速迭代意味着现在踩的坑和学习到的经验很长一段时间都会有效。而MLOps这套理念在AI应用真正大规模落地的时候会成为像测试、运维一样的基本功。我个人的体会是AI应用开发最缺的不是算法能力而是工程化意识。模型能力底座由专门的厂商和大模型团队负责应用层团队的价值在于怎么把这些能力变成稳定、可用、成本可控的产品。而这一层恰恰是Spring生态和MLOps最擅长的事情。最后分享一个小技巧给团队里面每一个AI特性项目都建立一份“模型效果周报”。每周固定时间看一眼Token消耗、评估通过率、用户反馈数量三个指标。只要这三个指标稳定大方向基本不会出大问题。等这三个指标出现趋势性变化就是你该动Prompt、动知识库或者考虑换模型的信号。这个习惯我们坚持了一年多帮我们避免了好几次“看起来没事但实际上在变差”的隐患。希望这条经验也对你有效。