什么是向量数据库?AI应用背后的数据枢纽
在AI应用开发中,向量数据库(Vector Database)已经成为不可或缺的基础设施。相比传统关系型数据库的精确匹配查询,向量数据库的核心能力是相似性搜索(Similarity Search)——当你输入一个向量作为查询条件时,它返回的是与该向量”最相似”的结果,而不是完全相等的数据。
这种设计非常适合大语言模型(LLM)的场景:我们需要根据用户问题从知识库中检索相关文档,然后将这些文档作为上下文发送给AI模型。这个过程就是RAG(检索增强生成)的核心思路。
工作流程简述
向量数据库的典型使用流程是这样的:先把你的数据(PDF、Word、文本等)加载到向量数据库中;当用户提出问题时,系统先从向量数据库中检索出最相似的文档;最后把这些文档和问题一起发送给AI模型,由模型生成回答。
下面我们来详细看看Spring AI框架中向量数据库的相关API设计。
Spring AI VectorStore API详解
Spring AI提供了抽象的VectorStore接口来统一操作各种向量数据库,同时提供了只读的VectorStoreRetriever接口。
VectorStoreRetriever:只读查询接口
如果你只需要从向量数据库查询数据,不需要写入操作,可以使用VectorStoreRetriever接口。这是一个函数式接口,遵循最小权限原则:
@FunctionalInterface
public interface VectorStoreRetriever {
List similaritySearch(SearchRequest request);
default List similaritySearch(String query) {
return this.similaritySearch(SearchRequest.builder().query(query).build());
}
}
这种设计很适合那些只需要查询功能的场景,比如只读的文档检索系统。
VectorStore:完整的增删改查
VectorStore接口继承了VectorStoreRetriever和DocumentWriter,同时支持读取和写入操作:
public interface VectorStore extends DocumentWriter, VectorStoreRetriever {
default String getName() {
return this.getClass().getSimpleName();
}
void add(List documents);
void delete(List idList);
void delete(Filter.Expression filterExpression);
default void delete(String filterExpression) { ... }
default Optional getNativeClient() {
return Optional.empty();
}
}
通过这个接口,你可以完成以下操作:
- add: 向向量数据库添加文档
- delete: 根据ID或过滤条件删除文档
- similaritySearch: 执行相似性搜索
- getNativeClient: 获取底层数据库的原生客户端(如果有)
SearchRequest:搜索参数配置
搜索时的各种参数通过SearchRequest的Builder模式来配置:
public class SearchRequest {
public static final double SIMILARITY_THRESHOLD_ACCEPT_ALL = 0.0;
public static final int DEFAULT_TOP_K = 4;
private String query = "";
private int topK = DEFAULT_TOP_K;
private double similarityThreshold = SIMILARITY_THRESHOLD_ACCEPT_ALL;
@Nullable
private Filter.Expression filterExpression;
public static class Builder {
private final SearchRequest searchRequest = new SearchRequest();
public Builder query(String query) {
Assert.notNull(query, "Query can not be null.");
this.searchRequest.query = query;
return this;
}
public Builder topK(int topK) {
Assert.isTrue(topK >= 0, "TopK should be positive.");
this.searchRequest.topK = topK;
return this;
}
public Builder similarityThreshold(double threshold) {
Assert.isTrue(threshold >= 0 && threshold <= 1,
"Similarity threshold must be in [0,1] range.");
this.searchRequest.similarityThreshold = threshold;
return this;
}
public Builder filterExpression(@Nullable Filter.Expression expression) {
this.searchRequest.filterExpression = expression;
return this;
}
public Builder filterExpression(@Nullable String textExpression) {
this.searchRequest.filterExpression = (textExpression != null)
? new FilterExpressionTextParser().parse(textExpression) : null;
return this;
}
public SearchRequest build() {
return this.searchRequest;
}
}
}
核心参数说明:
- query: 搜索关键词,会被embedding模型转换为向量
- topK: 返回最相似的K个结果,默认为4
- similarityThreshold: 相似度阈值,范围0-1,值越大表示要求越严格
- filterExpression: 元数据过滤条件,支持类似SQL的语法
Document:数据载体
要往向量数据库插入数据,需要把数据封装成Document对象。Document包含原始文本内容(content)和元数据(metadata,key-value形式):
// 示例:创建Document
Document doc = new Document("这是一段需要向量化的文本内容",
Map.of("source", "file.pdf", "author", "张三"));
documentStore.add(List.of(doc));
插入时,文本内容会被Embedding模型转换成向量(float[]数组)。常用的embedding模型包括OpenAI的text-embedding-ada-002、BERT、Word2Vec等。
需要注意的是,向量数据库本身不负责生成向量,它只负责存储向量和执行相似度搜索。生成向量的工作由EmbeddingModel完成。
Schema初始化:别忘了这一步
有些向量数据库需要提前创建索引或schema,默认情况下Spring AI不会自动帮你初始化。需要在构造方法中传入initialize-schema=true参数,或者在application.properties中配置:
# application.properties 示例
spring.ai.vectorstore.pgvector.initialize-schema=true
具体属性名取决于你使用的向量数据库实现(Milvus、Elasticsearch、PostgreSQL等各有不同)。
批处理策略:解决Token数量限制
当你需要一次性向量化大量文档时,不能简单地一次性调用embedding模型——大多数模型都有上下文窗口限制(比如OpenAI的embedding模型最大支持8191个token)。
Spring AI通过BatchingStrategy接口来解决这个问题:
public interface BatchingStrategy {
List> batch(List documents);
}
默认实现:TokenCountBatchingStrategy
Spring AI提供了默认的TokenCountBatchingStrategy,会根据token数量自动将文档分组:
- 默认使用OpenAI的8191作为最大token限制
- 预留10%的buffer防止超出限制
- 单个文档如果超过限制会抛出异常
自定义批处理策略
如果默认配置不满足需求,可以自定义TokenCountBatchingStrategy:
@Configuration
public class EmbeddingConfig {
@Bean
public BatchingStrategy customTokenCountBatchingStrategy() {
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE, // 分词编码类型
8000, // 最大输入token数
0.1 // 预留百分比
);
}
}
这里的关键参数:
- EncodingType: 指定分词编码,CL100K_BASE是OpenAI常用的编码
- 8000: 最大token数,应该小于模型的上下文窗口大小
- 0.1: 预留10%的buffer空间
实战建议
在实际项目中使用向量数据库时,有几个注意点:
- 选型问题: 如果是中小规模项目,PostgreSQL的pgvector插件足够用了;大规模场景可以考虑Milvus或Weaviate
- 索引优化: 大多数向量数据库支持多种索引类型(如HNSW、IVF),选择合适的索引能显著提升查询性能
- 过滤条件: 尽量在查询时使用metadata过滤,可以大幅减少向量搜索的范围
- 批量写入: 大量数据导入时记得启用批处理策略,避免触发API的rate limit
Spring AI的VectorStore抽象做得不错,基本主流的向量数据库都有对应的实现,切换成本不高。如果你在做AI应用开发这块,可以先从简单的pgvector开始上手。