在 RAG 系统里很多问题表面上看像是模型回答不准实际根源可能更早。用户问的问题明明在文档里系统却检索不到检索到了内容但答案只说了一半模型拿到上下文后仍然答偏引用来源看起来相关但点进去发现不是用户真正需要的那一段。这些问题不一定是大模型不够聪明也不一定是向量数据库不够强。很多时候是文档切分出了问题。文档切分也就是常说的 Chunking是 RAG 里非常容易被低估的一步。很多初版知识库系统会直接按固定字数切比如每 500 字切一段每段之间重叠 50 字。这样做实现简单Demo 也能跑起来但一旦文档复杂起来就很容易出现问题。因为 Chunk 不是普通文本碎片而是 RAG 系统里的检索单元。切分方式决定了后面系统能检索到什么、模型能看到什么、答案能不能完整、引用能不能准确。为什么文档一定要切分在理想情况下我们当然希望模型能直接读取完整文档然后回答用户问题。但真实系统里通常不能这样做。原因很简单。第一文档可能很长。一份制度文档、产品手册、接口说明、项目资料动不动就是几千字、几万字甚至更长。直接把完整文档塞进模型上下文成本高、速度慢也容易超过上下文限制。第二用户问题通常只对应文档中的局部内容。比如用户问“试用期员工能不能申请年假”真正相关的可能只是员工手册里的两三段。如果把整本文档都给模型模型反而会被大量无关内容干扰。第三检索需要一个合理的最小单位。向量检索不是在整份知识库里凭空找答案而是要在一个个可检索片段中计算相关性。如果每个片段太大相关信息会被淹没如果每个片段太小完整语义又会被拆散。所以文档切分的目标不是把文档切得越碎越好而是把文档切成适合检索和回答的语义单元。一个好的 Chunk应该尽量满足几个条件能表达一个相对完整的意思。包含足够回答问题的上下文。不混入太多无关内容。可以被用户问题准确召回。能作为答案引用的依据。这几个条件看起来简单但在真实文档里并不好做到。常见误区一按固定字数粗暴切分最常见的切分方式是固定长度切分。比如每 500 字切一个 chunk。 相邻 chunk 重叠 50 字。 超过长度继续切。这种方式最大的优点是简单。不管文档是什么格式都能快速切成一批片段马上进入 Embedding 和索引流程。但它的问题也很明显固定字数不理解文档结构。假设一段制度是这样写的员工入职未满一年时年休假按实际工作月份折算。 试用期员工如满足折算条件可以在系统中提交年休假申请。 申请需经直属负责人和人事部门审批后生效。如果系统刚好在第一句和第二句之间切开可能就会出现两个不完整的 Chunk员工入职未满一年时年休假按实际工作月份折算。试用期员工如满足折算条件可以在系统中提交年休假申请。 申请需经直属负责人和人事部门审批后生效。用户问“试用期员工能不能申请年假”第二个 Chunk 能回答一部分但缺少“按实际工作月份折算”的条件第一个 Chunk 有条件但没有直接提到试用期。如果检索只召回其中一个答案就可能不完整。再比如一个标题下面有几个连续段落共同描述一个流程。如果按固定字数切分很可能把流程步骤拆到不同 Chunk 里。模型拿到其中一段后只能回答局部内容。这就是固定字数切分的核心问题它保证了长度可控但不保证语义完整。常见误区二Chunk 越小越精准很多人会觉得Chunk 越小检索越精准。这个想法只对了一半。Chunk 小确实可以减少无关内容让每个片段更聚焦。但如果太小就会失去上下文。比如一个文档里写以下情况不允许远程办公 1. 涉及生产环境变更期间。 2. 涉及客户现场交付期间。 3. 部门负责人明确要求现场协作期间。如果切得太小可能变成以下情况不允许远程办公1. 涉及生产环境变更期间。2. 涉及客户现场交付期间。3. 部门负责人明确要求现场协作期间。这些片段单独看都不完整。用户问“客户现场交付期间能远程办公吗”系统可能召回“涉及客户现场交付期间”这个片段但模型如果没有看到前一句“以下情况不允许远程办公”就无法判断这是允许还是不允许。这就是 Chunk 过小带来的问题。它让召回结果看起来很精确但缺少判断答案所需的语义背景。所以 Chunk 的目标不是“越小越好”而是“刚好能承载一个可回答问题的最小语义单元”。这句话非常重要。一个好的 Chunk 应该让模型看到它时能理解这段内容在说什么而不是只看到孤立的一句话。常见误区三Overlap 越大越安全为了避免切分时把语义拆断很多系统会使用 overlap也就是相邻 Chunk 之间保留一部分重复内容。比如chunk size 500 overlap 100Overlap 是有用的。它可以缓解边界处语义被切断的问题让前后片段之间有一定连续性。但 overlap 不是越大越好。如果 overlap 太大会带来几个问题。第一索引体积变大。同一段内容被重复写入多个 ChunkEmbedding 成本和存储成本都会增加。第二检索结果容易重复。用户提问后TopK 里可能出现多个高度相似的片段占用候选位置却没有提供更多有效信息。第三引用来源会变得混乱。如果多个 Chunk 都包含同一段文字系统很难判断到底应该引用哪个片段。第四模型上下文被重复内容浪费。当多个相似 Chunk 一起进入 Prompt模型看到的是重复信息而不是更多互补信息。所以 overlap 应该是补偿切分边界的工具而不是掩盖粗糙切分策略的万能办法。如果一个系统需要非常大的 overlap 才能勉强回答问题往往说明切分方式本身需要重新设计。Chunk 的本质是检索单元要做好文档切分首先要改变一个理解Chunk 不是为了让文本长度整齐而是为了让检索结果可用。一个 Chunk 会经历这样的链路原始文档片段 ↓ Embedding 向量化 ↓ 进入向量索引 ↓ 被用户问题召回 ↓ 进入模型上下文 ↓ 支撑最终答案所以设计 Chunk 时要从后面的使用场景倒推。用户可能会问什么答案通常需要多长上下文一个制度条款是否必须和标题一起出现一个表格是否能拆成多行一个流程是否必须保留步骤顺序一个代码示例是否必须和说明文字放在一起这些问题比“每个 Chunk 切多少字”更重要。如果切出来的 Chunk 不能被准确召回或者召回后不能支撑答案生成那么长度再漂亮也没有意义。普通段落怎么切普通文本段落是最容易处理的一类文档。比如说明文、制度说明、产品介绍、FAQ 文档等。这类文档可以优先按自然段切分。自然段通常表达一个相对完整的意思比固定字数更符合语义结构。但也不能完全无脑按段落切。有些段落太短单独作为 Chunk 信息量不足有些段落太长包含多个主题需要进一步拆分。比较实用的做法是优先保留自然段。太短的段落可以和相邻段落合并。太长的段落再按句子或子主题拆分。标题要和下面的正文建立关联。切分后检查每个 Chunk 是否能独立表达意思。比如## 年假规则 员工入职未满一年时年休假按实际工作月份折算。 试用期员工如满足折算条件可以在系统中提交年休假申请。 申请需经直属负责人和人事部门审批后生效。这里最好不要只保留正文还要让 Chunk 知道它属于“年假规则”这一节。因为标题往往提供了重要语义。如果标题丢失正文里的“申请”“折算”“审批”可能会变得不够清楚。标题层级很重要很多文档是有层级结构的比如1. 请假制度 1.1 年假 1.2 病假 1.3 调休 2. 考勤制度 2.1 打卡规则 2.2 异常处理如果切分时只保留正文不保留标题路径就会丢失上下文。比如正文里写申请需提前三个工作日在系统中提交。这句话单独看并不知道是在说年假、病假、调休还是其他流程。如果 Chunk 中包含标题路径就更清楚请假制度 年假 申请需提前三个工作日在系统中提交。标题路径可以显著提升检索和生成质量。对 RAG 来说标题不只是排版元素而是重要的语义信息。所以切分 Markdown、Word、网页等结构化文档时建议尽量保留标题层级。一个常见做法是给每个 Chunk 附加 metadatadocument_title: 员工手册 section_path: 请假制度 年假 chunk_text: 申请需提前三个工作日在系统中提交。这样后续检索、过滤、引用都会更清楚。列表不要随便拆散列表在企业文档里非常常见。比如流程步骤、条件说明、风险点、操作清单、权限规则等。列表最怕被切散。比如报销申请需要满足以下条件 1. 发票真实有效。 2. 金额与申请单一致。 3. 审批流程已完成。 4. 未超过报销期限。如果每个列表项单独成为一个 Chunk用户问“报销申请需要满足哪些条件”系统可能只召回其中两三项答案就会漏。列表通常有两种处理方式。第一如果列表不长尽量整体保留。第二如果列表很长可以按小组拆分但每个小组都要带上列表主题。比如报销申请需要满足以下条件 1. 发票真实有效。 2. 金额与申请单一致。报销申请需要满足以下条件 3. 审批流程已完成。 4. 未超过报销期限。这样即使拆开每个 Chunk 也知道自己属于“报销申请条件”。这比单独保留“3. 审批流程已完成”要可靠得多。表格是 RAG 切分里的难点很多真实知识库都包含表格。比如价格表、参数表、权限矩阵、版本对照、接口字段说明、配置清单等。表格处理不好RAG 效果会明显下降。一个常见错误是直接把表格转成普通文本然后按字数切。比如原表格是| 角色 | 权限 | 审批人 | | --- | --- | --- | | 普通员工 | 提交申请 | 直属负责人 | | 部门经理 | 审批部门申请 | 人事部门 | | 财务人员 | 复核报销单 | 财务负责人 |如果切分后丢了表头某一行可能变成普通员工 提交申请 直属负责人模型看到这句话时很难知道三个字段分别是什么意思。表格切分时至少要注意保留表头。保留行和列的对应关系。避免把同一行拆断。长表格可以按行分组但每组都要带表头。表格标题和说明文字也要保留。比较可用的形式是表格角色权限说明 字段角色、权限、审批人 记录普通员工权限为提交申请审批人为直属负责人。 记录部门经理权限为审批部门申请审批人为人事部门。这样比简单拼接表格文本更适合模型理解也更适合检索。代码块和接口文档要保持结构技术文档里经常会有代码块、接口示例、JSON 结构、错误码表等内容。这类内容不能随便切。比如一个接口文档通常包括接口名称。请求路径。请求方法。请求参数。返回字段。示例请求。示例响应。错误码说明。如果把请求参数和接口路径切开用户问参数含义时系统可能不知道这个参数属于哪个接口。如果把返回示例和字段说明切开模型可能无法准确解释字段。所以接口文档切分时要尽量围绕接口粒度组织。一个接口不长时可以把接口说明整体作为一个 Chunk。如果接口很长可以按请求参数、返回参数、错误码拆分但每个 Chunk 都要保留接口名称和路径。比如接口创建订单 路径POST /orders 部分请求参数 参数 user_id 表示用户 ID必填。 参数 product_id 表示商品 ID必填。 参数 quantity 表示购买数量默认值为 1。这样用户问“创建订单接口的 quantity 参数是什么意思”系统更容易召回正确片段。技术文档的切分目标不是让文本变短而是让结构关系不丢。长文档可以先分层再切分长文档最容易让 RAG 系统失控。比如一份几十页的员工手册、一份完整产品白皮书、一份项目交付规范。如果直接按固定字数切系统会得到大量碎片后续检索很容易召回相似但不准确的内容。对长文档更推荐分层处理。可以先按文档结构拆成章节再在章节内部切分。大致流程是完整文档 ↓ 按一级标题拆分 ↓ 按二级标题拆分 ↓ 按自然段、列表、表格继续细分 ↓ 为每个 Chunk 附加标题路径和文档 metadata这样做的好处是每个 Chunk 都知道自己属于哪个章节。后续检索时可以结合标题路径、文档类型、更新时间、权限范围等 metadata 一起使用。这比单纯把文档切成几百个相似片段要可控得多。Chunk size 应该怎么定很多人最关心的问题是chunk size 到底设置多少合适这个问题没有统一答案。因为不同文档、不同模型、不同业务问题对 Chunk 的要求都不一样。但可以有一些判断方向。如果 Chunk 太小常见表现是检索结果命中了关键词但缺少上下文。模型回答很短只能答局部信息。列表、规则、步骤经常漏项。引用片段看起来像孤立句子。如果 Chunk 太大常见表现是检索结果主题相似但包含大量无关内容。多个问题都召回同一大段文本。模型答案容易混入不相关信息。Token 成本升高。Rerank 和引用定位变困难。所以设置 chunk size 时不能只看字数而要看效果。一个实用的判断方法是拿真实用户问题测试。对于每个问题检查正确 Chunk 是否能被召回。召回 Chunk 是否包含完整答案依据。召回内容是否混入太多无关信息。模型是否能基于该 Chunk 生成准确答案。引用是否能指向用户可以核查的范围。如果这些指标不好就需要调整切分策略而不是只改一个数字。切分策略要和后续链路配合文档切分不是孤立模块。它会影响后面的 Embedding、Retriever、Rerank、Prompt 和引用展示。比如Chunk 太碎Retriever 可能需要召回更多片段Rerank 压力也会变大。Chunk 太大Embedding 的语义表示会变得模糊检索命中可能不够精准。标题路径保留得好Prompt 里就可以展示更清楚的来源信息。metadata 设计得好后续就能做权限过滤、版本过滤、文档类型过滤。引用边界设计得好用户就更容易信任答案。所以做 RAG 时不要把文档切分当成预处理脚本里的小功能。它应该被当成知识库工程里的核心设计。一个实用的切分检查清单在实际项目里可以用下面这个清单检查切分结果。第一每个 Chunk 是否能独立表达一个完整意思如果一个 Chunk 只有半句话、一个列表项、一个孤立参数很可能不够好。第二标题和章节路径是否保留很多正文只有结合标题才有意义。第三列表和表格是否被拆坏流程、条件、权限矩阵、参数表都需要保留结构。第四Chunk 是否包含过多无关内容如果一个 Chunk 里混了多个主题检索和生成都会变差。第五是否保留 metadata文档名、章节、版本、更新时间、权限范围、来源链接都可能影响后续系统能力。第六是否用真实问题验证过不要只看切分结果整不整齐要看它能不能支撑真实问答。第七是否便于引用如果用户无法根据引用追溯答案来源RAG 的可信度会下降。这个清单不复杂但能避免很多早期 RAG 系统的问题。总结文档切分是 RAG 系统里非常关键的一环。Chunk 不是越小越好也不是越大越省事。它的本质是检索单元必须能承载相对完整的语义并且能支撑模型生成可验证的答案。固定字数切分可以作为起点但不能解决所有文档结构问题。真正可用的切分策略应该结合自然段、标题层级、列表、表格、代码块、接口说明和业务问题来设计。一个好的 Chunk应该让系统更容易召回正确资料也让模型更容易基于资料回答。如果 Chunk 切不好后面的 Embedding、Retriever、Rerank、Prompt 都会被拖累。所以在构建 RAG 知识库时不要急着堆模型和工具。先把文档切分做好很多问题会在源头上少很多。下一篇文章可以继续讨论 Embedding 模型怎么选。因为文档切好之后下一步就是让问题和文档在语义空间里真正匹配起来。