检索增强生成
检索增强生成 (RAG) 是一种有助于克服大型语言模型局限性的技术 在长篇内容、事实准确性和上下文意识方面遇到困难。
Spring AI 通过提供模块化架构来支持 RAG,允许您自己构建自定义 RAG 流
或使用Advisor
应用程序接口。
在概念部分了解有关检索增强生成的更多信息。 |
顾问
Spring AI 使用Advisor
应用程序接口。
要使用QuestionAnswerAdvisor
或VectorStoreChatMemoryAdvisor
,您需要添加spring-ai-advisors-vector-store
对项目的依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
问题答案顾问
矢量数据库存储 AI 模型不知道的数据。当用户问题发送到 AI 模型时,一个QuestionAnswerAdvisor
在向量数据库中查询与用户问题相关的文档。
来自向量数据库的响应被附加到用户文本中,为 AI 模型生成响应提供上下文。
假设您已经将数据加载到VectorStore
,您可以通过提供QuestionAnswerAdvisor
到ChatClient
.
ChatResponse response = ChatClient.builder(chatModel)
.build().prompt()
.advisors(new QuestionAnswerAdvisor(vectorStore))
.user(userText)
.call()
.chatResponse();
在此示例中,QuestionAnswerAdvisor
将对矢量数据库中的所有文档执行相似性搜索。要限制要搜索的文档类型,请SearchRequest
采用类似 SQL 的过滤器表达式,该表达式可在所有VectorStores
.
可以在创建QuestionAnswerAdvisor
因此,将始终适用于所有ChatClient
请求,也可以在运行时为每个请求提供。
以下是创建QuestionAnswerAdvisor
其中阈值为0.8
并返回顶部6
结果。
var qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build())
.build();
动态过滤器表达式
更新SearchRequest
filter 表达式,在运行时使用FILTER_EXPRESSION
advisor 上下文参数:
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()
builder 方法。
这PromptTemplate 此处提供的自定义顾问如何将检索到的上下文与用户查询合并。这不同于配置TemplateRenderer 在ChatClient 本身(使用.templateRenderer() ),这会影响顾问运行前初始用户/系统提示内容的呈现。有关客户端级模板渲染的更多详细信息,请参阅 ChatClient 提示模板。 |
自定义PromptTemplate
可以使用任何TemplateRenderer
实现(默认情况下,它使用StPromptTemplate
基于 StringTemplate 引擎)。重要的要求是模板必须包含以下两个占位符:
-
一个
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() 实现更灵活的定制。 |
检索增强顾问
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
使用大型语言模型压缩对话历史记录和后续查询
转换为捕获对话本质的独立查询。
当对话历史记录很长且后续查询相关时,此转换器非常有用 到对话上下文。
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
使用大型语言模型重写用户查询,以便在以下情况下提供更好的结果
查询目标系统,例如矢量存储或 Web 搜索引擎。
当用户查询冗长、模棱两可或包含不相关的信息时,此转换器非常有用 这可能会影响搜索结果的质量。
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
使用大型语言模型将查询翻译成受支持的目标语言
通过用于生成文档嵌入的嵌入模型。如果查询已使用目标语言,
它原封不动地返回。如果查询的语言未知,则也返回原封不动的语言。
当嵌入模型在特定语言上进行训练并且用户查询使用不同的语言时,此转换器非常有用。
Query query = new Query("Hvad er Danmarks hovedstad?");
QueryTransformer queryTransformer = TranslationQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder)
.targetLanguage("english")
.build();
Query transformedQuery = queryTransformer.transform(query);
此组件使用的提示可以通过promptTemplate()
构建器中可用的方法。
查询扩展
用于将输入查询扩展为查询列表的组件,以解决格式错误的查询等挑战通过提供替代查询公式,或将复杂问题分解为更简单的子查询。
MultiQuery扩展器
一个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
来自底层数据源,例如搜索引擎、矢量存储、
数据库或知识图谱。
VectorStore文档检索器
一个VectorStoreDocumentRetriever
从向量存储中检索语义上与输入相似的文档
查询。它支持基于元数据、相似性阈值和前 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);
生成
生成模块负责根据用户查询和检索到的文档生成最终响应。
查询扩充
用于使用附加数据扩充输入查询的组件,可用于提供大型语言模型 具有回答用户查询的必要上下文。
上下文查询增强器
这ContextualQueryAugmenter
使用所提供文档内容中的上下文数据来增强用户查询。
QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder().build();
默认情况下,ContextualQueryAugmenter
不允许检索到的上下文为空。发生这种情况时,它指示模型不要回答用户查询。
您可以启用allowEmptyContext
选项,以允许模型生成响应,即使检索到的上下文为空。
QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder()
.allowEmptyContext(true)
.build();
此组件使用的提示可以通过promptTemplate()
和emptyContextPromptTemplate()
方法
在构建器中可用。