long-ai-agent/src/main/java/com/huangge1199/aiagent/Service/impl/RagServiceImpl.java

293 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.huangge1199.aiagent.Service.impl;
import com.huangge1199.aiagent.Service.RagService;
import com.huangge1199.aiagent.config.MyLoggerAdvisor;
import com.huangge1199.aiagent.rag.MyMultiQueryExpander;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.generation.augmentation.ContextualQueryAugmenter;
import org.springframework.ai.rag.preretrieval.query.transformation.CompressionQueryTransformer;
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.ai.rag.retrieval.search.DocumentRetriever;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* RagServiceImpl
*
* @author huangge1199
* @since 2025/5/24 9:21:38
*/
@Service
public class RagServiceImpl implements RagService {
@Resource
private ChatClient chatClient;
@Resource
private VectorStore vectorStore;
@Resource
private ChatModel ollamaChatModel;
@Resource
private EmbeddingModel ollamaEmbeddingModel;
@Override
public String localDoc(String question) {
return chatClient.prompt().user(question).advisors(new MyLoggerAdvisor()).advisors(new QuestionAnswerAdvisor(vectorStore)).call().content();
}
@Override
public List<Query> getMultiQueryExpand(String question) {
ChatClient.Builder builder = ChatClient.builder(ollamaChatModel);
ChatClient chatClient = builder.defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\n" + "1. 准确理解用户的具体需求\n" + "2. 结合参考资料中的实际案例\n" + "3. 提供专业的设计理念和原理解释\n" + "4. 考虑实用性、美观性和成本效益\n" + "5. 如有需要,可以提供替代方案").build();
// MultiQueryExpander queryExpander = MultiQueryExpander.builder()
MyMultiQueryExpander queryExpander = MyMultiQueryExpander.builder().chatClientBuilder(builder)
// 不包含原始查询
.includeOriginal(false)
// 生成3个查询变体
.numberOfQueries(4).build();
return queryExpander.expand(new Query(question));
}
@Override
public String queryRewrite(String question) {
ChatClient.Builder builder = ChatClient.builder(ollamaChatModel);
// 创建一个模拟用户学习AI的查询场景
Query query = new Query(question);
// 创建查询重写转换器
QueryTransformer queryTransformer = RewriteQueryTransformer.builder().chatClientBuilder(builder).build();
// 执行查询重写
Query transformedQuery = queryTransformer.transform(query);
return transformedQuery.text();
}
@Override
public String queryTranslation(String question) {
ChatClient.Builder builder = ChatClient.builder(ollamaChatModel);
// 创建一个英文查询
Query query = new Query(question);
// 创建查询翻译转换器,设置目标语言为中文
QueryTransformer queryTransformer = TranslationQueryTransformer.builder().chatClientBuilder(builder)
// 设置目标语言为中文
.targetLanguage("chinese").build();
// 执行查询翻译
Query transformedQuery = queryTransformer.transform(query);
// 输出翻译后的查询
return transformedQuery.text();
}
@Override
public String contextAwareQueries(String question) {
ChatClient.Builder builder = ChatClient.builder(ollamaChatModel);
// 构建带有历史上下文的查询
// 这个例子模拟了一个房地产咨询场景,用户先问小区位置,再问房价
Query query = Query.builder()
// 当前用户的提问
.text(question)
// 历史对话中用户的问题
.history(new UserMessage("深圳市南山区的碧海湾小区在哪里?"),
// AI的回答
new AssistantMessage("碧海湾小区位于深圳市南山区后海中心区,临近后海地铁站。")).build();
// 创建查询转换器
// QueryTransformer用于将带有上下文的查询转换为完整的独立查询
QueryTransformer queryTransformer = CompressionQueryTransformer.builder()
.chatClientBuilder(builder)
.build();
// 执行查询转换
// 将模糊的代词引用("这个小区")转换为明确的实体名称("碧海湾小区"
Query transformedQuery = queryTransformer.transform(query);
return transformedQuery.text();
}
@Override
public String baseAdvisor(String question) {
Advisor advisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.build())
.build();
return advisor(question, advisor);
}
@Override
public String advancedAdvisor(String question) {
Advisor advisor = RetrievalAugmentationAdvisor.builder()
// 配置查询增强器
.queryAugmenter(ContextualQueryAugmenter.builder()
// 允许空上下文查询
.allowEmptyContext(true)
.build())
// 配置文档检索器
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
// 相似度阈值
.similarityThreshold(0.5)
// 返回文档数量
.topK(3)
.filterExpression(new FilterExpressionBuilder()
.eq("genre", "fairytale")
.build()) // 文档过滤表达式
.build())
.build();
return advisor(question, advisor);
}
/**
* 检索增强顾问
*
* @param question 问题
* @param advisor 检索增强顾问
* @return 查询结果
*/
private String advisor(String question, Advisor advisor) {
// 1. 初始化向量存储
SimpleVectorStore vectorStore = SimpleVectorStore.builder(ollamaEmbeddingModel)
.build();
// 2. 添加文档到向量存储
List<Document> documents = List.of(
new Document("产品说明书:产品名称:智能机器人\n" +
"产品描述:智能机器人是一个智能设备,能够自动完成各种任务。\n" +
"功能:\n" +
"1. 自动导航:机器人能够自动导航到指定位置。\n" +
"2. 自动抓取:机器人能够自动抓取物品。\n" +
"3. 自动放置:机器人能够自动放置物品。\n"));
vectorStore.add(documents);
// 3. 创建检索增强顾问 advisor
// 4. 在聊天客户端中使用顾问
return chatClient.prompt()
.user(question)
// 添加检索增强顾问
.advisors(advisor)
.call()
.content();
}
@Override
public String documentSelection() {
ChatClient.Builder builder = ChatClient.builder(ollamaChatModel);
// 生成室内设计案例文档
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"
)
));
// 1. 初始化向量存储
SimpleVectorStore vectorStore = SimpleVectorStore.builder(ollamaEmbeddingModel)
.build();
// 2. 配置AI助手角色
ChatClient chatClient = builder
.defaultSystem("你是一位专业的室内设计顾问,精通各种装修风格、材料选择和空间布局。请基于提供的参考资料,为用户提供专业、详细且实用的建议。在回答时,请注意:\n" +
"1. 准确理解用户的具体需求\n" +
"2. 结合参考资料中的实际案例\n" +
"3. 提供专业的设计理念和原理解释\n" +
"4. 考虑实用性、美观性和成本效益\n" +
"5. 如有需要,可以提供替代方案")
.build();
// 3. 构建复杂的文档过滤条件
var filterExpression = getOp();
// 4. 配置文档检索器
DocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
// 设置相似度阈值
.similarityThreshold(0.5)
// 返回前3个最相关的文档
.topK(3)
.filterExpression(filterExpression.build())
.build();
// 5. 创建上下文感知的查询增强器
Advisor advisor = RetrievalAugmentationAdvisor.builder()
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(true)
.build())
.documentRetriever(retriever)
.build();
// 6. 执行查询并获取响应
String userQuestion = "根据已经提供的资料,请描述所有相关的场景风格,输出案例编号,尽可能详细地描述其内容。";
return chatClient.prompt()
.user(userQuestion)
.advisors(advisor)
.call()
.content();
}
private static FilterExpressionBuilder.Op getOp() {
var b = new FilterExpressionBuilder();
// 筛选2023年的案例
// 仅选择室内案例
// 类型为室内设计
// 指定房间类型
return b.and(
b.and(
// 筛选2023年的案例
b.eq("year", "2023"),
// 仅选择室内案例
b.eq("location", "indoor")),
b.and(
// 类型为室内设计
b.eq("type", "interior"),
// 指定房间类型
b.in("room", "living_room", "study", "kitchen")
));
}
}