如果你是一名Java开发者,正站在AI应用开发的门口张望,觉得大模型、RAG、智能体这些概念离Spring Boot的日常开发很远,那这篇文章就是为你准备的。今天我们不谈空洞的理论,直接上手一个能让你快速把AI能力集成到Java应用中的技术栈:Spring AI与Spring AI Alibaba。这不是一个玩具项目,而是由Spring官方和阿里云共同推动的、面向生产环境的AI应用开发框架。它的核心价值在于,让你能用熟悉的Spring风格(注解、依赖注入、自动配置)去调用大模型、构建RAG知识库、开发智能体,而无需深入复杂的Python生态。
对于Java开发者而言,学习AI应用开发最大的障碍往往是环境与工具链的割裂。Spring AI的出现,正是为了解决这个问题。它提供了统一的抽象层,让你可以像切换数据库驱动一样,在OpenAI、Ollama(本地模型)、阿里云百炼等不同模型服务提供商之间轻松切换。配合Spring AI Alibaba,你还能无缝集成阿里云丰富的AI服务能力。本文将聚焦于最实用的本地开发场景:使用Ollama在本地运行大模型,并通过Spring AI框架进行调用和集成,最终构建一个简单的RAG应用。我们会从环境搭建、项目创建、基础调用,一路讲到RAG系统实现,全程提供可运行的代码。
1. 核心能力速览:Spring AI 能帮你做什么?
在深入代码之前,我们先快速了解Spring AI及Spring AI Alibaba的核心能力,判断它是否适合你的项目。
| 能力项 | 说明 |
|---|---|
| 统一模型抽象 | 定义了一套通用的API(如ChatClient,EmbeddingClient,ImageClient),无论底层是OpenAI、Azure、Ollama还是阿里云通义千问,上层代码几乎不变。 |
| 本地模型集成 | 通过Ollama或Transformers等连接器,轻松集成本地部署的大语言模型,实现数据不出域、低成本推理。 |
| 向量数据库支持 | 内置对PgVector、Redis、Milvus、阿里云向量检索等主流向量数据库的支持,方便构建RAG系统。 |
| 提示词工程 | 提供PromptTemplate、ChatResponse等工具,支持结构化输出(JSON绑定)、函数调用(Tool Calling),让提示词管理更工程化。 |
| 智能体(Agent)框架 | Spring AI Alibaba 提供了强大的Graph框架,支持通过可视化或代码方式编排复杂的AI工作流和智能体。 |
| 多模态支持 | 除文本对话外,也支持图像生成、视觉理解、语音合成等多模态AI能力的集成。 |
| 生产就绪特性 | 作为Spring生态的一部分,天然支持配置管理、健康检查、指标监控、重试机制等微服务治理能力。 |
硬件门槛与启动方式:
- 开发环境:主要依赖Java(JDK 17+)和Maven/Gradle。AI模型推理本身由Ollama服务承担。
- Ollama服务:这是一个独立的服务,需要单独安装并拉取模型。它对硬件的要求取决于你选择的模型大小。例如,运行
qwen2.5:7b模型,建议至少有8GB可用内存(显存+内存)。它支持CPU推理,GPU能显著加速。 - 启动方式:你的Spring Boot应用通过HTTP客户端调用本地或远程的Ollama服务,启动方式就是标准的
java -jar或通过IDE启动。
接下来,我们将从零开始,完成一个完整的“本地模型调用 -> 构建RAG系统”的实战流程。
2. 环境准备与前置条件
在编写第一行Spring AI代码之前,我们需要准备好运行环境。整个环境由两部分组成:Ollama服务(提供模型能力)和Spring Boot项目(业务逻辑)。
2.1 安装并启动 Ollama
Ollama 是运行本地大模型的利器,它简化了模型的下载、加载和服务化暴露。
- 下载安装:访问 Ollama 官网,根据你的操作系统(Windows/macOS/Linux)下载安装包。安装过程非常简单,一路下一步即可。
- 拉取模型:安装完成后,打开终端(或命令行),拉取一个适合你硬件的中文模型。这里我们使用通义千问的7B版本,它对中文支持好,且对硬件要求相对友好。
# 拉取通义千问 7B 模型(约4.2GB) ollama pull qwen2.5:7b # 你也可以选择其他模型,例如 llama3.2:3b (更小) 或 qwen2.5:14b (更强) # ollama pull llama3.2:3b - 启动服务与测试:Ollama 默认会在
http://127.0.0.1:11434启动一个API服务。你可以通过命令行直接测试模型是否正常工作。
如果模型能正常回复,说明Ollama服务已就绪。服务会一直在后台运行。# 与模型进行简单对话 ollama run qwen2.5:7b # 进入交互模式后,输入“你好”,看模型是否能正常回复。
2.2 创建 Spring Boot 项目
使用你熟悉的IDE(IntelliJ IDEA, Eclipse, VS Code)或 Spring Initializr 网站创建项目。
- 项目元数据:
- Project: Maven
- Language: Java
- Spring Boot: 3.2.5 或更高版本(必须支持JDK 17+)
- 依赖选择:
- Spring Web: 构建Web接口。
- Spring AI: 这是核心依赖。请注意,Spring AI的稳定版本依赖需要指定其特定的BOM(物料清单)。最方便的方式是使用Spring Initializr并添加“Spring AI”依赖,它会自动配置好。
- Lombok(可选): 简化POJO代码。
如果你手动管理依赖,需要在pom.xml中添加Spring AI的BOM和Ollama连接器依赖:
<!-- 在 pom.xml 的 <dependencyManagement> 部分添加Spring AI BOM --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>0.8.1</version> <!-- 请使用最新稳定版 --> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 在 dependencies 部分添加具体依赖 --> <dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring AI Ollama 连接器 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>3. 基础配置与模型调用
环境就绪后,我们来配置Spring AI,并实现第一个大模型调用接口。
3.1 配置 Ollama 连接
在application.yml或application.properties中配置 Ollama 服务器的地址和默认使用的模型。
# application.yml spring: ai: ollama: base-url: http://localhost:11434 # Ollama 服务地址 chat: options: model: qwen2.5:7b # 默认使用的聊天模型 temperature: 0.7 # 创造性,0-1,越高越随机3.2 创建聊天服务与控制器
首先,我们创建一个简单的服务来封装AI聊天功能。
// service/ChatService.java import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @Service @RequiredArgsConstructor public class ChatService { private final ChatClient chatClient; public String chat(String message) { return chatClient.prompt() .user(message) .call() .content(); } }然后,创建一个REST控制器来暴露接口。
// controller/ChatController.java import org.springframework.web.bind.annotation.*; import lombok.RequiredArgsConstructor; @RestController @RequestMapping("/api/chat") @RequiredArgsConstructor public class ChatController { private final ChatService chatService; @PostMapping public String chat(@RequestBody ChatRequest request) { return chatService.chat(request.getMessage()); } // 简单的请求体 public record ChatRequest(String message) {} }3.3 启动并测试
- 启动你的Spring Boot应用。
- 使用
curl、Postman 或任何HTTP客户端工具发送请求。curl -X POST http://localhost:8080/api/chat \ -H "Content-Type: application/json" \ -d '{"message": "请用Java写一个Hello World程序"}' - 观察控制台和响应。Spring Boot应用会向本地的Ollama服务(
localhost:11434)发起请求,并将模型的回复返回给你。
至此,你已经完成了Spring AI最基础的集成。你的Java应用现在具备了与大语言模型对话的能力。但这只是开始,接下来我们进入更实用的环节:构建RAG系统。
4. 构建RAG系统:让模型拥有“专属知识库”
RAG(检索增强生成)是当前AI应用的核心模式。它通过将外部知识库(如文档、数据库)转换为向量,在用户提问时先检索相关片段,再交给模型生成答案,从而让模型能回答超出其训练数据范围、更专业、更实时的问题。
我们将实现一个简单的文档问答RAG系统,流程如下:上传文档 -> 文本分割 -> 向量化 -> 存储到向量数据库 -> 用户提问 -> 检索相关片段 -> 组合成提示词 -> 模型生成答案。
4.1 引入向量数据库与Embedding模型
我们需要一个地方存储文档的向量,这里选择轻量且与Spring AI集成良好的PgVector(基于PostgreSQL)作为示例。你也可以选择Redis或内存向量库(如SimpleVectorStore)用于测试。
首先,添加依赖并配置PgVector(需要本地安装PostgreSQL并安装PgVector扩展)。
<!-- pom.xml 中添加 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>配置数据库连接和Embedding模型(我们继续使用Ollama提供的Embedding模型)。
# application.yml 追加配置 spring: datasource: url: jdbc:postgresql://localhost:5432/vectordb # 你的PG数据库 username: postgres password: yourpassword driver-class-name: org.postgresql.Driver ai: ollama: embedding: options: model: nomic-embed-text # Ollama上的一个轻量级嵌入模型 # 也可以使用 qwen2.5:7b 的 embedding 能力,但专用嵌入模型效率更高在PostgreSQL中创建数据库并启用PgVector扩展:
CREATE DATABASE vectordb; \c vectordb; CREATE EXTENSION IF NOT EXISTS vector;4.2 实现文档入库与检索服务
我们创建一个RagService来处理文档的存储和检索增强问答。
// service/RagService.java import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.SimpleVectorStoreAdvisor; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.springframework.util.StreamUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.nio.charset.StandardCharsets; import java.util.List; @Slf4j @Service @RequiredArgsConstructor public class RagService { private final VectorStore vectorStore; private final ChatClient chatClient; @Value("classpath:docs/spring-ai-intro.txt") // 示例文档放在 resources/docs/ 下 private Resource sampleDocResource; /** * 初始化:加载示例文档并存入向量库 */ public void initVectorStore() { try { String text = StreamUtils.copyToString(sampleDocResource.getInputStream(), StandardCharsets.UTF_8); // 将文本拆分成多个Document对象(Spring AI会自动进行文本分割和向量化) List<Document> documents = List.of(new Document(text, java.util.Map.of("source", "spring-ai-intro.txt"))); vectorStore.add(documents); log.info("已成功加载 {} 个文档片段到向量库。", documents.size()); } catch (Exception e) { log.error("初始化向量库失败", e); } } /** * 基于RAG的问答 * @param question 用户问题 * @return 模型生成的答案 */ public String ragChat(String question) { // 方式一:手动检索并构造提示词(更灵活) // List<Document> similarDocs = vectorStore.similaritySearch(SearchRequest.query(question).withTopK(3)); // String context = similarDocs.stream().map(Document::getContent).collect(Collectors.joining("\n\n")); // String prompt = String.format("请根据以下上下文回答问题。如果上下文不包含答案,请直接说不知道。\n\n上下文:\n%s\n\n问题:%s", context, question); // return chatClient.prompt().user(prompt).call().content(); // 方式二:使用Spring AI提供的VectorStoreAdvisor(更简洁) return chatClient.prompt() .user(question) .advisors(new SimpleVectorStoreAdvisor(vectorStore, SearchRequest.defaults())) .call() .content(); } }4.3 创建RAG控制器并测试
创建一个新的控制器来触发文档初始化和进行RAG问答。
// controller/RagController.java import org.springframework.web.bind.annotation.*; import lombok.RequiredArgsConstructor; @RestController @RequestMapping("/api/rag") @RequiredArgsConstructor public class RagController { private final RagService ragService; @PostMapping("/init") public String init() { ragService.initVectorStore(); return "向量库初始化完成!"; } @PostMapping("/chat") public String chat(@RequestBody ChatRequest request) { return ragService.ragChat(request.getMessage()); } public record ChatRequest(String message) {} }测试流程:
- 在
src/main/resources/docs/目录下创建一个spring-ai-intro.txt文件,里面粘贴一段关于Spring AI的简介文本。 - 启动应用。
- 调用初始化接口:
POST http://localhost:8080/api/rag/init - 调用RAG问答接口,询问文档中的内容:
curl -X POST http://localhost:8080/api/rag/chat \ -H "Content-Type: application/json" \ -d '{"message": "Spring AI 的主要目标是什么?"}' - 观察返回的答案,它应该基于你提供的文档内容生成,而不是模型固有的知识。
5. 进阶:使用Spring AI Alibaba与智能体(Agent)
Spring AI Alibaba 是阿里云对Spring AI的扩展,提供了与阿里云百炼模型服务平台、DashScope灵积模型API的深度集成,以及更强大的Graph(图)编程模型,用于构建复杂的AI智能体工作流。
5.1 引入Spring AI Alibaba依赖
<!-- 在 pom.xml 中添加 --> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-spring-boot-starter</artifactId> <version>2023.0.1.0</version> <!-- 请检查最新版本 --> </dependency>5.2 配置阿里云模型服务
在application.yml中配置阿里云的API密钥和要使用的模型(例如通义千问)。
spring: ai: alibaba: chat: enabled: true base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 api-key: ${ALIBABA_CLOUD_API_KEY:your-api-key-here} # 建议使用环境变量 options: model: qwen-max # 或其他模型,如 qwen-plus, qwen-turbo配置后,你可以通过注入AlibabaChatClient来调用阿里云的模型,代码风格与之前的ChatClient完全一致,体现了Spring AI统一抽象的优势。
5.3 体验智能体图(Graph)编程
Spring AI Alibaba Graph 提供了一个声明式的方式来编排AI工作流。下面是一个极度简化的示例,展示如何定义一个包含“问题分类”和“专业回答”两个节点的图。
// 这是一个概念性代码,实际Graph DSL更丰富 import com.alibaba.cloud.ai.graph.Graph; import com.alibaba.cloud.ai.graph.Node; import com.alibaba.cloud.ai.graph.builder.GraphBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AgentGraphConfig { @Bean public Graph customerServiceGraph(GraphBuilder graphBuilder) { return graphBuilder .startWith("classifyIntent") // 节点1:意图分类 .input("userQuestion") .action(ctx -> { String question = ctx.getInput("userQuestion"); // 调用LLM判断意图 String intent = callLlmForIntent(question); ctx.setOutput("intent", intent); }) .then("expertAnswer") // 节点2:根据意图专业回答 .action(ctx -> { String intent = ctx.getInput("intent"); String question = ctx.getInput("userQuestion"); String answer = generateAnswerByIntent(intent, question); ctx.setOutput("finalAnswer", answer); }) .build(); } private String callLlmForIntent(String question) { /* ... */ } private String generateAnswerByIntent(String intent, String question) { /* ... */ } }在实际项目中,你可以通过可视化编辑器或更详细的DSL来构建包含条件分支、循环、并行执行等复杂逻辑的AI智能体。这是将AI能力工作流化、工程化的关键一步。
6. 资源占用、性能观察与调优建议
在本地开发过程中,关注资源占用和性能对于构建稳定应用至关重要。
Ollama服务资源观察:
- 内存/显存:运行
ollama run qwen2.5:7b后,可以通过系统任务管理器或nvidia-smi(GPU)观察内存占用。7B模型在CPU模式下可能占用4-8GB内存,GPU模式下会占用显存并减少内存压力。 - 优化建议:如果资源紧张,可以尝试更小的模型(如
llama3.2:3b),或在Ollama启动时指定-num-gpu等参数控制资源使用。
- 内存/显存:运行
Spring Boot应用性能:
- 响应时间:大部分时间消耗在向Ollama服务发起网络请求和模型推理上。可以在
ChatClient调用前后记录时间戳来监控。 - 连接池:如果并发请求量高,考虑配置HTTP客户端(如RestTemplate或WebClient)的连接池,避免频繁创建连接的开销。
- 异步处理:对于耗时的AI调用,务必使用
@Async或Mono/Flux进行异步非阻塞处理,避免阻塞Web容器线程。
- 响应时间:大部分时间消耗在向Ollama服务发起网络请求和模型推理上。可以在
RAG系统性能瓶颈:
- Embedding耗时:文档入库时的向量化(Embedding)可能较慢,尤其是长文档。考虑在后台异步执行初始化任务。
- 向量检索速度:向量数据库的检索速度与索引类型、数据量有关。对于百万级以下的数据,PgVector的HNSW索引通常性能良好。确保为向量字段创建了适当的索引。
- 提示词长度:检索到的上下文(Context)会拼接到提示词中。上下文过长会显著增加模型推理的耗时和成本。务必合理设置
topK参数,并可以尝试对检索到的文档进行摘要压缩。
7. 常见问题与排查方法
在集成过程中,你可能会遇到以下典型问题:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
启动报错:Connection refused | Ollama服务未启动或端口不对。 | 1. 终端执行ollama serve看是否报错。2. 访问 http://localhost:11434或执行curl http://localhost:11434/api/tags。 | 确保Ollama服务正常运行。检查spring.ai.ollama.base-url配置。 |
| 调用接口超时或无响应 | 模型第一次加载或硬件不足导致推理极慢。 | 1. 直接通过ollama run命令行测试模型响应速度。2. 查看Ollama服务日志。 | 耐心等待首次加载。考虑换用更小模型或升级硬件。在代码中设置合理的超时时间。 |
| 向量库连接失败(PgVector) | PostgreSQL未安装PgVector扩展或连接信息错误。 | 1. 使用psql登录数据库执行SELECT * FROM pg_extension;。2. 检查Spring Boot数据源配置。 | 在数据库中执行CREATE EXTENSION vector;。核对application.yml中的数据库URL、用户名和密码。 |
| RAG回答质量差,答非所问 | 1. 文档未成功向量化或入库。 2. 检索到的上下文不相关。 3. 提示词构造不佳。 | 1. 检查initVectorStore方法是否执行成功,有无报错。2. 手动执行 vectorStore.similaritySearch(...)查看返回的文档是否相关。3. 打印出最终发送给模型的完整提示词。 | 确保文档文本被正确读取和分割。调整SearchRequest中的topK和相似度阈值。优化提示词模板,明确指令。 |
| 使用阿里云模型时鉴权失败 | API Key错误、未开通服务或网络问题。 | 1. 检查环境变量ALIBABA_CLOUD_API_KEY是否设置正确。2. 在阿里云控制台确认对应模型服务(如通义千问)已开通。 | 使用正确的API Key。确保账号有余额或该模型有免费额度。检查网络连通性。 |
8. 最佳实践与使用建议
- 配置外部化:模型API Key、数据库密码等敏感信息务必通过环境变量或配置中心管理,不要硬编码在代码中。
- 优雅降级与熔断:在生产环境中,调用外部模型服务必须设置超时、重试和熔断机制(可使用Spring Cloud CircuitBreaker或Resilience4j)。
- 提示词模板化:将常用的提示词模板(如RAG上下文模板、JSON输出模板)放在配置文件或数据库中,便于管理和迭代优化。
- 日志与监控:为AI调用记录详细的请求和响应日志(注意脱敏),并集成Micrometer等监控指标,追踪耗时、成功率和Token用量。
- 测试策略:AI应用的测试不同于传统业务。除了单元测试,更需要构建端到端的集成测试,使用固定的种子(seed)和输入,对比生成的输出是否符合预期(可以是语义相似度判断)。同时,要设计评估RAG检索相关性的测试用例。
- 版权与合规:如果你的应用处理用户上传的文档生成摘要或问答,务必在用户协议中明确版权和数据使用条款。使用模型生成的内容应注意是否符合平台规范,必要时加入人工审核或后处理过滤环节。
9. 总结与下一步
通过本文的实践,你应该已经掌握了使用Spring AI + Ollama在Java生态中快速集成大语言模型的核心方法,并成功构建了一个简单的本地RAG系统。这套技术栈的优势在于:
- Java开发者友好:无需离开熟悉的Spring生态。
- 本地化部署:通过Ollama保障数据隐私,降低推理成本。
- 生产就绪:继承了Spring的配置、监控、测试等最佳实践。
- 架构统一:一套API兼容多种模型后端,灵活性强。
接下来,你可以从以下几个方向深化:
- 探索更多连接器:尝试集成OpenAI、Azure OpenAI或 Anthropic Claude,对比不同模型的效果和成本。
- 深化RAG系统:引入更复杂的文本分割策略(递归分割、语义分割)、尝试重排序(Re-ranking)模型提升检索精度、实现多轮对话的上下文管理。
- 深入智能体开发:学习Spring AI Alibaba Graph,将复杂的业务逻辑(如数据库查询、工具调用、条件判断)编排成AI智能体工作流。
- 关注性能与成本:对高频问题缓存Embedding结果和最终答案,对输出内容进行长度限制,监控Token消耗以控制成本。
AI应用开发的世界刚刚开启,Spring AI为你提供了一条平稳的Java技术栈切入路径。从今天这个可运行的Demo开始,逐步迭代,你将能构建出真正解决业务问题的智能应用。建议将本文的代码作为基础模板收藏,在后续的开发中随时参考。