十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RAG技术解析:从检索增强生成到AI应用新范式

RAG技术解析:从检索增强生成到AI应用新范式 1. 从“检索”到“生成”RAG为何成为AI应用的新范式最近和不少做AI应用的朋友聊天发现一个挺有意思的现象大家不再一窝蜂地讨论哪个大模型参数更大、效果更惊艳而是开始频繁地聊一个词——RAG。无论是想做个能回答公司内部文档的智能助手还是想给产品加一个基于知识库的问答功能RAG似乎成了绕不开的“标配”。但如果你去问一个刚接触这个领域的朋友“RAG是什么”得到的答案可能五花八门有人说是“检索增强生成”有人说是“给大模型联网”还有人直接把它等同于“向量数据库”。这些说法都对但都不够完整。在我看来RAG更像是一种“思维模式”的转变。它承认了一个现实没有任何一个模型哪怕是千亿参数的大模型能够记住并理解世界上所有的知识尤其是那些实时变化、高度专业或者极度私密的领域知识。传统的做法是“训一个更大的模型”把知识“灌”进模型的参数里这成本高昂且不灵活。而RAG的思路则很巧妙我们让模型学会“查资料”。当模型遇到一个它不确定或者需要最新信息的问题时它不再是硬着头皮“编造”而是先去一个外部的知识库比如你的文档、数据库、网页里检索出最相关的信息片段然后基于这些“参考资料”来组织语言生成最终的回答。这样一来回答的准确性、时效性和专业性都得到了质的提升。所以RAG绝不仅仅是“向量搜索大模型”的简单拼接。它是一个系统工程涉及到如何把非结构化的文本比如PDF、Word变成机器能理解的“知识片段”如何高效地从海量片段中召回最相关的几条以及如何引导大模型“读懂”这些片段并生成流畅、准确的答案。这背后是一整套关于知识处理、信息检索和提示工程的组合拳。接下来我们就一层层剥开RAG的外壳看看它到底是怎么工作的以及为什么说它正在重塑我们构建AI应用的方式。2. RAG的核心架构拆解不只是“检索”与“生成”的串联当我们谈论RAG时一个常见的简化图是用户提问 - 检索相关文档 - 将文档和问题一起喂给大模型 - 得到答案。这个流程没错但它掩盖了其中大量的技术细节和设计抉择。一个健壮的、可用于生产的RAG系统其内部更像一个精密的流水线我们可以将其拆解为四个核心阶段知识切片、向量化与索引、多路召回与融合、重排序与生成。每一个环节的优劣都直接决定了最终答案的质量。2.1 知识切片把“书本”拆成有意义的“段落”这是整个RAG流程的起点也是最容易被低估的环节。它的目标是将原始的文档如PDF、网页、Markdown切割成一段段适合检索和模型理解的文本块。这里最大的误区是认为“切得越细越好”或者“固定长度切就行”。实际上糟糕的切片是后续所有问题的根源。想象一下如果你把一本法律条文按固定每500字切一刀很可能把一条完整的法律定义从中间切断前半部分在A片段后半部分在B片段。当用户问到这个定义时系统可能只检索到A片段导致模型得到的信息不完整从而生成错误答案。这就是所谓的“上下文割裂”问题。因此智能的切片策略至关重要。目前主流的做法包括基于语义的切片利用句子边界检测、自然段落识别尽可能在完整的语义单元处进行切割。例如LlamaIndex等框架提供了基于句子、段落甚至章节的切割器。重叠切片为了避免切割点恰好落在关键信息上可以在相邻片段之间设置一个重叠区域比如100个字符。这样即使切割点不理想关键信息也有很大概率在重叠区被保留从而出现在两个相邻片段中提高被检索到的几率。混合切片对于结构复杂的文档可以采用分层切片。先按章节切再在章节内按段落切并建立父子关系。这样在检索时既可以召回细粒度的答案片段也能保留其所在的宏观背景。提示切片的大小需要权衡。片段太小可能信息不完整片段太大会引入噪声并且可能超出大模型的上下文窗口限制。一个常见的起点是尝试256-512个token的片段并根据具体任务效果进行调整。2.2 向量化与索引为文本片段制作“身份证”并建立档案馆切片完成后我们得到了一堆文本片段。下一步是让计算机能快速找到它们。这就是向量化和索引的目的。向量化通常通过嵌入模型来完成。嵌入模型如text-embedding-ada-002、bge-large-zh可以将一段文本转换成一个固定长度的数字数组即向量。这个向量的神奇之处在于语义相似的文本其向量在空间中的距离通常用余弦相似度衡量也会很近。比如“狗”和“犬”的向量距离会比“狗”和“汽车”的近得多。索引则是为了高效管理这些向量。当你有百万甚至千万个文本片段时逐一计算用户问题与每个片段的相似度是不现实的。向量数据库如Pinecone、Weaviate、Qdrant或支持向量检索的库如Faiss就是干这个的。它们使用近似最近邻搜索等算法在毫秒级时间内从海量向量中找出与问题向量最相似的Top K个片段。这里的一个关键选择是嵌入模型。不同的模型在不同语言、不同领域的表现差异很大。例如处理中文法律文档bge-large-zh-v1.5可能比通用的英文模型效果更好。同时索引的配置如向量维度、距离度量方式、索引算法参数也会影响检索的精度和速度。2.3 多路召回与融合不把鸡蛋放在一个篮子里如果只依赖向量检索这一种方式我们可能会错过一些关键信息。因为向量检索本质上是“语义相似度”检索它擅长找到“表述不同但意思相近”的内容。但对于一些关键词匹配、精确术语查找传统的全文检索如Elasticsearch、BM25算法可能更有效。因此先进的RAG系统会采用多路召回策略。常见的有向量检索路基于语义相似度召回最相关的片段。关键词检索路基于问题中的关键词进行匹配召回包含这些关键词的片段。元数据过滤路如果片段带有元数据如文档来源、作者、日期可以先根据这些条件过滤再检索。例如限定只检索2023年之后的文档。每一路召回都会得到一个候选片段列表。接下来就需要融合这些结果。最简单的融合方式是“加权求和”比如给向量检索的结果更高的初始分。更复杂的方法包括“交叉编码器重排”用一个更精细但更耗时的模型对所有候选片段进行两两比较直接给出一个全局的排序。多路召回的核心思想是综合利用不同检索技术的优势提高召回内容的覆盖率和相关性。2.4 重排序与生成去芜存菁组织答案经过多路召回和融合我们得到了一个可能包含10-20个相关片段的列表。但直接把这些片段全部塞给大模型是不明智的因为模型上下文窗口有限可能装不下。片段之间可能存在冗余甚至矛盾的信息。不是所有片段都与最终答案强相关噪声会影响模型判断。因此重排序环节应运而生。它的任务是对这10-20个片段进行精排只选出最相关、最关键的3-5个片段送给大模型。常用的重排序器Reranker本身也是一个轻量级的神经网络如bge-reranker、Cohere Rerank它比嵌入模型更擅长判断“问题-片段”之间的相关性但计算成本也更高所以只用于对少量候选进行精排。最后把精排后的Top N个片段连同用户的问题和精心设计的提示词一起构造成一个完整的提示输入给大语言模型。提示词会明确指示模型“请基于以下提供的参考信息来回答问题如果信息不足以回答请说明你不知道。” 这个步骤就是生成。一个设计良好的提示词能极大地提升模型遵循指令、利用参考资料的能力减少幻觉即编造信息的发生。至此一个完整的RAG流程才走完。我们可以看到从原始的文档到最终的答案中间经历了层层加工、筛选和优化。这也就是为什么说构建一个高质量的RAG系统是一个需要深入细节的工程问题。3. 超越基础范式Agentic RAG与Graph RAG的探索当我们把基础的RAG流程跑通后很快会遇到它的天花板对于复杂、多步骤的推理问题或者知识之间存在复杂关联的场景简单的“检索-生成”模式就显得力不从心了。于是社区开始探索RAG的进阶形态其中两个重要的方向是Agentic RAG智能体驱动的RAG和Graph RAG图增强的RAG。3.1 Agentic RAG让RAG学会“思考”和“行动”传统的RAG是被动的用户问系统检索然后生成答案。Agentic RAG则引入了“智能体”的概念让整个过程变得主动和具有规划能力。你可以把它想象成一个拥有RAG作为核心工具的研究员。在这个范式下系统接收到一个复杂问题后不会立即去检索。而是先让一个“规划智能体”去拆解问题。例如用户问“对比一下特斯拉Model 3和比亚迪汉EV在2023年的销量、主要技术路线和车主口碑。” 规划智能体可能会将其分解为几个子任务查找特斯拉Model 3在2023年的全球及中国市场销量数据。查找比亚迪汉EV在2023年的销量数据。总结特斯拉的主要技术特点如纯电平台、自动驾驶FSD。总结比亚迪汉EV的主要技术特点如刀片电池、DM-i混动系统。搜集关于两款车型的车主评价和常见投诉。然后一个“执行智能体”会带着这些子问题去调用RAG系统可能针对不同的子问题访问不同的知识库甚至调用其他工具如计算器、搜索引擎API来获取信息。最后一个“合成智能体”将各个子任务的结果汇总、分析、对比生成一份结构化的完整报告。LangChain、LlamaIndex等框架目前都在积极集成Agent的能力。通过定义工具Tools、设定智能体Agent的执行逻辑我们可以构建出能够处理多轮对话、复杂查询和自我验证的RAG系统。这大大扩展了RAG的应用边界使其能够胜任诸如深度分析报告生成、复杂问题诊断等任务。3.2 Graph RAG挖掘知识背后的“关系网”基础RAG将知识视为独立的文本片段忽略了片段之间丰富的关联关系。而Graph RAG则尝试用图结构来建模知识。在图数据库中节点代表实体如人物、地点、概念、事件边代表实体之间的关系如“出生于”、“就职于”、“属于”。构建Graph RAG通常分为两步知识图谱构建从文档中抽取实体和关系存入图数据库如Neo4j、Nebula Graph。例如从一篇公司财报中抽取出“公司A”、“CEO张三”、“产品B”、“收购了”、“公司C”等实体和关系。图检索增强当用户提问时除了进行传统的向量/关键词检索还可以将问题中的实体在图数据库中进行查询。例如用户问“张三领导的公司有哪些产品”系统可以识别出实体“张三”然后在知识图谱中查询与“张三”有“领导”关系的公司再查询这些公司的“产品”从而精准定位到相关文本片段甚至直接根据图谱生成部分答案。Graph RAG的优势在于它能处理需要多跳推理的问题。比如“帮我找一下我们公司负责AI产品线的总监的助理的联系方式”。传统RAG可能很难直接检索到答案因为信息可能分散在组织架构图、员工通讯录等多个文档中。而Graph RAG可以通过“公司-AI产品线-总监-助理-联系方式”这条路径一步步推理找到答案。它将离散的知识片段连接成网让RAG系统具备了更强的推理和连接能力。这两种进阶范式并非互斥未来很可能出现融合方案例如一个智能体在规划任务时既使用向量检索获取事实细节又使用图查询来理清实体关系从而做出更精准的决策。4. RAG的工程化挑战与评测从Demo到生产系统让一个RAG原型在几个PDF文件上跑起来并不难但要让一个RAG系统在真实业务中稳定、可靠、高效地运行并持续提升效果就是另一回事了。这就是RAG工程化要解决的问题它主要围绕稳定性、可观测性和可迭代性展开。4.1 核心工程化挑战数据管道与更新知识不是静态的。如何设计一个自动化的管道监控源文档的变更新增、修改、删除并触发重新切片、向量化和索引更新这涉及到版本管理、增量更新和原子性发布确保线上检索到的知识始终是最新且一致的。检索质量与幻觉缓解如何确保检索到的片段真正相关当检索结果不相关时如何防止大模型“强行”编造答案幻觉除了优化切片和检索策略还需要在生成环节设置“拒答”机制。例如可以训练一个分类器来判断检索到的上下文是否足以回答问题如果不够则直接回复“根据现有资料无法回答”而不是冒险生成错误信息。性能与成本向量检索、重排序、大模型调用都是计算密集型操作尤其是当QPS每秒查询量很高时。如何通过缓存缓存相似的查询和结果、索引优化、模型蒸馏使用更小的重排序模型等手段来降低延迟和成本同时如何为不同的查询需求配置不同的检索链路简单查询走轻量路径复杂查询走完整路径可观测性与调试当用户反馈一个答案不准时如何快速定位问题出在哪个环节是切片切碎了关键信息是嵌入模型不匹配是检索参数不对还是提示词没写好这就需要建立完善的日志和追踪系统记录每一次请求的输入、检索到的片段、传递给模型的提示词以及最终输出以便进行根因分析。4.2 如何评测一个RAG系统评测是迭代优化的指南针。不能只靠“感觉”需要有量化的指标。RAG的评测通常分为多个维度检索阶段评测命中率对于一组有标准答案的问题系统检索到的Top K个片段中包含正确答案的比率。这是衡量检索效果的核心指标。平均排序倒数正确答案在检索结果列表中的平均排名的倒数。排名越靠前得分越高。生成阶段评测忠实度生成的答案是否严格基于提供的上下文有没有捏造上下文之外的信息这可以通过将答案与上下文进行对比来判断。答案相关性生成的答案是否直接回答了用户的问题是否答非所问或包含冗余信息流畅度答案的语言是否通顺、自然 这些指标通常可以通过基于大模型的评测器如使用GPT-4作为裁判来自动化评估也可以结合人工评估。端到端评测整体准确率直接判断最终答案是否正确。这是最直接的业务指标。幻觉率答案中包含事实性错误的比例。构建一个评测基准对于RAG项目至关重要。你需要准备测试集一批有代表性的用户问题。参考答案每个问题的标准答案以及标注了答案出处的“黄金上下文”片段。评估脚本自动化计算上述指标的工具。只有这样当你调整了切片策略、更换了嵌入模型或修改了提示词后才能科学地评估这些改变是带来了提升还是下降。5. RAG实战入门从零搭建一个简易知识库问答系统理论说了这么多我们来动手搭建一个最简单的RAG系统直观感受一下整个流程。我们将使用Python并借助一些成熟的开源库。这个例子将涵盖从文档加载、文本切片、向量化存储到检索问答的全过程。5.1 环境准备与工具选型首先我们需要安装必要的库。这里我们选择LangChain和Chroma。LangChain是一个强大的框架它将RAG流程中的各个组件模块化让我们可以像搭积木一样构建应用。Chroma是一个轻量级、易用的开源向量数据库非常适合原型开发和学习。# 创建虚拟环境可选但推荐 python -m venv rag_env source rag_env/bin/activate # Linux/Mac # rag_env\Scripts\activate # Windows # 安装核心库 pip install langchain langchain-community langchain-chroma # 安装文本加载器和嵌入模型相关库 pip install pypdf sentence-transformers # 用于处理PDF和使用本地嵌入模型 # 安装一个开源大模型例如使用Ollama本地运行或接入API # 这里以使用Ollama运行本地模型为例需要先安装Ollama并拉取模型 # 访问 https://ollama.com/ 安装Ollama然后在终端运行ollama pull qwen2.5:7b pip install ollama5.2 文档加载与智能切片假设我们有一个名为company_handbook.pdf的公司手册PDF文件。第一步是加载并切割它。from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加载PDF文档 loader PyPDFLoader(./company_handbook.pdf) documents loader.load() # 此时documents是一个包含每页内容的列表 # 2. 创建文本分割器 # 我们使用递归字符分割器它会尝试按 [\n\n, \n, , ] 的顺序进行分割尽量保持段落完整性。 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个片段的理想大小字符数 chunk_overlap100, # 片段之间的重叠字符数防止上下文割裂 length_functionlen, # 计算长度的方法 separators[\n\n, \n, , ] # 分割符优先级 ) # 3. 执行分割 all_splits text_splitter.split_documents(documents) print(f原始文档页数{len(documents)}) print(f切割后的片段数{len(all_splits)}) print(第一个片段预览, all_splits[0].page_content[:200])5.3 向量化与存储到Chroma接下来我们需要为每个文本片段生成向量并存储到向量数据库中。from langchain_chroma import Chroma from langchain_community.embeddings import OllamaEmbeddings # 使用Ollama的嵌入模型 # 如果你有OpenAI API也可以使用from langchain_openai import OpenAIEmbeddings # 1. 选择嵌入模型 # 使用本地Ollama服务的嵌入模型确保Ollama服务已运行且拉取了模型如nomic-embed-text embeddings OllamaEmbeddings(modelnomic-embed-text) # 如果使用OpenAI: embeddings OpenAIEmbeddings(modeltext-embedding-ada-002) # 2. 创建向量数据库并存储所有片段 # persist_directory 指定持久化目录这样数据会保存到磁盘下次可以直接加载。 vectorstore Chroma.from_documents( documentsall_splits, embeddingembeddings, persist_directory./chroma_db # 数据保存路径 ) print(向量数据库创建并持久化完成。)5.4 构建检索链并进行问答现在我们已经有了一个“知识库”。接下来构建一个检索问答链。这个链会自动处理“将用户问题转换为向量 - 在库中检索相似片段 - 组合片段和问题形成提示词 - 调用大模型生成答案”这一系列操作。from langchain.chains import RetrievalQA from langchain_community.llms import OllamaLLM # 如果使用OpenAI: from langchain_openai import ChatOpenAI # 1. 从磁盘加载已创建的向量数据库避免重复生成 vectorstore Chroma( persist_directory./chroma_db, embedding_functionembeddings ) # 2. 将向量数据库转换为检索器设置检索返回的片段数量 retriever vectorstore.as_retriever(search_kwargs{k: 4}) # 返回最相似的4个片段 # 3. 选择大语言模型 # 使用本地Ollama运行的模型 llm OllamaLLM(modelqwen2.5:7b) # 如果使用OpenAI: llm ChatOpenAI(modelgpt-3.5-turbo) # 4. 创建检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # “stuff”模式将检索到的所有文档简单拼接后输入模型。还有“map_reduce”、“refine”等复杂模式。 retrieverretriever, return_source_documentsTrue, # 返回检索到的源文档方便调试 verboseTrue # 打印链的详细执行过程便于理解 ) # 5. 进行提问 query 我们公司的年假政策是怎样的 result qa_chain.invoke({query: query}) print(\n 问题 ) print(query) print(\n 模型生成的答案 ) print(result[result]) print(\n 检索到的参考片段前2个) for i, doc in enumerate(result[source_documents][:2]): print(f\n--- 片段 {i1} ---) print(doc.page_content[:300]) # 打印前300个字符预览运行这段代码你就可以体验到一个最基本的RAG系统是如何工作的了。它会从你的公司手册PDF中检索与“年假政策”相关的段落并让大模型基于这些段落生成一个总结性的答案。5.5 关键环节的注意事项与调优这个简易系统虽然跑通了但离生产可用还有距离。以下是几个可以立即着手优化的点切片策略调优chunk_size500和chunk_overlap100只是起点。对于法律合同可能需要更大的chunk_size来保证条款完整性对于技术文档可能需要更小的chunk_size来精准定位API参数。最好的方法是准备一批测试问题调整参数看检索命中率的变化。嵌入模型选择nomic-embed-text是一个不错的通用开源模型。但对于中文场景可以尝试bge-large-zh-v1.5。你可以用HuggingFaceEmbeddings来接入它。更换嵌入模型后需要重新生成向量数据库。提示词工程RetrievalQA使用了默认的提示词。你可以通过chain_type_kwargs参数传入自定义的提示词模板来更好地控制模型的回答风格和格式。例如明确要求模型“如果资料中没有提到就说不知道”。检索后处理重排序我们目前只用了向量检索。可以引入一个重排序模型如BAAI/bge-reranker-large对检索到的4个片段进行精排只将前2个最相关的片段送给模型这通常能提升答案质量。多路召回可以结合Chroma的关键词搜索功能search_typehybrid或集成Elasticsearch实现向量检索和关键词检索的混合查询。通过这个实战例子你应该对RAG的骨架有了更具体的认识。它就像搭积木每个组件加载器、分割器、嵌入模型、向量库、检索器、大模型都可以根据你的需求进行替换和升级。而工程化的挑战就在于如何让这些组件稳定、高效、可观测地协同工作。
返回列表