耄大厨——AI厨师智能体(2-RAG知识库)
文章目录
- RAG知识库集成
- RAG的基本概念
- 什么是RAG?
- RAG工作流程
- 1.文档收集与切割
- 2. 向量转换与存储
- 3. 文档过滤与存储
- 4.查询增强与关联
- 完整工作流程
- SpringAI + 本地知识库
- 1.文档准备
- 2. 文档读取
- 引入依赖
- 编写文档加载器
- 3. 向量转换与存储
- 4. 查询增强
- 基于PGVector实现向量存储
- 1.引入依赖
- 2. 编写向量数据库配置类
- 3.启动类排除配置类
- 4. 实现RAG
RAG知识库集成
RAG的基本概念
什么是RAG?
RAG(Retrieval-Augmented Generation
,检索增强生成)是一种结合信息检索技术和Al内容生成的混合架构,
可以解决大模型的知识时效性限制和幻觉问题。
从技术角度看,R八G在大语言模型生成回答之前,会先从外部知识库中检索相关信息,然后将这些检索到的内容
作为额外上下文提供给模型,引导其生成更准确、更相关的回答。
RAG工作流程
1.文档收集与切割
文档收集:从各种来源(网页、PDF、数据库等)收集原始文档
文档预处理:清洗、标准化文本格式
文档切割:将长文档分割成适当大小的片段(俗称chunks)
- 基于固定大小(如512个token)
- 基于语义边界(如段落、章节)
- 基于递归分割策略(如递归字符n-gram切割)
2. 向量转换与存储
向量转换:使用Embedding模型将文本块转换为高维向量表示,可以捕获到文本的语义特征
向量存储:将生成的向量和对应文本存入向量数据库,支持高效的相似性搜索
3. 文档过滤与存储
查询处理:将用户问题也转换为向量表示
过滤机制:基于元数据、关键词或自定义规则进行过滤
相似度搜索:在向量数据库中查找与问题向量最相似的文档块,常用的相似度搜索算法有余弦相似度、欧氏距离
等
上下文组装:将检索到的多个文档块组装成连贯上下文
4.查询增强与关联
提示词组装:将检索到的相关文档与用户问题组合成增强提示词
上下文融合:大模型基于增强提示生成回答
源引用:在回答中添加信息来源引用
后处理:格式化、摘要或其他处理以优化最终输出
完整工作流程
SpringAI + 本地知识库
Spring Al框架为我们实现RAG提供了全流程的支持,参考Spring Al和Spring Al Alibaba的官方文档。
由于是第一个RAG程序,我们参考标准的RAG开发步骤并进行一定的简化,来实现基于本地知识库的AI厨师智能体的问答应用。
标准的RAG开发步骤:
- 文档收集和切割
- 向量转换和存储
- 切片过滤和检索
- 查询增强和关联
简化后的RAG开发步骤:
- 文档准备
- 文档读取
- 向量转换和存储
- 查询增强
1.文档准备
Anduin2017/HowToCook: 程序员在家做饭方法指南
Gar-b-age/CookLikeHOC: 🥢像老乡鸡🐔那样做饭
2. 文档读取
首先,我们要对自己准备好的知识库文档进行处理,然后保存到向量数据库中。这个过程俗称TL(抽取、转
换、加载),Spring Al提供了对ETL的支持,参考官方文档。
ETL的3大核心组件,按照顺序执行:
- DocumentReader:读取文档,得到文档列表
- DocumentTransformer:转换文档,得到处理后的文档列表
- DocumentWriter:将文档列表保存到存储中(可以是向量数据库,也可以是其他存储)
引入依赖
Spring Al提供了很多种DocumentReaders,用于加载不同类型的文件。
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
编写文档加载器
在根目录下新建rag
包,编写文档加载器类CookerAppDocumentLoader,负责读取所有PDF文档并转
换为Document列表。代码如下:
/*** 知识库文件加载** @author: cheng fu**/
@Component
@Slf4j
public class CookerAppDocumentLoader {public final ResourcePatternResolver resourcePatternResolver;CookerAppDocumentLoader(ResourcePatternResolver resourcePatternResolver) {this.resourcePatternResolver = resourcePatternResolver;}public List<Document> loadPDFs() {List<Document> allDocuments = new ArrayList<>();try {Resource[] resources = resourcePatternResolver.getResources("classpath:document/*pdf");for (Resource resource : resources) {String filename = resource.getFilename();PdfDocumentReaderConfig config = PdfDocumentReaderConfig.builder().withPageTopMargin(0).withPageExtractedTextFormatter(ExtractedTextFormatter.builder().withNumberOfTopTextLinesToDelete(0).build()).withPagesPerDocument(1).build();PagePdfDocumentReader reader = new PagePdfDocumentReader(resource, config);allDocuments.addAll(reader.get());}} catch (IOException e) {log.error("Document loader filed",e);}return allDocuments;}
}
3. 向量转换与存储
为了实现方便,我们先使用Spring Al内置的、基于内存读写的向量数据库SimpleVectorStore来保存文档。
SimpleVectorStore实现了VectorStore接口,而VectorStore接口集成了DocumentWriter,.所以具备文档写入能
力。如图:

@Configuration
@Slf4j
public class CookerAppVectorStoreConfig {@Resourcepublic CookerAppDocumentLoader cookerAppDocumentLoader;@BeanVectorStore cookerAppVectorStore(EmbeddingModel dashscopeEmbeddingModel) {SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(dashscopeEmbeddingModel).build();//加载文档List<Document> documents = cookerAppDocumentLoader.loadPDFs();simpleVectorStore.add(documents);return simpleVectorStore;}
}
4. 查询增强
Spring Al通过Advisor特性提供了开箱即用的RAG功能。主要是QuestionAnswerAdvisor问答拦截器和Retrieva
lAugmentationAdvisor检索增强拦截器,前者更简单易用、后者更灵活强大。
查询增强的原理其实很简单。向量数据库存储着A!模型本身不知道的数据,当用户问题发送给A!模型时,Quest
ionAnswerAdvisor会查询向量数据库,获取与用户问题相关的文档。然后从向量数据库返回的响应会被附加到用
户文本中,为AI模型提供上下文,帮助其生成回答。
此处我们就选用更简单易用的QuestionAnswerAdvisor问答拦截器,在CookerApp中新增和RAG知识库进行对话
的方法。代码如下:
public String doChatWithRag(String message,String chatId){ChatResponse chatResponse = chatClient.prompt().user(message).advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,chatId)).advisors(QuestionAnswerAdvisor.builder(cookerAppVectorStore).build()).call().chatResponse();String content = chatResponse.getResult().getOutput().getText();log.info("content: {}",content);return content;}
结果显示RAG能正常实现,接下来进行RAG的一些高级用法。
基于PGVector实现向量存储
PGVector是经典数据库PostgreSQL的扩展,为 PostgreSQL 提供了存储和检索高维向量数据的能力。
为什么选择它来实现向量存储呢?因为很多传统业务都会把数据存储在这种关系型数据库中,直接给原有的数据
库安装扩展就能实现向量相似度搜索、而不需要额外搞一套向量数据库,人力物力成本都很低,所以这种方案很
受企业青睐,也是目前实现RAG的主流方案之一。
首先我们准备PostgreSQL数据库,并为其添加扩展。有2种方式,第一种是在自己的本地或服务器安装,可以参
考下列文章实现:
- Linux服务器快速安装PostgreSQL15与pgvector向量插件实践
- 宝塔 PostgreSQL 安装 pgvector 插件实现向量存储_宝塔安装pgvector-CSDN博客
1.引入依赖
参考Spring Al官方文档整合PGVector,先引入依赖,版本号可以在 Maven 中央仓库查找:
<!-- https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-starter-vector-store-pgvector -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-pgvector</artifactId><version>1.0.3</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><scope>runtime</scope>
</dependency>
编写配置,建立数据库连接:
spring:datasource:url: jdbc:postgresql://改为你的公网地址/yu_ai_agentusername: 改为你的用户名password: 改为你的密码ai:vectorstore:pgvector:index-type: HNSWdimensions: 1536distance-type: COSINE_DISTANCEmax-document-batch-size: 10000 # Optional: Maximum number of documents per batch
2. 编写向量数据库配置类
@Configuration
public class PgVectorVectorStoreConfig {@Resourceprivate CookerAppDocumentLoader cookerAppDocumentLoader;@Beanpublic VectorStore pgVectorVectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel dashscopeEmbeddingModel) {VectorStore vectorStore = PgVectorStore.builder(jdbcTemplate, dashscopeEmbeddingModel).dimensions(1536) // Optional: defaults to model dimensions or 1536.distanceType(COSINE_DISTANCE) // Optional: defaults to COSINE_DISTANCE.indexType(HNSW) // Optional: defaults to HNSW.initializeSchema(true) // Optional: defaults to false.schemaName("public") // Optional: defaults to "public".vectorTableName("vector_store") // Optional: defaults to "vector_store".maxDocumentBatchSize(10000) // Optional: defaults to 10000.build();// 加载文档List<Document> documents = cookerAppDocumentLoader.loadPDFs();vectorStore.add(documents);return vectorStore;}
}
3.启动类排除配置类
@SpringBootApplication(exclude = PgVectorStoreAutoConfiguration.class)
public class AiCookerApplication {public static void main(String[] args) {SpringApplication.run(AiCookerApplication.class, args);}}
4. 实现RAG
public String doChatWithRag(String message,String chatId){ChatResponse chatResponse = chatClient.prompt().user(message).advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID,chatId)).advisors(QuestionAnswerAdvisor.builder(pgVectorVectorStore).build()).call().chatResponse();String content = chatResponse.getResult().getOutput().getText();log.info("content: {}",content);return content;}
advisorSpec.param(ChatMemory.CONVERSATION_ID,chatId))
.advisors(QuestionAnswerAdvisor.builder(pgVectorVectorStore).build())
.call().chatResponse();
String content = chatResponse.getResult().getOutput().getText();log.info("content: {}",content);return content;
}