1、创建查询重写转换器
// 创建查询重写转换器
queryTransformer = RewriteQueryTransformer.builder()
.chatClientBuilder(openAiChatClient.mutate())
.build();
查询重写是RAG系统中的一个重要优化技术,它能够将用户的原始查询转换成更加结构化和明确的形式。这种转换可以提高检索的准确性,并帮助系统更好地理解用户的真实意图。
Spring AI提供了RewriteQueryTransformer
来实现查询重写功能。以下是一个具体的示例:
package com.alibaba.cloud.ai.example.chat.openai.controller;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.preretrieval.query.expansion.MultiQueryExpander;
import org.springframework.ai.rag.preretrieval.query.transformation.QueryTransformer;
import org.springframework.ai.rag.preretrieval.query.transformation.RewriteQueryTransformer;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* @Author: wst
* @Date: 2024-12-16
*/
@RestController
@RequestMapping("/rag")
public class RagController {
private final ChatClient openAiChatClient;
private final ChatModel chatModel;
private final MultiQueryExpander queryExpander;
private final QueryTransformer queryTransformer;
public RagController(ChatModel chatModel) {
this.chatModel = chatModel;
// 创建聊天客户端实例
// 设置系统提示信息,定义AI助手作为专业的室内设计顾问角色
// 构造时,可以设置 ChatClient 的参数
// {@link org.springframework.ai.chat.client.ChatClient};
this.openAiChatClient = ChatClient.builder(chatModel)
.defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\n" +
"1. 准确理解用户的具体需求\n" +
"2. 结合参考资料中的实际案例\n" +
"3. 提供专业的设计理念和原理解释\n" +
"4. 考虑实用性、美观性和成本效益\n" +
"5. 如有需要,可以提供替代方案")
// 实现 Chat Memory 的 Advisor
// 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。
.defaultAdvisors(
new MessageChatMemoryAdvisor(new InMemoryChatMemory())
)
// 实现 Logger 的 Advisor
.defaultAdvisors(
new SimpleLoggerAdvisor()
)
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
OpenAiChatOptions.builder()
.topP(0.7)
.build()
)
.build();
// 构建查询扩展器
// 用于生成多个相关的查询变体,以获得更全面的搜索结果
queryExpander = MultiQueryExpander.builder()
.chatClientBuilder(openAiChatClient.mutate())
.includeOriginal(false) // 不包含原始查询
.numberOfQueries(3) // 生成3个查询变体
.build();
// 创建查询重写转换器
queryTransformer = RewriteQueryTransformer.builder()
.chatClientBuilder(openAiChatClient.mutate())
.build();
}
@GetMapping("/multiQuery")
public List<Query> multiQuery() {
// 执行查询扩展
// 将原始问题"请提供几种推荐的装修风格?"扩展成多个相关查询
List<Query> queries = queryExpander.expand(
new Query("请提供几种推荐的装修风格?"));
return queries;
}
@GetMapping("/rewriteQuery")
public String rewriteQuery( ) {
// 查询重写的主要优势:查询明确化:将模糊的问题转换为具体的查询点
//
//这种转换不仅有助于系统检索到更相关的文档,还能帮助生成更全面和专业的回答。
// 创建一个模拟用户学习AI的查询场景
Query query = new Query("我正在学习人工智能,什么是大语言模型?");
// 执行查询扩展
// 将原始问题"请提供几种推荐的装修风格?"扩展成多个相关查询
// 执行查询重写
Query transformedQuery = queryTransformer.transform(query);
String rewirte = transformedQuery.text();
// 输出重写后的查询
System.out.println(rewirte);
return rewirte;
}
}
重写后的查询可能会变成:
什么是大语言模型?
查询重写的主要优势:查询明确化:将模糊的问题转换为具体的查询点
这种转换不仅有助于系统检索到更相关的文档,还能帮助生成更全面和专业的回答
2、查询翻译
查询翻译是RAG系统中的一个实用功能,它能够将用户的查询从一种语言翻译成另一种语言。这对于多语言支持和跨语言检索特别有用。Spring AI提供了TranslationQueryTransformer
来实现这一功能。
// 创建查询翻译转换器,设置目标语言为中文
translationQueryTransformer = TranslationQueryTransformer.builder()
.chatClientBuilder(openAiChatClient.mutate())
.targetLanguage("chinese") // 设置目标语言为中文
.build();
完整代码
package com.alibaba.cloud.ai.example.chat.openai.controller;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.preretrieval.query.expansion.MultiQueryExpander;
import org.springframework.ai.rag.preretrieval.query.transformation.QueryTransformer;
import org.springframework.ai.rag.preretrieval.query.transformation.RewriteQueryTransformer;
import org.springframework.ai.rag.preretrieval.query.transformation.TranslationQueryTransformer;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* @Author: wst
* @Date: 2024-12-16
*/
@RestController
@RequestMapping("/rag")
public class RagController {
private final ChatClient openAiChatClient;
private final ChatModel chatModel;
private final MultiQueryExpander queryExpander;
private final QueryTransformer queryTransformer;
private QueryTransformer translationQueryTransformer;
public RagController(ChatModel chatModel) {
this.chatModel = chatModel;
// 创建聊天客户端实例
// 设置系统提示信息,定义AI助手作为专业的室内设计顾问角色
// 构造时,可以设置 ChatClient 的参数
// {@link org.springframework.ai.chat.client.ChatClient};
this.openAiChatClient = ChatClient.builder(chatModel)
.defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\n" +
"1. 准确理解用户的具体需求\n" +
"2. 结合参考资料中的实际案例\n" +
"3. 提供专业的设计理念和原理解释\n" +
"4. 考虑实用性、美观性和成本效益\n" +
"5. 如有需要,可以提供替代方案")
// 实现 Chat Memory 的 Advisor
// 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。
.defaultAdvisors(
new MessageChatMemoryAdvisor(new InMemoryChatMemory())
)
// 实现 Logger 的 Advisor
.defaultAdvisors(
new SimpleLoggerAdvisor()
)
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
OpenAiChatOptions.builder()
.topP(0.7)
.build()
)
.build();
// 构建查询扩展器
// 用于生成多个相关的查询变体,以获得更全面的搜索结果
queryExpander = MultiQueryExpander.builder()
.chatClientBuilder(openAiChatClient.mutate())
.includeOriginal(false) // 不包含原始查询
.numberOfQueries(3) // 生成3个查询变体
.build();
// 创建查询重写转换器
queryTransformer = RewriteQueryTransformer.builder()
.chatClientBuilder(openAiChatClient.mutate())
.build();
// 创建查询翻译转换器,设置目标语言为中文
translationQueryTransformer = TranslationQueryTransformer.builder()
.chatClientBuilder(openAiChatClient.mutate())
.targetLanguage("chinese") // 设置目标语言为中文
.build();
}
@GetMapping("/multiQuery")
public List<Query> multiQuery() {
// 执行查询扩展
// 将原始问题"请提供几种推荐的装修风格?"扩展成多个相关查询
List<Query> queries = queryExpander.expand(
new Query("请提供几种推荐的装修风格?"));
return queries;
}
@GetMapping("/rewriteQuery")
public String rewriteQuery( ) {
// 查询重写的主要优势:查询明确化:将模糊的问题转换为具体的查询点
//
//这种转换不仅有助于系统检索到更相关的文档,还能帮助生成更全面和专业的回答。
// 创建一个模拟用户学习AI的查询场景
Query query = new Query("我正在学习人工智能,什么是大语言模型?");
// 执行查询扩展
// 将原始问题"请提供几种推荐的装修风格?"扩展成多个相关查询
// 执行查询重写
Query transformedQuery = queryTransformer.transform(query);
String rewirte = transformedQuery.text();
// 输出重写后的查询
System.out.println(rewirte);
return rewirte;
}
@GetMapping("/translationQuery")
public String translationQuery( ) {
Query query = new Query("What is LLM?");
// 执行查询翻译
Query transformedQuery = translationQueryTransformer.transform(query);
// 输出翻译后的查询
String transforme = transformedQuery.text();
System.out.println(transforme);
return transforme;
}
}
查询翻译的主要优势:
- 多语言支持:支持不同语言之间的查询转换
- 本地化处理:将查询转换为目标语言的自然表达方式
- 跨语言检索:支持在不同语言的文档中进行检索
- 用户友好:允许用户使用自己熟悉的语言进行查询
Document Selection (文档选择)
在理解了检索增强顾问的基础上,我们来看看更复杂的文档选择机制。文档选择是RAG系统的核心组件之一,它决定了系统能够为用户提供多么准确和相关的信息。
3.7.1 文档结构设计
首先,让我们看一个结构良好的文档示例:
// 生成室内设计案例文档
List<Document> documents = new ArrayList<>();
// 现代简约风格客厅案例
documents.add(new Document(
"案例编号:LR-2023-001\n" +
"项目概述:180平米大平层现代简约风格客厅改造\n" +
"设计要点:\n" +
"1. 采用5.2米挑高的落地窗,最大化自然采光\n" +
"2. 主色调:云雾白(哑光,NCS S0500-N)配合莫兰迪灰\n" +
"3. 家具选择:意大利B&B品牌真皮沙发,北欧白橡木茶几\n" +
"4. 照明设计:嵌入式筒灯搭配意大利Flos吊灯\n" +
"5. 软装配饰:进口黑胡桃木电视墙,几何图案地毯\n" +
"空间效果:通透大气,适合商务接待和家庭日常起居",
Map.of(
"type", "interior", // 文档类型
"year", "2023", // 年份
"month", "06", // 月份
"location", "indoor", // 位置类型
"style", "modern", // 装修风格
"room", "living_room" // 房间类型
)));
每个文档包含两个主要部分:
- 文档内容:结构化的文本描述,包含项目编号、概述、详细信息等
- 元数据:用于快速筛选和分类的键值对,如类型、年份、位置等
3.7.2 高级检索实现
以下是一个完整的高级检索示例:
// 1. 初始化向量存储
SimpleVectorStore vectorStore = SimpleVectorStore.builder(embeddingModel)
.build();
// 2. 配置AI助手角色
ChatClient chatClient = builder
.defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\n" +
"1. 准确理解用户的具体需求\n" +
"2. 结合参考资料中的实际案例\n" +
"3. 提供专业的设计理念和原理解释\n" +
"4. 考虑实用性、美观性和成本效益\n" +
"5. 如有需要,可以提供替代方案")
.build();
// 3. 构建复杂的文档过滤条件
var b = new FilterExpressionBuilder();
var filterExpression = b.and(
b.and(
b.eq("year", "2023"), // 筛选2023年的案例
b.eq("location", "indoor")), // 仅选择室内案例
b.and(
b.eq("type", "interior"), // 类型为室内设计
b.in("room", "living_room", "study", "kitchen") // 指定房间类型
));
// 4. 配置文档检索器
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.5) // 设置相似度阈值
.topK(3) // 返回前3个最相关的文档
.filterExpression(filterExpression.build())
.build();
// 5. 创建上下文感知的查询增强器
Advisor advisor = RetrievalAugmentationAdvisor.builder()
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(true)
.build())
.documentRetriever(retriever)
.build();
// 6. 执行查询并获取响应
String userQuestion = "根据已经提供的资料,请描述所有相关的场景风格,输出案例编号,尽可能详细地描述其内容。";
String response = chatClient.prompt()
.user(userQuestion)
.advisors(advisor)
.call()
.content();
这个实现包含以下关键特性:
-
元数据过滤:
- 使用
FilterExpressionBuilder
构建复杂的过滤条件 - 支持精确匹配(eq)、范围查询(in)等多种过滤方式
- 可以组合多个条件(and/or)实现精确筛选
- 使用
-
相似度控制:
- 通过
similarityThreshold
设置相似度阈值(0.3) - 使用
topK
限制返回结果数量(3) - 确保只返回最相关的文档
- 通过
-
上下文感知:
- 集成
ContextualQueryAugmenter
实现上下文感知 - 允许空上下文查询(allowEmptyContext)
- 自动关联相关文档和查询上下文
- 集成
-
智能顾问集成:
- 使用
RetrievalAugmentationAdvisor
增强查询效果 - 自动整合文档检索和查询处理
- 提供更智能的响应生成
- 使用
通过这种多层次的文档选择机制,系统能够:
- 快速定位相关文档
- 准确评估文档相关性
- 智能组合多个信息源
- 生成高质量的回答