Appearance
2.1.1 做 RAG 之前,为什么要先处理数据而不是直接喂给模型?
先给结论:RAG 不是“把资料上传给模型”,而是“把资料变成系统能稳定使用的知识”。
如果只是把原始文档直接扔进去,系统表面上看像是“接入了知识库”,但真实效果通常会很不稳定。因为原始资料天然不是为检索和生成准备的。
原始资料通常不适合直接进入 RAG
真实业务里的资料往往有这些问题:
- 一篇文档过长,信息分布很散
- 页面里混着导航栏、页眉页脚、模板文案
- 同一主题在多个版本里重复出现
- 标题、时间、部门、权限范围没有结构化
- 内容格式不统一,有 PDF、网页、表格、图片、代码说明
如果不先处理这些问题,后面就会出现一种常见现象:
资料明明在知识库里,但系统就是找不到、找不准,或者找到了也用不好。
RAG 真正需要的是“可检索知识”,不是“原始文件堆”
一个可用的 RAG 系统,通常不会直接把原始资料拿去回答,而是先做下面几件事:
- 把原始资料清洗干净。
- 把长内容拆成更合适的片段。
- 给片段补充来源、标题、时间、权限等元数据。
- 建立适合检索的索引。
- 保证内容后续还能更新、失效和追踪来源。
这几步的目标,本质上都是同一件事:让知识从“人能读”变成“系统也能有效使用”。
如果你把这件事说得更直接一点,可以理解成:
- 原始资料解决的是“有没有东西可看”
- RAG 处理解决的是“系统能不能把对的东西在对的时候拿出来”
这中间缺掉任何一步,都会让“资料很多”变成一种表面繁荣。
一个最小的数据预处理示意
下面这段代码可以帮助你直观看到“原始资料”和“可进入 RAG 的知识”之间到底差了哪些步骤:
python
from dataclasses import dataclass
@dataclass
class Chunk:
text: str
metadata: dict
raw_doc = {
"title": "退款说明",
"url": "/help/refund",
"updated_at": "2026-04-01",
"content": """
首页 > 帮助中心 > 售后服务
退款说明
商品签收后 7 天内支持无理由退货。
客服电话:400-000-0000
版权所有 2026 Example Inc.
"""
}
def clean_text(text: str) -> str:
noise = ["首页 > 帮助中心 > 售后服务", "版权所有 2026 Example Inc."]
for item in noise:
text = text.replace(item, "")
return "\n".join(line.strip() for line in text.splitlines() if line.strip())
def split_text(text: str, max_len: int = 40) -> list[str]:
return [text[i:i + max_len] for i in range(0, len(text), max_len)]
cleaned = clean_text(raw_doc["content"])
chunks = [
Chunk(
text=part,
metadata={
"title": raw_doc["title"],
"source": raw_doc["url"],
"updated_at": raw_doc["updated_at"],
"doc_type": "help_center"
}
)
for part in split_text(cleaned)
]这段代码最重要的不是具体实现细节,而是它体现出的处理顺序:
- 先清理噪声
- 再切分内容
- 再补充元数据
到这一步,内容才开始接近“可被检索”的知识形态。
为什么不能直接把整篇文档塞给模型
很多人会想,既然模型上下文窗口越来越大,为什么不直接把文档整篇丢进去?
问题在于,这种做法通常只在非常小的 Demo 里勉强成立,到了真实环境就很快失效。
原因包括:
- 文档太多时,根本放不下
- 放得下也未必读得准
- 相关信息常常只占文档的一小部分
- 无关内容会稀释有效上下文
- 成本和延迟会迅速上升
所以在工程上,关键不是“模型能不能看很多字”,而是“系统能不能把最相关的知识挑出来,再交给模型”。
而且就算上下文窗口真的足够大,工程上也仍然会面对这些问题:
- 哪一版资料才该被送进去
- 哪些内容当前用户根本没权限看
- 多篇资料冲突时谁优先
- 相似问题是不是每次都要重复喂整批材料
所以“窗口更大”能缓解一部分问题,但不能替代知识准备和检索设计。
数据处理其实是在为后面每一环降噪
前面的数据准备,影响的不是某一个环节,而是整条 RAG 链路。
对检索的影响
如果原始内容脏、乱、重复多,检索出来的结果就更容易偏。
对排序的影响
如果没有清晰的来源、标题、时间和业务字段,后续很难做过滤、重排和优先级控制。
对生成的影响
如果送给模型的上下文本身就是噪声和重复,模型再强也很难稳定作答。
对治理的影响
如果前面没有把来源、时间、版本、权限这些边界处理好,后面就很难做:
- 版本优先级控制
- 失效内容下线
- 权限过滤
- 回答追溯和审计
也就是说,数据处理不仅影响“答得准不准”,还影响“出了问题能不能查、能不能控”。
一个更准确的理解方式
做 RAG 之前,真正要先问的不是:
- 用哪个模型?
而是:
- 我有哪些知识源?
- 这些知识干不干净?
- 它们能不能被拆解、标记和过滤?
- 它们后面怎么更新?
如果这些问题没有想清楚,模型往往只是在放大前面数据阶段的问题。
一个更实用的判断顺序
如果你现在正准备做一个 RAG 系统,更稳的顺序通常不是:
- 先选模型
- 先写 Prompt
- 再看数据能不能凑合用
而是:
- 先确认知识源值不值得接。
- 再确认这些知识能不能被清洗、切块、标记和更新。
- 再确认它们能不能在真实问题下被稳定召回。
- 最后再去优化模型表达和回答质量。
这个顺序的价值在于:它能让你先把“证据层”站稳,再去优化“表达层”。
你可以先记住一句话
RAG 的起点不是模型,而是知识准备。
模型决定的是“怎么表达答案”,而前面的数据处理决定的是“系统有没有机会拿到正确材料”。在很多真实场景里,后者往往更先决定系统上限。