ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring AI实战:Java开发者大模型应用工程化指南

Spring AI实战:Java开发者大模型应用工程化指南 Java 开发者做 AI 大模型应用绕不开一个尴尬Python 生态里随便几行代码就能调用大模型而 Java 后端要把鉴权、参数组装、JSON 解析、超时重试、多轮上下文、向量检索、工具调用全部自己写一遍。代码写多了你会发现模型能力本身不是难点难点全在工程化。Spring AI 的价值就在这里它在 Spring 生态里把大模型接入变成像 JdbcTemplate 一样的组件让你不用重复造轮子。这篇文章不是把官方文档复述一遍。我会按一条主线把 Spring AI 从入门到可落地讲清楚先理解它到底解决了什么再跑通一个最小示例然后逐步补上 Prompt、多轮记忆、Agent 工具调用、RAG 和本地模型选型最后整理常见坑和工程建议。读完你会有能力把大模型接入 Spring Boot 项目并且能自己判断该走哪条技术路线。先给一个判断Spring AI 最适合的不是零基础学 AI 的人而是已经有 Java/Spring 项目经验、想在业务系统中稳定接入大模型的开发者。它不能替代 Dify 这类可视化编排平台也不负责解决算法问题但它把“换模型”“接工具”“做检索”这些高频动作统一成了 Spring 风格。一旦理解这套抽象你的 AI 功能会变得非常容易维护。1. 这篇文章真正要解决的问题很多教程一上来就讲 ChatClient 怎么用、代码怎么跑但读者往往不知道这个框架解决了什么问题也不知道不同版本之间为什么 API 会变。我们先从痛点说起。假如你现在要在 Spring Boot 项目里接入一个 Qwen 模型最原始的做法是用 RestClient 手动拼 HTTP 请求String url https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions; String requestBody { model: qwen-plus, messages: [ {role: user, content: %s} ], temperature: 0.7 } .formatted(question); String response restClient.post() .uri(url) .header(Authorization, Bearer apiKey) .contentType(MediaType.APPLICATION_JSON) .body(requestBody) .retrieve() .body(String.class);这只是一个“能跑”的 demo。真实项目里还要处理多个模型服务商的 API 格式差异请求失败后的重试和熔断多轮对话时的历史消息维护输出结果的结构化解析模型返回的工具调用参数反序列化向量化与知识库检索的集成。这些逻辑如果每个项目都重写一遍代码会很快失控。Spring AI 做的事情就是把“模型调用”这一层抽象成统一的 Spring 组件把鉴权、参数、消息、输出解析、重试都由框架帮你管理。1.1 不同方案对比对比维度原生 HTTP 调用各家模型平台 SDKSpring AI接入 OpenAI 兼容模型自己拼 JSON、自己处理鉴权可用但换个平台又要换 SDK改配置即可切换多轮上下文自己存消息数组SDK 差异大统一 Message 对象工具调用 / Function Calling手写 JSON Schema部分支持统一抽象支持多种模型Spring Boot 集成自己封装不原生自动装配开箱即用向量检索 / RAG自己集成基本不覆盖Embedding VectorStore从这张表能看出来Spring AI 的核心价值不是“调用模型更简单”而是把模型能力接入了 Spring 的自动装配、配置体系、异常体系和生态组件。它不是简单的 HTTP 封装而是企业级集成层。2. Spring AI 的核心概念与关键技术链路Spring AI 的知识体系看起来碎实际上主线很清楚。无论 1.x 还是 2.x你要抓住下面这组概念2.1 ChatModel 与 ChatClientChatModel是统一的模型接口。不管你接的是 OpenAI、Qwen、DeepSeek 还是本地 Ollama业务代码面对的模型对象都是ChatModel。Spring Boot 会根据 classpath 中引入的 starter 和配置文件自动帮你创建对应实现的 Bean。ChatClient则是在ChatModel之上提供更友好的调用门面。它类似RestClient和JdbcTemplate的关系ChatModel负责底层协议ChatClient让你用更少的代码完成业务调用。2.2 Prompt 与 MessagePrompt是发送给模型的完整指令里面包含系统消息、用户消息、历史消息以及模型参数。Message是消息单元常见的是SystemMessage、UserMessage、AssistantMessage。理解这个模型很重要大模型本身不保留状态所谓的“多轮对话”其实是把历史消息重新组装成一个完整的Prompt再发过去。2.3 Tool / Function CallingFunction Calling 是 Agent 的基础能力。模型不直接执行你的业务逻辑而是根据你的问题生成一个“调用计划”Spring AI 把计划转成 Java 方法调用再把结果回传给模型生成最终回答。这套机制的难点在于把 Java 方法描述成模型能理解的 JSON Schema以及把模型返回的参数安全地绑定到方法上。2.4 Embedding 与 VectorStoreEmbedding 模型把文本变成向量VectorStore 负责存储和相似度检索。RAG 应用的核心链路是知识文档 → 分块 → Embedding → 向量存储 → 用户提问时检索 topK 相关片段 → 拼进 Prompt 交给大模型回答。2.5 Spring AI 与 Dify 的关系很多人在同一个项目里纠结“到底用 Spring AI 还是 Dify”。准确地说两者不是替代关系。Dify 是低代码可视化工作流平台适合业务人员快速搭 AI 应用Spring AI 是 Java 代码级框架适合把 AI 能力嵌到事务、缓存、消息、数据库等既有系统里。Dify 的“工作流转成 Spring AI Java 代码”目前在 GitHub 上有不少实验项目但成熟度都不高。原因在于可视化节点和代码对象之间不是一一对应的比如 Dify 里的“知识检索”节点对应 Spring AI 里的多个组件组合逻辑转换复杂。更稳妥的做法是把 Dify 作为快速验证工具简单链路直接改写成 Spring AI复杂链路继续保留 Dify 并对外提供 API。3. 环境准备与基础工程创建动手之前先确认环境。本文示例以 JDK 17 和 Spring Boot 3.x 为准Maven 或 Gradle 都行这里用 Maven 演示。Spring AI 的版本和 Spring Boot 版本是强绑定的不同大版本的包名和自动配置可能有调整建议你打开官方文档查看版本矩阵不要死抄博客里的版本号。3.1 创建 Spring Boot 项目pom.xml 中引入 web 和 Spring AI OpenAI starterparent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.4.1/version relativePath/ /parent properties java.version17/java.version spring-ai.version1.0.0/spring-ai.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency /dependencies注意spring-ai-bom把 Spring AI 各模块的版本统一管理避免出现依赖冲突。如果你的 Spring AI 版本已经进入 2.x包名和自动配置类可能有迁移IDE 会自动修正 import真正要理解的是配置属性对应关系。3.2 配置模型服务在src/main/resources/application.yml中配置 OpenAI 兼容端点spring: application: name: spring-ai-demo ai: openai: api-key: ${AI_API_KEY} base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 chat: options: model: qwen-plus temperature: 0.7这里使用的是阿里云百炼的 OpenAI 兼容模式。base-url 指向兼容模式的地址api-key 就是百炼控制台里的 API Key。不要把密钥硬编码在 yml 里用环境变量${AI_API_KEY}替代本地开发可以在 IDE 的 Environment variables 里配置。模型名称以百炼控制台展示为准常见的有 qwen-plus、qwen-max、qwen3 等不要相信一个“固定型号”能用一辈子。模型服务商更新型号很频繁上生产前一定要确认自己账号能访问的模型 ID。4. 最小可运行示例用 Spring AI 接入大模型配置完成后直接注入ChatModel就可以调用。这里写一个 servicepackage com.example.ai; import org.springframework.ai.chat.ChatModel; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.stereotype.Service; Service public class QwenChatService { private final ChatModel chatModel; public QwenChatService(ChatModel chatModel) { this.chatModel chatModel; } public String ask(String question) { return chatModel.call(new Prompt(question)) .getResult() .getOutput() .getText(); } }再写一个 REST 接口验证package com.example.ai; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController public class AiController { private final QwenChatService chatService; public AiController(QwenChatService chatService) { this.chatService chatService; } GetMapping(/api/ai/chat) public String chat(RequestParam(defaultValue 用一句话介绍Spring AI) String q) { return chatService.ask(q); } }启动项目mvn spring-boot:run然后访问curl http://localhost:8080/api/ai/chat?q请用三句话说明Spring AI的核心价值如果配置正确接口会返回模型生成的内容。这里能跑通说明你已经打通了最核心的链路Spring Boot 根据 classpath 自动装配了聊天模型ChatModel对象已经连接到了百炼平台。这段代码是 Spring AI 的“Hello World”。很多教程让你从这里开始但真正的关键在于你不应该止步于“能返回字符串”下一步是让返回内容稳定、可控、可结构化。5. 从“能跑”到“好用”Prompt 模板、参数与多轮记忆5.1 用 PromptTemplate 统一提示词在业务代码里拼字符串非常危险。提示词一旦散落各处后期维护就是噩梦。Spring AI 提供了PromptTemplate可以把模板和参数分离package com.example.ai; import org.springframework.ai.chat.ChatModel; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.chat.prompt.SystemMessage; import org.springframework.stereotype.Service; import java.util.Map; Service public class ConsultantService { private static final String SYSTEM_TEMPLATE 你是一名资深Java架构师。 请用{style}的风格回答用户问题。 如果问题与Java无关请礼貌地拒绝回答。 ; private final ChatModel chatModel; public ConsultantService(ChatModel chatModel) { this.chatModel chatModel; } public String consult(String question, String style) { PromptTemplate systemPromptTemplate new PromptTemplate(SYSTEM_TEMPLATE, Map.of(style, style)); SystemMessage systemMessage new SystemMessage(systemPromptTemplate.render()); Prompt prompt new Prompt(systemMessage, new UserMessage(question)); return chatModel.call(prompt).getResult().getOutput().getText(); } }PromptTemplate的render()方法会把模板里的占位符替换成参数值。这样提示词模板可以放到配置中心修改时不用改代码重新发布更符合工程化要求。这个例子也提醒你不要跳过 System Message 直接让用户提问。在真实业务中系统提示词是控制 AI 行为边界最重要的手段。5.2 多轮记忆的原理大模型没有记忆。所谓“多轮对话”本质是把历史消息一起发送。手工实现一个最简单的内存级记忆import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import java.util.ArrayList; import java.util.List; public class ChatMemory { private final ListMessage history new ArrayList(); public String chatWithMemory(ChatModel chatModel, String userInput) { history.add(new UserMessage(userInput)); String answer chatModel.call(new Prompt(history)) .getResult() .getOutput() .getText(); history.add(new AssistantMessage(answer)); return answer; } }这个实现只能用于学习。生产项目必须考虑按用户 ID、会话 ID 隔离历史消息限制历史 token 数量防止超出模型上下文窗口敏感信息脱敏后再放入消息支持从 Redis 或数据库加载历史。5.3 常见的误区很多初学者直接把所有历史消息无限累加结果请求越长越慢最后模型直接报错。正确做法是先做截断策略比如只保留最近几轮或者先做 token 长度估算。另外多轮对话里系统提示词要保持在第一条用户和助手的消息交替排列否则模型容易“角色错乱”。6. Agent 与 Function Calling让模型调用 Java 方法Agent 是 2026 年 AI 应用绕不开的关键词。很多人以为 Agent 很神秘其实它最底层的机制就是 Function Calling模型不直接执行业务而是告诉你“我想调用哪一个函数参数是什么”由 Spring AI 找到对应的 Java 方法去执行。6.1 从实际问题出发一个典型的场景是用户问“帮我查一下 SKU-10086 的库存”。模型本来不知道该查数据库但如果你告诉它有一个query_stock函数它就明白要先调用这个函数才能回答。Spring AI 支持通过注解声明工具方法。下面是一个简洁的例子package com.example.ai.tool; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Service; Service public class InventoryTool { Tool(name query_stock, description 查询指定SKU的实时库存数量) public Integer queryStock( ToolParam(description 商品SKU编号) String sku) { // 实际项目在这里查数据库或调用库存服务 return 128; } }这段代码的核心是Tool注解。Spring AI 会把方法名、描述、参数描述生成 JSON Schema发给模型。模型判断需要查询库存时就会返回一个调用query_stock的请求。不同版本中把工具注册进 ChatModel 或 ChatClient 的写法略有差异常见的是通过 chat options 的withFunctionCallbacks或tools方法传入。最新版本请参考你使用的 Spring AI release notes。理解本质比背 API 重要无论 API 怎么变本质都是“Java 方法 → JSON Schema → 模型发起调用 → Java 方法执行 → 结果回传模型”。6.2 工具调用的工程注意点工具方法一旦让模型调用就暴露到了外部必须做参数校验和权限控制。用户可以通过巧妙的提问让模型调用你没有预期到的函数这在安全上非常危险。实际项目中应该做到只注册当前业务确实需要的工具对工具参数做白名单校验工具执行结果要日志审计敏感操作要二次确认不能让模型直接执行。7. RAG 应用给模型喂企业私有知识模型训练数据再大也不了解你的内部文档和最新业务规则。RAG检索增强生成就是把私有知识检索出来塞进 Prompt 让模型回答。7.1 RAG 的完整链路RAG 本质上只有四步把文档切成小块用 Embedding 模型把每块转成向量用户提问时把问题转成向量在向量库检索最相关的 topK 片段把检索到的片段拼进 Prompt交给大模型生成回答。一个最简的内存版实现package com.example.ai.config; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class RagConfig { Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { return SimpleVectorStore.builder(embeddingModel).build(); } }然后在 service 里做检索和拼接package com.example.ai; import org.springframework.ai.chat.ChatModel; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; import java.util.stream.Collectors; Service public class RagService { private static final String TEMPLATE 基于下面资料回答问题。 如果资料中没有答案请直接说“我不确定”。 资料 {context} 问题{question} ; private final VectorStore vectorStore; private final ChatModel chatModel; public RagService(VectorStore vectorStore, ChatModel chatModel) { this.vectorStore vectorStore; this.chatModel chatModel; } public String ask(String question) { ListDocument docs vectorStore.similaritySearch( SearchRequest.builder().query(question).topK(3).build()); String context docs.stream() .map(Document::getFormattedContent) .collect(Collectors.joining(\n---\n)); PromptTemplate promptTemplate new PromptTemplate(TEMPLATE, Map.of(context, context, question, question)); return chatModel.call(promptTemplate.create()) .getResult() .getOutput() .getText(); } }这个例子虽然能跑通但SimpleVectorStore是内存向量库重启数据就没了。生产环境要换成 PGVector、Milvus、Redis、Elasticsearch 等带持久化能力的向量存储并配套做文档切片策略、Embedding 模型选型、索引维护。7.2 什么时候不需要 RAG如果你的知识库只有几十条规则直接写进系统提示词更简单如果有上万条动态更新的文档才值得引入 RAG。判断标准不是“RAG 很流行所以我用它”而是“模型答不准的信息是否频繁出现、是否动态变化”。如果问题集中在固定业务规则用更细的 Prompt 约束成本低得多。8. 本地模型与云 API 怎么选接入 Spring AI 时很多人纠结到底用云 API 还是本地模型这个问题没有标准答案要看数据敏感度、预算、GPU 算力和并发要求。8.1 云 API 与本地模型的对比对比维度云 API百炼、OpenAI 等本地模型Ollama 等部署成本低按量付费中等需要 GPU 或高性能 CPU数据控制数据出内网需评估合规数据不出域适合敏感数据模型效果通常更强更新快受硬件限制模型规模有限延迟与并发由服务商控制自己控制但并发取决于硬件运维成本低高要维护模型版本和推理服务8.2 32G 内存能装本地大模型吗这个问题在社区里很常见。结论是32G 内存的机器可以跑本地大模型但必须区分“能跑”和“跑得好”。常见的做法是使用 Ollama 部署量化后的模型。7B、14B 量级的模型经过量化后对内存的要求明显降低。32G 内存的机器用于 demo 和小流量内部工具是可行的但如果要同时服务多个用户、处理长上下文、保证低延迟CPU 推理会非常吃力建议还是上 GPU。对生产并发要求较高时模型推理的瓶颈主要在显存、内存带宽和 GPU 算力而不是内存容量本身。在 Spring AI 中接入本地模型非常简单引入 Ollama starter 后spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b业务代码还是用ChatModel甚至不需要改一行调用代码。这也是 Spring AI“换模型成本低”的最好体现。8.3 工业检测、服装检测这类场景怎么选像工业 AI 检测、服装瑕疵检测这类任务本质上是计算机视觉问题主要依赖目标检测、图像分类、异常检测模型。这类模型通常跑在专用推理服务上不一定需要对话大模型。Spring AI 更适合处理“检测结果的自然语言解释、产线日报生成、质量报告问答”这类文本任务。如果是入门测试可以先接云 API 验证效果再考虑本地部署。很多团队一开始就把 32G 内存的服务器用来跑 7B 模型结果发现效果不如云 API硬生生拖慢了整个项目。先用小成本验证业务价值再决定是否投入硬件是更稳妥的路径。9. 常见问题与排查思路Spring AI 开发过程中问题大多集中在依赖、配置和模型返回格式上。下面这张表覆盖了高频问题问题现象可能原因排查方式解决方案启动报错找不到 ChatModel Bean没有引入对应 starter或自动配置未生效检查 pom 依赖、启动日志中的 Auto Configuration 报告引入正确的 Spring AI starter调用时报 401API Key 错误或 base-url 不是兼容模式地址用 curl 直接测试模型服务核对百炼控制台 API Key 和 base-url报错 model not found模型名不对或当前账号未开通该模型在服务商控制台查看可用模型列表换成控制台可用的模型名返回内容被截断超出上下文窗口长度限制检查请求 token 数量和 maxTokens 配置减少历史消息轮数适当增大 maxTokens函数调用不触发工具未注册或方法描述不清晰打印实际发送给模型的 JSON检查 description避免歧义向量检索结果不对文档切片过大或 Embedding 特征不匹配打印检索到的文档内容调整切片策略换合适的 Embedding 模型中文回答乱码或格式差输出没有使用结构化约束检查 Prompt 中是否要求 JSON 或 Markdown 格式使用 OutputParser 或强格式提示词9.1 Spring AI Alibaba 是不是停更了关于“spring ai alibaba 停更了吗”不要只看标题就下结论。Spring AI Alibaba 是阿里云社区在 Spring AI 基础上做的扩展项目它的更新节奏取决于社区投入某个时间段更新少不代表项目死亡。工程上的稳妥做法是如果你只需要调用百炼的 LLM优先用 OpenAI 兼容端点因为它能跟随 Spring AI 主线版本走而不依赖第三方扩展的生命周期如果你需要阿里云体系里更深度、更独特的能力再评估第三方 starter 的活跃度和维护状态。9.2 Dify 工作流能一键转成 Spring AI 代码吗答案比较现实不能完全一键。GitHub 上确实有一些 Dify DSL 转 Spring AI Java 代码的项目但 Dify 工作流里的节点类型非常多比如知识检索、条件分支、HTTP 请求、变量聚合等转换时很难保证逻辑完全等价。如果 Dify 工作流只是几个固定节点重写成 Spring AI 并不难如果工作流很复杂更推荐让 Dify 继续承担编排工作Spring AI 通过 HTTP 调用 Dify 暴露的 API两边各司其职。10. 最佳实践与 2026 年学习建议10.1 工程落地必须注意的七件事第一API Key 永远走环境变量或配置中心不要提交到 Git。第二把“模型调用”收敛到一个 service 层不要在 controller 和其他 service 里散落 Prompt 字符串。第三设置统一的超时、重试和降级策略模型服务不可靠时不能让主流程同步拖垮。第四所有请求响应都记录日志加上会话 ID方便审计和排查。第五对用户输入做长度限制和敏感词过滤防止外部 prompt 注入和资源耗尽。第六模型参数如 temperature、maxTokens集中放在配置中不要散落在代码里。第七升级 Spring AI 版本前先看官方 release notes 中的迁移指南不要一把梭升级。10.2 学习路线建议如果你想在 2026 年系统掌握 Spring AI建议按这个顺序推进先跑通本文第 4 节的最小示例理解ChatModel和Prompt用PromptTemplate改造一次真实业务接口实现带用户隔离的多轮记忆了解 token 截断写一个 Function Calling 工具让模型调用数据库或第三方 API搭建一个简单的 RAG demo用你自己的文档做问答评估云 API 和本地模型的适合场景做一个选型记录最后再读官方源码重点看自动配置和模型适配器是怎么设计的。这七步走完你已经不是“会调接口”的水平而是理解了大模型在 Java 后端落地的完整链路。网上还有大量视频教程可以帮助建立印象但一定不要只看不练。Spring AI 的 API 版本迭代比较快你用 AI 工具补代码都比闭着眼睛抄视频可靠。把 Spring AI 当成一个普通的 Spring 组件去学习你的心态会稳很多。它不神奇也不可怕。真正决定项目成败的往往不是模型效果而是接入之后的工程治理。希望这篇文章能帮你少走那些弯路。
返回列表