向量資料庫
向量資料庫是一種專門的資料庫類型,在 AI 應用程式中扮演至關重要的角色。
在向量資料庫中,查詢方式與傳統關聯式資料庫不同。它們執行相似性搜尋,而不是精確比對。當給定一個向量作為查詢時,向量資料庫會傳回與查詢向量「相似」的向量。關於如何在高階層次上計算這種相似性的更多詳細資訊,請參閱向量相似性。
向量資料庫用於將您的資料與 AI 模型整合。其使用的第一步是將您的資料載入到向量資料庫中。然後,當使用者查詢要傳送到 AI 模型時,首先檢索一組相似的文件。這些文件隨後作為使用者問題的上下文,並與使用者的查詢一起傳送到 AI 模型。這種技術稱為檢索增強生成 (RAG)。
以下章節描述了 Spring AI 介面,用於使用多個向量資料庫實作,以及一些高階範例用法。
最後一節旨在闡明向量資料庫中相似性搜尋的底層方法。
API 概觀
本節作為 Spring AI 框架內 VectorStore
介面及其相關類別的指南。
Spring AI 提供了一個抽象的 API,用於透過 VectorStore
介面與向量資料庫互動。
以下是 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 文件,並包含表示為字串的文字。它還包含金鑰值對形式的 metadata,包括檔案名稱等詳細資訊。
插入向量資料庫後,文字內容會使用嵌入模型轉換為數值陣列或 float[]
,稱為向量嵌入。嵌入模型,例如 Word2Vec、GLoVE 和 BERT,或 OpenAI 的 text-embedding-ada-002
,用於將單字、句子或段落轉換為這些向量嵌入。
向量資料庫的角色是儲存這些嵌入並促進其相似性搜尋。它本身不產生嵌入。若要建立向量嵌入,應使用 EmbeddingModel
。
介面中的 similaritySearch
方法允許檢索與給定查詢字串相似的文件。這些方法可以使用以下參數進行微調
-
k
:一個整數,指定要傳回的相似文件最大數量。這通常稱為「前 K 個」搜尋或「K 最近鄰居」(KNN)。 -
threshold
:一個介於 0 到 1 之間的雙精度值,值越接近 1 表示相似度越高。預設情況下,如果您設定閾值為 0.75,例如,則只會傳回相似度高於此值的文件。 -
Filter.Expression
:一個類別,用於傳遞流暢的 DSL(領域特定語言)表達式,其功能類似於 SQL 中的「where」子句,但它僅適用於Document
的 metadata 金鑰值對。 -
filterExpression
:一個基於 ANTLR4 的外部 DSL,它接受篩選器表達式作為字串。例如,對於國家/地區、年份和isActive
等 metadata 金鑰,您可以使用如下表達式:country == 'UK' && year >= 2020 && isActive == true.
在Metadata 篩選器章節中找到有關 Filter.Expression
的更多資訊。
Schema 初始化
某些向量儲存需要先初始化其後端 schema 才能使用。預設情況下不會為您初始化它。您必須選擇加入,方法是為適當的建構子引數傳遞 boolean
,或者,如果使用 Spring Boot,則在 application.properties
或 application.yml
中將適當的 initialize-schema
屬性設定為 true
。查看您正在使用的向量儲存的文件以取得特定屬性名稱。
批次處理策略
當使用向量儲存時,通常需要嵌入大量文件。雖然一次呼叫嵌入所有文件似乎很簡單,但這種方法可能會導致問題。嵌入模型將文字處理為 token,並具有最大 token 限制,通常稱為上下文視窗大小。此限制限制了單個嵌入請求中可以處理的文字量。嘗試在一次呼叫中嵌入過多 token 可能會導致錯誤或截斷的嵌入。
為了處理此 token 限制,Spring AI 實作了批次處理策略。這種方法將大型文件集分解為較小的批次,這些批次符合嵌入模型的最大上下文視窗。批次處理不僅解決了 token 限制問題,還可以提高效能,更有效率地使用 API 速率限制。
Spring AI 透過 BatchingStrategy
介面提供此功能,該介面允許根據文件的 token 計數,以子批次處理文件。
核心 BatchingStrategy
介面定義如下
public interface BatchingStrategy {
List<List<Document>> batch(List<Document> documents);
}
此介面定義了一個方法 batch
,它接受文件列表並傳回文件批次列表。
預設實作
Spring AI 提供了一個名為 TokenCountBatchingStrategy
的預設實作。此策略根據文件的 token 計數對文件進行批次處理,確保每個批次都不超過計算出的最大輸入 token 計數。
TokenCountBatchingStrategy
的主要功能
-
使用 OpenAI 的最大輸入 token 計數 (8191) 作為預設上限。
-
納入了保留百分比(預設 10%)以提供潛在 overhead 的緩衝區。
-
將實際最大輸入 token 計數計算為:
actualMaxInputTokenCount = originalMaxInputTokenCount * (1 - RESERVE_PERCENTAGE)
該策略估計每個文件的 token 計數,將它們分組到批次中,而不會超過最大輸入 token 計數,如果單個文件超過此限制,則擲回例外。
您也可以自訂 TokenCountBatchingStrategy
,以更好地滿足您的特定需求。這可以透過在 Spring Boot @Configuration
類別中使用自訂參數建立新實例來完成。
以下是如何建立自訂 TokenCountBatchingStrategy
bean 的範例
@Configuration
public class EmbeddingConfig {
@Bean
public BatchingStrategy customTokenCountBatchingStrategy() {
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE, // Specify the encoding type
8000, // Set the maximum input token count
0.9 // Set the threshold factor
);
}
}
在此組態中
-
EncodingType.CL100K_BASE
:指定用於 token 化的編碼類型。此編碼類型由JTokkitTokenCountEstimator
使用,以準確估計 token 計數。 -
8000
:設定最大輸入 token 計數。此值應小於或等於您的嵌入模型的最大上下文視窗大小。 -
0.9
:設定閾值因子。此因子決定在開始新批次之前,批次可以填滿多少。值為 0.9 表示每個批次將填滿到最大輸入 token 計數的 90%。
預設情況下,此建構子使用 Document.DEFAULT_CONTENT_FORMATTER
進行內容格式化,並使用 MetadataMode.NONE
進行 metadata 處理。如果您需要自訂這些參數,可以使用帶有其他參數的完整建構子。
定義後,此自訂 TokenCountBatchingStrategy
bean 將自動由應用程式中的 EmbeddingModel
實作使用,取代預設策略。
TokenCountBatchingStrategy
在內部使用 TokenCountEstimator
(特別是 JTokkitTokenCountEstimator
)來計算 token 計數以進行有效率的批次處理。這確保了基於指定編碼類型的準確 token 估計。
此外,TokenCountBatchingStrategy
透過允許您傳入自己實作的 TokenCountEstimator
介面來提供彈性。此功能使您能夠使用針對您的特定需求量身定制的自訂 token 計數策略。例如
TokenCountEstimator customEstimator = new YourCustomTokenCountEstimator();
TokenCountBatchingStrategy strategy = new TokenCountBatchingStrategy(
this.customEstimator,
8000, // maxInputTokenCount
0.1, // reservePercentage
Document.DEFAULT_CONTENT_FORMATTER,
MetadataMode.NONE
);
自訂實作
雖然 TokenCountBatchingStrategy
提供了強大的預設實作,但您可以自訂批次處理策略以符合您的特定需求。這可以透過 Spring Boot 的自動組態來完成。
若要自訂批次處理策略,請在您的 Spring Boot 應用程式中定義 BatchingStrategy
bean
@Configuration
public class EmbeddingConfig {
@Bean
public BatchingStrategy customBatchingStrategy() {
return new CustomBatchingStrategy();
}
}
然後,此自訂 BatchingStrategy
將自動由應用程式中的 EmbeddingModel
實作使用。
Spring AI 支援的向量儲存已配置為使用預設的 TokenCountBatchingStrategy 。SAP Hana 向量儲存目前未配置為進行批次處理。 |
VectorStore 實作
以下是 VectorStore
介面的可用實作
-
Azure 向量搜尋 - Azure 向量儲存。
-
Apache Cassandra - Apache Cassandra 向量儲存。
-
Chroma 向量儲存 - Chroma 向量儲存。
-
Elasticsearch 向量儲存 - Elasticsearch 向量儲存。
-
GemFire 向量儲存 - GemFire 向量儲存。
-
Milvus 向量儲存 - Milvus 向量儲存。
-
MongoDB Atlas 向量儲存 - MongoDB Atlas 向量儲存。
-
Neo4j 向量儲存 - Neo4j 向量儲存。
-
OpenSearch 向量儲存 - OpenSearch 向量儲存。
-
Oracle 向量儲存 - Oracle Database 向量儲存。
-
PgVector 向量儲存 - PostgreSQL/PGVector 向量儲存。
-
Pinecone 向量儲存 - PineCone 向量儲存。
-
Qdrant 向量儲存 - Qdrant 向量儲存。
-
Redis 向量儲存 - Redis 向量儲存。
-
SAP Hana 向量儲存 - SAP HANA 向量儲存。
-
Typesense 向量儲存 - Typesense 向量儲存。
-
Weaviate 向量儲存 - Weaviate 向量儲存。
-
SimpleVectorStore - 簡易向量儲存的簡單實作,適用於教育目的。
未來版本可能會支援更多實作。
如果您有需要 Spring AI 支援的向量資料庫,請在 GitHub 上開啟 issue,或者,更好的做法是提交包含實作的 pull request。
有關每個 VectorStore
實作的資訊,請參閱本章的子章節。
使用範例
若要計算向量資料庫的嵌入,您需要選擇一個與正在使用的高階 AI 模型相符的嵌入模型。
例如,對於 OpenAI 的 ChatGPT,我們使用 OpenAiEmbeddingModel
和一個名為 text-embedding-ada-002
的模型。
Spring Boot Starter 的 OpenAI 自動組態使 EmbeddingModel
的實作可在 Spring 應用程式上下文中用於依賴注入。
將資料載入向量儲存的一般用法是您在類似批次的工作中執行的操作,方法是先將資料載入 Spring AI 的 Document
類別,然後呼叫 save
方法。
給定一個 String
參考,指向表示包含我們要載入向量資料庫之資料的 JSON 檔案的來源檔案,我們使用 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 = <question from user>
List<Document> similarDocuments = store.similaritySearch(this.question);
其他選項可以傳遞到 similaritySearch
方法中,以定義要檢索多少文件以及相似性搜尋的閾值。
Metadata 篩選器
本節介紹您可以針對查詢結果使用的各種篩選器。
篩選器字串
您可以將類似 SQL 的篩選器表達式作為 String
傳遞到其中一個 similaritySearch
多載。
考慮以下範例
-
"country == 'BG'"
-
"genre == 'drama' && year >= 2020"
-
"genre in ['comedy', 'documentary', 'drama']"
Filter.Expression
您可以使用 FilterExpressionBuilder
建立 Filter.Expression
的實例,該建構器公開了流暢的 API。一個簡單的範例如下
FilterExpressionBuilder b = new FilterExpressionBuilder();
Expression expression = this.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();