RAG 建库:资料是怎么存进去的?

《AI 知识卡片》第 10 期 · 一堆"块"还是一张"网"?存法决定捞法

  聊 RAG 时,大家的注意力几乎都在"检索"上,但这件事发生在用户提问之后 。在那之前,还有一整套离线 的活儿:把你的文档读进来、处理好、存进知识库。把 RAG 拆开看,核心的两条时间线

  Line 1:离线(提问之前) :加载 → 切块 → 变成向量 → 存入知识库。做一次,之后一直复用 ,称为索引构建

  Line 2:在线(提问之后) :把问题也变成向量 → 去库里检索 → 把捞到的资料拼进提示词 → 交给模型生成答案。每次提问都走一遍

  两条线之间有个硬约束:必须用同一个 Embedding 模型 。存的时候和查的时候得用同一把尺子,否则没法比较相关性。这一期主要来聊聊离线 部分。简单来说存进去的是什么样,检索就只能捞出什么样

第一步:把各种格式读成"统一的文本"

  现实里的资料格式很杂,如:PDF、Word、Markdown、HTML、网页、表格等,而后面所有环节只认一种东西------纯文本 + 元数据

  首先要加载 ,这里要用到不同文件格式的Loader**,**不管来源是什么格式,都解析成统一的结构。正文 ------抽出来的纯文本;元数据------这段文字来自哪个文件、哪一页、哪个章节、什么日期等。

  这一步有个残酷的现实:垃圾进,垃圾出 。纯文本和 Markdown 好解析,但复杂 PDF 很容易解析得错行乱序,甚至只剩一堆乱码。这时候普通解析器不够用,得上专门的版面分析或 OCR 工具。一旦这里读错了,后面 Embedding 再准、模型再强,也救不回来。

第二步:切块,再变成向量

  读进来的文档往往很长,不能整篇存。所以要先切块 ------把长文档切成一个个小块(chunk)。那这一刀往哪儿下?------常见的切法有四类,从"完全不看内容"到"看懂了内容再切":

切法 怎么切 代价
按字数硬切 数到 N 个字符就一刀,再让相邻两块重叠 一小段(chunk_overlap),把切断的语义接回来 最快,但很容易切在句子中间
递归切分 按分隔符层层退让:先按段落切,还太长就按句号、逗号、空格切,最后才硬切字符 通用默认选择,兼顾块大小和句子完整
按文档结构切 顺着 Markdown 标题、HTML 标签、代码里的函数边界切,还能把标题路径一并写进元数据 只适用于结构规整的文档;某一节特别长时还得再切一刀
语义切分 用 Embedding 算相邻句子的距离,在语义跳变最大的地方断开(比如把所有距离里最大的 5% 当断点) 最贴合语义,但建库时要多跑一遍模型,慢且贵

  实际项目里用得最多的是中间两类。按 Markdown 标题切 ,每个小标题下正好是一件事。但不管用哪种,都要记住一个结论:切出来的块,是后面检索和生成的最小单位。切太大,重点会被稀释;切太碎,上下文会残缺。

然后是关键一步:把每个块交给 Embedding 模型 ,变成一串定长的数字,也就是向量 。上一期「RAG 向量检索」讲过。

  真实项目里资料会不断新增、修订,这时的做法是增量入库 :只把新增或改动的那部分文档走一遍上面的流程,追加进索引即可。这也正是 RAG 最实用的地方------知识要更新,动的是知识库,模型一个参数都不用改

向量库里,到底存了什么?

  很多人以为向量库里只有一堆数字。其实它至少存了三样东西,而且分工明确:

存的东西 干什么用
向量索引 只存向量,负责算距离、找最近邻
原文 存每个块的文本和元数据(向量是没法还原成文字的)
两者的映射 把"第 123 号向量"连回"第 123 块的原文"

  为什么要分开存?因为检索命中时,向量索引只会告诉你"第 123 号最像 "。要把这段内容真正交给模型,还得凭这个编号去把原文 取回来。向量负责找,原文负责还原,缺一样都不行。

  还有一个绕不开的问题:几百万、上亿条向量,怎么在几十毫秒内找到最近的几个? 靠的是专门的近似最近邻(ANN)索引------它不保证百分百找到最准的那几条,而是牺牲一点点精度,换来几个数量级的速度。这也是"向量数据库"存在的意义:它不是拿传统数据库改一改,而是为"找相似"这件事从头设计的。

常见的两类数据库:

  • 嵌入式:FAISS、Chroma、LanceDB。装上就能用,跑在自己的进程里,索引就是磁盘上那几个文件。原型和中小规模的首选。
  • 服务化:Milvus、Qdrant、Weaviate(自建)或 Pinecone(托管)。数据量过了百万级,或者要高并发、实时更新、复杂的元数据过滤,就选这一类。

另一种存法:把资料存成一张"关系网"

  上面说的资料都是一堆互相独立的小块 。这种存法对付"这个东西是什么、怎么做 "很在行,但碰上另一类问题就吃力了,比如:"A 和 B 之间有什么关联?""换成 C 行不行?"

  因为这类问题的答案不在任何单独一块里 ,而藏在块与块的关系里。而向量库只懂"像不像",压根没有"关系"这个概念。

于是有了第二种知识图谱存法,它不存文本块,存两样东西:

  • 节点:实体(可以是一个产品、一种材料、一个人、一个步骤);
  • :实体之间的关系,而且关系本身是可查询的(谁需要谁、谁属于谁、谁替代谁);

  怎么把文档变成这样一张网?------现在常见的做法是让 LLM 去读文档、抽取出实体和关系知识抽取 ),再存进图数据库

  图数据库同样分这两类:Neo4j 要单独起服务,Kuzu 是嵌入式的、整个库就是本地一个目录。查询语言都是 Cypher ,写起来很像"画路径"------MATCH (r:Recipe)-[:REQUIRES]->(i:Ingredient)

经过本地实测,踩到两类问题:

  • 抽取会出错。LLM 会把分类判错,也会"过度抽取"------把文中一句"可选的、可以考虑加的东西"当成正式条目抽出来。
  • 同名不同物、同物不同名 。文档里反复出现的同一个实体,抽出来常常变成好几个节点,不同东西又可能撞上同名。这些都得靠后续的对齐、去重、校验来收拾。

  所以建图谱的成本,远高于建向量库 ------不是代码难写,而是这些"数据治理"的脏活儿绕不过去。也正因如此,实践里很常见的选择是两种存法并用:向量库管"找相似",图谱管"查关系",各干各最擅长的那件事。

一句话总结

  存进去的是什么样,检索就只能捞出什么样。至于存成一堆"块"还是一张"网",取决于你要回答的是"这是什么",还是"它们之间有什么关系"。

相关推荐
Java编程爱好者1 小时前
AI Agent、架构决策记录与工程上下文治理:团队如何把隐性约束留在仓库里。
人工智能
自律懒人1 小时前
AI应用从原型到上线的最后一公里——灵光闪应用一键部署深度实测,30+免费API + Serverless零配置发布
人工智能·云原生·开源·serverless
大模型念念2 小时前
Codex:AI 编程助手的核心引擎
人工智能
AndrewHZ2 小时前
【LLM技术全景】多模态大模型:当语言模型学会“看“和“听“
人工智能·gpt·深度学习·语言模型·自然语言处理·llm·多模态
湘美书院--湘美谈教育2 小时前
湘美谈教育互联网逻辑:AI时代的社会学猜想
大数据·人工智能·深度学习·机器学习·生活
东方佑2 小时前
MA-RMSNorm:打破“缩放换智能”的魔咒,大模型归一化的一次范式革命!
数据库·人工智能·计算机视觉
KKKlucifer2 小时前
多源异构通信数据统一识别:运营商分类分级平台关键技术与落地成
人工智能·分类·数据挖掘
jinggongszh2 小时前
从长鑫科技的十年突围,看中国制造的“硬核”与“底座”
人工智能·科技·制造
程序员cxuan2 小时前
A 社官方:我们删掉了 80% 的 skills
人工智能·后端·程序员