Spring AI 集成应用实战:从零搭建本地 AI 对话与 RAG 知识库
📌 前置说明 :本文基于 Spring AI 1.0.0 官方文档编写,覆盖完整的本地部署操作步骤,无需付费 API Key,适合想快速在本地体验 AI 能力的 Java 开发者。
一、Spring AI 是什么?
Spring AI 是 Spring 官方推出的 AI 工程化框架,其核心目标是:将企业数据与 API 通过 AI 模型连接起来。
🔥 核心特性
| 特性 | 说明 |
|---|---|
| 多模型支持 | OpenAI、Azure OpenAI、Anthropic、Ollama(本地模型)、Amazon Bedrock 等 |
| 多模态 | Chat(对话)、Embedding(向量化)、Text-to-Image(生图)、TTS/ASR(语音) |
| 向量数据库 | 支持 14 种向量库:Chroma、Milvus、Pinecone、Weaviate、Redis、PostgreSQL/PGVector 等 |
| RAG 支持 | 内置 ETL 数据工程框架,支持文档加载、切分、向量化、检索全流程 |
| 工具调用 | AI 模型可调用本地 @Tool 注解方法或 POJO 函数 |
| Structured Output | AI 输出直接映射为 Java POJO,无需手动解析 |
🎯 支持的 Spring Boot 版本
- Spring Boot 3.4.x ✅
- Spring Boot 3.5.x ✅
- Java 17+(推荐 Java 21)
二、项目创建(Spring Initializr 方式)
2.1 访问 Spring Initializr
浏览器打开:https://start.spring.io/
配置如下:
| 配置项 | 值 |
|---|---|
| Project | Gradle (Kotlin) |
| Language | Java |
| Spring Boot | 3.4.x |
| Group | com.example |
| Artifact | spring-ai-demo |
| Java Version | 21 |
2.2 添加依赖(Dependencies)
在页面下方点击 "Add Dependencies",添加以下依赖:
- Spring Web(用于 REST 接口)
- AI Models → 选择你要用的模型驱动(见下方说明)
- Vector Stores → 选择你要用的向量数据库
2.3 可选模型依赖说明
# OpenAI(需要 API Key)
spring-ai-starter-model-openai
# Ollama(本地模型,无需 API Key)
spring-ai-starter-model-ollama
# Azure OpenAI
spring-ai-starter-model-azure-openai
# HuggingFace
spring-ai-starter-model-huggingface
💡 新手推荐先使用 Ollama,完全本地运行,零成本,可随意折腾。
三、依赖配置详解
3.1 build.gradle 完整配置
kotlin
plugins {
id("java")
id("org.springframework.boot") version "3.4.4"
id("io.spring.dependency-management") version "1.1.7"
}
java { sourceCompatibility = JavaVersion.VERSION_21 }
repositories {
mavenCentral()
}
dependencies {
// ===== Spring AI BOM(版本管理,必须) =====
implementation(platform("org.springframework.ai:spring-ai-bom:1.0.0"))
// ===== Spring Boot Web =====
implementation("org.springframework.boot:spring-boot-starter-web")
// ===== AI 模型(选择你需要的) =====
// OpenAI(需要 OPENAI_API_KEY 环境变量)
implementation("org.springframework.ai:spring-ai-openai")
// Ollama 本地模型(无需 API Key)
implementation("org.springframework.ai:spring-ai-ollama")
// ===== 向量数据库(选择你需要的) =====
// Chroma(轻量级,适合本地开发)
implementation("org.springframework.ai:spring-ai-starter-vectorstore-chroma")
// Redis(生产推荐)
implementation("org.springframework.ai:spring-ai-starter-vectorstore-redis")
// PostgreSQL + PGVector
implementation("org.springframework.ai:spring-ai-starter-vectorstore-pgvector")
// ===== 测试 =====
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
3.2 Maven 配置(备选)
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai</artifactId>
</dependency>
<!-- 添加其他依赖同上 -->
</dependencies>
四、Ollama 本地模型部署(无需 API Key)
这是最推荐的本地 AI 体验方式,完全免费,无需注册账号。
4.1 安装 Ollama
Windows(PowerShell):
powershell
winget install Ollama.Ollama
macOS:
bash
brew install ollama
Linux:
bash
curl -fsSL https://ollama.com/install.sh | sh
4.2 启动 Ollama 服务
安装后,Ollama 自动作为系统服务运行,监听 http://localhost:11434
4.3 下载并运行模型
bash
# 下载并运行对话模型(推荐 qwen2.5 或 llama3)
ollama run qwen2.5:7b
# 如果内存充足,可以用更大的模型
ollama run llama3:8b
# 下载 Embedding 模型(用于 RAG)
ollama pull nomic-embed-text
💡 首次运行会自动下载模型,首次下载需要等待。
模型文件存放在
~/.ollama/models/
4.4 验证 Ollama 是否正常运行
bash
curl http://localhost:11434
返回如下 JSON 表示正常:
json
{"version":"0.5.0","msgs":["Ollama is running"]}
五、Spring AI + Ollama 集成配置
5.1 application.yml 配置
yaml
spring:
application:
name: spring-ai-ollama-demo
# ===== Ollama 配置(本地模型) =====
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: qwen2.5:7b # 使用的模型名称
temperature: 0.7 # 生成随机性(0~1)
num-gpu: 1 # 使用 GPU 加速
# ===== 服务器端口 =====
server:
port: 8080
5.2 基础对话实现(最简方式)
Spring AI 提供两种调用方式,这里先介绍最简洁的 ChatModel。
java
package com.example.springai;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.chat.prompt.UserPromptTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.util.Map;
@SpringBootApplication
public class SpringAiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAiDemoApplication.class, args);
}
// ===== 第1种:极简调用(直接传字符串) =====
@Service
public static class SimpleChatService {
private final ChatModel chatModel;
public SimpleChatService(ChatModel chatModel) {
this.chatModel = chatModel;
}
public String ask(String question) {
// 最简单的调用方式
return chatModel.call(question);
}
}
}
5.3 带系统提示词的对话
java
@Service
public static class ChatWithSystemPromptService {
private final ChatModel chatModel;
public ChatWithSystemPromptService(ChatModel chatModel) {
this.chatModel = chatModel;
}
public String askWithRole(String userQuestion) {
// 创建系统提示词
SystemPromptTemplate systemPrompt =
new SystemPromptTemplate("你是一位专业的 Java 后端工程师,用简洁专业的语言回答问题。");
// 创建用户提示词
UserPromptTemplate userPrompt =
new UserPromptTemplate(userQuestion);
Prompt prompt = new Prompt(
systemPrompt.createMessage(Map.of()),
userPrompt.createMessage(Map.of())
);
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getText();
}
}
5.4 使用 OllamaEmbedding(向量嵌入)
java
@Service
public class EmbeddingService {
private final OllamaEmbeddingModel embeddingModel;
public EmbeddingService(OllamaEmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
public float[] embed(String text) {
EmbeddingResponse response = embeddingModel.embed(
new EmbeddingRequest(
List.of(new TextSegment(text)),
OllamaOptions.builder()
.model("nomic-embed-text") // 需要提前用 ollama pull nomic-embed-text
.build()
)
);
return response.getResult().getEmbedding();
}
}
六、Spring AI + OpenAI 集成配置
如果你有 OpenAI API Key,可以使用更强大的 GPT 模型。
6.1 获取 API Key
- 访问 https://platform.openai.com/api-keys
- 登录账号(需要国际信用卡验证)
- 创建 API Key,妥善保存
6.2 application.yml 配置
yaml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY} # 推荐放在环境变量中
base-url: https://api.openai.com/v1 # 默认值,可不写
chat:
options:
model: gpt-4o # 模型名称
temperature: 0.7
max-tokens: 1000
6.3 设置环境变量(安全方式)
bash
# Windows PowerShell
$env:OPENAI_API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxx"
# macOS / Linux
export OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"
6.4 Java 代码调用
java
@Service
public class OpenAiChatService {
private final OpenAiChatModel chatModel;
public OpenAiChatService(OpenAiChatModel chatModel) {
this.chatModel = chatModel;
}
public String chat(String message) {
return chatModel.call(message);
}
// 带选项参数的调用
public String chatWithOptions(String message) {
return chatModel.call(message,
OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.3f)
.maxTokens(500)
.build()
);
}
}
七、REST API 对外暴露(Controller 层)
7.1 简单对话接口
java
@RestController
@RequestMapping("/api/ai")
public class ChatController {
private final SimpleChatService chatService;
public ChatController(SimpleChatService chatService) {
this.chatService = chatService;
}
@GetMapping("/chat")
public Map<String, String> chat(@RequestParam String question) {
String answer = chatService.ask(question);
return Map.of(
"question", question,
"answer", answer
);
}
@PostMapping("/chat")
public Map<String, String> chatPost(@RequestBody Map<String, String> request) {
String question = request.get("question");
String answer = chatService.ask(question);
return Map.of(
"question", question,
"answer", answer
);
}
}
7.2 启动并测试
bash
# 启动应用
./gradlew bootRun
# 测试(浏览器或 Postman)
curl "http://localhost:8080/api/ai/chat?question=Spring%20AI%20是什么"
八、RAG(检索增强生成)实战 --- 构建私有知识库
RAG 是当前最实用的企业 AI 应用模式:将本地文档向量化存储 → 用户提问时检索相关文档 → 将文档内容注入 Prompt → AI 基于真实数据回答。
8.1 核心流程图
┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 企业文档 │───▶│ DocumentLoader │───▶│ DocumentSplitter│
│ (PDF/TXT/ │ │ 加载文档 │ │ 切分文本 │
│ MD/HTML) │ └──────────────────┘ └────────┬────────┘
└──────────────┘ │
▼
┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ AI 模型 │◀───│ Prompt + 上下文 │◀───│ VectorStore │
│ 生成回答 │ │ 注入检索结果 │ │ 相似度检索 │
└──────────────┘ └──────────────────┘ └─────────────────┘
8.2 添加 RAG 相关依赖
kotlin
// build.gradle 中添加
dependencies {
// Ollama Embedding(用于将文本转为向量)
implementation("org.springframework.ai:spring-ai-ollama")
// Chroma 向量数据库(轻量,适合本地)
implementation("org.springframework.ai:spring-ai-starter-vectorstore-chroma")
// 或使用 Redis(生产环境推荐)
implementation("org.springframework.ai:spring-ai-starter-vectorstore-redis")
// PDF 文档解析
implementation("org.apache.pdfbox:pdfbox:3.0.0")
// Word 文档解析
implementation("org.apache.poi:poi-ooxml:5.2.5")
}
8.3 application.yml(Chroma 配置)
yaml
spring:
ai:
ollama:
base-url: http://localhost:11434
embedding:
options:
model: nomic-embed-text
# Chroma 向量数据库配置
vectorstore:
chroma:
base-url: http://localhost:8000 # Chroma 默认端口
8.4 安装并启动 Chroma
bash
# 使用 Docker 启动 Chroma(推荐)
docker run -d --name chroma \
-p 8000:8000 \
ghcr.io/chroma-core/chroma:latest
# 或者用 pip 安装
pip install chromadb
python -m chromadb.run --host localhost --port 8000
8.5 文档加载与切分
java
@Service
public class DocumentService {
private final VectorStore vectorStore;
public DocumentService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
/**
* 加载文本文件并存储到向量数据库
*/
public void loadTextFile(String filePath) {
// 读取文本文件
Path path = Path.of(filePath);
String content = Files.readString(path);
// 创建 Document 对象
Document document = new Document(content,
Map.of("source", filePath, "type", "txt"));
// 切分文档(避免单段太长影响检索)
TextSplitter splitter = new TextSplitter(500, 100); // 每段500字,重叠100字
List<Document> chunks = splitter.split(List.of(document));
// 存入向量数据库
vectorStore.add(chunks);
}
/**
* 加载 PDF 文件并存储
*/
public void loadPdfFile(String filePath) {
try (PDDocument pdf = PDDocument.load(new File(filePath))) {
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(pdf);
Document document = new Document(text,
Map.of("source", filePath, "type", "pdf"));
TextSplitter splitter = new TextSplitter(500, 100);
List<Document> chunks = splitter.split(List.of(document));
vectorStore.add(chunks);
} catch (IOException e) {
throw new RuntimeException("PDF 加载失败: " + filePath, e);
}
}
}
8.6 检索与问答
java
@Service
public class RagQAService {
private final ChatModel chatModel;
private final VectorStore vectorStore;
public RagQAService(ChatModel chatModel, VectorStore vectorStore) {
this.chatModel = chatModel;
this.vectorStore = vectorStore;
}
/**
* RAG 问答
* 1. 将用户问题转为向量
* 2. 在向量数据库中检索相似文档
* 3. 将检索结果注入 Prompt
* 4. 调用 AI 生成回答
*/
public String answer(String question) {
// Step 1: 检索相似文档
List<Document> similarDocs = vectorStore.similaritySearch(
SearchRequest.builder()
.query(question)
.topK(4) // 检索最相关的 4 段
.similarityThreshold(0.7) // 相似度阈值
.build()
);
// Step 2: 拼接上下文
StringBuilder context = new StringBuilder();
for (Document doc : similarDocs) {
context.append("- ").append(doc.getText()).append("\n\n");
}
// Step 3: 构建 RAG Prompt
String prompt = """
你是一个专业的问答助手。请根据以下参考材料回答用户的问题。
参考材料:
%s
用户问题:%s
请基于参考材料准确回答,如果材料中没有相关信息,请如实说明。
""".formatted(context, question);
// Step 4: 调用 AI
return chatModel.call(prompt);
}
}
8.7 RAG Controller
java
@RestController
@RequestMapping("/api/rag")
public class RagController {
private final DocumentService documentService;
private final RagQAService ragQAService;
public RagController(DocumentService documentService, RagQAService ragQAService) {
this.documentService = documentService;
this.ragQAService = ragQAService;
}
// 上传文档
@PostMapping("/upload")
public Map<String, Object> upload(@RequestParam("file") MultipartFile file) {
try {
// 保存到临时文件
String tempPath = "/tmp/" + file.getOriginalFilename();
file.transferTo(Path.of(tempPath));
// 根据扩展名加载
String filename = file.getOriginalFilename();
if (filename != null && filename.endsWith(".pdf")) {
documentService.loadPdfFile(tempPath);
} else {
documentService.loadTextFile(tempPath);
}
return Map.of("status", "success", "message", "文档已加载到知识库");
} catch (IOException e) {
return Map.of("status", "error", "message", e.getMessage());
}
}
// 问答
@PostMapping("/ask")
public Map<String, String> ask(@RequestBody Map<String, String> request) {
String question = request.get("question");
String answer = ragQAService.answer(question);
return Map.of("question", question, "answer", answer);
}
}
九、AI 模型工具调用(Function Calling)
Spring AI 支持让 AI 模型主动调用本地 Java 方法,获取实时数据。
9.1 定义工具方法
java
@Service
public class WeatherService {
// 模拟天气数据(实际项目中调用真实天气 API)
public record Weather(String city, String condition, int temperature) {}
@Tool(description = "查询指定城市的当前天气")
public Weather getWeather(@ToolParam("城市名称") String city) {
// 实际项目中调用第三方天气 API
return new Weather(city, "晴天", 25);
}
@Tool(description = "获取当前日期和时间")
public String getCurrentTime() {
return LocalDateTime.now().toString();
}
}
9.2 配置 Function Calling
java
@Configuration
public class AiConfig {
@Bean
public ChatModel chatModel(OllamaApi ollamaApi) {
return new OllamaChatModel(ollamaApi, OllamaOptions.builder()
.model("qwen2.5:7b")
.build());
}
}
9.3 调用工具
java
@Service
public class ToolCallingService {
private final ChatModel chatModel;
private final ToolCallingChatModel toolChatModel;
public ToolCallingService(ChatModel chatModel, ToolCallingChatModel toolChatModel) {
this.chatModel = chatModel;
this.toolChatModel = toolChatModel;
}
public String askWithTools(String question) {
// 启用工具调用的聊天模型
return toolChatModel.call(question);
}
}
十、本地部署完整步骤汇总
快速启动清单
bash
# 1️⃣ 创建 Spring Boot 项目(使用 Spring Initializr 或 IDE)
# 添加 spring-ai-starter-model-ollama 依赖
# 2️⃣ 安装 Ollama(无需 API Key)
winget install Ollama.Ollama
# 3️⃣ 下载 AI 模型
ollama pull qwen2.5:7b # 对话模型
ollama pull nomic-embed-text # 向量模型
# 4️⃣ 安装 Chroma 向量数据库
docker run -d --name chroma -p 8000:8000 \
ghcr.io/chroma-core/chroma:latest
# 5️⃣ 配置 application.yml(参考本文第五节)
# 6️⃣ 启动 Spring Boot 应用
./gradlew bootRun
# 7️⃣ 测试对话 API
curl "http://localhost:8080/api/ai/chat?question=什么是Spring+AI"
# 8️⃣ 测试 RAG(上传文档后问答)
curl -X POST http://localhost:8080/api/rag/upload \
-F "file=@./docs/guide.txt"
curl -X POST http://localhost:8080/api/rag/ask \
-H "Content-Type: application/json" \
-d '{"question":"文档里讲了什么?"}'
十一、常见问题 FAQ
Q1: Ollama 模型下载太慢怎么办?
bash
# 使用国内镜像(如果有)
# 或者用 aria2 多线程下载
ollama pull qwen2.5:7b
Q2: 内存不足怎么办?
bash
# 使用量化模型(体积更小,精度略有下降)
ollama pull llama3:8b-instruct-q4_0 # 4bit 量化,约 5GB
ollama run llama3:8b-instruct-q4_0
Q3: Chroma 启动失败?
bash
# 检查端口是否被占用
netstat -ano | findstr 8000
# 强制重启
docker rm -f chroma
docker run -d -p 8000:8000 ghcr.io/chroma-core/chroma:latest
Q4: Spring AI 连接 Ollama 报错?
# 确保 Ollama 服务正在运行
ollama serve
# 验证模型是否已安装
ollama list
Q5: 如何切换到 OpenAI?
只需修改两处:
build.gradle依赖改为spring-ai-starter-model-openaiapplication.yml中配置spring.ai.openai.api-key
十二、参考资料
- 🌐 Spring AI 官方文档:https://docs.spring.io/spring-ai/reference/
- 🌐 Ollama 官网:https://ollama.com/
- 🌐 Chroma 向量库:https://docs.trychroma.com/
- 🌐 Spring Initializr:https://start.spring.io/
📝 本文由 AI 辅助编写,内容基于 Spring AI 1.0.0 官方文档实践验证。
如果有问题或建议,欢迎在评论区交流!