Skip to content

RAG 的核心环节

这一页把 RAG 的两条链路展开,逐环节讲清楚「在做什么、为什么这么做、容易在哪里出错」。 读完这一页,你会对后面所有模块代码建立直觉。


一、入库链路(Ingestion)

入库链路负责把不可信的原始文件变成可信、可追溯、可检索的索引

1. 上传与校验

  • 用户在界面上传文件(Markdown / PDF / Word / Excel / PPT / HTML / 图片)。
  • 系统先做输入安全校验:文件大小、扩展名、MIME 类型、内容是否为空。
  • 关键点:上传文件是不可信输入,文件名不能用来拼路径(防路径穿越),扩展名不能当作内容真相(后面 Parser 会再校验真实结构)。

2. 保存原始文件

  • 原始文件存入 MinIO(对象存储),对象键由系统生成(如 知识库ID/文档UUID/source.pdf),不用用户文件名。
  • 先保存原文件再建记录:即使后续处理失败,也能用原文件排查或重建索引。

3. 解析(Parsing)

这是 V2 的核心能力。把各种格式统一成一种内部模型:

text
Markdown / PDF / DOCX / XLSX / PPTX / HTML / 图片
                    ↓   Parser(翻译官)
          ParsedDocument(统一文档模型)

        Block[](标题 / 正文 / 表格 / 代码 / 图片…)

每个 Block 还带一个 SourceLocator(来源定位器),记录「这段内容来自哪里」:

  • Markdown → 标题路径(如 ["RAG", "Embedding"]
  • PDF → 页码 + 坐标框(BBox)
  • Excel → 工作表 + 单元格区域
  • PPT → 幻灯片序号

这一层是关键设计:RAG 主流程永远不判断文件后缀,只认统一的 ParsedDocument。新增一种文件格式,只需要新增一个 Parser,主流程不动。

4. 切块(Chunking)

解析完的文档可能很长,不能整篇送去向量化,所以要切成小片段(Chunk)

切块策略直接决定检索质量,要点是:

  • 结构边界切(标题、表格、代码块),而不是机械地按字符数切
  • 每个 Chunk 保留来源信息(标题路径、页码),方便日后引用
  • 控制 Chunk 大小(本项目默认 512 tokens),并留少量重叠(overlap,默认 64)避免切断语义
  • 表格重复表头、代码保持围栏、正文优先按段落/句子切

5. 向量化(Embedding)

把文本 Chunk 变成向量(如 1024 维浮点数组)。向量化的意义是:语义相近的文本,向量距离也近

关键要求:文档向量化与问题向量化必须用同一个模型,否则两者的向量不在同一个语义空间,检索没有意义。

6. 索引(Indexing)

把「文本 + 向量 + 来源信息」写入向量数据库(本项目用 Milvus),并保持「主键稳定、可重复写入」,保证重试不会产生重复数据。


二、问答链路(Query)

1. 问题向量化

同一个 Embedding 模型把用户问题转成向量。

2. 检索(Retrieval)

在向量库里找出与问题向量最相似的 K 个 Chunk,同时限定知识库范围(不能跨库召回)。

3. 构建上下文(Context Building)

把召回的 Chunk 按相似度排序,每个标上 [来源 1] [来源 2]…,在字符预算内拼成一段知识上下文。

上下文预算(本项目默认 12000 字符)决定 LLM 每次最多「看」多少证据。超出的低排名 Chunk 会被丢弃。

4. 生成(Generation)

把「知识上下文 + 用户问题」一起发给 LLM,要求它只依据上下文回答,不能编造,并输出时标注 [来源 N]

5. 引用(Citation)

系统在返回答案的同时返回结构化引用(文档名、章节、页码),让用户能回到原文验证。


三、两条链路如何衔接

text
            入库链路(做一次)
上传 → 校验 → 存MinIO → 解析 → 切块 → 向量化 → 索引


                                        PostgreSQL(事实) + Milvus(向量)

            问答链路(做多次)                        │
用户提问 → 向量化 → 检索 ←────────────────────────────┘
        → 拼上下文 → LLM → 答案 + 引用

核心要点:入库产生「事实数据 + 派生索引」,问答只消费它们。

  • PostgreSQL 保存事实(文档状态、Chunk、Asset 元数据、会话与回答证据)
  • MinIO 保存原始文件和抽取图片 Asset
  • Milvus 保存可重建的派生索引(丢了可以用事实数据重新生成)

四、两条容易出错的地方

易错点正确做法
用字符数切块,导致语义被切断用 Token 预算 + 结构边界
文档向量和问题向量用了不同模型全程共用同一个 Embedder
把「未处理完的文档」放进检索结果只有状态 READY 的文档才参与检索
把外部服务当作永不出错设计超时、有界重试、失败状态

这些原则正是 UltimateRAG 代码里反复出现的注释主题。

下一步

UltimateRAG · 从最小可用 RAG 演进为企业级知识平台