Spring AI Retrieval Augmented Generation (RAG)

Spring AI Retrieval Augmented Generation (RAG)
检索增强生成检索增强生成RAG是一种有助于克服大语言模型在处理长文本、事实准确性和上下文感知方面局限性的技术。Spring AI通过提供模块化架构来支持RAG您可以使用该架构构建自定义的RAG流程或使用Advisor API开箱即用的RAG流程。在概念部分了解更多关于检索增强生成的信息。AdvisorSpring AI使用Advisor API为常见的RAG流程提供开箱即用的支持。要使用QuestionAnswerAdvisor或VectorStoreChatMemoryAdvisor您需要在项目中添加spring-ai-vector-store-advisor依赖dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-vector-store-advisor/artifactId/dependencyQuestionAnswerAdvisor向量数据库存储了AI模型不知道的数据。当用户问题被发送到AI模型时QuestionAnswerAdvisor会查询向量数据库获取与用户问题相关的文档。向量数据库的响应会被追加到用户文本中为AI模型生成响应提供上下文。假设您已经将数据加载到VectorStore中您可以通过向ChatClient提供QuestionAnswerAdvisor实例来执行检索增强生成RAG。ChatResponseresponseChatClient.builder(chatModel).build().prompt().advisors(QuestionAnswerAdvisor.builder(vectorStore).build()).user(userText).call().chatResponse();在此示例中QuestionAnswerAdvisor将对向量数据库中的所有文档执行相似性搜索。要限制搜索的文档类型SearchRequest接受一个类似SQL的过滤表达式该表达式在所有VectorStore中都是可移植的。这个过滤表达式可以在创建QuestionAnswerAdvisor时配置因此将始终应用于所有ChatClient请求或者可以在每个请求的运行时提供。以下是创建QuestionAnswerAdvisor实例的方法其中阈值为0.8返回前6个结果。varqaAdvisorQuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build()).build();动态过滤表达式使用FILTER_EXPRESSION advisor上下文参数在运行时更新SearchRequest过滤表达式ChatClientchatClientChatClient.builder(chatModel).defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().build()).build()).build();// 在运行时更新过滤表达式Stringcontentthis.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占位符用于接收检索到的上下文。PromptTemplatecustomPromptTemplatePromptTemplate.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 dont know. 2. Avoid statements like Based on the context... or The provided information.... ).build();StringquestionWhere does the adventure of Anacletus and Birba take place?;QuestionAnswerAdvisorqaAdvisorQuestionAnswerAdvisor.builder(vectorStore).promptTemplate(customPromptTemplate).build();StringresponseChatClient.builder(chatModel).build().prompt(question).advisors(qaAdvisor).call().content();QuestionAnswerAdvisor.Builder.userTextAdvise()方法已被弃用推荐使用.promptTemplate()进行更灵活的自定义。RetrievalAugmentationAdvisorSpring AI包含一个RAG模块库您可以使用它们构建自己的RAG流程。RetrievalAugmentationAdvisor是一个Advisor基于模块化架构为最常见的RAG流程提供开箱即用的实现。要使用RetrievalAugmentationAdvisor您需要在项目中添加spring-ai-rag依赖dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-rag/artifactId/dependency顺序RAG流程基础RAGAdvisorretrievalAugmentationAdvisorRetrievalAugmentationAdvisor.builder().documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.50).vectorStore(vectorStore).build()).build();StringanswerchatClient.prompt().advisors(retrievalAugmentationAdvisor).user(question).call().content();默认情况下RetrievalAugmentationAdvisor不允许检索到的上下文为空。当发生这种情况时它会指示模型不要回答用户查询。您可以按如下方式允许空上下文。AdvisorretrievalAugmentationAdvisorRetrievalAugmentationAdvisor.builder().documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.50).vectorStore(vectorStore).build()).queryAugmenter(ContextualQueryAugmenter.builder().allowEmptyContext(true).build()).build();StringanswerchatClient.prompt().advisors(retrievalAugmentationAdvisor).user(question).call().content();VectorStoreDocumentRetriever接受一个FilterExpression用于根据元数据过滤搜索结果。您可以在实例化VectorStoreDocumentRetriever时提供一个或在每个请求的运行时使用FILTER_EXPRESSION advisor上下文参数提供。AdvisorretrievalAugmentationAdvisorRetrievalAugmentationAdvisor.builder().documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.50).vectorStore(vectorStore).build()).build();StringanswerchatClient.prompt().advisors(retrievalAugmentationAdvisor).advisors(a-a.param(VectorStoreDocumentRetriever.FILTER_EXPRESSION,type Spring)).user(question).call().content();请参阅VectorStoreDocumentRetriever了解更多信息。高级RAGAdvisorretrievalAugmentationAdvisorRetrievalAugmentationAdvisor.builder().queryTransformers(RewriteQueryTransformer.builder().chatClientBuilder(chatClientBuilder.build().mutate()).build()).documentRetriever(VectorStoreDocumentRetriever.builder().similarityThreshold(0.50).vectorStore(vectorStore).build()).build();StringanswerchatClient.prompt().advisors(retrievalAugmentationAdvisor).user(question).call().content();您还可以使用DocumentPostProcessor API在将检索到的文档传递给模型之前对其进行后处理。例如您可以使用此类接口根据文档与查询的相关性进行重新排序删除不相关或冗余的文档或压缩每个文档的内容以减少噪声和冗余。模块Spring AI实现了模块化RAG架构其灵感来自论文《模块化RAG将RAG系统转变为类似乐高的可重构框架》中详述的模块化概念。检索前检索前模块负责处理用户查询以获得最佳的检索结果。查询转换用于转换输入查询的组件使其更有效地用于检索任务解决查询格式不佳、术语模糊、词汇复杂或不支持的语言等挑战。使用QueryTransformer时建议将ChatClient.Builder配置为较低的温度例如0.0以确保更确定性和准确的结果提高检索质量。大多数聊天模型的默认温度通常对于最佳的查询转换来说过高导致检索效果降低。CompressionQueryTransformerCompressionQueryTransformer使用大语言模型将对话历史和后续查询压缩成一个独立查询该查询捕捉对话的要点。当对话历史较长且后续查询与对话上下文相关时此转换器非常有用。QueryqueryQuery.builder().text(And what is its second largest city?).history(newUserMessage(What is the capital of Denmark?),newAssistantMessage(Copenhagen is the capital of Denmark.)).build();QueryTransformerqueryTransformerCompressionQueryTransformer.builder().chatClientBuilder(chatClientBuilder).build();QuerytransformedQueryqueryTransformer.transform(query);此组件使用的提示可以通过构建器中的promptTemplate()方法进行自定义。RewriteQueryTransformerRewriteQueryTransformer使用大语言模型重写用户查询以便在查询目标系统如向量存储或网络搜索引擎时提供更好的结果。当用户查询冗长、模糊或包含可能影响搜索结果质量的不相关信息时此转换器非常有用。QueryquerynewQuery(Im studying machine learning. What is an LLM?);QueryTransformerqueryTransformerRewriteQueryTransformer.builder().chatClientBuilder(chatClientBuilder).build();QuerytransformedQueryqueryTransformer.transform(query);此组件使用的提示可以通过构建器中的promptTemplate()方法进行自定义。TranslationQueryTransformerTranslationQueryTransformer使用大语言模型将查询翻译为目标语言该语言由用于生成文档嵌入的嵌入模型支持。如果查询已经是目标语言则保持不变。如果查询的语言未知也保持不变。当嵌入模型在特定语言上训练而用户查询使用不同语言时此转换器非常有用。QueryquerynewQuery(Hvad er Danmarks hovedstad?);QueryTransformerqueryTransformerTranslationQueryTransformer.builder().chatClientBuilder(chatClientBuilder).targetLanguage(english).build();QuerytransformedQueryqueryTransformer.transform(query);此组件使用的提示可以通过构建器中的promptTemplate()方法进行自定义。查询扩展用于将输入查询扩展为查询列表的组件通过提供替代查询表述或通过将复杂问题分解为更简单的子查询来解决查询格式不佳等挑战。MultiQueryExpanderMultiQueryExpander使用大语言模型将查询扩展为多个语义多样的变体以捕获不同的视角有助于检索额外的上下文信息并增加找到相关结果的机会。MultiQueryExpanderqueryExpanderMultiQueryExpander.builder().chatClientBuilder(chatClientBuilder).numberOfQueries(3).build();ListQueryqueriesqueryExpander.expand(newQuery(How to run a Spring Boot app?));默认情况下MultiQueryExpander在扩展查询列表中包含原始查询。您可以通过构建器中的includeOriginal方法禁用此行为。MultiQueryExpanderqueryExpanderMultiQueryExpander.builder().chatClientBuilder(chatClientBuilder).includeOriginal(false).build();此组件使用的提示可以通过构建器中的promptTemplate()方法进行自定义。检索检索模块负责查询数据系统如向量存储并检索最相关的文档。文档搜索负责从底层数据源如搜索引擎、向量存储、数据库或知识图谱检索文档的组件。VectorStoreDocumentRetrieverVectorStoreDocumentRetriever从向量存储中检索与输入查询语义相似的文档。它支持基于元数据的过滤、相似性阈值和top-k结果。DocumentRetrieverretrieverVectorStoreDocumentRetriever.builder().vectorStore(vectorStore).similarityThreshold(0.73).topK(5).filterExpression(newFilterExpressionBuilder().eq(genre,fairytale).build()).build();ListDocumentdocumentsretriever.retrieve(newQuery(What is the main character of the story?));过滤表达式可以是静态的或动态的。对于动态过滤表达式您可以传入一个Supplier。DocumentRetrieverretrieverVectorStoreDocumentRetriever.builder().vectorStore(vectorStore).filterExpression(()-newFilterExpressionBuilder().eq(tenant,TenantContextHolder.getTenantIdentifier()).build()).build();ListDocumentdocumentsretriever.retrieve(newQuery(What are the KPIs for the next semester?));您还可以通过Query API提供请求特定的过滤表达式使用FILTER_EXPRESSION参数。如果同时提供了请求特定和检索器特定的过滤表达式则请求特定的过滤表达式优先。QueryqueryQuery.builder().text(Who is Anacletus?).context(Map.of(VectorStoreDocumentRetriever.FILTER_EXPRESSION,location Whispering Woods)).build();ListDocumentretrievedDocumentsdocumentRetriever.retrieve(query);文档连接用于将基于多个查询和从多个数据源检索到的文档组合成单个文档集合的组件。在连接过程中它还可以处理重复文档和互惠排名策略。ConcatenationDocumentJoinerConcatenationDocumentJoiner通过将基于多个查询和从多个数据源检索到的文档连接成单个集合来组合它们。在重复文档的情况下保留第一次出现的文档。每个文档的分数保持不变。MapQuery,ListListDocumentdocumentsForQuery...DocumentJoinerdocumentJoinernewConcatenationDocumentJoiner();ListDocumentdocumentsdocumentJoiner.join(documentsForQuery);检索后检索后模块负责处理检索到的文档以获得最佳的生成结果。文档后处理用于根据查询后处理检索到的文档的组件解决诸如中间丢失、模型的上下文长度限制以及减少检索信息中的噪声和冗余等挑战。例如它可以根据文档与查询的相关性对文档进行排名删除不相关或冗余的文档或压缩每个文档的内容以减少噪声和冗余。生成生成模块负责根据用户查询和检索到的文档生成最终响应。查询增强用于使用额外数据增强输入查询的组件有助于为大语言模型提供回答用户查询所需的上下文。ContextualQueryAugmenterContextualQueryAugmenter使用所提供的文档内容中的上下文数据来增强用户查询。QueryAugmenterqueryAugmenterContextualQueryAugmenter.builder().build();默认情况下ContextualQueryAugmenter不允许检索到的上下文为空。当发生这种情况时它会指示模型不要回答用户查询。您可以启用allowEmptyContext选项允许模型即使在检索到的上下文为空时也能生成响应。QueryAugmenterqueryAugmenterContextualQueryAugmenter.builder().allowEmptyContext(true).build();此组件使用的提示可以通过构建器中的promptTemplate()和emptyContextPromptTemplate()方法进行自定义。