Skip to content

2.1.1 做 RAG 之前,为什么要先处理数据而不是直接喂给模型? ​

先给结论:RAG 不是“把资料上传给模型”,而是“把资料变成系统能稳定使用的知识”。

如果只是把原始文档直接扔进去,系统表面上看像是“接入了知识库”,但真实效果通常会很不稳定。因为原始资料天然不是为检索和生成准备的。

原始资料通常不适合直接进入 RAG ​

真实业务里的资料往往有这些问题:

  • 一篇文档过长,信息分布很散
  • 页面里混着导航栏、页眉页脚、模板文案
  • 同一主题在多个版本里重复出现
  • 标题、时间、部门、权限范围没有结构化
  • 内容格式不统一,有 PDF、网页、表格、图片、代码说明

如果不先处理这些问题,后面就会出现一种常见现象:

资料明明在知识库里,但系统就是找不到、找不准,或者找到了也用不好。

RAG 真正需要的是“可检索知识”,不是“原始文件堆” ​

一个可用的 RAG 系统,通常不会直接把原始资料拿去回答,而是先做下面几件事:

  1. 把原始资料清洗干净。
  2. 把长内容拆成更合适的片段。
  3. 给片段补充来源、标题、时间、权限等元数据。
  4. 建立适合检索的索引。
  5. 保证内容后续还能更新、失效和追踪来源。

这几步的目标,本质上都是同一件事:让知识从“人能读”变成“系统也能有效使用”。

如果你把这件事说得更直接一点,可以理解成:

  • 原始资料解决的是“有没有东西可看”
  • 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 系统,更稳的顺序通常不是:

  1. 先选模型
  2. 先写 Prompt
  3. 再看数据能不能凑合用

而是:

  1. 先确认知识源值不值得接。
  2. 再确认这些知识能不能被清洗、切块、标记和更新。
  3. 再确认它们能不能在真实问题下被稳定召回。
  4. 最后再去优化模型表达和回答质量。

这个顺序的价值在于:它能让你先把“证据层”站稳,再去优化“表达层”。

你可以先记住一句话 ​

RAG 的起点不是模型,而是知识准备。

模型决定的是“怎么表达答案”,而前面的数据处理决定的是“系统有没有机会拿到正确材料”。在很多真实场景里,后者往往更先决定系统上限。