Skip to main content

07 · 文档与切分:把知识变成模型能用的”块”

本片目标:让模型认识公司文档——先讲 Document(LangChain 里知识的基本单位),再讲切分(为什么必须切、怎么切)。 新增规定性:7(知识单位:Document 有固定字段;切分器有固定参数) 数据字典:Document / RecursiveCharacterTextSplitter。 进程线程模型:切分是纯 CPU 文本操作,毫秒级,无阻塞。 网络模型:无(本片不联网;embedding 联网是第 08 篇的事)。

1. 上集回顾

第 06 篇模型能记住对话了。但用户问”转正需要什么条件”,模型只能瞎编——它没看过你们公司的新人培训手册。 直觉方案:把整本新人培训手册塞进 system 提示。但三个问题立刻出现:
  1. 塞不下:新人培训手册两万多字符,加上对话历史很容易超上下文窗口;
  2. 塞得下也太贵:每次问答都带全文,token 费爆炸;
  3. 检索定位难:问”转正”,模型要在整本手册里找相关内容——找不到就乱答。
所以正确路线不是”全塞”,而是”先召回相关内容,再只塞相关内容”(这就是 RAG)。而”召回”的前提是:把文档切成一块块,每块是一个检索单元。

2. 数据字典:Document(知识的原子单位)

关键metadata 是 RAG 溯源的地基——第 09 篇回答”答案来自哪块”就靠它。

3. 数据字典:RecursiveCharacterTextSplitter(递归字符切分器)

切分逻辑(递归)
  1. 先尝试按 \n\n(段落)切;
  2. 切出的块还太大 → 按 \n(行)切;
  3. 还太大 → 按 。!?;(句子)切;
  4. 还太大 → 按空格 → 最后按字符硬切。
为什么 overlap 必要:切块切在句中被切断的语义,靠重叠块”粘”回来——第 2 块的开头重复第 1 块的结尾,检索时不会漏掉跨块的关键信息。

4. 关键方法

新人培训手册实测data/新人培训手册.md,22201 字符):

5. 进程线程模型

  • 切分是纯内存 CPU 操作,22201 字符毫秒级完成,不涉及网络、不阻塞。
  • 生产环境对超大文档集切分时,考虑并行切分(第 12 篇 batch);但单文件切分无压力。

5.5 chunk_size 对比实验:粒度如何影响块数

chunk_size 是切分最重要的旋钮。实测新人培训手册(22201 字符)在不同 chunk_size 下的结果:
权衡本质
  • 块越小:检索单元越小、越精确(能捞到具体某条规则),但一个问题的答案可能被切成多块,喂给模型时要拼多个块(上下文碎片多、token 浪费);
  • 块越大:每块信息越完整(一条规则自成一个块),但检索粒度粗——问一个细节,可能整块都偏题。
这是第 15 篇调参的核心依据:粗排 k 值(召回几块)+ final_k(最终喂模型几块)都是在这个粒度权衡上选的。

6. 网络模型

本片完全不联网——文档读取和切分都是本地操作。这是 RAG 管道里唯一”不出网”的环节。从第 08 篇开始,embedding 和模型调用会重新联网。

7. 验证:跑起来

配套代码 code/07_load_split.py
  1. 读新人培训手册;
  2. 英文默认分隔符切一次(演示句子被腰斩的坑);
  3. 中文分隔符切一次,打印块数、每块前 60 字、块长度;
  4. 看 overlap 的效果(相邻块首尾重复);
  5. chunk_size 对比:100/200/500/1000 四种粒度各切一次,看块数怎么变。
预期输出(节选)

8. 边界

  • chunk_size 没有”标准答案”——检索粒度 vs 上下文效率的权衡。200~500 字符常见;语义完整的长段落可更大。第 15 篇讲调参。
  • 文本文件(.txt/.md)用 split_text;PDF/网页等多格式文档有专用 loader(langchain_community.document_loaders 停更,1.x 用各官方集成包或 pypdf 等),本系列聚焦文本文件。
  • metadata 会复制到每个小块——大文档切出的 163 块都带 {"source": "新人培训手册.md"},溯源没问题;但注意别把巨大的对象塞进 metadata。

推荐资料(延伸阅读)


9. 未完待续

文档切好了,163 块。现在问题:用户问”转正需要什么条件”,怎么让机器知道”哪几块最相关”? 关键词搜索(if "转正" in chunk)太脆弱——用户可能问”我多久能转正”,里面没有”条件”二字。让机器理解”意思相近”,这就是第 08 篇:向量化与向量库。 08 · 向量化与向量库