向量数据库
向量数据库是一种在人工智能应用中发挥重要作用的专门类型的数据库。
在向量数据库中,查询与传统关系数据库不同。它们执行相似性搜索,而不是精确匹配。当给定一个向量作为查询时,向量数据库返回与查询向量“相似”的向量。有关如何在高层次计算此相似性的更多细节,请参阅向量相似性。
向量数据库用于将您的数据与AI模型集成。在使用它们时的第一步是将您的数据加载到向量数据库中。然后,当用户查询要发送到AI模型时,首先检索一组相似的文档。然后,这些文档作为用户问题的上下文,并与用户的查询一起发送到AI模型。这种技术称为检索增强生成(RAG)。
以下各节描述了Spring AI界面用于使用多个向量数据库实现以及一些高级示例用法。
最后一节旨在揭示向量数据库中相似性搜索的基本方法。
API概述
"本节是对 Spring AI 框架中 VectorStore
接口及其相关类的指南。
Spring AI 通过 VectorStore
接口提供了与向量数据库交互的抽象 API。
下面是 VectorStore
接口的定义:
public interface VectorStore {
void add(List<Document> documents);
Optional<Boolean> delete(List<String> idList);
List<Document> similaritySearch(String query);
List<Document> similaritySearch(SearchRequest request);
}
以及相关的 SearchRequest
构建器:
public class SearchRequest {
public final String query;
private int topK = 4;
private double similarityThreshold = SIMILARITY_THRESHOLD_ALL;
private Filter.Expression filterExpression;
public static SearchRequest query(String query) { return new SearchRequest(query); }
private SearchRequest(String query) { this.query = query; }
public SearchRequest withTopK(int topK) {...}
public SearchRequest withSimilarityThreshold(double threshold) {...}
public SearchRequest withSimilarityThresholdAll() {...}
public SearchRequest withFilterExpression(Filter.Expression expression) {...}
public SearchRequest withFilterExpression(String textExpression) {...}
public String getQuery() {...}
public int getTopK() {...}
public double getSimilarityThreshold() {...}
public Filter.Expression getFilterExpression() {...}
}
要将数据插入向量数据库中,请将其封装在 Document
对象中。Document
类封装了来自数据源(如 PDF 或 Word 文档)的内容,并以字符串形式表示文本。它还包含以键值对形式的元数据,包括文件名等详细信息。
在将文本内容插入向量数据库后,文本内容通过嵌入模型转换为数值数组,即 List<Double>
,称为向量嵌入。嵌入模型(如 Word2Vec、GLoVE 和 BERT,或 OpenAI 的 text-embedding-ada-002
)用于将单词、句子或段落转换为这些向量嵌入。
向量数据库的作用是存储和方便对这些嵌入进行相似性搜索。它本身不生成嵌入。要创建向量嵌入,应使用 EmbeddingClient
。
接口中的 similaritySearch
方法允许检索与给定查询字符串相似的文档。这些方法可以通过使用以下参数进行微调:
-
k
: 一个整数,指定要返回的相似文档的最大数量。这通常被称为“top K”搜索,或者“K最近邻居”(KNN)。 -
threshold
: 一个从 0 到 1 的双精度值,值越接近 1 表示相似度越高。默认情况下,如果您设置阈值为 0.75,那么只有相似度高于此值的文档才会被返回。 -
Filter.Expression
: 用于传递流畅 DSL(领域特定语言)表达式的类,其功能类似于 SQL 中的“where”子句,但它仅适用于Document
的元数据键值对。 -
filterExpression
: 基于 ANTLR4 的外部 DSL,接受字符串形式的过滤器表达式。例如,对于像 country、year 和isActive
这样的元数据键,您可以使用如下表达式:country == 'UK' && year >= 2020 && isActive == true。
在元数据过滤器部分找到有关 Filter.Expression
的更多信息。
可用实现
这是VectorStore
接口的可用实现:
-
Azure 矢量搜索 - Azure 矢量存储。
-
ChromaVectorStore - Chroma 矢量存储。
-
MilvusVectorStore - Milvus 矢量存储。
-
Neo4jVectorStore - Neo4j 矢量存储。
-
PgVectorStore - PostgreSQL/PGVector 矢量存储。
-
PineconeVectorStore - PineCone 矢量存储。
-
QdrantVectorStore - Qdrant 矢量存储。
-
RedisVectorStore - Redis 矢量存储。
-
WeaviateVectorStore - Weaviate 矢量存储。
-
SimpleVectorStore - 持久矢量存储的简单实现,适用于教育目的。
将来的版本可能会支持更多的实现。
如果您有需要由 Spring AI 支持的矢量数据库,请在 GitHub 上提出问题,或者更好的是,提交一个带有实现的拉取请求。
有关每个VectorStore
实现的信息可以在本章的各小节中找到。
示例用法
要计算向量数据库的嵌入,您需要选择一个与所使用的高级AI模型相匹配的嵌入模型。
例如,使用OpenAI的ChatGPT,我们使用OpenAiEmbeddingClient
和模型名称text-embedding-ada-002
。
Spring Boot starter对OpenAI的自动配置使得EmbeddingClient
的实现在Spring应用程序上下文中可用于依赖注入。
将数据加载到向量存储中的通用用法是通过类似批处理的作业来完成的,首先将数据加载到Spring AI的Document
类中,然后调用save
方法。
给定一个指向代表我们想要加载到向量数据库中的数据的JSON文件的String
引用,我们使用Spring AI的JsonReader
来加载JSON中的特定字段,将它们分成小块,然后将这些小块传递给向量存储实现。 VectorStore
实现计算嵌入并将JSON和嵌入存储在向量数据库中:
@Autowired
VectorStore vectorStore;
void load(String sourceFile) {
JsonReader jsonReader = new JsonReader(new FileSystemResource(sourceFile),
"price", "name", "shortDescription", "description", "tags");
List<Document> documents = jsonReader.get();
this.vectorStore.add(documents);
}
稍后,当用户问题传递到AI模型时,会执行相似性搜索以检索相似的文档,然后将其作为用户问题的上下文“塞入”到提示中。
String question = <用户提问>
List<Document> similarDocuments = store.similaritySearch(question);
可以传递额外的选项到similaritySearch
方法中,以定义要检索的文档数量和相似性搜索的阈值。
元数据过滤器
本节描述了您可以针对查询结果使用的各种过滤器。
过滤字符串
您可以将类似SQL的过滤表达式作为String
传递给similaritySearch
的一个重载方法。
考虑以下示例:
-
"country == 'BG'"
-
"genre == 'drama' && year >= 2020"
-
"genre in ['comedy', 'documentary', 'drama']"
过滤表达式
您可以使用Filter.Expression
的一个实例和一个暴露流畅API的FilterExpressionBuilder
来创建。一个简单的例子如下:
FilterExpressionBuilder b = new FilterExpressionBuilder();
Expression expression = b.eq("country", "BG").build();
您可以通过以下运算符构建复杂的表达式:
EQUALS: '=='
MINUS : '-'
PLUS: '+'
GT: '>'
GE: '>='
LT: '<'
LE: '<='
NE: '!='
您可以通过以下运算符组合表达式:
AND: 'AND' | 'and' | '&&';
OR: 'OR' | 'or' | '||';
考虑以下示例:
Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();
您还可以使用以下运算符:
IN: 'IN' | 'in';
NIN: 'NIN' | 'nin';
NOT: 'NOT' | 'not';
考虑以下示例:
Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();