檢索增強生成
檢索增強生成(Retrieval Augmented Generation, RAG)是一種有用的技術,用於克服大型語言模型在長篇內容、事實準確性和上下文感知方面的侷限性。
Spring AI 透過提供模組化架構來支援 RAG,該架構允許您自行構建自定義 RAG 流,或使用 Advisor API 使用開箱即用的 RAG 流。
| 在概念部分了解有關檢索增強生成的更多資訊。 |
Advisor
Spring AI 使用 Advisor API 為常見的 RAG 流提供開箱即用的支援。
要使用 QuestionAnswerAdvisor 或 VectorStoreChatMemoryAdvisor,您需要在專案中新增 spring-ai-advisors-vector-store 依賴。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
QuestionAnswerAdvisor
向量資料庫儲存 AI 模型不知道的資料。當用戶問題傳送到 AI 模型時,QuestionAnswerAdvisor 會查詢向量資料庫以獲取與使用者問題相關的文件。
向量資料庫的響應會附加到使用者文字中,為 AI 模型生成響應提供上下文。
假設您已經將資料載入到 VectorStore 中,您可以透過向 ChatClient 提供 QuestionAnswerAdvisor 例項來執行檢索增強生成(RAG)。
ChatResponse response = ChatClient.builder(chatModel)
.build().prompt()
.advisors(QuestionAnswerAdvisor.builder(vectorStore).build())
.user(userText)
.call()
.chatResponse();
在此示例中,QuestionAnswerAdvisor 將對向量資料庫中的所有文件執行相似性搜尋。為了限制搜尋的文件型別,SearchRequest 接受一個類似 SQL 的過濾表示式,該表示式在所有 VectorStore 中都是可移植的。
此過濾表示式可以在建立 QuestionAnswerAdvisor 時配置,因此它將始終適用於所有 ChatClient 請求,或者可以在執行時根據每個請求提供。
以下是如何建立 QuestionAnswerAdvisor 例項,其中閾值為 0.8 並返回前 6 個結果。
var qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build())
.build();
動態過濾表示式
使用 FILTER_EXPRESSION advisor 上下文引數在執行時更新 SearchRequest 過濾表示式。
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().build())
.build())
.build();
// Update filter expression at runtime
String content = this.chatClient.prompt()
.user("Please answer my question XYZ")
.advisors(a -> a.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "type == 'Spring'"))
.call()
.content();
FILTER_EXPRESSION 引數允許您根據提供的表示式動態過濾搜尋結果。
自定義模板
QuestionAnswerAdvisor 使用預設模板來使用檢索到的文件增強使用者問題。您可以透過 .promptTemplate() 構建器方法提供自己的 PromptTemplate 物件來定製此行為。
此處提供的 PromptTemplate 自定義了 advisor 如何將檢索到的上下文與使用者查詢合併。這與在 ChatClient 本身(使用 .templateRenderer())上配置 TemplateRenderer 不同,後者會影響 advisor 執行**之前**初始使用者/系統提示內容的渲染。有關客戶端級別模板渲染的更多詳細資訊,請參閱ChatClient 提示模板。 |
自定義 PromptTemplate 可以使用任何 TemplateRenderer 實現(預設情況下,它使用基於 StringTemplate 引擎的 StPromptTemplate)。重要的要求是模板必須包含以下兩個佔位符。
-
一個
query佔位符,用於接收使用者問題。 -
一個
question_answer_context佔位符用於接收檢索到的上下文。
PromptTemplate customPromptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
<query>
Context information is below.
---------------------
<question_answer_context>
---------------------
Given the context information and no prior knowledge, answer the query.
Follow these rules:
1. If the answer is not in the context, just say that you don't know.
2. Avoid statements like "Based on the context..." or "The provided information...".
""")
.build();
String question = "Where does the adventure of Anacletus and Birba take place?";
QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.promptTemplate(customPromptTemplate)
.build();
String response = ChatClient.builder(chatModel).build()
.prompt(question)
.advisors(qaAdvisor)
.call()
.content();
QuestionAnswerAdvisor.Builder.userTextAdvise() 方法已棄用,取而代之的是使用 .promptTemplate() 以實現更靈活的自定義。 |
RetrievalAugmentationAdvisor
Spring AI 包含一個RAG 模組庫,您可以用於構建自己的 RAG 流。RetrievalAugmentationAdvisor 是一個 Advisor,它基於模組化架構為最常見的 RAG 流提供開箱即用的實現。
要使用 RetrievalAugmentationAdvisor,您需要將 spring-ai-rag 依賴項新增到您的專案中。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
順序 RAG 流
樸素 RAG
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.similarityThreshold(0.50)
.vectorStore(vectorStore)
.build())
.build();
String answer = chatClient.prompt()
.advisors(retrievalAugmentationAdvisor)
.user(question)
.call()
.content();
預設情況下,RetrievalAugmentationAdvisor 不允許檢索到的上下文為空。當這種情況發生時,它會指示模型不回答使用者查詢。您可以按如下方式允許空上下文。
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.similarityThreshold(0.50)
.vectorStore(vectorStore)
.build())
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(true)
.build())
.build();
String answer = chatClient.prompt()
.advisors(retrievalAugmentationAdvisor)
.user(question)
.call()
.content();
VectorStoreDocumentRetriever 接受一個 FilterExpression 以根據元資料過濾搜尋結果。您可以在例項化 VectorStoreDocumentRetriever 時提供一個,或者在執行時透過 FILTER_EXPRESSION advisor 上下文引數為每個請求提供。
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.similarityThreshold(0.50)
.vectorStore(vectorStore)
.build())
.build();
String answer = chatClient.prompt()
.advisors(retrievalAugmentationAdvisor)
.advisors(a -> a.param(VectorStoreDocumentRetriever.FILTER_EXPRESSION, "type == 'Spring'"))
.user(question)
.call()
.content();
有關更多資訊,請參閱VectorStoreDocumentRetriever。
高階 RAG
Advisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.queryTransformers(RewriteQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder.build().mutate())
.build())
.documentRetriever(VectorStoreDocumentRetriever.builder()
.similarityThreshold(0.50)
.vectorStore(vectorStore)
.build())
.build();
String answer = chatClient.prompt()
.advisors(retrievalAugmentationAdvisor)
.user(question)
.call()
.content();
您還可以使用 DocumentPostProcessor API 在將檢索到的文件傳遞給模型之前對其進行後處理。例如,您可以使用這樣的介面根據文件與查詢的相關性對其進行重新排名,刪除不相關或冗餘的文件,或壓縮每個文件的內容以減少噪聲和冗餘。
模組
Spring AI 實現了模組化 RAG 架構,其靈感來自論文“模組化 RAG:將 RAG 系統轉變為樂高式可重構框架”中詳述的模組化概念。
預檢索
預檢索模組負責處理使用者查詢以獲得最佳檢索結果。
查詢轉換
一個用於轉換輸入查詢的元件,使其更有效地用於檢索任務,解決諸如格式不良的查詢、模糊的術語、複雜的詞彙或不支援的語言等挑戰。
在使用 QueryTransformer 時,建議將 ChatClient.Builder 配置為低溫度(例如 0.0),以確保更確定和準確的結果,從而提高檢索質量。大多數聊天模型的預設溫度通常過高,不利於最佳查詢轉換,從而降低檢索效率。 |
CompressionQueryTransformer
CompressionQueryTransformer 使用大型語言模型將對話歷史記錄和後續查詢壓縮成一個獨立的查詢,該查詢捕獲了對話的精髓。
當對話歷史記錄很長且後續查詢與對話上下文相關時,此轉換器非常有用。
Query query = Query.builder()
.text("And what is its second largest city?")
.history(new UserMessage("What is the capital of Denmark?"),
new AssistantMessage("Copenhagen is the capital of Denmark."))
.build();
QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder)
.build();
Query transformedQuery = queryTransformer.transform(query);
此元件使用的提示可以透過構建器中可用的 promptTemplate() 方法進行自定義。
RewriteQueryTransformer
RewriteQueryTransformer 使用大型語言模型重寫使用者查詢,以便在查詢目標系統(例如向量儲存或網路搜尋引擎)時提供更好的結果。
當用戶查詢冗長、模糊或包含可能影響搜尋結果質量的不相關資訊時,此轉換器非常有用。
Query query = new Query("I'm studying machine learning. What is an LLM?");
QueryTransformer queryTransformer = RewriteQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder)
.build();
Query transformedQuery = queryTransformer.transform(query);
此元件使用的提示可以透過構建器中可用的 promptTemplate() 方法進行自定義。
TranslationQueryTransformer
TranslationQueryTransformer 使用大型語言模型將查詢翻譯成嵌入模型用於生成文件嵌入的目標語言。如果查詢已經使用目標語言,則原樣返回。如果查詢的語言未知,也原樣返回。
當嵌入模型使用特定語言進行訓練而使用者查詢使用不同語言時,此轉換器非常有用。
Query query = new Query("Hvad er Danmarks hovedstad?");
QueryTransformer queryTransformer = TranslationQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder)
.targetLanguage("english")
.build();
Query transformedQuery = queryTransformer.transform(query);
此元件使用的提示可以透過構建器中可用的 promptTemplate() 方法進行自定義。
查詢擴充套件
一個用於將輸入查詢擴充套件為查詢列表的元件,透過提供替代查詢形式或將複雜問題分解為更簡單的子查詢來解決格式不良查詢等挑戰。
MultiQueryExpander
MultiQueryExpander 使用大型語言模型將查詢擴充套件為多個語義多樣化的變體,以捕捉不同的視角,這對於檢索額外的上下文資訊和增加找到相關結果的機會非常有用。
MultiQueryExpander queryExpander = MultiQueryExpander.builder()
.chatClientBuilder(chatClientBuilder)
.numberOfQueries(3)
.build();
List<Query> queries = queryExpander.expand(new Query("How to run a Spring Boot app?"));
預設情況下,MultiQueryExpander 將原始查詢包含在擴充套件查詢列表中。您可以透過構建器中的 includeOriginal 方法停用此行為。
MultiQueryExpander queryExpander = MultiQueryExpander.builder()
.chatClientBuilder(chatClientBuilder)
.includeOriginal(false)
.build();
此元件使用的提示可以透過構建器中可用的 promptTemplate() 方法進行自定義。
檢索
檢索模組負責查詢向量儲存等資料系統並檢索最相關的文件。
文件搜尋
負責從底層資料來源(例如搜尋引擎、向量儲存、資料庫或知識圖)檢索 Documents 的元件。
VectorStoreDocumentRetriever
VectorStoreDocumentRetriever 從向量儲存中檢索與輸入查詢語義相似的文件。它支援基於元資料、相似性閾值和 top-k 結果進行過濾。
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.73)
.topK(5)
.filterExpression(new FilterExpressionBuilder()
.eq("genre", "fairytale")
.build())
.build();
List<Document> documents = retriever.retrieve(new Query("What is the main character of the story?"));
過濾表示式可以是靜態的或動態的。對於動態過濾表示式,您可以傳遞一個 Supplier。
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.filterExpression(() -> new FilterExpressionBuilder()
.eq("tenant", TenantContextHolder.getTenantIdentifier())
.build())
.build();
List<Document> documents = retriever.retrieve(new Query("What are the KPIs for the next semester?"));
您還可以透過 Query API,使用 FILTER_EXPRESSION 引數提供請求特定的過濾表示式。如果同時提供了請求特定和檢索器特定的過濾表示式,則請求特定的過濾表示式優先。
Query query = Query.builder()
.text("Who is Anacletus?")
.context(Map.of(VectorStoreDocumentRetriever.FILTER_EXPRESSION, "location == 'Whispering Woods'"))
.build();
List<Document> retrievedDocuments = documentRetriever.retrieve(query);
文件合併
一個元件,用於將基於多個查詢和來自多個數據源檢索到的文件合併成一個文件集合。作為合併過程的一部分,它還可以處理重複文件和互惠排名策略。
ConcatenationDocumentJoiner
ConcatenationDocumentJoiner 透過將基於多個查詢和來自多個數據源檢索到的文件連線成一個文件集合來合併它們。如果存在重複文件,則保留第一個出現的文件。每個文件的得分保持不變。
Map<Query, List<List<Document>>> documentsForQuery = ...
DocumentJoiner documentJoiner = new ConcatenationDocumentJoiner();
List<Document> documents = documentJoiner.join(documentsForQuery);
生成
生成模組負責根據使用者查詢和檢索到的文件生成最終響應。
查詢增強
一個元件,用於使用額外資料增強輸入查詢,這對於為大型語言模型提供必要的上下文以回答使用者查詢非常有用。
ContextualQueryAugmenter
ContextualQueryAugmenter 使用提供文件內容中的上下文資料增強使用者查詢。
QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().build();
預設情況下,ContextualQueryAugmenter 不允許檢索到的上下文為空。當這種情況發生時,它會指示模型不回答使用者查詢。
您可以啟用 allowEmptyContext 選項,以允許模型即使在檢索到的上下文為空時也能生成響應。
QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder()
.allowEmptyContext(true)
.build();
此元件使用的提示可以透過構建器中可用的 promptTemplate() 和 emptyContextPromptTemplate() 方法進行自定義。