AI- RAG笔记02 - Load Chunking
导读本文学习来源 all-in-rag个人学习笔记整理总结有错误或者遗漏希望大家指正Load解决“怎么把不同格式的资料读进来并变成可处理的文本和元数据”。Chunking解决“怎么把长文档切成适合检索和生成的知识块”。Load 和 Chunking 在 RAG 中的位置RAG 一般分为离线知识库构建和在线问答两条链路。离线知识库构建文档收集 - 加载解析 - 清洗过滤 - 文本切分 - 向量化 - 写入向量库在线问答用户问题 - 问题向量化 - 检索相关 chunk - 可选重排 - 拼接上下文 - 大模型生成答案Load和Chunking决定了向量库里到底存放什么知识、以什么粒度存放。后面的 embedding、retrieval、generation 都建立在它们的输出之上。如果这一步做差了文本没加载全后面永远检索不到缺失内容。噪声没清掉向量库会存入大量无意义内容。chunk 切得太碎答案缺上下文。chunk 切得太大语义被稀释检索不准。元数据缺失回答无法引用来源和页码。一句话Load 决定原材料质量Chunking 决定知识入库粒度。Load1. Load是什么Data Load不是简单的open().read()而是把不同格式、不同结构、不同质量的原始资料解析成统一的文本对象和元数据对象。它要解决三个问题读什么PDF、Word、Markdown、HTML、TXT、网页、数据库、API 等。怎么读选择合适的 loader 和解析策略。读出来怎么用保留正文、结构、元数据并过滤噪声。典型输出不是一个普通字符串而是类似这样的结构{page_content:RAG 是一种结合检索和生成的技术……,metadata:{source:rag.pdf,page_number:3,category:NarrativeText,section:技术定义}}其中page_content是后续要切分和向量化的正文metadata是后续检索过滤、来源引用、错误排查的重要依据。2. Load 做什么2.1 解析原始格式不同格式的资料有完全不同的解析难点。格式加载重点TXT编码、换行、空行Markdown标题、列表、代码块、链接PDF阅读顺序、页眉页脚、表格、扫描件、OCRWord标题样式、段落、表格、批注HTML正文抽取、导航栏、广告、脚本、页脚Excel行列关系、表头、sheet 名称代码文件函数、类、注释、依赖结构PDF 最麻烦因为它更关心“页面长什么样”不一定保存了正确的文本逻辑顺序。2.2 提取文档结构好的 loader 不只提取文字还会尽量识别文档元素元素类型含义RAG 中的处理建议Title标题通常保留可作为 chunk 上下文NarrativeText正文段落主要知识来源ListItem列表项常和上级标题合并Table表格尽量转 Markdown 或 JSONFigureCaption图片说明可与图片或附近正文绑定Header页眉经常是噪声需要评估过滤Footer页脚常见噪声如页码、水印、版权PageNumber页码更适合作为 metadataCodeSnippet代码块保持格式不要随意切碎UncategorizedText未分类文本需要抽样判断注意元素类型是加载器的判断结果不是真理。一段正文可能被误判为Title导航栏也可能被解析成Header。2.3 保留元数据元数据是“关于文本的信息”。它不一定参与正文语义但对 RAG 非常重要。常见元数据包括source文件路径或 URL。page_number页码。section_title所属章节标题。filetype文件类型。category元素类型。created_at或last_modified时间信息。permission权限范围企业知识库常用。元数据的价值溯源回答时能引用文件、页码或链接。过滤只检索某类文档、某个时间范围、某个部门资料。调试定位错误来自加载、切分、检索还是生成。权限避免用户查到不该看的私有知识。3. 常见 loader加载器没有绝对最好只有是否适合当前数据。工具适合场景特点TextLoader纯文本简单、快、依赖少DirectoryLoader批量目录文件适合本地知识库批处理UnstructuredPDF、Word、HTML、Markdown 等统一接口能识别文档元素PyMuPDF4LLM文本型 PDF 转 Markdown对 PDF 文本抽取友好MarkerPDF 转 Markdown适合书籍、论文类 PDFMinerU学术论文、财报、复杂 PDF版面、公式、表格能力更强Docling企业报告、合同、表格偏企业级文档解析LlamaParse复杂 PDF、法律、论文商业 API解析质量较高FireCrawlLoader网页、在线文档抓取并抽取网页正文选择思路简单文本用简单 loader不要过度复杂化。网页重点处理导航栏、广告、推荐内容和页脚。扫描 PDF 必须考虑 OCR。论文、合同、财报要重点关注标题层级、表格、公式和跨页内容。技术文档要保护代码块和标题结构。3.1 Unstructured 基本理解Unstructured是面向非结构化文档处理的工具。它的优点支持多种文档格式。提供统一的partition入口。能把文档拆成带类型的Element。能保留元数据。能在解析之后继续做元素级 chunking。示例fromunstructured.partition.autoimportpartition elementspartition(filename../../data/C2/pdf/rag.pdf,content_typeapplication/pdf)forelementinelements:print(element.category)print(element)常见参数参数作用filename本地文件路径file文件对象url远程文件地址content_type指定 MIME 类型减少自动识别误差include_page_breaks是否保留分页符strategy解析策略如auto、fast、hi_res、ocr_onlyencoding文本编码策略理解fast速度快适合文本层清晰的 PDF。hi_res更重视版面分析适合复杂 PDF。ocr_only适合扫描件或图片型 PDF。auto自动选择适合入门但生产环境要抽样验证。4. Load 质量怎么判断不要只看“代码是否跑通”要看“解析结果是否适合作为知识入库”。维度检查问题坏结果表现完整性正文、标题、表格、列表是否都在原文有答案解析结果里没有准确性文字是否识别正确OCR 错字、乱码、符号丢失顺序性阅读顺序是否正确多栏 PDF 左右栏串读结构性标题、正文、列表、表格是否区分全部混成一坨文本干净程度是否混入噪声导航栏、广告、水印、页脚大量出现元数据是否保留来源、页码、章节答案无法引用来源可切分性输出是否适合进入 chunking片段过碎、过长或语义断裂推荐检查方式fromcollectionsimportCounter typesCounter(e.categoryforeinelements)print(types)fori,einenumerate(elements[:20],1):print(i,e.category,str(e)[:200])要重点抽样看文档开头、中间、结尾。开头容易有目录和导航中间代表正文质量结尾容易有参考文献、版权、水印和页脚。5. Load 后的清洗与规范化加载成功不等于可以直接入库。加载后通常还需要清洗和规范化。常见处理删除页眉、页脚、广告、导航栏、水印、版权声明。删除空文本、无意义短文本、重复菜单。合并被错误拆开的相邻段落。把标题挂到对应正文前面。表格转成 Markdown 或 JSON。保留代码块缩进和格式。统一 metadata 字段名称。保存中间结果方便回溯。推荐流程Load - Inspect - Clean - Normalize - Chunk - Embedding - 入库不要直接Load - Chunk - Embedding - 入库6. Load、Element、Chunk 的区别概念含义例子Load把原始文件读入并解析PDF - 一组元素Element加载器解析出的结构单元一个标题、一个段落、一个表格Chunk为检索和向量化准备的文本块一个语义完整的知识片段关系一个 chunk 可以由多个 element 合并而来。一个过长的 element 也可以被继续切成多个 chunk。element 偏文档结构chunk 偏检索粒度。例如Title: 工作流程 NarrativeText: RAG 包含三个主要过程检索、增强和生成。 ListItem: 检索从外部知识库获取相关信息。 ListItem: 增强将查询和检索内容放入提示词模板。 ListItem: 生成让大模型生成答案。这些 element 可以合并成一个 chunk工作流程 RAG 包含三个主要过程检索、增强和生成。 检索从外部知识库获取相关信息。 增强将查询和检索内容放入提示词模板。 生成让大模型生成答案。Chunking1. chunk是什么Text Chunking是把加载后的长文档切成更小、更适合处理的文本块。它不是为了“把文本切短”这么简单而是为了设计 RAG 系统中的知识检索单位。一句话Chunk 是向量库里的基本知识单位也是检索返回给大模型的基本上下文单位。如果用户问一个问题检索系统并不是把整篇文档都拿出来而是找出最相关的几个 chunk再交给大模型生成答案。所以 chunking 的目标是每个 chunk 足够小能被 embedding 模型完整处理。每个 chunk 足够完整能表达一个相对清楚的语义。每个 chunk 噪声少主题集中容易被问题召回。每个 chunk 带有 metadata方便溯源和过滤。2. 为什么要 Chunking2.1 适应 Embedding 模型上下文限制Embedding 模型有输入长度上限。超过上限的内容可能被截断导致向量不能代表完整文本。例如一个 embedding 模型最多处理 512 token如果传入 2000 token后面内容可能直接丢失或被截断。所以 chunk 大小必须适配 embedding 模型的上下文窗口。2.2 适应 LLM 上下文窗口生成阶段会把多个检索结果、用户问题和提示词一起放入 LLM 上下文。如果单个 chunk 过大能放入 prompt 的 chunk 数量会减少。模型看到的信息广度会下降。无关内容会挤占上下文窗口。2.3 提高检索精准度检索的基本单位是 chunk。chunk 主题越集中越容易和用户问题匹配。如果一个 chunk 同时包含“技能介绍、背景故事、推荐出装”用户问“怎么出装”时这个 chunk 的语义会被其他主题稀释可能召回不出来。2.4 降低生成噪声LLM 拿到的上下文越干净越容易给出可靠答案。chunk 太大、太杂、噪声太多会增加幻觉和答非所问的概率。3. 为什么 chunk 不是越大越好既然模型上下文很长那 chunk 大一点不是更完整吗答案是否定的。3.1 Embedding 会压缩信息Embedding 的本质是把一段文本压缩成一个固定维度向量。例如把一段文本压缩成 768 维向量很短且主题单一的文本 - 768 维向量 很长且主题很多的文本 - 也是 768 维向量文本越长、主题越多一个向量要承载的信息越多语义就越容易被稀释。3.2 Lost in the Middle长上下文模型也不是平均关注所有位置。大量研究和实践都发现模型更容易关注开头和结尾中间信息可能被忽略。如果 chunk 很大关键信息可能埋在中间生成时更难被模型利用。3.3 主题稀释一个好的 chunk 应该围绕一个相对明确的主题。坏 chunk角色背景 技能介绍 参考资料 页面导航 广告好 chunk技能激素枪 激素枪可以远程治疗队友也可以自我治疗……主题越集中检索越精准。4. chunk_size / chunk_overlap / separator / metadata4.1 chunk_sizechunk_size是每个 chunk 的目标大小。它可以按字符数、token 数或其他长度函数计算。LangChain 中很多 splitter 默认按字符数计算也可以传入 token 计数器。影响太小上下文不足语义容易断。太大主题混杂检索不准成本更高。4.2 chunk_overlapchunk_overlap是相邻 chunk 之间重复保留的内容。作用缓解边界处语义被切断的问题。保留跨段落、跨句子的上下文。提高边界附近内容被召回的概率。代价overlap 越大重复内容越多。向量库体积变大。embedding 成本和检索噪声可能增加。4.3 separatorseparator是切分优先使用的分隔符例如段落、换行、句号、逗号、空格。好的分隔符顺序应该尽量从大语义单位到小语义单位[\n\n,\n,。,, ,]这表示优先按段落切再按换行、句子、短语、空格最后必要时按字符切。4.4 metadatachunk 不应该只有正文还应该继承或补充元数据{source:蜂医.txt,section:技能,chunk_index:12}metadata 让 chunk 可过滤、可排序、可引用、可调试。5. 常见切分策略5.1 基础切分策略一CharacterTextSplitterCharacterTextSplitter通常被理解为固定大小分块但 LangChain 的实现并不是机械地每 N 个字符切一次。它大致做两件事先按分隔符切分默认常用段落分隔符。再把小片段合并到接近chunk_size的大小。示例fromlangchain.text_splitterimportCharacterTextSplitter text_splitterCharacterTextSplitter(chunk_size200,chunk_overlap10)chunkstext_splitter.split_documents(docs)优点简单、快、容易理解。适合日志、短文本、结构不复杂的材料。缺点语义感知弱。遇到超长段落时可能无法继续细切。容易在不合适的位置切断内容。理解重点CharacterTextSplitter 更像“按分隔符切分后再按大小合并”不是绝对均匀切块。5.2 基础切分策略二RecursiveCharacterTextSplitterRecursiveCharacterTextSplitter是 RAG 中最常用的基础切分器之一。它的核心思想先用大粒度分隔符切如果还太长就递归使用更小粒度分隔符继续切。典型分隔符separators[\n\n,\n,。,, ,]算法过程1. 优先按段落切 2. 段落仍太长就按换行切 3. 仍太长就按句号切 4. 仍太长就按逗号、空格切 5. 最后必要时按字符切示例fromlangchain.text_splitterimportRecursiveCharacterTextSplitter text_splitterRecursiveCharacterTextSplitter(separators[\n\n,\n,。,, ,],chunk_size200,chunk_overlap10,)chunkstext_splitter.split_documents(docs)优点比固定字符切分更尊重语义边界。能处理超长段落。配置简单适合大多数普通文档。缺点本质仍是字符规则不真正理解语义。分隔符设计不好时中文文本容易切得不理想。中文文本建议加入中文标点separators[\n\n,\n, ,。,,,,、,]代码文档可以使用语言特化分隔符RecursiveCharacterTextSplitter.from_language(languageLanguage.PYTHON,chunk_size500,chunk_overlap50)5.3 基础切分策略三SemanticChunkerSemanticChunker是语义分块。它不主要依赖字符数或固定分隔符而是尝试在语义发生明显变化的位置切开。核心思想相邻句子语义差异小就放在一起语义差异大就在中间切开。工作流程1. 把文本切成句子 2. 给句子或句子窗口生成 embedding 3. 计算相邻句子的语义距离 4. 根据阈值识别语义断点 5. 按断点合并成 chunk它需要的是embedding model不是聊天模型。DeepSeek 这类聊天模型通常用于生成不适合直接作为SemanticChunker的 embedding 来源。可以使用本地bgeembedding也可以使用千问、OpenAI 等 embedding API。示例fromlangchain_experimental.text_splitterimportSemanticChunker text_splitterSemanticChunker(embeddings,breakpoint_threshold_typepercentile)docstext_splitter.split_documents(documents)断点识别方法方法含义适合场景percentile超过某个百分位的语义距离就切默认方法通用standard_deviation超过均值加 N 倍标准差就切语义变化比较明显的文本interquartile用四分位距识别异常跳跃抗异常值能力较好gradient看语义距离变化率法律、医疗等语义变化较细的文本优点更接近“按主题变化切分”。对长文本的主题边界更敏感。缺点依赖 embedding 模型质量。成本更高速度更慢。参数不好时可能切得太少或太多。语义切分不保证 chunk 大小一定适合检索。对于 Markdown、HTML、LaTeX、代码等结构明显的文档优先利用文档结构。5.4 MarkdownHeaderTextSplitterMarkdown 文档天然有标题层级# 第一章 ## 1.1 背景 ## 1.2 方法可以用MarkdownHeaderTextSplitter按标题切分并把标题路径写入 metadata。好处保留章节结构。chunk 能知道自己属于哪个标题。检索和生成时上下文更明确。典型流程先按标题切成逻辑块 - 再用 RecursiveCharacterTextSplitter 控制大小这是非常实用的组合结构切分负责语义边界递归切分负责长度控制。5.5 HTML、JSON、代码不同结构文档适合不同切分方式文档类型推荐思路Markdown按标题层级切再按长度细分HTML先抽正文再按标题、段落、DOM 区块切JSON按对象、字段、路径切保留 key path代码按类、函数、方法切保留文件路径和符号名表格按表、行组、语义字段切保留表头结构化文档不要一上来粗暴按字符切否则会丢掉天然结构优势。6. 如何选择切分策略没有通用最优 chunking。要根据文档类型、任务目标、embedding 模型和检索方式选择。场景推荐策略普通文章、说明文档RecursiveCharacterTextSplitterMarkdown 技术文档标题切分 递归字符切分HTML 网页正文抽取 标题/段落切分PDF 报告、合同Unstructured/MinerU 解析元素 by_title 或递归切分代码库按文件、类、函数切分法律、医疗长文档结构切分 语义切分 严格质检问答型短知识小 chunk低 overlap需要综合上下文的场景父子 chunk 或句子窗口初学和大多数普通 RAG 项目可以先用Load/Clean - RecursiveCharacterTextSplitter - Embedding - 检索评估如果文档结构明显再升级为结构切分 - 递归切分 - 保留标题 metadata - Embedding7. 切分参数怎么调调参没有固定答案但有经验范围。7.1 chunk_size常见经验中文短问答知识200 到 500字符。普通说明文档500 到 1000字符。英文或 token 计数场景200 到 800token。代码块尽量按函数或类不只看长度。表格尽量按表格语义不只看长度。判断方式如果召回结果经常缺上下文chunk 可能太小。如果召回结果经常包含多个无关主题chunk 可能太大。7.2 chunk_overlap常见经验普通文本chunk_size 的10% 到 20%。结构清晰文档overlap 可以小一些。叙事连续文档overlap 可以适当大一些。知识点独立文档overlap 不宜过大。判断方式如果边界处信息经常丢失增加 overlap。如果重复召回严重、向量库膨胀减少 overlap。7.3 不要只看数量chunk 数量多不一定好少也不一定坏。重点看是否覆盖关键知识。是否主题集中。是否大小合适。是否能被典型问题召回。是否能支撑模型回答。8. chunk结果怎么判断效果好 chunk 的特征主题集中。语义完整。长度适中。噪声少。有清楚的来源和标题 metadata。能独立回答某一类问题。不把无关章节强行混在一起。坏 chunk 的特征只有半句话缺上下文。太长包含多个主题。混入导航栏、页脚、水印、参考资料噪声。表格行列关系丢失。代码块被切断。没有 source、page、section 等元数据。检索时经常答非所问。8.1 肉眼抽查抽查每个 chunk开头是否突兀。结尾是否断裂。是否包含完整知识点。是否混入无关主题。metadata 是否正确。8.2 用典型问题测试召回准备一些真实问题蜂医的技能有哪些 蜂医在团队中的定位是什么 激素枪有什么作用看检索结果是否召回正确 chunk。正确 chunk 是否排名靠前。召回内容是否足够回答问题。是否混入大量噪声。8.3 看最终回答质量最终还是要看 RAG 回答是否准确。是否引用来源。是否遗漏关键点。是否因为上下文不足而幻觉。9. Chunking 常见误区9.1 只追求 chunk 小chunk 太小会导致上下文不足。模型可能只看到一个局部片段不知道它属于哪个主题。9.2 只追求 chunk 大chunk 太大会导致主题稀释。embedding 向量会变得笼统检索不精准。9.3 只用一种策略处理所有文档PDF、Markdown、网页、代码、表格的结构不同不应该全部用同一种切法。9.4 忽略 metadata只保存正文不保存来源、标题、页码会让系统难以溯源和调试。9.5 认为语义切分一定最好语义切分更智能但也更依赖 embedding 模型和参数。它可能切得太粗也可能切得太碎。语义切分仍然需要评估。总结Load 是把原始资料变成可处理的知识原料。 Chunking 是把知识原料设计成适合检索的知识单位。Load 的核心关注文件是否能读出来。内容是否完整准确。结构是否被识别。噪声是否被清理。元数据是否保留。Chunking 的核心关注chunk 是否语义完整。chunk 是否主题集中。chunk 是否长度合适。chunk 是否能被问题召回。chunk 是否带有可溯源 metadata。