AI03——简单的 RAG 开发步骤
文档准备文档读取向量转换和存储查询增强。
简单的 RAG 开发步骤
-
文档准备
-
文档读取
-
向量转换和存储
-
查询增强
Spring AI + 本地知识库实现
准备好知识库文档——用ai结构化一下,使其条理更清晰
准备好知识库文档——用ai结构化一下,使其条理更清晰
文档读取
对自己准备好的知识库文档进行处理,然后保存到向量数据库中。这个过程俗称 ETL(抽取、转换、加载)
ETL 的 3 大核心组件,按照顺序执行:
-
DocumentReader:读取文档,得到文档列表
-
DocumentTransformer:转换文档,得到处理后的文档列表
-
DocumentWriter:将文档列表保存到存储中(可以是向量数据库,也可以是其他存储)
Spring AI 提供了很多种 DocumentReaders(JSON Text HTML (JSoup) Markdown PDF Page PDF Paragraph Tika(DOCX,PPTX, HTML...)) 用于加载不同类型的文件。使用不同的 DocumentReaders要引入对应的依赖
例如:以读取markdown文档为例——可以使用 MarkdownDocumentReader 来读取 Markdown 文档
引入依赖
引入处理对应文档的阅读器依赖
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-markdown-document-reader</artifactId> <version>1.0.0-M6</version> </dependency>
读取 Markdown 文档并转换为 Document 列表
在根目录下新建包,编写文档加载器类 ,读取所有 Markdown 文档并转换为 Document 列表。
package com.yupi.aiagent.rag; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.document.Document; import org.springframework.ai.reader.markdown.MarkdownDocumentReader; import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * 应用文档加载器 */ @Slf4j @Component public class LoveAppDocumentLoader { //用spring内置的资源解析类——用构造函数的方法注入 private final ResourcePatternResolver resourcePatternResolver;//这是 Spring 提供的资源解析器,用于加载类路径下的资源 //通过构造函数注入ResourcePatternResolver对象 public LoveAppDocumentLoader(ResourcePatternResolver resourcePatternResolver) { this.resourcePatternResolver = resourcePatternResolver; } //Document Spring AI 框架 中定义的一个特定类,。在 Spring AI中,各种文档读取器都会将文件内容解析为 List<Document> 格式,以便统一处理不同类型的文档。 public List<Document> loadMarkdowns(){ List<Document> allDocuments =new ArrayList<>(); //加载多篇markDown文档 try { //通过resourcePatternResolver.getResources()方法加载资源 Resource[] resources = resourcePatternResolver.getResources("classpath:document/*.md");//classPath:为设置从类路径下加载文档 for (Resource resource : resources) { String filename = resource.getFilename(); //得到文件名 //指定了如何加载读取Markdown文件 MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()//创建MarkdownDocumentReaderConfig配置对象: .withHorizontalRuleCreateDocument(true) //withHorizontalRuleCreateDocument(true):设置通过水平分隔线 (---) 分割文档 .withIncludeCodeBlock(false)//是否包含代码块 .withIncludeBlockquote(false)//是否包含引用格式 .withAdditionalMetadata("filename", filename)//为文档添加元数据-————给文档内容附加一些额外的描述性信息(不属于文档的内容),但能帮助后续处理(如检索、过滤、溯源等)更高效地进行。 .build(); MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config); allDocuments.addAll(reader.get()); //reader.get():读取并解析 Markdown 文件,返回Document对象列表 //allDocuments.addAll():将解析得到的文档添加到总文档列表中 } } catch (IOException e) { log.error("MarkDowns error", e); } return allDocuments; } }
提取文档的文件名(fileName)作为文档的元信息,可以便于后续知识库实现更精确的检索。
向量转换和存储
为了实现方便,我们先使用 Spring AI 内置的基于内存读写的向量数据库 SimpleVectorStore 来保存文档。
SimpleVectorStore 实现了 VectorStore 接口,而 VectorStore 接口集成了 DocumentWriter,所以具备文档写入能力。
在rag
包下新建类,实现初始化向量数据库并且保存文档的方法。
package com.yupi.aiagent.rag; import jakarta.annotation.Resource; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; /** * 向量数据库配置(初始化基于内存的向量数据库 Bean) */ @Configuration//标识该类为 Spring 的配置类,Spring 会扫描并加载其中的配置 public class LoveAppVectorStoreConfig { //引入刚刚的文档加载器 @Resource private LoveAppDocumentLoader loveAppDocumentLoader; @Bean//创建一个 Bean 对象,并将其放入 Spring 容器中 //VectorStore(向量存储接口) VectorStore loveAppVectorStore(EmbeddingModel dashscopeEmbeddingModel) { SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(dashscopeEmbeddingModel) .build();//SimpleVectorStore.builder(dashscopeEmbeddingModel):SimpleVectorStore是基于内存的实现,传入嵌入模型(用于文本向量化) // 加载文档 List<Document> documents = loveAppDocumentLoader.loadMarkdowns();//调用刚刚注入的loveAppDocumentLoader中的loadMarkdowns()方法,获取所有解析后的文档列表 simpleVectorStore.add(documents);//将加载的文档添加到向量数据库中,内部会通过传入的EmbeddingModel将文档内容转换为向量 return simpleVectorStore; } }
查询增强
向量数据库存储着 AI 模型本身不知道的数据,当用户问题发送给 AI 模型时,QuestionAnswerAdvisor 会查询向量数据库,获取与用户问题相关的文档。然后从向量数据库返回的响应会被附加到用户文本中,为 AI 模型提供上下文,帮助其生成回答。
引入依赖
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-advisors-vector-store</artifactId> </dependency>
完成查询的对应代码
新增和 RAG 知识库进行对话的方法。
@Resource private VectorStore loveAppVectorStore; /** * RAG知识库进行对话 * @param message * @param chatId * @return */ public String doChatWithRage(String message, String chatId) { ChatResponse chatResponse = chatClient .prompt()//prompt():开始构建一个对话请求(创建一个提示信息构建器) .user(message) .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)//CHAT_MEMORY_CONVERSATTON_ID_KEY指定的为上下文关联的id .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) //应用RAG知识库问答-要找到我们的知识库去调用响应的模型 .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))//RAG 核心增强器QuestionAnswerAdvisor,并传入之前配置的向量数据库loveAppVectorStore .call() .chatResponse(); //.call():发送构建好的请求给 AI 模型 // .chatResponse():获取 AI 返回的对话响应结果,封装为ChatResponse对象 String content = chatResponse.getResult().getOutput().getText();//拿到返回结果中的输出信息,在从输出信息中拿到ai生成的文本 log.info("content: {}",content); return content; }
QuestionAnswerAdvisor核心的作用:
1,自动将用户问题(message)转换为向量
2,在loveAppVectorStore中检索与问题最相关的知识库文档
3,将检索到的文档内容作为上下文传递给 AI 模型,让 AI 基于知识库回答
Spring AI + 云知识库服务实现
很多 AI 大模型应用开发平台都提供了云知识库服务,我们先选择 阿里云百炼,因为 Spring AI Alibaba 可以和它轻松集成
完成云知识库的配置
我们可以利用云知识库完成文档读取、文档处理、文档加载、保存到向量数据库、知识库管理等操作
上传原始文档数据到平台
导入数据到知识库中
RAG 开发
可以参考 Spring AI Alibaba 的官方文档 来学习
Spring AI Alibaba 利用了 Spring AI 提供的文档检索特性(DocumentRetriever),自定义了一套文档检索的方法,使得程序会调用阿里灵积大模型 API 来从云知识库中检索文档
创建基于阿里云知识库服务的RAG增强Advisor
/** * 自定义基于阿里云知识库服务的RAG增强顾问 */ @Configuration @Slf4j public class LoveAppRagCloudAdvisorConfig { //注入自己的阿里大模型的api——key @Value("${spring.ai.dashscope.api-key}")//从配置文件中读取spring.ai.dashscope.api-key属性的值 private String dashScopeApiKey; @Bean//标识这是一个 Spring Bean,会被注册到 Spring 容器中 public Advisor loveAppRagCloudAdvisor() { DashScopeApi dashScopeApi = new DashScopeApi(dashScopeApiKey);//创建阿里云 DashScope 服务API 客户端,传入我们的api final String KNOWLEDGE_INDEX = "你的知识库名";//要索引的知识库的名称 //创建阿里云文档检索器实例,用于从知识库中检索相关文档 DocumentRetriever documentRetriever = new DashScopeDocumentRetriever(dashScopeApi, DashScopeDocumentRetrieverOptions.builder()//构建检索器的配置选项 .withIndexName(KNOWLEDGE_INDEX)//指定要检索的知识库索引名称 .build());//.build()完成配置选项的构建 //文档检索器 return RetrievalAugmentationAdvisor.builder()//创建 RAG 增强顾问的构建器 .documentRetriever(documentRetriever)//设置文档检索器,用于在回答前检索相关知识 .build();//完成顾问的构建并返回 } }
使用该Advisor
@Resource private Advisor loveAppRagCloudAdvisor; public String doChatWithRag(String message, String chatId) { ChatResponse chatResponse = chatClient .prompt() .user(message) .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) // 开启日志,便于观察效果 .advisors(new MyLoggerAdvisor()) // 应用增强检索服务(云知识库服务) .advisors(loveAppRagCloudAdvisor) .call() .chatResponse(); String content = chatResponse.getResult().getOutput().getText(); log.info("content: {}", content); return content; }

为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。
更多推荐
所有评论(0)