在探索AI落地应用的过程中,RAG知识库系统是一项无法回避的关键技术。近期我开始系统学习这一领域,并决定以笔记形式持续记录和分享学习心得,一方面督促自己深入理解,另一方面也希望能与大家共同探讨、相互启发。
本文整理自我对RAG技术的学习总结,内容涵盖其核心原理、发展演进以及从零搭建的完整步骤,并附上关键环节的实操代码。期待能为同样对RAG感兴趣的朋友提供一个清晰的学习框架。
一、什么是RAG?它如何解决大模型的三大痛点
RAG全称为"检索增强生成"。2020年,Meta AI研究院的Patrick Lewis团队在其里程碑式的论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中首次系统性地提出了这一框架。它的诞生,直接针对早期大语言模型(如GPT-3)的三个致命短板:
易产生"幻觉":可能生成不准确或完全虚构的内容;
知识更新滞后:模型训练后知识即固化,难以跟进最新信息;
缺乏可追溯性:回答往往不标注来源,难以验证可信度。
RAG的核心思想非常清晰且有力:将信息检索系统与大语言生成模型深度融合。具体来说,在生成回答之前,系统会首先从外部知识库(如企业文档、技术手册)中检索相关资料,再严格基于这些检索到的证据来合成答案。这相当于为原本"黑盒"且静态的大模型,配备了一个实时更新、可验证的外部记忆库,从而从架构根源上缓解了上述问题。
二、RAG发展的三个阶段:从基础检索到智能调度
自提出以来,RAG技术快速演进,其发展脉络可清晰地划分为三个阶段:
原始RAG:即基础的"检索-生成"流程。其效果高度依赖检索质量,是理解所有进阶技术的基础。
高级RAG:在检索前后引入查询优化、结果重排等策略,形成"检索前优化-检索-检索后优化-生成"的精细流水线,以提升整体效果。
模块化RAG:当前的前沿方向。将系统拆分为可灵活组装的独立模块(如检索器、路由模块等),支持像搭积木一样按场景定制流程,极大地提升了系统的适应性与智能化水平。
在我个人的学习路径中,我选择从原始RAG开始,因为它不仅是技术演进的起点,更是理解整个RAG体系的核心基础。原始RAG作为从论文走向工程实践的第一个完整框架,其结构清晰、流程直接,包含了检索增强生成最本质的"检索-生成"闭环。通过亲手实现这个经典流程,我能够透彻地理解数据是如何流动的、向量检索究竟在做什么、大模型又如何依据检索结果生成答案——这些认知是后续学习任何高级变体的根基。
更重要的是,原始RAG暴露了该技术最初面临的核心挑战:检索可能不够精准,流程也相对固化。而后来出现的所有"升级补丁"——无论是优化查询的"查询重写",还是灵活调度的"模块化智能体"——本质上都是在解决这些早期问题。因此,掌握原始RAG,就像拿到了一幅技术演进的地图,让你能一眼看穿每个新模块、新策略究竟意图解决什么真实痛点,从而在后续学习和应用中,做到心中有图、脚下有路。
我建议任何初学者也以原始RAG为起点,亲手走通这七个步骤。这不仅是学习技术,更是在积累一种"问题意识"——知道RAG哪里会痛,以后才知道该用什么药。
三、RAG落地七步走:从文档到答案的全流程详解
一个完整的RAG系统从知识输入到可信答案输出,可清晰拆解为七个关键步骤。每个步骤环环相扣,共同构建起检索增强生成的技术闭环。以下是各步骤的详细解析:
步骤1:文件上传——知识源的输入接口
文件上传是整个RAG系统的起点,其核心作用是确定系统知识范围的边界并完成外部知识到可处理数据的初步转换。用户通过这一接口将非结构化文档(如公司内部文档、产品手册、研究报告等)注入系统,系统能回答什么问题完全取决于上传了什么样的文档。实际操作中,这一步不仅是简单的文件搬运,更需要筛选文档质量,剔除无关或过时内容,确保知识库的准确性和时效性。它为后续所有处理环节划定了明确的知识范围,实现了从"外部世界知识"到"系统内部可处理数据"的基础转变。
步骤2:文件读取与内容提取——格式解析与信息标准化
文件读取与内容提取的核心任务是从复杂格式中无损提取机器可读的纯文本,为后续处理奠定坚实基础。不同格式的文件(.pdf, .docx等)不仅包含纯文本,还涉及排版、图片、表格等复杂信息,这一步需要完成"格式降维",即在去除格式干扰的同时尽可能保留原始语义结构。例如,从PDF中正确提取文字流并保持段落逻辑,从Word文档中读取文字而忽略样式信息。这一环节的质量直接影响整个系统效果,如果提取过程出现乱码、顺序错乱或信息丢失,后续所有步骤都将建立在错误的基础上,导致最终结果严重失真。
// 文件读取与内容提取核心逻辑(支持PDF、DOCX格式) asyncreadFileAndExtractContent(file: Express.Multer.File) { // 根据文件类型选择对应加载器 const fileType = file.mimetype === 'application/pdf' ? 'PDF' : 'DOCX'; const loader = fileType === 'PDF' ? new PDFLoader(file.path) : new DocxLoader(file.path); // 加载文档(每页一个文档对象) const docs = await loader.load(); // 合并所有页面内容为完整文本,保留段落逻辑 const fullDoc = docs[0]; for (let i = 1; i < docs.length; i++) { fullDoc.pageContent += '\n' + docs[i].pageContent; } return { fileType, fullContent: fullDoc.pageContent // 提取后的完整纯文本 }; }代码解读:这段代码实现了多格式文件的读取与内容提取核心逻辑,通过PDFLoader和DocxLoader分别处理对应格式文件,加载后合并所有页面内容为完整纯文本,既保证了信息的完整性,又保留了段落逻辑,为后续文本拆分奠定基础。
步骤3:文本拆分(Chunking)——优化信息粒度,平衡检索精度与上下文完整性
文本拆分是影响检索精度的关键环节,主要作用体现在两方面:一是适配大语言模型的上下文窗口限制,二是提升语义检索的相关性。由于大语言模型有严格的输入长度限制(如GPT-3.5 Turbo的4k/16k tokens),拆分使处理长篇文档成为可能;更重要的是,长文档包含多个主题,直接向量化会得到模糊的"平均语义"表示,拆分后每个片段语义更加集中,向量表示更精确,能显著提升检索命中率。拆分策略的选择直接影响效果:定长拆分最常用但可能切断语义;按句拆分保持句子完整性;语义逻辑拆分基于文档结构最符合阅读习惯。实际操作中通常设置10-20%的重叠区域来避免信息切断,保持上下文连贯性。
// 文档拆分核心逻辑(适配上传至知识库场景) asyncsplitDocument(doc: Document) { // 使用递归字符文本拆分器,按语义边界智能拆分 const textSplitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, // 每个块约1000个字符,适配模型上下文窗口 chunkOverlap: 100, // 块之间重叠100字符,避免切断完整语义 }); // 执行拆分,返回拆分后的文本块数组 const splitDocs = await textSplitter.splitDocuments([doc]); return splitDocs; }代码解读:选用递归字符文本拆分器,能智能识别标点、换行等语义边界,比固定长度拆分更贴合自然语言;通过chunkSize控制长度、chunkOverlap保留连贯性,避免语义断裂。
步骤4:文本向量化(Embedding)——将人类语言转化为机器可理解的数学表示
文本向量化是实现语义检索的数学基础,核心作用是将自然语言映射到高维向量空间,使计算机能够通过数学运算理解语义相关性。通过Embedding模型,每段文本(包括知识片段和用户问题)被转换为高维空间中的一个点,语义相近的文本在向量空间中距离也更近,这为后续的相似度计算提供了理论基础。这一步骤的关键在于一致性:必须确保生成向量与向量数据库维度完全匹配,且存储和查询必须使用相同的Embedding模型。常用的向量维度包括384、768、1024、1536等,不同模型在不同语种和领域表现各异,需要根据实际场景选择。此环节还涉及批量处理优化,以提升整体处理效率。
// 阿里云向量化处理(批量处理Chunk) asyncembeddingAliyun(allSplits: Document<Record<string, any>>[] | [{ pageContent: string }]) { const completion = awaitthis.openai.embeddings.create({ model: 'text-embedding-v2', // 阿里云Embedding模型 input: allSplits.map((item) => item.pageContent), // 批量提取Chunk内容 dimensions: 1536, // 输出维度(需与向量数据库字段维度一致) }); return completion.data; // 返回向量数组 }代码解读:实现批量向量化,通过map提取所有Chunk的pageContent作为输入;指定1536维输出,与后续向量数据库字段维度保持一致,避免向量不匹配。实践中还可选择OpenAI的text-embedding-3-small、开源BERT系列模型等,需根据效果和成本选择。
步骤5:向量存储到向量数据库——构建可高效查询的"知识记忆体"
向量存储的核心作用是构建支持高效相似度检索的知识库,将数学化的向量表示与原始文本及元数据关联存储。这一步骤创建了系统的"长期记忆",其中存储的不仅包括向量和对应文本,还有关键元数据(如来源文档、页码、章节等),这些元数据对后续的答案溯源至关重要。与传统数据库不同,向量数据库专门为高维向量相似度搜索优化,能够在大规模数据中快速找到最相似的向量。常用的向量数据库包括Pinecone(全托管服务)、Chroma(轻量级开源)、Milvus(功能全面)和Qdrant(性能优秀),选择时需综合考虑数据规模、性能要求和部署环境。此环节还需要设计合理的索引策略,如使用HNSW、IVF等算法平衡检索精度与速度。
// 创建Milvus向量数据库集合(类似传统数据库的"表") asynccreateCollection(collectionName: string) { const fields = [ { name: 'id', // 主键ID字段 data_type: DataType.Int64, // 数据类型 is_primary_key: true, // 为主键 autoID: true, // 自动增长 description: '主键ID字段', }, { name: 'docId', // 文档ID字段 data_type: DataType.VarChar, max_length: 100, description: '文档ID字段', }, { name: 'docTitle', // 文档标题字段 data_type: DataType.VarChar, max_length: 500, description: '文档标题字段', }, { name: 'docText', // 文档内容字段 data_type: DataType.VarChar, max_length: 9000, // 足够存储拆分后的文本块 description: '文档切片字段', }, { name: 'embedDocTitle', // 文档标题向量字段 data_type: DataType.FloatVector, dim: 1536, // 向量维度(与Embedding模型输出一致) description: '文档标题向量字段', }, { name: 'embedDocText', // 文档内容向量字段 data_type: DataType.FloatVector, dim: 1536, description: '文档内容向量字段', } ]; // 创建索引配置(余弦相似度度量) const index_params = [ { field_name: 'embedDocTitle', // 标题向量索引 index_type: "AUTOINDEX", // 自动选择合适索引 metric_type: "COSINE" }, { field_name: 'embedDocText', // 内容向量索引 index_type: "AUTOINDEX", metric_type: "COSINE" } ]; // 创建集合并释放资源 awaitthis.milvusClient.createCollection({ collection_name: collectionName, fields, index_params, }); awaitthis.milvusClient.releaseCollection({ collection_name: collectionName }); }// 批量插入数据到向量数据库 asyncinsertData( collectionName: string, originalname: string, docId: Types.ObjectId, data: Document<Record<string, any>>[], vectorDocTitle: OpenAI.Embeddings.Embedding[], vectorDocText: OpenAI.Embeddings.Embedding[] ) { // 格式化数据:关联Chunk、向量和元数据 const group = data.map((item, index) => ({ docId: docId.toString(), // 文档唯一标识 docTitle: originalname, // 原始文件名 docText: item.pageContent, // 文本内容 embedDocTitle: vectorDocTitle[0].embedding, // 标题向量(唯一) embedDocText: vectorDocText[index].embedding, // 每个Chunk的内容向量 })); try { // 批量插入 const res = awaitthis.milvusClient.insert({ collection_name: collectionName, data: group }); if (res.status.error_code === 'Success') { return'插入数据成功'; } else { thrownew BadRequestException(`插入失败: ${res}`); } } catch (error) { thrownew BadRequestException(`插入失败: ${error}`); } }代码解读:核心是定义"向量+文本+元数据"的存储结构,向量维度1536与Embedding模型一致;配置余弦相似度度量,确保后续能精准计算语义相关性。数据插入部分通过map将Chunk、标题向量、内容向量和元数据一一对应,格式化后批量插入,提升效率。
步骤6:用户提问与向量检索——从知识库中精准定位相关信息
用户提问与向量检索是"检索增强"中的核心检索环节,作用是在海量知识库中快速精准地找到与用户问题最相关的参考资料。当用户提问时,系统首先用相同的Embedding模型将问题向量化,确保与知识片段在同一语义空间,然后通过向量数据库的最近邻搜索找到相似度最高的Top-K个知识片段。这一环节充当大模型的"外部工作记忆",使其无需记住所有知识,而是在需要时实时从知识库调取相关信息。为了提升效果,常采用混合搜索(结合向量和关键词)、重排序(用精细模型重新评估相关性)、元数据过滤(基于时间、来源等条件筛选)等优化技术。Top-K值的选择需要平衡召回率与精确率,通常从3-5开始根据实际效果调整。
// 查询向量数据库 asyncsearchDataBase( userId: string, userQuestion: string, userQuestionEmbedding: number[] ) { // 1. 准备查询环境:按用户ID隔离集合,加载到内存提升速度 const collectionName = `_${userId}`; awaitthis.milvusClient.loadCollection({ collection_name: collectionName }); // 2. 配置混合搜索参数:标题+内容双路检索 const search_param_1 = { "data": userQuestionEmbedding, "anns_field": "embedDocTitle", // 搜索标题向量 "param": { "metric_type": "COSINE" }, // 余弦相似度 "limit": 9// 返回9条标题相似结果 }; const search_param_2 = { "data": userQuestionEmbedding, "anns_field": "embedDocText", // 搜索内容向量 "param": { "metric_type": "COSINE" }, "limit": 9// 返回9条内容相似结果 }; // 3. 执行混合搜索:设置权重,内容权重高于标题 const res = awaitthis.milvusClient.search({ collection_name: collectionName, data: [search_param_1, search_param_2], // 双路并行 limit: 18, // 共返回18条结果 output_fields: ["docId", "docTitle"], // 只返回必要字段,减少传输 rerank: WeightedRanker([0.3, 0.8]), // 权重:标题0.3,内容0.8 }); // 4. 释放集合资源 awaitthis.milvusClient.releaseCollection({ collection_name: collectionName }); // 5. 关键词提取+过滤优化,剔除无关结果 const keyWordList = awaitthis.extractKeywords(userQuestion); if (res.status.error_code === 'Success' && res.status.code === 0 && res.results && res.results.length > 0) { const filteredDocs = awaitthis.filterDocsByKeywords(keyWordList.keywords, res.results); // 6. 整理返回数据 let searchDocTitle: string[] = []; let searchDocText: string = ''; if (filteredDocs.length > 0) { searchDocTitle = [...new Set(filteredDocs.map(doc => doc.docTitle))]; // 标题去重 filteredDocs.forEach((item, index) => { searchDocText += `${index + 1}. ${item.docText}\n`; // 合并内容 }); } else { searchDocText = '&没有检索到相关文档&'; } return { searchDocTitle, searchDocText: `请根据知识库内容回复用户问题:${userQuestion};\n知识库内容:\n${searchDocText}` }; } else { return { searchDocTitle: [], searchDocText: '&没有检索到相关文档&', }; } }代码解读:亮点是"精准检索+结果优化":① 双路混合搜索,内容权重更高,确保核心匹配精准;② 关键词二次过滤,剔除无关结果;③ 资源优化:加载集合提升速度,释放资源避免内存占用,指定返回字段减少传输。K值选择很关键:太小易遗漏信息,太大引入冗余,这里各返回9条,平衡候选范围和处理效率。
步骤7:大语言模型生成答案——整合信息,生成自然、精准、可信的回答
大语言模型生成答案是RAG系统的价值最终体现,核心作用是基于检索结果整合信息,生成自然、精准且可信的答案。这一环节接收用户问题和检索到的相关片段,通过大模型的推理能力对信息进行总结、归纳和重组,形成连贯的答案输出。其关键价值在于:一是将可能零散的检索结果转化为流畅自然的语言;二是基于事实资料生成,有效约束大模型的"幻觉"倾向,提升答案可信度;三是支持引用溯源,通过Prompt设计可要求模型注明信息来源。Prompt工程在此至关重要,需要明确指令(要求基于参考资料回答)、格式约束、安全边界等要素。生成参数如温度值也需要仔细调整,在创造性与稳定性间取得平衡。
四、总结:理解流程是优化与排查的基础
这七个步骤构成了RAG系统的完整技术链路,可分为三个核心阶段:数据准备阶段(步骤1-2)完成知识的数字化和标准化;向量化阶段(步骤3-5)构建可检索的语义知识库;检索生成阶段(步骤6-7)实现智能问答的完整闭环。每个步骤都有明确的技术目标和质量标准,理解这个完整流程是进行系统优化、问题排查和性能提升的基础。
通过这七步的实践,我们可以搭建出一个可运行的原始RAG系统。这个过程也让我们深刻体会到,RAG的每个环节都环环相扣:拆分策略影响向量质量,向量质量决定检索精度,检索精度又直接关系到最终答案的可靠性。
常见挑战与解决方案
检索不准:通过调整Chunk大小和重叠度,并优化Embedding模型来改善。
答案冗长或偏离:通过优化Prompt设计,加入更严格的指令约束。
处理速度慢:对向量检索部分进行索引优化,并对文本处理流程进行批量操作。
在实际应用中,还需要根据具体业务场景调整各个环节的参数和策略,同时考虑数据安全、系统可扩展性、成本控制等多方面因素,才能构建出真正可用的企业级RAG系统。
如何学习AI大模型?
如果你对AI大模型入门感兴趣,那么你需要的话可以点击这里大模型重磅福利:入门进阶全套104G学习资源包免费分享!
这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
这是一份大模型从零基础到进阶的学习路线大纲全览,小伙伴们记得点个收藏!
第一阶段:从大模型系统设计入手,讲解大模型的主要方法;
第二阶段:在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;
第三阶段:大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;
第四阶段:大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;
第五阶段:大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;
第六阶段:以SD多模态大模型为主,搭建了文生图小程序案例;
第七阶段:以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。
100套AI大模型商业化落地方案
大模型全套视频教程
200本大模型PDF书籍
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
LLM面试题合集
大模型产品经理资源合集
大模型项目实战合集
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓