文章目录简介RAG文本处理核心知识LangChain组件标准流程数据准备用户检索生成回答优化技巧案例代码案例一案例二案例三简介**RAG (Retrieval-Augmented Generation检索增强生成) **是目前大模型应用的核心技术。简单来说它的作用是为大模型挂载一个“外部知识库”。如果把大模型比作一名正在参加闭卷考试的学霸那么 RAG 就是允许这位学霸在遇到不懂的问题时可以翻阅一本指定的参考书再回答。**大模型如 GPT-4, Gemini**虽然博学但存在三个致命弱点幻觉问题 面对不知道的知识模型会“一本正经地胡说八道”。时效性滞后 模型的知识停留在训练数据截止的那一刻无法了解最新的新闻或私有文档。数据安全 企业不希望将敏感的内部文档发送给大模型进行训练。**解决方案1**每次问答都把所有文档资料问题都输入给模型保证模型获取最大知识量。**分析**很显然这种方案是不可行的原因在于(1) 上下文窗口限制(2) 成本昂贵(3) 响应速度变慢。解决方案2在模型回答之前先检索资料再基于检索到的资料生成答案。也就是RAG设计理念RAG技术就像给AI大模型装上了「实时百科大脑」为了让大模型获取足够的上下文以便获得更加广泛的信息源通过先查资料后回答的机制让AI摆脱传统模型的知识遗忘和幻觉回复的困境RAG文本处理核心知识LangChain组件LangChain组件作用常用组件类文档加载器对各种格式的文档信息进行加载转为Document对象如下page_content: 文档内容metadata元数据 Document文档组件 CSVLoadercsv JSONLoaderjson BHTMLhtml UnstructuredPDFLoaderPDF UnstructuredFileLoader文件文档 UnstructuredMarkdownLoadermarkdown文档文档分割器将加载的文档分割成文档片段RecursiveCharacterTextSplitter递归字符文本分割器 CharacterTextSplitter按指定字符分割文本 MarkdownTextSplitter按md标题分割文本 PythonCodeTextSplitter专门分割Python代码TokenTextSplitter按Token数量分割文本嵌入模型将文本信息向量化 OpenAIEmbeddings HuggingFaceEmbeddings向量数据库将向量和元数据信息保存到向量数据库 VectorStore向量数据库文本检索器根据用户提问在向量数据库中进行检索 VectorStoreRetriever向量数据库检索器文档加载器核心方法load()Load data into Document objectslazy_load()A lazy loader for Document文档分割器核心方法split_text()将文本字符串分割成字符串列表split_documents():将Document对象列表分割成更小文本片段的Document对象列表create_documents():通过字符串列表创建Document对象RecursiveCharacterTextSplitter核心参数参数名核心含义详细说明chunk_size文本块最大长度单文本块最大字符数可通过 length_function 自定义计数适配模型上下文窗口如 GPT-3.5 设 3000 。chunk_overlap文本块重叠长度相邻块重叠字符数保留上下文需小于 chunk_size建议为其 10%-20%。separators递归拆分分隔符按优先级拆分超尺寸则用下一个分隔符最后强制拆分可自定义领域分隔符。length_function长度计算函数默认按字符计数可自定义如 tiktoken 按 token 计数适配大模型。keep_separator是否保留分隔符默认 False 丢弃True 保留于块末尾助力保留原格式。标准流程数据准备将长文档切成小块Chunks通过 Embedding 模型转换成高维向量存储在向量数据库中。RAG效果好不好80% 取决于数据准备阶段。文档加载与清洗 (Load Clean)核心处理原始垃圾从 PDF、网页或数据库等企业内部文档中提取文本。关键任务是去除噪声删除页眉页脚、广告条、乱码以及不相关的格式字符涉及数据清洗、OCR文档识别等技术。文档切分 (Chunking)核心确定颗粒度将长文章按章节、段落、固定字符等粗略切成小块Chunks。难点在于chunk若太大会包含太多噪声太小会丢失上下文。通常采用“固定长度 重叠Overlap”的策略确保相邻块之间保留语义连续性。文档向量化 (Embedding)核心文字转数字通过 Embedding 模型将文本块转换为一串数字高维向量。相似意思的文本在数学空间里的距离会更近。构建索引Indexing核心建立搜索目录选择适合的算法如 HNSW 或 IVF来组织这些向量确保在数百万条数据中能以毫秒级速度找到最相关的项。入库storage核心存入向量数据库。将向量与其原始文本、元数据如文件名、页码、日期一起存入向量数据库如 Milvus 或 Pinecone。用户检索当用户提问时系统将问题也转化为向量在数据库中搜索最相似的 top-k 个文档块。用户提问用户输入问题例如“张三是谁”。问题改写 (Query Rewrite)将模糊的问题转化为更具体的描述如“详细介绍张三的性格与年龄”。向量化将问题转化为向量。相似度检索 (Similarity Search)计算问题向量与数据库中各块向量的距离如余弦相似度、欧氏距离。混合检索 (Hybrid Search)结合“关键词检索”与“向量相似度检索”以提高准确率。召回 (Recall)取出 Top-K 个最相关的文本块。重排 (Rerank)对召回的文本块进行二次排序精选出最相关的部分。生成回答构建 Prompt将[用户问题] [检索到的参考文档] [提示词]组合在一起。LLM 生成模型参考背景资料输出最终答案Response有效缓解幻觉问题提高逻辑性与准确性。优化技巧在实际落地中需要关注以下优化方向数据清洗与 OCR提高源文件质量。Chunk 策略块太大会引入噪音太小会导致语义丢失。多路召回与重排优化检索的相关度。开源部署针对私有化部署场景的优化。案例代码案例一# 加载TXT文件from langchain_community.document_loadersimportTextLoader file_pathassets/sample.txttxtTextLoader(file_pathfile_path,encodingutf-8,).load()print(txt)# [Document(metadata{source: assets/sample.txt}, page_contentHello world!追加内容.)]# 加载PDF文件from langchain_community.document_loadersimportPyPDFLoader file_pathassets/sample.pdfpdfPyPDFLoader(file_pathfile_path,# plain 提取文本# layout 按布局提取extraction_modeplain).load()print(pdf)案例二from langchain_text_splittersimportRecursiveCharacterTextSplitter# 1.分割文本内容content 单文本块最大字符数可通过 length_function 自定义计数适配模型上下文窗口如 GPT-3.5 设3000左右相邻块重叠字符数保留上下文需小于 chunk_size建议为其10%-20%。, 按优先级拆分超尺寸则用下一个分隔符最后强制拆分可自定义领域分隔符,默认按字符计数可自定义如 tiktoken 按 token 计数适配大模型。# 2.定义递归按字符文本分割器# 遵循“重叠后向前取有效内容且不生成小碎片”的核心分割逻辑不会让最后一个片段的有效内容只剩扣除重叠后的少量字符text_splitterRecursiveCharacterTextSplitter(chunk_size100,# 文本块最大长度是「最大限制」不是精确值当文本结构不符合分隔符时会出现不均匀分割chunk_overlap10,# 文本块重叠长度length_functionlen,# 长度计算函数)# 3.分割文本将原始大文本分割成多个文本块splitter_textstext_splitter.split_text(content)# 4.转换为文档对象splitter_documentstext_splitter.create_documents(splitter_texts)print(f原始文本大小: {len(content)})print(f分割文本数量: {len(splitter_texts)})print(f分割文档数量: {len(splitter_documents)})forsplitter_documentinsplitter_documents: print(f文档片段大小: {len(splitter_document.page_content)}, 文档内容: {splitter_document.page_content})案例三from langchain_community.document_loadersimportTextLoader from langchain_text_splittersimportRecursiveCharacterTextSplitter# 1.TXT文档加载器txt_loaderTextLoader(file_pathassets/sample.txt,encodingutf-8,).load()# 2.定义递归文本分割器text_splitterRecursiveCharacterTextSplitter(chunk_size100,chunk_overlap10,length_functionlen)# 3.分割文本splitter_documentstext_splitter.split_documents(documentstxt_loader)print(f分割文本数量: {len(splitter_documents)})fordocumentinsplitter_documents: print(f文档片段: {document.page_content})print(f文档片段大小: {len(document.page_content)})