做 RAG 最容易翻车的不是检索算法,而是数据源那一层没想清楚:文件格式五花八门、接口拉回来的内容带一堆噪声、权限和更新节奏对不上。这篇把常见数据源分成几类,逐类讲接入时要先确认什么、先做什么处理,再给一份接入前的检查顺序,方便你按自己手头的数据对号入座。
做 RAG 最容易翻车的不是检索算法,而是数据源那一层没想清楚:文件格式五花八门、接口拉回来的内容带一堆噪声、权限和更新节奏对不上。算法调半天,结果知识库里就没几条能用的原文,问出来的答案自然是拼凑的。这篇不谈模型选型,只把常见数据源分成几类,逐类讲接入时要先确认什么、先做什么处理。
另一件常被忽略的事:数据源不是「能读进来」就算接完了,而是要能回答「这条内容给谁看、什么时候更新、更新后旧索引怎么处理」。建议你对着下面几类数据,边看边在自己的清单上打勾。想先了解检索侧对数据质量的具体要求,可以到 /guides 看相关指南,再回来对照。
先把数据源分成哪几类
分类的目的不是为了分类本身,而是因为不同类的预处理成本差距非常大。同一个团队里,接一批原生电子文档可能半天搞定,接一批扫描件加接口流水可能要排一周。先分类,你才知道时间该压在哪一类上。
| 分类维度 | 常见取值 | 对 RAG 的直接影响 |
|---|---|---|
| 是否已是结构化文本 | 纯文本类、版式文档类、半结构化类、接口流式类 | 决定预处理是抽文本、做 OCR 还是解析字段 |
| 更新频率 | 一次性归档、定期覆盖、实时增量 | 决定全量重建索引还是走增量更新 |
| 权限边界 | 全员可见、部门可见、单人可见 | 决定取数阶段就要做的过滤,检索层补不回来 |
分类之后容易踩的坑是「只按格式分」。格式一样的两个数据源,更新频率可能完全不同,一个是三年不动的归档 PDF,一个是每小时刷新的接口。对这两种,索引策略不该一样。什么情况下分类可以简化?如果你手上只有一类数据、且更新节奏统一,那维度二可以暂时不单独处理,但权限维度仍然必须提前切。
文件与版式文档类:最常见的入口,也是最脏的入口
这类数据几乎每个项目都有,问题也最集中。第一个判断是:它是原生电子文档还是扫描件。前者有文本层,直接抽就行;后者要先走 OCR,而 OCR 的失败原因和抽文本失败完全是两回事,混在一起排查会浪费很多时间。
- 先分清原生电子文档还是扫描件,两者失败原因完全不同,别用一套排查流程
- 版式文档要按「一段内容是否跨页或跨栏」决定切分策略,否则一句话被切成两半
- 表格和代码块单独抽出来,别和正文混切,混切后检索回来的往往是半个表格
- 每份文档入库前至少留三个字段:来源标识、更新时间、可见范围,缺了后面排查召回错误会很难受
为什么要强调那三个字段?举个通用场景:一家 5 人小团队发现某个问题答错了,如果没有来源标识,你无法知道答案是从哪份文档拼出来的;没有更新时间,你不知道是不是用了过期内容;没有可见范围,你可能把内部资料喂给了外部用户。这三个字段的成本极低,但省掉它们,后期排查成本极高。
半结构化与业务表:字段比正文更重要
表格、CSV、数据库导出的记录,这类数据的特点是字段清晰但语义弱。你把它整行拼成一段自然语言,检索时容易匹配上,但回答里会缺上下文;你按字段拆成多段,检索精度可能上去了,但拼回来又容易丢关系。这个取舍要在接入前定好,不要边跑边改。
- 行级粒度
- 先定义「一行代表什么」,再决定是整行拼成一段还是按字段拆成多段
- 层级路径
- 带父子或分类树的记录,考虑保留路径信息,否则检索回来的是碎片、拼不出上下文
- 可过滤字段
- 时间、金额、编号这类字段单独留存,检索时可用于过滤,不要只压在正文文本里
什么情况下不适合拆字段?当用户提问本身是「这行记录整体是什么情况」时,拆得越细越糟。相反,当用户经常按某个维度筛选或比较时,字段不单独留存就会很被动。判断标准很简单:看你的目标问题里,有多少是带条件的。带条件的比例高,字段就该独立出来。
接口与实时数据:接入容易,稳定难
接口数据接起来最快,但长期最不稳。原因不在代码,而在内容:接口返回的字段可能变、长度可能抖、失败可能悄悄发生。接入前要定三件事,缺一件后期都会变成玄学问题。
- 定拉取频率明确多久拉一次,并确认这个频率和数据本身的更新节奏匹配,拉太勤是浪费、拉太慢是过期。
- 定失败重试策略想清楚失败后重试几次、重试间隔多少、连续失败怎么告警,不要默认「它会成功」。
- 定是否存快照决定拉到的内容是只入索引还是也留原始快照,留快照便于回溯,不留则省空间但排查困难。
内容长度波动大的接口要特别当心,单条超长内容会把整批切分节奏打乱,建议先做截断或摘要再入库,不要指望切分环节兜底。另外,实时数据的更新必须能在索引侧体现,否则用户问的是今天的事、答的是上周的库,这种错误比答不上来更伤信任。
入库前的检查顺序
把上面几类数据整理完之后,不要直接全量灌进去。按下面三遍走一遍,每一遍都只看一个维度,混着看容易漏。这三遍都不涉及具体数字,具体阈值到 /tools/speed-test 之类的站内工具页按当时情况核对。
| 遍次 | 看什么 | 不通过怎么办 |
|---|---|---|
| 第一遍 | 覆盖度:这类数据是否覆盖了用户真正会问的问题范围 | 没覆盖的先别急着入库,补数据源优先 |
| 第二遍 | 噪声:随机抽样本,抽出来的文本能不能直接读懂 | 读不懂说明预处理没做完,回去补清洗 |
| 第三遍 | 更新:更新方式与索引重建方式能否对齐 | 对不齐就先不要纳入正式库,单独放试验库 |
- 第一遍看覆盖度,别把「读得进来」当成「答得出来」
- 第二遍看噪声,人工抽读是最便宜也最有效的验证方式
- 第三遍看更新,更新和索引对不齐,库越准过期得越快
- 三遍都过了再决定是全量重建还是走增量,顺序别反
什么情况下可以跳过第三遍?如果你做的是一次性归档查询,数据不再变化,那更新维度确实不适用。但只要数据会变,第三遍就不能省,否则你会得到一批「曾经正确」的索引。
RAG 的质量上限,往往在数据源那一层就已经定死了,检索算法只是在剩余空间里腾挪。下一步把你手上的数据源按上面四类填一遍,再去核对一下检索链路的实际情况,比对之后你会发现瓶颈通常不在你以为的地方。→
常见问题
RAG 的数据源是不是越全越好?
不是。数据源越多,噪声和权限问题越难控,召回准确率反而可能下降。建议先按用户高频问题圈定最小可用集合,跑通问答链路后再逐步扩源。什么情况下要多源:跨部门的综合性问答场景,且每一路数据都能保证质量与更新节奏。
没有现成文档,只有一堆接口返回的 JSON,能直接喂给 RAG 吗?
可以,但别直接塞原始 JSON。先把字段映射成人能读懂的句子或短段落,保留关键字段做过滤条件,再入库。直接塞原始结构的后果是检索命中一堆括号和字段名,模型拿到也读不出有效信息。
文档里的表格和图片怎么处理?
表格优先抽成结构化文本单独入库,保留表头和行标识;图片能取到文字就走 OCR,纯图无文字的单独建一路索引或先跳过。什么情况下先不处理:图片占比很低、且用户提问几乎不涉及图内信息时,先做文本链路更划算。