什么是检索增强生成(RAG)?
检索增强生成(Retrieval Augmented Generation,简称 RAG)是一种强大的技术,用于克服大型语言模型(LLM)在处理长文本内容、事实准确性和上下文感知方面的局限性。在实际应用中,AI 模型虽然具备强大的生成能力,但其训练数据往往存在时效性限制,且无法直接访问企业的私有文档或特定领域的专业知识。
Spring AI 提供了完整的 RAG 实现框架,通过模块化的架构设计,允许开发者既可以使用开箱即用的 Advisor API 快速构建 RAG 流程,也可以根据业务需求自定义个性化的检索增强方案。
Spring AI 中的 Advisor 架构
Spring AI 的 Advisor API 是实现 RAG 功能的核心组件。它提供了一种声明式的方式来增强聊天客户端的能力,使得文档检索与 AI 响应生成能够无缝协作。
要使用 QuestionAnswerAdvisor 或 VectorStoreChatMemoryAdvisor,首先需要在项目中添加以下依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
QuestionAnswerAdvisor 的工作原理
在深入了解 QuestionAnswerAdvisor 之前,我们需要理解向量数据库在 RAG 系统中的关键作用。向量数据库专门用于存储经过 embedding 处理的文档数据,这些数据对于 AI 模型来说是”未知”的外部知识。当用户提出问题时,系统会首先从向量数据库中检索与问题相关的文档,然后将这些文档作为上下文提供给 AI 模型,从而生成更加准确和基于事实的答案。
QuestionAnswerAdvisor 正是实现了这一流程的核心组件。假设你已经将数据加载到 VectorStore 中,可以使用以下代码实现 RAG:
ChatResponse response = ChatClient.builder(chatModel)
.build().prompt()
.advisors(QuestionAnswerAdvisor.builder(vectorStore).build())
.user(userText)
.call()
.chatResponse();
在上述示例中,QuestionAnswerAdvisor 会对向量数据库中的所有文档执行相似度搜索。如果需要限制搜索的文档范围,可以通过 SearchRequest 配置 SQL 风格的过滤表达式,这种表达式在不同的 VectorStore 实现之间具有良好的可移植性。
配置搜索阈值和返回数量
可以通过 SearchRequest 灵活配置相似度阈值和返回结果数量:
var qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build())
.build();
这里我们将相似度阈值设置为 0.8,表示只返回与用户问题高度相关的文档;同时设置 topK 为 6,即最多返回 6 条检索结果。这种配置方式可以帮助你在检索质量和响应速度之间取得平衡。
动态过滤表达式
有时我们需要在运行时动态调整过滤条件。Spring AI 提供了 FILTER_EXPRESSION 参数来实现这一功能:
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().build())
.build())
.build();
// 在运行时更新过滤表达式
String content = this.chatClient.prompt()
.user("请回答我的问题 XYZ")
.advisors(a -> a.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "type == 'Spring'"))
.call()
.content();
这种动态过滤机制特别适用于需要根据用户权限、场景或时间条件来限制搜索范围的场景。
自定义提示词模板
QuestionAnswerAdvisor 使用默认模板将检索到的文档与用户问题进行融合。如果你需要自定义这种行为,可以通过 .promptTemplate() 方法提供自己的 PromptTemplate:
PromptTemplate customPromptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
<query>
以下是相关上下文信息。
---------------------
<question_answer_context>
---------------------
根据提供的上下文信息回答问题,不要使用先验知识。
请遵循以下规则:
1. 如果答案不在上下文中,请明确说明不知道。
2. 避免使用"根据上下文..."或"提供的信息显示..."等表述。
""")
.build();
String question = "Anacletus 和 Birba 的冒险发生在哪里?";
QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.promptTemplate(customPromptTemplate)
.build();
String response = ChatClient.builder(chatModel).build()
.prompt(question)
.advisors(qaAdvisor)
.call()
.content();
需要注意的是,自定义模板必须包含两个占位符:query 用于接收用户问题,question_answer_context 用于接收检索到的上下文内容。
RetrievalAugmentationAdvisor 进阶使用
对于更复杂的 RAG 场景,Spring AI 提供了 RetrievalAugmentationAdvisor。要使用此组件,需要添加以下依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
基础 RAG 流程(Naive 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 不允许检索结果为空。当没有找到相关文档时,它会指示模型不要回答用户问题。如果希望允许空上下文,可以通过 ContextualQueryAugmenter 配置:
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 支持基于元数据的过滤表达式,你可以在实例化时配置或在运行时通过 FILTER_EXPRESSION 参数动态提供:
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();
高级 RAG 流程
高级 RAG 通过引入查询转换(Query Transformation)来优化检索效果。一个常见的场景是用户的原始问题可能表述不够清晰或包含歧义,这时可以先使用 LLM 对问题进行重写,使其更适合向量检索:
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 对检索到的文档进行后处理,例如执行文档重排序以提高相关性、去除无关或冗余的文档、压缩文档内容以减少噪音等。
模块化 RAG 架构
Spring AI 的 RAG 实现采用了模块化设计理念,灵感来源于论文《Modular RAG: Transforming RAG Systems into LEGO-like Reconfigurable Frameworks》。这种设计将 RAG 流程拆分为多个独立的模块,使得开发者可以根据具体需求灵活组合。
查询转换模块(Pre-Retrieval)
检索前模块负责处理用户查询,以获得最佳的检索效果。查询转换是一种常见的技术,用于解决查询表述不当、歧义术语、复杂词汇或不支持的语言等问题。
使用 QueryTransformer 时,建议在 ChatClient.Builder 中将温度参数设置为较低值(如 0.0),以确保结果更加确定性和准确。大多数聊天模型的默认温度对于查询转换任务来说过高,可能会降低检索效果。
压缩查询转换器(CompressionQueryTransformer)
CompressionQueryTransformer 使用大型语言模型将对话历史和后续问题压缩为一个独立的查询,从而捕捉对话的核心内容。这对于对话历史较长且后续问题与上下文相关的情况特别有用:
Query query = Query.builder()
.text("它的第二大城市是什么?")
.history(new UserMessage("丹麦的首都是哪里?"),
new AssistantMessage("哥本哈根是丹麦的首都。"))
.build();
QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
.chatClientBuilder(chatClientBuilder)
.build();
Query transformedQuery = queryTransformer.transform(query);
该组件使用的提示词模板可以通过 builder 的 promptTemplate() 方法进行自定义。
重写查询转换器(RewriteQueryTransformer)
RewriteQueryTransformer 使用大型语言模型对用户查询进行重写,以便在查询目标系统(如向量存储或网络搜索引擎)时获得更好的结果。
这种转换器在用户查询表述不够理想的情况下特别有价值,例如查询过于简短、包含口语化表达或缺乏必要的上下文信息时。
总结
本文详细介绍了 Spring AI 中检索增强生成(RAG)的完整实现方案。从基础的 QuestionAnswerAdvisor 到高级的 RetrievalAugmentationAdvisor,再到模块化的查询转换架构,Spring AI 提供了一套完整且灵活的工具体系。
在实际项目中选择合适的 RAG 方案时,建议根据业务需求进行评估:对于简单的场景,可以使用 QuestionAnswerAdvisor 快速实现;对于需要更多定制的场景,可以利用 RetrievalAugmentationAdvisor 的模块化架构进行组合;而对于处理复杂对话或需要查询优化的场景,则可以引入查询转换模块来提升检索质量。
RAG 技术的核心价值在于将 AI 的生成能力与私有知识库相结合,使企业能够构建既智能又可控的 AI 应用。通过合理使用 Spring AI 提供的这些工具,开发者可以快速构建生产级的 RAG 应用,同时保持代码的可维护性和可扩展性。