乐于分享
好东西不私藏

AI 基础-文档入库第一步,Loader 和 Splitter 决定 RAG 上限

AI 基础-文档入库第一步,Loader 和 Splitter 决定 RAG 上限

很多人做 RAG,第一反应是上向量数据库。

选 Milvus、选 pgvector、选 Pinecone、选 Elasticsearch,开始比较索引、召回、Rerank、Embedding 模型。

这些当然重要。

但我见过很多 RAG 效果差的系统,问题根本不在向量库,而在更前面:文档入库第一步就错了。

文档读得脏,后面检索再高级也救不回来。

切块切得碎,模型拿到的上下文就断。

元数据丢了,回答就没法追溯来源。

权限没带进去,召回就可能越权。

版本没记录,用户问的是新制度,模型引用的却是旧文档。

这就是 Loader 和 Splitter 的重要性。

Loader 负责把不同来源的资料读进来。

Splitter 负责把长文档切成适合检索和生成的小块。

听起来很基础,但这一步决定了知识库的地基。

地基歪了,上面盖什么都不稳。

## 一、Loader 不是“读文件”,而是把资料变成统一 Document

LangChain 官方文档里,Document Loader 的定义很直接:它提供标准接口,把不同来源的数据读入 LangChain 的 Document 格式。

这个定义里有两个重点。

第一,不同来源。

你的资料不一定是纯文本文件。

它可能是 PDF、Word、Markdown、网页、Notion、Slack、Google Drive、数据库记录、CSV、会议纪要、工单、代码仓库、知识库页面。

每种来源的结构都不一样。

PDF 有页码。

网页有标题、正文、导航、广告。

Notion 有层级块。

Slack 有频道、用户、时间。

数据库有字段和行。

如果每种资料都用不同格式进入系统,后面的切分、索引、检索、评测都会乱。

所以 Loader 的第一层价值,是统一入口。

第二,Document 格式。

Document 不只是文本。

它通常至少包含两类信息:page_content 和 metadata。

page_content 是正文。

metadata 是来源、页码、标题、时间、作者、权限、版本、业务域等上下文。

很多人只关心 page_content,这是大坑。

因为 RAG 系统最后要回答的不只是“这段话是什么”,还要回答:

– 这段话来自哪里?
– 是哪个版本?
– 谁能看?
– 是否过期?
– 属于哪个业务域?
– 能不能引用给用户?

这些都靠 metadata。

所以,Loader 不是简单读文件。它是在把原始资料变成机器可处理、可追溯、可治理的 Document。

## 二、真正的文档处理,第一步是清洗

文档刚读进来,往往很脏。

网页里有导航栏、页脚、推荐阅读、广告、版权声明。

PDF 里有页眉、页脚、页码、断行、表格错位。

Word 里有批注、修订、目录、格式噪音。

会议纪要里有口头语、重复表达、无效寒暄。

如果这些东西不处理,模型后面会认真地学习垃圾。

这就是知识库建设最容易被忽视的地方:清洗不是洁癖,是质量控制。

比如一个制度文档,每页页脚都有“内部资料,请勿外传”。如果切分时每个 chunk 都带这句话,向量检索可能会反复召回这些无意义文本。

再比如网页抓取时,把菜单栏“首页、产品、价格、登录、联系我们”也放进正文,模型检索时就会拿到大量噪声。

再比如 PDF 里表格被解析成错乱文本,金额和字段对不上,模型后面引用时就可能答错。

所以文档入库至少要做三类清洗:

第一,去噪。

删除导航、广告、页眉页脚、重复版权、无意义空行。

第二,结构修复。

尽量保留标题层级、列表、表格、章节关系。

第三,字段补齐。

补上来源、时间、版本、业务域、权限、文档类型。

这一步做得越好,后面 RAG 越稳。

AI Native 的知识库,不是给人看着舒服就行,而是要让机器能理解、能召回、能引用、能校验。

## 三、Splitter 不是按字数切,而是按语义切

很多人第一次切文档,会这样做:

每 500 字切一段。

然后加 50 字 overlap。

能不能跑?能。

效果好不好?不一定。

因为文档不是均匀的字数块,而是有结构的。

一个标题下面可能是一整段业务规则。

一个表格可能对应一套费用标准。

一个问答条目可能必须问题和答案一起出现。

一个代码说明可能必须函数名、参数、返回值放在同一块里。

如果机械按字数切,很容易把语义切断。

比如原文是:

“退款规则如下:已发货订单不支持无理由退款。未发货订单可在 24 小时内申请退款。”

如果切块刚好把“退款规则如下”切在上一段,把具体规则切在下一段,检索时可能召回不到完整含义。

再比如制度文档里有一个小标题:

“三、费用报销标准”

后面才是具体金额。如果标题和正文分开,模型看到金额时不知道它属于哪个制度。

所以 Splitter 的本质不是切字数,而是尽量在控制 chunk 大小的同时保留语义完整性。

LangChain 官方建议多数场景可以从 RecursiveCharacterTextSplitter 开始,因为它会按一组分隔符递归尝试切分,在 chunk size 和上下文完整性之间取得一个比较稳的平衡。

这也是实用工程里的好起点。

先用默认稳妥方案,再根据业务文档调整。

## 四、chunk_size 和 chunk_overlap 怎么理解

Splitter 最常见的两个参数,是 chunk_size 和 chunk_overlap。

chunk_size 是每个文本块的目标大小。

chunk_overlap 是相邻文本块之间重叠多少内容。

很多人会问:到底设置多少最好?

没有通用答案。

因为它取决于几个因素:

– 文档类型。
– Embedding 模型上下文长度。
– 检索任务粒度。
– 目标模型上下文窗口。
– 用户问题复杂度。
– 是否需要引用原文。

如果 chunk 太小,问题是语义不完整。

用户问“报销规则是什么”,召回出来的可能只有一个金额,没有上下文。

如果 chunk 太大,问题是召回不精准。

用户只问“差旅住宿标准”,系统却召回一大段行政制度,模型需要在里面自己找重点。

overlap 的作用,是减少切块边界带来的语义断裂。

但 overlap 太大,也会带来重复内容、索引变大、召回结果相似度过高的问题。

我的建议是:不要迷信固定参数。

先基于文档类型做一个初始值,再用评测集调。

比如:

– FAQ:可以按问答对切,chunk 不必太大。
– 制度文档:按章节和小标题切,保留标题路径。
– 技术文档:按标题、代码块、参数说明切。
– 会议纪要:按议题、结论、行动项切。
– 表格数据:不要简单转成散文,要保留字段关系。

真正成熟的系统,不是调一个神奇 chunk_size,而是针对资料类型设计切分策略。

## 五、metadata 是 RAG 的身份证

如果只能强调一个点,我会强调 metadata。

很多 RAG 系统只把文本塞进向量库,metadata 极其敷衍。

最后就会遇到很多问题。

用户问:“这个政策是哪天发布的?”

答不上来。

用户问:“这个规则适用于哪个城市?”

答不上来。

用户问:“这段答案能引用原文吗?”

找不到来源。

用户权限不够,系统却召回了敏感文档。

新旧制度冲突,模型不知道哪个更新。

这些问题不是模型问题,是 metadata 缺失。

一个合格的 Document,至少要考虑这些元数据:

– source:来源路径或 URL。
– title:文档标题。
– section:章节标题。
– page:页码或位置。
– created_at:创建时间。
– updated_at:更新时间。
– version:版本号。
– owner:负责人。
– permission_scope:权限范围。
– doc_type:制度、FAQ、会议纪要、代码文档、合同等类型。
– business_domain:业务域。

metadata 的价值有三层。

第一,检索过滤。

比如只检索用户有权限看的文档,只检索最新版本,只检索某个业务域。

第二,答案引用。

让模型回答时能给出来源,而不是空口断言。

第三,问题排查。

答案错了,你能追到是哪份文档、哪个 chunk、哪个版本导致的。

没有 metadata,RAG 就像没有身份证的人群。看起来热闹,但无法治理。

## 六、文档入库要服务机器,不是服务人的阅读习惯

这里要讲一个很重要的认知。

很多人整理知识库时,会下意识按照人类阅读习惯来整理。

排版漂亮,标题好看,段落顺眼。

这当然不是坏事。

但 AI 知识库的第一目标,不是让人看着舒服,而是让机器能正确理解、检索和引用。

人阅读时,可以靠上下文脑补。

机器检索时,拿到的可能只是一个 chunk。

如果这个 chunk 里没有标题,没有来源,没有业务域,没有时间,没有权限,它就很难被正确使用。

所以 AI Native 的文档处理,要换一个视角。

不要只问:

“这篇文档人看起来顺不顺?”

还要问:

“如果模型只拿到其中一块,它能不能知道这块在讲什么?”

“它能不能知道这块适用于什么场景?”

“它能不能知道这块是不是最新版本?”

“它能不能把答案引用回原文?”

“它能不能避免越权召回?”

这才是机器可理解的知识库。

## 七、怎么评估切分效果

文档切完以后,不要直接入库就完事。

要评估。

最简单的评估方式,是准备一批真实问题。

比如制度问答,可以准备:

– 报销上限是多少?
– 哪些情况不能退款?
– 审批超过几天会自动提醒?
– 某个城市是否适用这条规则?
– 新旧制度冲突时以哪个为准?

然后看检索结果。

第一,正确 chunk 有没有被召回。

如果正确内容根本没进 top-k,后面模型再强也没用。

第二,chunk 是否完整。

召回结果是否包含必要标题、规则正文、适用范围。

第三,噪声是否过多。

是不是召回了导航、页脚、重复声明、无关章节。

第四,metadata 是否够用。

能不能过滤版本、权限、业务域、时间。

第五,模型能不能基于 chunk 正确回答。

最终答案是否引用了正确来源,是否有编造。

这才是文档处理的闭环。

不要只看“切了多少块、入了多少库”。

知识库不是仓库越大越好,而是能不能在关键问题上召回正确证据。

## 八、怎么练:从一个小知识库开始

如果你要练 Loader 和 Splitter,不建议一上来搞几万份文档。

先做一个小知识库。

选 10 份文档就够。

最好包含几种类型:

– 一份 PDF 制度。
– 一份 Markdown 技术文档。
– 一份 FAQ。
– 一份会议纪要。
– 一份表格导出的文本。

第一步,用 Loader 读入。

观察 Document 的 page_content 和 metadata。

第二步,做清洗。

去掉页眉页脚、重复文本、乱码、导航。

第三步,设计 metadata。

至少补上 source、title、section、updated_at、doc_type、permission_scope。

第四步,尝试 Splitter。

先用 RecursiveCharacterTextSplitter,再按文档类型调整。

第五步,人工检查 20 个 chunk。

看每个 chunk 是否能独立表达含义。

第六步,准备 20 个真实问题做检索评测。

看正确 chunk 能不能进 top-k。

第七步,再入向量库。

不要反过来,一上来就向量化。

这条路径看起来慢,但非常稳。

因为你不是在做“文档入库 Demo”,你是在建设知识资产生产线。

## 九、最后:RAG 的上限,往往在入库前就决定了

RAG 不是把文档丢进向量数据库。

RAG 是一条信息生产线。

Loader 负责把资料读进来。

清洗负责去掉噪声。

Splitter 负责保留语义地切块。

metadata 负责来源、权限、版本和追溯。

Embedding 负责语义表示。

Retriever 负责召回。

Rerank 负责重排。

LLM 负责基于证据生成答案。

评测负责告诉你哪里错了。

如果前面 Loader 和 Splitter 没做好,后面每一步都会被拖累。

所以,别小看文档处理。

它看起来是脏活、累活、基础活。

但真正能落地的 AI 系统,往往就赢在这些基础活。

AI 越强,越不能低估底座。

知识库越大,越要重视入库质量。

文档越复杂,越要让机器能理解。

这就是 Loader 和 Splitter 在 RAG 里的位置:它们不是配角,而是地基。

## 参考来源

– LangChain 官方文档:Document loader integrations,说明 Document loaders 提供标准接口,把 Slack、Notion、Google Drive 等不同来源数据读入 LangChain Document 格式:https://docs.langchain.com/oss/python/integrations/document_loaders
– LangChain 官方文档:Text splitter integrations,建议多数场景从 RecursiveCharacterTextSplitter 开始,在保持上下文和控制 chunk size 之间取得平衡:https://docs.langchain.com/oss/python/integrations/splitters
– LangChain 官方文档:Recursive text splitter,说明递归分割会按字符列表尝试切分,并支持 split_text / create_documents:https://docs.langchain.com/oss/python/integrations/splitters/recursive_text_splitter
– LangChain Reference:langchain_text_splitters,提供文本切分工具参考:https://reference.langchain.com/python/langchain-text-splitters