Spring AI(7)——RAG
检索增强生成(RAG),用于解决将相关数据纳入提示词中以获得准确 AI 模型响应的挑战。
该方法采用批处理式编程模型,从指定的文档中读取非结构化数据,进行转换,然后写入向量数据库。从高层次来看,这是一个 ETL(提取、转换和加载)管道。向量数据库用于 RAG 技术的检索部分。
在将非结构化数据加载到向量数据库时,最重要的转换之一是将原始文档分割成更小的片段。将原始文档分割成更小片段的过程有两个重要步骤:
-
在保持内容语义边界的同时将文档分割成部分。例如,对于包含段落和表格的文档,应避免在段落或表格中间分割文档。对于代码,避免在方法的实现中间分割代码。
-
将文档的部分进一步分割成大小占 AI 模型词元限制很小百分比的部分。
RAG 的下一阶段是处理用户输入。当需要 AI 模型回答用户的提问时,该问题以及所有“相似”的文档片段都会被放入发送给 AI 模型的提示词中。这就是使用向量数据库的原因。它非常善于查找相似的内容。
注意:关于文档的拆分,数据的向量化处理和向量存储等内容,在之前的博客中已经介绍,本文不再过多说明
Spring AI(5)——通过嵌入模型进行数据的向量化处理-CSDN博客
Spring AI(6)——向量存储-CSDN博客
本例使用Ollama部署的dmeta-embedding作为嵌入模型,使用milvus作为向量数据库
导入jar
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
初始化数据
本例仅用于测试,读取指定的文本文件,按照指定的大小对文件进行分割,将分割后的块,进行向量化处理,并将向量化后的数据写入milvus中。
@PostConstructpublic void init() {// 读取文本文件TextReader textReader = new TextReader(this.resource);// 元数据中增加文件名textReader.getCustomMetadata().put("filename", "医院.txt");// 获取Document对象,只有一个记录List<Document> docList = textReader.read();TokenTextSplitter splitter = new TokenTextSplitter(300, 350, 5, 10000, true);List<Document> splitDocuments = splitter.apply(docList);// 分割后的文档存入向量数据库milvusVectorStore.add(splitDocuments);}
测试RAG代码
@GetMapping("/chat")public String chat(String message) {// 定义提示词模版PromptTemplate customPromptTemplate = PromptTemplate.builder().renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build()).template("""<query>上下文信息如下:---------------------<question_answer_context>---------------------根据上下文信息回答查询。遵循以下规则:1. 如果答案不在上下文中,只需说你不知道。2. 避免使用“根据上下文...”或“提供的信息...”这样的表述。3. 回答问题尽量精简""").build();QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(milvusVectorStore)// 设置提示词模版对象,如果不设置,使用默认的模版.promptTemplate(customPromptTemplate)// 指定进行向量搜索时的基本条件.searchRequest(SearchRequest.builder().topK(3).similarityThreshold(0.5).build()).build();ChatResponse chatResponse = this.client.prompt().advisors(qaAdvisor).user(message).call().chatResponse();System.out.println(chatResponse.getResult().getOutput().getText());return "success";}
本例使用<>表示占位符 <query>表示用户提出的问题,<question_answer_context>表示检索的内容当用户问题发送到 AI 模型时,QuestionAnswerAdvisor 查询向量数据库以获取与用户问题相关的文档。
向量数据库的响应被附加到用户文本中,为 AI 模型生成响应提供上下文。
发送的提示词如下:
request: ChatClientRequest[prompt=Prompt{messages=[SystemMessage{textContent='你是一个java架构师', messageType=SYSTEM, metadata={messageType=SYSTEM}}, UserMessage{content='医院职工数
上下文信息如下:
---------------------
70%,获批省级特色专科、省级专病治疗中心。
心脏大血管外科入选河南省“十四五”首批省级临床重点专科,开展冠脉搭桥手术、经导管主动脉瓣置换术(TAVI手术)、HYBRID心脏杂交手术。血管外科是河南省医学会、医师协会副主委单位,完成主动脉夹层(瘤)介入技术、颈动脉体瘤切除、颈动脉内膜剥脱、一站式治疗VTE。
整形修复科是中国创面修复建设培育单位,入选河南省“十四五”首批省级临床重点专科,开展耳、鼻、口唇、颌面、手足、乳房、腹壁、生殖器、瘢痕、体表肿瘤
河南省直第三人民医院简介
(修订日期 2025年3月)河南省直第三人民医院是河南省卫健委直属的一家“医教研转工作统筹推进、防治康养手段综合应用、吃动睡想行为全面科学”的省三级公立综合医院。是河南省干部保健定点医院。
医院位于河南省省会郑州,有三个院区,郑东院区(郑东新区人民医院)比邻河南省政府。西院区位于中原区伏牛路陇海路交叉口;857院区位于中原区陇海路328号。医院有2个急救站,5个急救联盟单位、4个社区卫生服务中心;下设司法鉴定中心。
医院核定床位1800张,职工2113人,专业技术人员1903人,二级主任医�
化,汲取“智慧管理、人文管理、高科技创新、低成本高效运营”的现代化综合性医院之精髓,为患者提供安全、优质、便捷的医疗服务。
---------------------
根据上下文信息回答查询。
遵循以下规则:
1. 如果答案不在上下文中,只需说你不知道。
2. 避免使用“根据上下文...”或“提供的信息...”这样的表述。
3. 回答问题尽量精简
'
从提示词中看出,在向大模型发送消息前,先通过向量数据库,搜索对应的信息。然后按照提示词模版,生成最新的提示词信息,然后将用户的提问和提示词模版生成的提示词信息一并发送给大模型。
大模型返回的信息:
大模型根据我们发送的提示词信息,找到其中的职工数,并组织语言进行了回答。