Spring AI Alibaba 向量(VectorStore)
1. 概述
Spring AI Alibaba VectorStore 是 Spring AI Alibaba 生态系统中用于与向量数据库交互的核心组件。它基于 Spring AI 框架的抽象设计,提供了一套统一的 API 来操作不同的向量数据库,极大地简化了 AI 应用中向量数据的存储、检索和管理流程。
VectorStore 是实现**检索增强生成(RAG)**技术的关键基础设施。它允许开发者将私有数据转换为向量表示并存储在向量数据库中,当用户提问时,系统会先从向量数据库中检索相关上下文,再将其与用户问题一起发送给大语言模型,从而生成更准确、更有针对性的回答。
2. 核心概念
2.1 VectorStore 接口
Spring AI 通过 VectorStore 接口提供了与向量数据库交互的抽象 API,定义了所有向量数据库实现都必须支持的核心操作:
java
public interface VectorStore extends DocumentWriter {
// 获取向量存储名称
default String getName() {
return this.getClass().getSimpleName();
}
// 批量添加文档(自动生成向量并存储)
void add(List<Document> documents);
// 根据文档ID批量删除
void delete(List<String> idList);
// 根据元数据过滤条件删除
void delete(Filter.Expression filterExpression);
// 简单相似度搜索
List<Document> similaritySearch(String query);
// 高级相似度搜索(支持过滤、topK、相似度阈值等)
List<Document> similaritySearch(SearchRequest request);
// 获取底层原生客户端
default <T> Optional<T> getNativeClient() {
return Optional.empty();
}
}
2.2 Document 类
Document 是 Spring AI 中表示文本数据的核心类,包含以下主要属性:
- id:文档唯一标识符
- content:文档的文本内容
- metadata:文档的元数据(键值对形式)
- embedding:文档的向量表示(可选,通常由 EmbeddingModel 自动生成)
2.3 EmbeddingModel
EmbeddingModel 负责将文本内容转换为高维向量表示。Spring AI Alibaba 内置了对多种国产嵌入模型的支持,包括:
- 通义千问 Embedding(DashScope)
- 百川 Embedding
- Moonshot Embedding
2.4 相似度搜索
相似度搜索是向量数据库的核心功能,它通过计算查询向量与数据库中存储向量之间的距离(如余弦距离、欧氏距离)来找出最相似的文档。Spring AI 支持通过 SearchRequest 构建器来配置搜索参数:
java
SearchRequest request = SearchRequest.builder()
.query("Spring AI Alibaba 是什么?")
.topK(5) // 返回前5个最相似的文档
.similarityThreshold(0.7) // 相似度阈值(0~1,值越高越相似)
.filterExpression(filter) // 元数据过滤条件
.build();
2.5 元数据过滤
元数据过滤允许在相似度搜索的同时,基于文档的元数据进行精确过滤,从而提高检索的准确性和效率。Spring AI 提供了两种过滤方式:
- SQL-like 字符串表达式:简单直观,但缺乏类型安全
- FilterExpressionBuilder:类型安全的构建器 API,推荐在生产环境使用
3. 支持的向量数据库
Spring AI Alibaba 不仅提供了对阿里云原生向量服务的支持,还兼容 Spring AI 官方支持的所有向量数据库实现:
| 向量数据库 | 特点 | 适用场景 |
|---|---|---|
| DashScopeCloudStore | 阿里云原生向量检索服务,无需自建,高可用 | 企业级应用,快速上线 |
| Milvus | 专为向量设计,高吞吐、高可用 | 大规模向量检索场景 |
| PGVector | PostgreSQL 扩展,关系型+向量 | 已有 PostgreSQL 基础设施 |
| Redis | 高性能,成熟生态 | 已有 Redis 基础设施,实时性要求高 |
| Elasticsearch | 全文搜索+向量搜索 | 混合检索场景 |
| Chroma | 轻量级,易用 | 小型项目、原型开发 |
| SimpleVectorStore | 内存/文件存储,无需额外依赖 | 开发测试、演示 |
4. 快速开始
4.1 环境准备
- 获取 DashScope API Key :访问 阿里云百炼平台 注册并获取 API Key
- 创建 Spring Boot 项目:使用 Spring Initializr 创建一个新的 Spring Boot 3.x 项目
4.2 添加依赖
在 pom.xml 中添加 Spring AI Alibaba 依赖:
xml
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>2024.0.1.0</version>
</dependency>
4.3 配置应用
在 application.properties 中添加配置:
properties
# DashScope API Key
spring.ai.dashscope.api-key=YOUR_DASHSCOPE_API_KEY
# 配置嵌入模型
spring.ai.dashscope.embedding.model=text-embedding-v3
# 配置聊天模型(用于RAG)
spring.ai.dashscope.chat.model=qwen-turbo
4.4 基础使用示例
创建一个简单的控制器来演示 VectorStore 的基本操作:
java
@RestController
@RequestMapping("/vector")
public class VectorStoreController {
private final VectorStore vectorStore;
// Spring Boot 自动注入配置好的 VectorStore
public VectorStoreController(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
// 添加文档到向量数据库
@PostMapping("/add")
public String addDocuments() {
List<Document> documents = List.of(
new Document("Spring AI Alibaba 是阿里云基于 Spring AI 框架开发的 AI 应用开发工具包。"),
new Document("VectorStore 是 Spring AI 中用于与向量数据库交互的核心接口。"),
new Document("RAG(检索增强生成)是一种将检索系统与大语言模型结合的技术。",
Map.of("type", "tutorial", "version", "1.0"))
);
vectorStore.add(documents);
return "文档添加成功!";
}
// 简单相似度搜索
@GetMapping("/search")
public List<Document> search(@RequestParam String query) {
return vectorStore.similaritySearch(query);
}
// 高级相似度搜索
@GetMapping("/advanced-search")
public List<Document> advancedSearch(@RequestParam String query) {
SearchRequest request = SearchRequest.builder()
.query(query)
.topK(3)
.similarityThreshold(0.6)
.build();
return vectorStore.similaritySearch(request);
}
// 根据ID删除文档
@DeleteMapping("/delete")
public String delete(@RequestParam List<String> ids) {
vectorStore.delete(ids);
return "文档删除成功!";
}
}
5. 高级特性
5.1 元数据过滤
元数据过滤是提高检索准确性的重要手段。Spring AI 提供了强大的过滤表达式支持:
5.1.1 使用 FilterExpressionBuilder(推荐)
java
// 构建过滤条件:type == "tutorial" AND version >= 1.0
Filter.Expression filter = FilterExpressionBuilder.builder()
.eq("type", "tutorial")
.and()
.ge("version", 1.0)
.build();
SearchRequest request = SearchRequest.builder()
.query("什么是RAG?")
.filterExpression(filter)
.topK(5)
.build();
List<Document> results = vectorStore.similaritySearch(request);
5.1.2 支持的操作符
| 操作符 | 说明 | 示例 |
|---|---|---|
== |
等于 | eq("status", "active") |
!= |
不等于 | ne("status", "deleted") |
> |
大于 | gt("price", 100) |
>= |
大于等于 | ge("version", 2.0) |
< |
小于 | lt("score", 60) |
<= |
小于等于 | le("age", 18) |
in |
包含于 | in("category", List.of("tech", "ai")) |
and |
逻辑与 | eq("a", 1).and().eq("b", 2) |
or |
逻辑或 | eq("a", 1).or().eq("b", 2) |
5.2 与 RAG 集成
Spring AI Alibaba 提供了开箱即用的 RAG 支持,通过 QuestionAnswerAdvisor 可以轻松实现检索增强生成:
5.2.1 添加 RAG 依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
5.2.2 配置 RAG 聊天客户端
java
@Configuration
public class RagConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) {
return builder
.defaultSystem("你是一个专业的技术文档助手,只能使用提供的上下文信息回答问题。如果上下文没有相关信息,请明确说明你不知道。")
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore)
.topK(3)
.similarityThreshold(0.7)
.build())
.build();
}
}
5.2.3 使用 RAG 回答问题
java
@RestController
@RequestMapping("/rag")
public class RagController {
private final ChatClient chatClient;
public RagController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/ask")
public String ask(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
// 动态过滤的 RAG 查询
@GetMapping("/ask-filtered")
public String askFiltered(@RequestParam String question, @RequestParam String type) {
return chatClient.prompt()
.user(question)
.advisors(advisorSpec -> advisorSpec
.param(VectorStoreDocumentRetriever.FILTER_EXPRESSION, "type == '" + type + "'"))
.call()
.content();
}
}
5.3 批量导入文档
在实际应用中,通常需要批量导入大量文档。Spring AI 提供了文档分割器来处理长文本:
java
@Service
public class DocumentImportService {
private final VectorStore vectorStore;
private final TextSplitter textSplitter;
public DocumentImportService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
// 创建一个基于 token 的文本分割器
this.textSplitter = TokenTextSplitter.builder()
.chunkSize(500) // 每个块的大小(token 数)
.chunkOverlap(50) // 块之间的重叠大小
.build();
}
public void importDocument(String content, Map<String, Object> metadata) {
// 创建原始文档
Document document = new Document(content, metadata);
// 将长文档分割成小块
List<Document> chunks = textSplitter.apply(List.of(document));
// 批量添加到向量数据库
vectorStore.add(chunks);
}
// 从文件导入文档
public void importFromFile(String filePath, Map<String, Object> metadata) throws IOException {
String content = Files.readString(Paths.get(filePath));
importDocument(content, metadata);
}
}
6. 最佳实践
6.1 文档分块策略
不同类型的文档适合不同的分块策略:
| 文档类型 | 推荐策略 | 说明 |
|---|---|---|
| 长文本(书籍、报告) | 递归分块 | 先按段落分割,再按句子分割 |
| 结构化文档(Markdown、HTML) | 基于结构分块 | 保留标题、章节等结构信息 |
| 表格数据 | Text-to-SQL | 不建议存入向量库,使用 SQL 查询 |
| 短文档(FAQ、问答对) | 整体作为一个块 | 保持语义完整性 |
6.2 元数据设计
合理的元数据设计可以显著提高检索效率和准确性:
java
// 推荐的元数据结构
Map<String, Object> metadata = Map.of(
"source", "spring-ai-alibaba-docs.pdf", // 文档来源
"type", "tutorial", // 文档类型
"version", "1.0", // 文档版本
"author", "Alibaba", // 作者
"created_at", LocalDateTime.now(), // 创建时间
"chapter", "第3章", // 章节信息
"page", 45 // 页码
);
6.3 性能优化
- 先过滤后检索:尽可能使用元数据过滤减少需要进行相似度计算的向量数量
- 合理设置 topK:根据业务需求调整返回结果数量,避免不必要的计算
- 批量操作 :使用
add(List<Document>)方法批量添加文档,提高写入效率 - 索引优化:为常用的元数据字段创建索引
- 向量维度选择:根据业务需求选择合适的向量维度,维度越高精度越高但计算成本也越高
6.4 错误处理
java
@Service
public class VectorStoreService {
private static final Logger logger = LoggerFactory.getLogger(VectorStoreService.class);
private final VectorStore vectorStore;
public VectorStoreService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
public void safeAddDocuments(List<Document> documents) {
try {
vectorStore.add(documents);
logger.info("成功添加 {} 个文档", documents.size());
} catch (Exception e) {
logger.error("添加文档失败", e);
// 实现重试逻辑或错误处理
}
}
public List<Document> safeSearch(SearchRequest request) {
try {
return vectorStore.similaritySearch(request);
} catch (Exception e) {
logger.error("相似度搜索失败", e);
return Collections.emptyList();
}
}
}
7. 常见问题
7.1 为什么搜索结果不相关?
可能的原因和解决方案:
- 文档分块不合理:调整分块大小和重叠度
- 嵌入模型不适合:尝试使用针对中文优化的嵌入模型
- 相似度阈值设置不当:降低相似度阈值以返回更多结果
- 元数据过滤过于严格:检查过滤条件是否正确
7.2 如何处理大文件?
使用 Spring AI 提供的文档读取器和分割器:
TextReader:读取纯文本文件PdfReader:读取 PDF 文件MarkdownReader:读取 Markdown 文件(保留结构信息)TokenTextSplitter:基于 token 数量分割文本
7.3 如何更新向量数据库中的文档?
Spring AI 目前没有提供直接的更新方法,推荐的做法是:
- 根据 ID 删除旧文档
- 添加更新后的新文档
7.4 SimpleVectorStore 可以用于生产环境吗?
不推荐。SimpleVectorStore 是一个基于内存和文件的简单实现,不支持高并发和大规模数据存储。生产环境建议使用专业的向量数据库如 Milvus、PGVector 或阿里云 DashScopeCloudStore。
8. 总结
Spring AI Alibaba VectorStore 为开发者提供了一套简单、统一、高效的向量数据库操作 API,极大地降低了构建 RAG 应用的门槛。通过本文档的学习,您应该已经掌握了 VectorStore 的核心概念、基本使用方法和高级特性。