Spring AI
本文基于 Spring AI 1.1.7(Stable)版本,官方文档:https://docs.spring.io/spring-ai/reference/
# 概述
Spring AI 是 Spring 官方推出的 AI 应用开发框架,目标是简化 Java 应用集成 AI 能力的复杂度。它借鉴了 Python 生态的 LangChain、LlamaIndex 等项目的设计理念,但并非直接移植,而是以 Spring Boot 的风格提供了一套可移植、可插拔的 AI 抽象层。核心优势在于:通过统一的 API 抽象,只需修改配置就可以在不同的 AI 模型提供商之间切换(比如从 OpenAI 切到 Ollama),业务代码几乎不用改。
# 组件总览
| 组件 | 作用 |
|---|---|
| ChatClient | 对话客户端,统一的聊天 API(类似 RestClient) |
| ChatModel | 对话模型,各大模型提供商的适配层 |
| EmbeddingModel | 嵌入模型,文本 / 图片转向量 |
| ImageModel | 图片生成模型 |
| AudioModel | 语音识别(Transcription)& 语音合成(TTS)模型 |
| ModerationModel | 内容审核 / 敏感词检测模型 |
| Multimodality | 多模态 API,混合输入(文本 + 图片 + 音频) |
| Prompts | 提示词模板 API |
| Structured Output | 结构化输出转换器,LLM 输出映射为 Java 对象 |
| Advisors | 顾问 / 拦截器 API,拦截增强 AI 对话链路 |
| Chat Memory | 对话记忆,多轮对话上下文保持 |
| Tool Calling | 工具调用(Function Call 升级版) |
| MCP | 模型上下文协议,标准化 LLM 与外部系统的交互 |
| RAG | 检索增强生成 |
| ETL Pipeline | 数据抽取转换加载管道 |
| Vector Databases | 向量数据库集成(20 + 种) |
| Observability | 可观测性(指标、追踪、日志) |
| Model Evaluation | AI 模型评估测试 |
| Development-time Services | 开发时服务(Docker Compose 集成) |
| Testcontainers | 测试容器集成 |
# ChatClient
作用:Spring AI 提供的统一对话客户端 API,是开发者与 LLM 交互的最核心入口。设计风格类似于 Spring 的 WebClient 和 RestClient ,采用 Fluent API(链式调用),支持同步和流式两种模式。
为什么需要它:不同的大模型提供商(OpenAI、Ollama、通义千问等)各自有不同的 SDK 和调用方式,ChatClient 提供了统一的抽象层,一套代码适配所有模型。
// 注入 ChatClient(Spring Boot 自动装配)
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultSystem("你是一个专业的Java架构师,回答问题简洁专业")
.build();
}
// 同步调用
String answer = chatClient.prompt()
.user("Spring AI是什么?")
.call()
.content();
// 流式调用(适合打字机效果)
Flux<String> stream = chatClient.prompt()
.user("给我讲讲微服务架构")
.stream()
.content();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
与 ChatModel 的区别:
- ChatClient 是高层 API,面向业务开发者,支持 Advisor 链、记忆注入、工具调用等高级功能
- ChatModel 是底层 API,面向各模型提供商的适配层,关注的是模型参数(温度、top_p 等)
# ChatModel
作用:为每个 AI 模型提供商建立的底层适配层,每个提供商有自己的 ChatModel 实现。不同大模型在对话方面有细微区别(比如参数名不同、支持的特性不同),ChatModel 就是抹平这些差异的。
# 支持的 Chat Model 提供商(1.1.7)
| 提供商 | 说明 |
|---|---|
| OpenAI | GPT-4o、GPT-4、GPT-3.5 等,最主流的商业大模型 |
| Ollama | 本地部署开源模型(LLaMA、Qwen、DeepSeek 等),免费无需 API Key |
| Anthropic | Claude 系列,长上下文能力强(200K tokens) |
| Azure OpenAI | 微软 Azure 托管的 OpenAI 服务,企业合规场景首选 |
| DeepSeek | 国产大模型,性价比高,中文能力强 |
| Google GenAI | Gemini 系列模型 |
| Google VertexAI Gemini | 谷歌云平台托管的 Gemini |
| Mistral AI | 法国开源大模型,轻量高效 |
| QianFan(百度千帆) | 百度文心一言等国产模型 |
| ZhiPu AI(智谱) | 智谱 GLM 系列,国内学术背景深厚 |
| MiniMax | 国产大模型提供商 |
| Moonshot AI(月之暗面) | Kimi 背后的模型提供商 |
| Hugging Face | 开源模型社区,海量模型可选 |
| NVIDIA | NVIDIA NIM 推理服务 |
| Groq | 超快推理速度,基于 LPU 硬件 |
| Perplexity AI | 搜索增强型大模型 |
| Amazon Bedrock Converse | AWS 托管的多模型服务 |
| OCI Generative AI (Cohere) | Oracle 云 AI 服务 |
| Docker Model Runner | Docker Desktop 内置模型运行(1.1.7 新增) |
// 直接使用 ChatModel(底层 API)
@Autowired
OllamaChatModel chatModel;
ChatResponse response = chatModel.call(
new Prompt("你好",
OllamaOptions.builder()
.model("qwen2.5:7b")
.temperature(0.7)
.build())
);
2
3
4
5
6
7
8
9
10
11
# EmbeddingModel
作用:将文本、图像等数据转换为浮点数向量(数组),这些向量能捕获语义含义。语义相近的内容,生成的向量在空间中距离更近。它是 RAG(检索增强生成)的核心基础组件。
举例:"我喜欢美丽的花朵" 和 "我喜爱漂亮的鲜花",两句话语义相近,嵌入后的向量距离会很近(余弦相似度接近 1)。
# 支持的 Embedding 提供商
| 提供商 | 说明 |
|---|---|
| OpenAI | text-embedding-ada-002 等,最常用 |
| Azure OpenAI | 微软托管版 |
| Ollama | 本地嵌入(nomic-embed-text 等) |
| Google GenAI | 谷歌文本嵌入 |
| Mistral AI | Mistral 嵌入模型 |
| MiniMax / QianFan / ZhiPu AI | 国产嵌入模型 |
| Amazon Bedrock(Cohere/Titan) | AWS 嵌入服务 |
| VertexAI(Text/Multimodal) | 谷歌云,支持多模态嵌入 |
| PostgresML | 数据库内嵌入,无需外部调用 |
| ONNX Transformers | 纯本地运行,JVM 内跑 ONNX 模型,数据不出服务器 |
ONNX Transformers 是唯一一个纯本地运行的嵌入方案,不需要任何外部 API,适合对数据安全要求极高的场景。
@Autowired
EmbeddingModel embeddingModel;
// 文本转向量
EmbeddingResponse response = embeddingModel.call(
new EmbeddingRequest(
List.of("Spring AI是什么?", "Java微服务架构"),
EmbeddingOptions.EMPTY)
);
// 拿到向量后存到向量数据库,供后续 RAG 检索使用
2
3
4
5
6
7
8
9
10
# ImageModel
作用:调用 AI 模型生成图片。输入文本描述(prompt),输出一张 AI 生成的图片。
# 支持的提供商
| 提供商 | 说明 |
|---|---|
| OpenAI(DALL·E) | 最主流的图片生成,支持 DALL・E 3 |
| Azure OpenAI | 微软托管版 DALL・E |
| Stability AI | Stable Diffusion 系列,开源图片生成的标杆 |
| ZhiPuAI | 智谱图片生成 |
| QianFan | 百度千帆图片生成 |
@Autowired
ImageModel imageModel;
ImageResponse response = imageModel.call(
new ImagePrompt("一只穿着西装的猫在写Java代码,赛博朋克风格")
);
String imageUrl = response.getResult().getOutput().getUrl();
2
3
4
5
6
7
# AudioModel
作用:分为两个子方向 —— 语音转文字(Transcription) 和 文字转语音(TTS)。
# 支持的提供商
| 方向 | 提供商 | 说明 |
|---|---|---|
| 语音转文字 | OpenAI Whisper | 多语言语音识别,准确率高 |
| 语音转文字 | Azure OpenAI | 微软托管版 Whisper |
| 文字转语音 | OpenAI TTS | 多种声音可选(alloy、echo、fable 等) |
| 文字转语音 | ElevenLabs | 1.1.7 新增,音质更自然逼真,支持声音克隆 |
OpenAI TTS 与 ElevenLabs 的区别:
- OpenAI TTS:成本低,延迟低,适合标准场景
- ElevenLabs:音质更好,支持声音克隆和多语言混读,适合对音质要求高的场景(如有声书、客服系统),但价格更贵
// 语音转文字
@Autowired
OpenAiAudioTranscriptionModel transcriptionModel;
AudioTranscriptionResponse response = transcriptionModel.call(
new AudioTranscriptionPrompt(new ClassPathResource("interview.mp3"))
);
String text = response.getResult().getOutput();
// 文字转语音
@Autowired
OpenAiAudioSpeechModel speechModel;
byte[] audio = speechModel.call("欢迎使用Spring AI框架");
2
3
4
5
6
7
8
9
10
11
12
13
14
# ModerationModel
作用:内容审核模型,检测用户输入或模型输出中的敏感内容(暴力、色情、仇恨言论、自残等)。在生产环境中,这是保障内容安全的关键环节。
# 支持的提供商
| 提供商 | 说明 |
|---|---|
| OpenAI Moderation | 免费调用,支持多种分类(暴力、色情、仇恨等) |
| Mistral AI Moderation | Mistral 提供的内容审核 |
通常配合 Advisor 使用,在对话链路中自动拦截不合规的内容。
@Autowired
OpenAiModerationModel moderationModel;
ModerationResponse response = moderationModel.call(
new ModerationPrompt("需要审核的文本内容")
);
boolean flagged = response.getResult().getOutput().isFlagged();
2
3
4
5
6
7
# Multimodality(多模态)
作用:支持在一次对话中混合输入多种类型的数据(文本 + 图片 + 音频等)。比如上传一张图片并问 "这张图片里有什么?",此时请求中同时包含了图片和文本两种模态的信息。
与 ChatModel 的关系:多模态是 ChatModel 的能力扩展,不是独立的 Model,而是在对话时允许消息中携带多种媒体类型。并非所有 ChatModel 都支持多模态,目前支持的包括 OpenAI(GPT-4o)、Ollama(LLaVA 等)、Anthropic(Claude 3)、Google Gemini 等。
// 上传图片进行多模态对话
UserMessage userMessage = new UserMessage(
"请描述这张图片的内容",
new Media(MimeTypeUtils.IMAGE_PNG, new ClassPathResource("test.png"))
);
ChatResponse response = chatModel.call(new Prompt(userMessage));
2
3
4
5
6
# Prompts(提示词模板)
作用:结构化的提示词管理 API,类似于 Spring MVC 的模板引擎(Thymeleaf)。支持用占位符 {变量名} 构建动态提示词,避免在代码中硬编码拼接字符串,提高可维护性和复用性。
与直接拼字符串的区别:
- 模板可以从外部文件加载(比如 resources 目录下的
.st文件) - 支持变量替换,提示词和业务逻辑分离
- 更容易做版本管理和 A/B 测试
// 使用 PromptTemplate
PromptTemplate template = new PromptTemplate(
"你是{role},请用{style}的风格回答以下问题:{question}"
);
Prompt prompt = template.create(Map.of(
"role", "资深Java架构师",
"style", "通俗易懂",
"question", "什么是微服务?"
));
ChatResponse response = chatModel.call(prompt);
// 也可以从文件加载模板
PromptTemplate fileTemplate = new PromptTemplate(
new ClassPathResource("prompts/qa.st")
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Structured Output(结构化输出转换器)
作用:将 LLM 返回的非结构化文本自动映射为 Java 对象(POJO)。大模型默认返回的是自然语言文本,但在实际开发中,我们往往需要结构化数据(JSON 对象、List 列表)才方便后续处理。
工作原理:在提示词中自动注入格式说明(告诉模型按什么格式返回),响应后自动反序列化,开发者无需手动写 JSON 解析逻辑。
// 定义返回结构
record BookInfo(String title, String author, int year, String summary) {}
// ChatClient 直接映射为对象
BookInfo book = chatClient.prompt()
.user("介绍一下《深入理解Java虚拟机》这本书")
.call()
.entity(BookInfo.class); // 自动映射
// 也可以映射为 List
List<BookInfo> books = chatClient.prompt()
.user("推荐3本Java入门书籍")
.call()
.entity(new ParameterizedTypeReference<List<BookInfo>>() {});
2
3
4
5
6
7
8
9
10
11
12
13
14
# Advisors(顾问 / 拦截器 API)
作用:类似于 Spring MVC 的拦截器(Interceptor)或 AOP 切面,是应用在 AI 对话链路中的拦截增强机制。可以在请求发送给 LLM 之前、以及 LLM 返回响应之后,拦截、修改、增强数据。
典型应用场景:
- 自动注入对话记忆(MessageChatMemoryAdvisor)
- 自动执行 RAG 检索(QuestionAnswerAdvisor)
- 日志审计、Token 统计
- 内容安全过滤
- 自定义业务逻辑拦截
# 核心组件
| 组件 | 作用 |
|---|---|
| CallAdvisor / CallAdvisorChain | 非流式场景的拦截器和链 |
| StreamAdvisor / StreamAdvisorChain | 流式场景的拦截器和链 |
| Recursive Advisors | 递归型 Advisor,让 LLM 多轮自我调用直到得出满意结果 |
# 执行流程
- Spring AI 框架将用户的 Prompt 封装为
ChatClientRequest - 请求依次经过 Advisor 链中的每个 Advisor(按
getOrder()排序,值小的先执行) - 每个 Advisor 可以修改请求(比如注入记忆消息、追加系统提示词)
- 最后一个 Advisor(框架自动添加)将请求发送给 ChatModel
- 响应沿 Advisor 链反向传递,每个 Advisor 可以处理或修改响应
- 最终返回给调用方
与 Spring MVC Interceptor 的对比:思路完全一致,只是拦截的对象从 HTTP 请求变成了 AI 对话请求。
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // 记忆注入
QuestionAnswerAdvisor.builder(vectorStore).build() // RAG检索
)
.build();
String response = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-123"))
.user("上次我们聊到哪了?")
.call()
.content();
2
3
4
5
6
7
8
9
10
11
12
# Chat Memory(对话记忆)
作用:LLM 是无状态的,每次请求都是独立的,不记得上一轮对话说了什么。Chat Memory 让大模型在多轮对话中保持上下文记忆。
Chat Memory 与 Chat History 的区别:
- Chat Memory(对话记忆):LLM 当前需要的上下文窗口,可能只保留最近 N 条消息
- Chat History(对话历史):完整的所有对话记录,用于存档或审计
# 记忆类型
| 类型 | 说明 |
|---|---|
| MessageWindowChatMemory | 滑动窗口记忆(默认),保留最近 N 条消息,超出的自动丢弃 |
# 存储实现(ChatMemoryRepository)
记忆的底层存储通过 ChatMemoryRepository 接口实现,Spring AI 提供了多种开箱即用的实现:
| 存储实现 | 说明 | 适用场景 |
|---|---|---|
| InMemoryChatMemoryRepository | 内存存储(默认),重启后丢失 | 开发测试、单机临时场景 |
| JdbcChatMemoryRepository | 基于 JDBC 持久化,支持 MySQL/PostgreSQL 等 | 生产环境最常用,直接复用现有关系库 |
| CassandraChatMemoryRepository | Apache Cassandra 存储 | 大规模分布式、高写入场景 |
| Neo4jChatMemoryRepository | Neo4j 图数据库存储 | 需要分析对话关系网络的场景 |
| MongoChatMemoryRepository | MongoDB 存储 | 文档型存储偏好、已有 Mongo 基础设施 |
| CosmosDBChatMemoryRepository | Azure CosmosDB 存储 | Azure 云原生环境 |
# 记忆与 ChatClient 的配合方式
| Advisor | 工作方式 | 适用场景 |
|---|---|---|
| MessageChatMemoryAdvisor | 将历史消息作为消息列表注入(最推荐) | 大多数多轮对话场景 |
| PromptChatMemoryAdvisor | 将历史消息拼入系统提示词文本 | 模型不支持多消息格式时 |
| VectorStoreChatMemoryAdvisor | 基于向量相似度检索相关历史记忆 | 超长对话、只需召回相关片段 |
// Spring Boot 自动装配(默认 InMemory + MessageWindow)
@Autowired
ChatMemory chatMemory;
// 配合 ChatClient 使用
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
// 通过 conversationId 区分不同用户的对话
String response = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-456"))
.user("我叫张三")
.call()
.content();
// 下一轮对话,模型会记得你叫张三
String response2 = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-456"))
.user("我叫什么名字?")
.call()
.content(); // 会回答 "你叫张三"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Tool Calling(工具调用)
作用:允许 LLM 在对话过程中请求调用客户端定义的工具 / 函数,获取实时信息或执行特定操作。这是解决 LLM "知识截止日期" 和 "无法操作外部系统" 两大问题的核心方案。
Tool Calling 是 1.1.x 版本对旧版 Function Call API 的全面升级。旧的
FunctionCallback已迁移为ToolCallback,推荐使用新 API。
两大用途:
- 信息检索:获取 LLM 不知道的实时数据(天气、股价、数据库查询)
- 执行动作:让 LLM 触发实际操作(发邮件、下订单、调用第三方 API)
与 RAG 的区别:
- Tool Calling:获取精确结果和执行特定操作(比如查天气得到 "30°C")
- RAG:从大量文档中检索相关信息并整合成回答(比如从知识库中找到相关政策条文)
# 定义工具的三种方式
方式一:@Tool 注解(推荐,最简洁)
public class WeatherTools {
@Tool(description = "获取指定城市的当前天气信息")
public String getCurrentWeather(String city) {
// 实际调用天气 API
return city + ":25°C,晴天,东风3级";
}
}
// 使用
String response = chatClient.prompt()
.user("北京明天天气怎么样?")
.tools(new WeatherTools())
.call()
.content();
2
3
4
5
6
7
8
9
10
11
12
13
14
方式二:MethodToolCallback(程序化定义)
ToolCallback toolCallback = MethodToolCallback.builder()
.toolDefinition(ToolDefinition.builder()
.name("getCurrentWeather")
.description("获取当前天气")
.build())
.toolMethod(WeatherTools.class.getMethod("getCurrentWeather", String.class))
.toolObject(new WeatherTools())
.build();
2
3
4
5
6
7
8
方式三:FunctionToolCallback(函数式定义,兼容旧版)
@Bean
public ToolCallback weatherTool() {
return FunctionToolCallback.builder("getCurrentWeather", new MockWeatherService())
.description("获取指定地点的当前天气")
.inputType(MockWeatherService.Request.class)
.build();
}
2
3
4
5
6
7
# 核心组件
| 组件 | 作用 |
|---|---|
| ToolCallback | 工具回调接口,定义工具的执行逻辑 |
| ToolDefinition | 工具定义,包含名称、描述、参数 Schema |
| ToolCallingManager | 工具执行生命周期管理器 |
| ToolCallbackResolver | 动态工具名称解析器 |
| ToolCallAdvisor | 以 Advisor 方式控制工具调用流程 |
# MCP(模型上下文协议)
作用:MCP(Model Context Protocol)是一个标准化协议,用于让 AI 应用与外部工具 / 数据源建立标准化连接。可以理解为 **"AI 世界的 USB 接口"** —— 定义了一套统一规范,任何遵循 MCP 协议的工具 / 服务都可以即插即用地接入 AI 应用。
与 Tool Calling 的区别:
- Tool Calling:工具定义在自己的应用代码中,是 "本地工具"
- MCP:工具由独立的 MCP Server 提供,可以是远程服务、第三方组件,是 "远程标准化工具"。MCP 让工具的提供方和使用方彻底解耦
# 核心组件
| 组件 | 作用 |
|---|---|
| MCP Client Boot Starter | MCP 客户端启动器,让 Spring AI 应用作为客户端连接 MCP 服务 |
| MCP Server Boot Starter | MCP 服务端启动器,将你的服务暴露为 MCP 服务供其他 AI 应用调用 |
| STDIO and SSE MCP Server | 基于标准输入输出 + SSE 传输协议的服务端 |
| Streamable-HTTP MCP Server | 基于 HTTP 流式传输的服务端 |
| Stateless Streamable-HTTP MCP Server | 无状态版本,适合无状态微服务架构 |
| MCP Annotations | 注解式开发 MCP 客户端 / 服务端 |
| MCP Security | MCP 安全机制(开发中) |
# 传输方式对比
| 传输方式 | 说明 | 适用场景 |
|---|---|---|
| STDIO | 标准输入输出,通过子进程通信 | 本地命令行工具、桌面应用 |
| SSE | Server-Sent Events,单向流 | 简单的远程服务 |
| Streamable-HTTP | 基于 HTTP 的双向流式通信 | 生产环境的远程 MCP 服务 |
| Stateless Streamable-HTTP | 无状态版本 | K8s 等无状态微服务架构 |
<!-- 引入 MCP Client Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
2
3
4
5
# application.yml 配置连接一个文件系统 MCP Server
spring:
ai:
mcp:
client:
stdio:
servers:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
2
3
4
5
6
7
8
9
10
配置完成后,MCP Server 提供的工具(如读取文件、搜索文件等)会自动注册为 AI 可调用的工具,无需手动编写 ToolCallback。
# RAG(检索增强生成)
作用:在 LLM 生成回答时,先从外部知识库中检索相关信息,再将检索到的内容作为上下文注入提示词,让模型基于这些真实数据生成更准确的回答。核心解决 LLM "知识过时" 和 "缺乏私有数据" 的问题。
与微调(Fine-tuning)的区别:
- RAG:不修改模型参数,通过外部数据增强回答,实时性强,成本低
- 微调:修改模型参数,让模型内化新知识,适合需要改变模型风格 / 能力的场景
与 Tool Calling 的区别:
- RAG:从大量非结构化文档中模糊检索相关片段,适合问答、知识咨询
- Tool Calling:调用精确的 API 获取精确结果,适合查天气、数据库查询、执行操作
# RAG 完整流程
- 数据准备阶段:文档读取 → 文本切块(Chunking) → 向量化(Embedding) → 存入向量数据库
- 查询阶段:用户提问 → 问题向量化 → 向量数据库检索相似文档 → 取出最相关的文档片段
- 生成阶段:将检索到的文档片段 + 用户问题拼接为提示词 → 调用 LLM 生成回答
# 核心组件
Spring AI 通过 QuestionAnswerAdvisor 实现 RAG 功能,它是一个 Advisor,自动完成检索和注入流程:
// 配置 RAG Advisor
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder()
.similarityThreshold(0.7) // 相似度阈值
.topK(5) // 返回前5个最相关文档
.build())
.build()
)
.build();
// 用户提问时,Advisor 自动检索向量库并注入上下文
String answer = chatClient.prompt()
.user("公司的年假政策是什么?")
.call()
.content();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ETL Pipeline(数据管道)
作用:ETL(Extract-Transform-Load)管道,是 RAG 数据准备阶段的核心工具。负责从各种数据源读取原始数据,转换为标准的 Document 格式,最终加载到向量数据库中。
# 三个阶段
| 阶段 | 组件 | 作用 |
|---|---|---|
| Extract(抽取) | DocumentReader | 从各种数据源读取数据(PDF、Word、HTML、JSON、文本文件等) |
| Transform(转换) | DocumentTransformer | 对文档进行处理(文本切块、关键词提取、元数据增强等) |
| Load(加载) | DocumentWriter | 将处理后的文档写入目标(通常是向量数据库) |
# 内置的 DocumentReader
| Reader | 说明 |
|---|---|
| TextReader | 读取纯文本文件 |
| JsonReader | 读取 JSON 文件 |
| PagePdfDocumentReader | 按页读取 PDF |
| ParagraphPdfDocumentReader | 按段落读取 PDF |
| TikaDocumentReader | 基于 Apache Tika,支持 1000+ 种文件格式(Word、Excel、PPT 等) |
| HtmlDocumentReader | 读取 HTML 网页 |
# 内置的 DocumentTransformer
| Transformer | 说明 |
|---|---|
| TokenTextSplitter | 按 Token 数切块(最常用) |
| ContentFormatTransformer | 内容格式转换 |
| KeywordMetadataEnricher | 自动提取关键词并添加到元数据 |
| SummaryMetadataEnricher | 自动生成摘要并添加到元数据 |
// ETL 完整流程示例:读取 PDF -> 切块 -> 存向量库
PagePdfDocumentReader reader = new PagePdfDocumentReader(
new ClassPathResource("company-policy.pdf")
);
List<Document> documents = reader.read();
// 文本切块
TokenTextSplitter splitter = new TokenTextSplitter();
List<Document> chunks = splitter.apply(documents);
// 存入向量数据库
vectorStore.add(chunks);
2
3
4
5
6
7
8
9
10
11
12
# Vector Databases(向量数据库)
作用:向量数据库是专门用于存储和检索向量数据(高维浮点数组)的数据库。在 AI 场景中,文本经过 Embedding 模型转换为向量后存入向量库,查询时通过计算向量间的相似度(余弦相似度、欧氏距离等)来找到语义最相关的内容。它是 RAG 的核心基础设施。
与传统关系型数据库的区别:
- 关系型数据库(MySQL):精确匹配,
WHERE name = '张三' - 向量数据库:语义相似匹配,"搜索与 ' 如何提高代码质量 ' 语义最接近的文档片段"
Spring AI 1.1.7 支持 20+ 种向量数据库,通过统一的 VectorStore 接口抽象,切换数据库只需更换依赖和配置:
# 向量数据库详细对比
# PGvector
| 项目 | 说明 |
|---|---|
| 是什么 | PostgreSQL 的向量搜索扩展插件 |
| 核心优势 | 直接在现有 PostgreSQL 上添加向量能力,无需引入新数据库;SQL 生态成熟,运维团队熟悉 |
| 适用场景 | 已有 PostgreSQL 基础设施的团队、中小规模数据集(百万级以下)、希望一个库同时存业务数据和向量数据 |
| 劣势 | 大规模向量检索性能不如专业向量库(千万级以上会有瓶颈) |
| 与其他的区别 | 最大优势是 "零额外基础设施",对于已有 PG 的团队来说成本最低 |
# Chroma
| 项目 | 说明 |
|---|---|
| 是什么 | 轻量级开源向量数据库,专为 AI 应用设计 |
| 核心优势 | 部署简单(Docker 一键启动)、API 友好、支持内存和持久化两种模式 |
| 适用场景 | 开发测试环境、个人项目、快速原型验证 |
| 劣势 | 不适合大规模生产环境,集群能力弱 |
| 与其他的区别 | 开发体验最好,上手最快,但生产能力不如 Milvus、Qdrant |
# Milvus
| 项目 | 说明 |
|---|---|
| 是什么 | 高性能分布式向量数据库,国内 Zilliz 公司开源 |
| 核心优势 | 十亿级向量秒级检索、分布式架构、支持多种索引类型(IVF、HNSW、GPU 索引等) |
| 适用场景 | 大规模生产环境、十亿级向量数据、对检索性能要求极高的场景 |
| 劣势 | 部署复杂度高(依赖 etcd、MinIO 等组件)、运维成本较高 |
| 与其他的区别 | 性能天花板最高,国内社区活跃,中文文档丰富,是国内企业级 RAG 的首选 |
# Redis
| 项目 | 说明 |
|---|---|
| 是什么 | Redis Stack 提供的向量搜索模块(RediSearch) |
| 核心优势 | 极低延迟(内存操作)、已有 Redis 集群可直接复用、支持混合查询(向量 + 标签过滤) |
| 适用场景 | 对延迟要求极高的实时场景、已有 Redis 基础设施、中小规模数据集 |
| 劣势 | 内存成本高、数据规模受内存限制 |
| 与其他的区别 | 延迟最低,但成本最高(纯内存),适合对响应速度有极端要求的场景 |
# Elasticsearch
| 项目 | 说明 |
|---|---|
| 是什么 | Elasticsearch 8.x+ 原生支持向量检索(dense_vector 字段 + kNN 搜索) |
| 核心优势 | 同时支持全文检索 + 向量检索的混合搜索、生态成熟、运维工具丰富 |
| 适用场景 | 已有 ES 集群的团队、需要全文检索 + 语义检索混合的场景 |
| 劣势 | 向量检索性能不如 Milvus 等专业向量库、JVM 内存占用大 |
| 与其他的区别 | 最大优势是 "全文检索 + 向量检索" 一体化,不用维护两套系统 |
# MongoDB Atlas
| 项目 | 说明 |
|---|---|
| 是什么 | MongoDB Atlas 的向量搜索服务(Atlas Vector Search) |
| 核心优势 | 文档型存储天然适合存储非结构化数据和元数据、与 MongoDB 生态无缝集成 |
| 适用场景 | 已有 MongoDB 基础设施、需要灵活 Schema 的场景 |
| 劣势 | 需要 Atlas 云服务(本地部署的 MongoDB 不支持向量搜索) |
| 与其他的区别 | 适合 "文档 + 向量" 混合存储的场景,Schema-free 的灵活性是优势 |
# Neo4j
| 项目 | 说明 |
|---|---|
| 是什么 | 图数据库 + 向量搜索能力 |
| 核心优势 | 同时支持图关系查询和向量检索、适合知识图谱 + RAG 的融合场景 |
| 适用场景 | 知识图谱应用、需要关系推理 + 语义检索的复杂场景 |
| 劣势 | 纯向量检索性能不如专业向量库 |
| 与其他的区别 | 唯一一个支持 "图关系 + 向量" 融合查询的选项 |
# Pinecone
| 项目 | 说明 |
|---|---|
| 是什么 | 全托管的云原生向量数据库 |
| 核心优势 | 零运维、自动扩缩容、全球分布式部署 |
| 适用场景 | 不想运维向量库、追求开箱即用的团队 |
| 劣势 | 纯云服务,数据在海外、价格较贵、网络延迟 |
| 与其他的区别 | 最省心的方案(全托管),但对国内用户有网络和数据合规问题 |
# Qdrant
| 项目 | 说明 |
|---|---|
| 是什么 | Rust 编写的高性能向量搜索引擎 |
| 核心优势 | 性能极高(Rust 无 GC)、支持丰富的过滤条件、云服务和私有化部署都支持 |
| 适用场景 | 对性能要求高、需要复杂过滤条件的场景 |
| 劣势 | 社区相比 Milvus 较小、中文资料较少 |
| 与其他的区别 | 性能与 Milvus 同级,但更轻量,单机部署更简单 |
# Weaviate
| 项目 | 说明 |
|---|---|
| 是什么 | 开源向量搜索引擎,支持模块化扩展 |
| 核心优势 | 内置向量化模块(不需要单独调 Embedding API)、GraphQL 查询接口 |
| 适用场景 | 希望数据库自带向量化能力、偏好 GraphQL 的团队 |
| 劣势 | 性能不如 Milvus/Qdrant |
| 与其他的区别 | 唯一一个内置向量化的数据库,其他都需要先调 Embedding 模型再存入 |
# 其他支持的向量数据库
| 数据库 | 说明 |
|---|---|
| Azure AI Service | 微软 Azure 的 AI 搜索服务,企业级,与 Azure 生态深度集成 |
| Azure Cosmos DB | 微软全球分布式数据库的向量搜索能力 |
| Apache Cassandra | 分布式 NoSQL 数据库 + 向量扩展,适合超大规模写入场景 |
| Couchbase | 分布式文档数据库 + 向量搜索 |
| GemFire | VMware 的内存数据平台 + 向量能力 |
| MariaDB | MariaDB 11.7+ 支持向量字段,与 PGvector 类似的 "关系库 + 向量" 方案 |
| OpenSearch | AWS 开源的搜索引擎(ES 分支),与 ES 类似但 AWS 生态更友好 |
| Oracle | Oracle 23ai 版本原生支持向量,适合已有 Oracle 基础设施的企业 |
| SAP Hana | SAP 内存数据库 + 向量能力,适合 SAP 企业客户 |
| Typesense | 轻量级开源搜索引擎 + 向量检索 |
# 如何选择向量数据库?
| 场景 | 推荐方案 |
|---|---|
| 已有 PostgreSQL,中小规模 | PGvector |
| 已有 Elasticsearch | Elasticsearch |
| 已有 Redis,对延迟要求极高 | Redis |
| 十亿级数据,国内生产环境 | Milvus |
| 追求性能 + 轻量部署 | Qdrant |
| 开发测试、快速原型 | Chroma |
| 知识图谱 + RAG | Neo4j |
| 不想运维,全托管 | Pinecone(海外)/ Milvus Cloud(国内) |
| 已有 MongoDB | MongoDB Atlas |
// 统一的 VectorStore 接口,切换数据库只需换实现
@Autowired
VectorStore vectorStore;
// 存入向量
vectorStore.add(List.of(
new Document("Spring AI是一个AI应用开发框架"),
new Document("它支持20多种向量数据库")
));
// 相似度搜索
List<Document> results = vectorStore.similaritySearch(
SearchRequest.builder()
.query("什么是Spring AI?")
.topK(3)
.similarityThreshold(0.7)
.build()
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Observability(可观测性)
作用:对 AI 相关操作提供指标(Metrics)、追踪(Traces)、日志(Logs) 三个维度的可观测能力。可以监控 Token 使用量、请求延迟、模型调用次数、Advisor 执行情况等。
集成方式:基于 Spring Boot Actuator + Micrometer,天然支持 Prometheus + Grafana 的监控体系。Advisor 也参与 Observability 栈,可以查看每个 Advisor 的执行指标和追踪信息。
监控维度:
- ChatModel 调用次数、延迟、Token 消耗
- Embedding 请求量、向量维度
- Tool Calling 执行次数、成功 / 失败率
- Advisor 链路追踪
- 向量数据库查询延迟
# Model Evaluation(模型评估测试)
作用:评估 AI 模型生成内容的质量和准确性,防止模型幻觉(hallucination)。典型用法是对加载到 Vector Store 中的文档执行 RAG 查询,然后评估响应是否与用户问题相关、是否忠于原始文档。
评估方式:
- 相关性评估:回答是否与问题相关
- 忠实度评估:回答是否忠于检索到的源文档(没有编造内容)
- LLM-as-a-Judge:用一个 LLM 来评估另一个 LLM 的输出质量
# Development-time Services(开发时服务)
作用:类似 Spring Boot 的 Docker Compose 集成,在开发阶段自动启动依赖的 AI 基础设施。比如启动项目时自动拉起 Ollama 容器、向量数据库容器等,免去手动管理开发环境的麻烦。
工作方式:在 compose.yaml 中定义好依赖的服务,Spring Boot 启动时自动检测并启动这些容器。
# compose.yaml
services:
ollama:
image: ollama/ollama
ports:
- "11434:11434"
chroma:
image: chromadb/chroma
ports:
- "8000:8000"
2
3
4
5
6
7
8
9
10
# Testcontainers(测试容器集成)
作用:在自动化测试阶段,通过 Testcontainers 自动拉起 AI 相关的 Docker 容器(如 Ollama、Chroma、PGvector、Milvus 等),实现集成测试的自动化。测试完成后容器自动销毁,环境干净无残留。
与 Development-time Services 的区别:
- Development-time Services:用于开发阶段,容器一直运行
- Testcontainers:用于测试阶段,容器随测试生命周期创建和销毁
@SpringBootTest
@Testcontainers
class RagIntegrationTest {
@Container
static ChromaDBContainer chroma = new ChromaDBContainer("chromadb/chroma");
@Test
void testRagQuery() {
// 测试 RAG 查询逻辑
}
}
2
3
4
5
6
7
8
9
10
11
12