欢迎光临
我们一直在努力

RAG核心特性详解:ETL流水线

ETL流水线

ETL流水线

前言

在 RAG(检索增强生成)应用中,有一个绕不开的核心环节——如何把海量的文档"喂"给 AI?这些文档可能散落在各处:有的是 PDF 报告,有的是 Markdown 笔记,有的是飞书文档,甚至还有 B 站视频字幕。直接把它们扔给大模型?不现实,大模型的上下文窗口有限,而且一股脑塞进去效果也很差。

这就引出了今天的主角:ETL Pipeline。

ETL 是三个单词的缩写:Extract(抽取)、Transform(转换)、Load(加载),它是 Spring AI 中处理文档流水线的核心框架。简单来说,ETL 做了一件事:把原始文档变成向量数据库中可检索的知识碎片。

读完这篇博客,你将彻底搞懂:

  • ETL 到底是什么,每个阶段在干什么
  • Spring AI 提供了哪些开箱即用的"武器"
  • Spring AI Alibaba 社区又补充了哪些"神器"
  • 如何用代码实现一个完整的 ETL 流水线

一、大白话理解 ETL

先抛开代码,用生活场景来理解 ETL。

想象你要开一家"AI 智能客服",知识来源是一堆乱七八糟的资料:PDF 产品手册、Word 操作指南、公司内部网页、Excel 价目表……

直接把这些资料甩给 AI 说"你学一下",显然不行。你得先做三件事:

1. Extract(抽取)——“把书从书架拿下来”

首先你得能"读取"各种格式的文档。PDF 需要 PDF 阅读器,Word 需要 Word 解析器,网页需要 HTML 爬虫——这就是 DocumentReader 干的活。它负责从各种数据源把文档读进内存。

2. Transform(转换)——“把书拆成卡片”

一本 500 页的手册不可能一口气喂给 AI(也喂不下)。你得把它拆成一小段一小段的"知识卡片",每张卡片包含一个相对完整的信息点。可能还要给卡片打标签、写摘要——这就是 DocumentTransformer 干的活。

3. Load(加载)——“把卡片放进柜子”

拆分好的知识卡片得存到某个地方,方便以后快速查找。RAG 场景下通常是存到向量数据库(Vector Store),把每张卡片转成向量——这就是 DocumentWriter 干的活。

用一张流程图来概括:

#mermaid-svg-st9CDcotGL4IOVYW{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-st9CDcotGL4IOVYW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-st9CDcotGL4IOVYW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-st9CDcotGL4IOVYW .error-icon{fill:#552222;}#mermaid-svg-st9CDcotGL4IOVYW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-st9CDcotGL4IOVYW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-st9CDcotGL4IOVYW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-st9CDcotGL4IOVYW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-st9CDcotGL4IOVYW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-st9CDcotGL4IOVYW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-st9CDcotGL4IOVYW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-st9CDcotGL4IOVYW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-st9CDcotGL4IOVYW .marker.cross{stroke:#333333;}#mermaid-svg-st9CDcotGL4IOVYW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-st9CDcotGL4IOVYW p{margin:0;}#mermaid-svg-st9CDcotGL4IOVYW .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-st9CDcotGL4IOVYW .cluster-label text{fill:#333;}#mermaid-svg-st9CDcotGL4IOVYW .cluster-label span{color:#333;}#mermaid-svg-st9CDcotGL4IOVYW .cluster-label span p{background-color:transparent;}#mermaid-svg-st9CDcotGL4IOVYW .label text,#mermaid-svg-st9CDcotGL4IOVYW span{fill:#333;color:#333;}#mermaid-svg-st9CDcotGL4IOVYW .node rect,#mermaid-svg-st9CDcotGL4IOVYW .node circle,#mermaid-svg-st9CDcotGL4IOVYW .node ellipse,#mermaid-svg-st9CDcotGL4IOVYW .node polygon,#mermaid-svg-st9CDcotGL4IOVYW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-st9CDcotGL4IOVYW .rough-node .label text,#mermaid-svg-st9CDcotGL4IOVYW .node .label text,#mermaid-svg-st9CDcotGL4IOVYW .image-shape .label,#mermaid-svg-st9CDcotGL4IOVYW .icon-shape .label{text-anchor:middle;}#mermaid-svg-st9CDcotGL4IOVYW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-st9CDcotGL4IOVYW .rough-node .label,#mermaid-svg-st9CDcotGL4IOVYW .node .label,#mermaid-svg-st9CDcotGL4IOVYW .image-shape .label,#mermaid-svg-st9CDcotGL4IOVYW .icon-shape .label{text-align:center;}#mermaid-svg-st9CDcotGL4IOVYW .node.clickable{cursor:pointer;}#mermaid-svg-st9CDcotGL4IOVYW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-st9CDcotGL4IOVYW .arrowheadPath{fill:#333333;}#mermaid-svg-st9CDcotGL4IOVYW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-st9CDcotGL4IOVYW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-st9CDcotGL4IOVYW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-st9CDcotGL4IOVYW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-st9CDcotGL4IOVYW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-st9CDcotGL4IOVYW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-st9CDcotGL4IOVYW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-st9CDcotGL4IOVYW .cluster text{fill:#333;}#mermaid-svg-st9CDcotGL4IOVYW .cluster span{color:#333;}#mermaid-svg-st9CDcotGL4IOVYW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-st9CDcotGL4IOVYW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-st9CDcotGL4IOVYW rect.text{fill:none;stroke-width:0;}#mermaid-svg-st9CDcotGL4IOVYW .icon-shape,#mermaid-svg-st9CDcotGL4IOVYW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-st9CDcotGL4IOVYW .icon-shape p,#mermaid-svg-st9CDcotGL4IOVYW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-st9CDcotGL4IOVYW .icon-shape .label rect,#mermaid-svg-st9CDcotGL4IOVYW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-st9CDcotGL4IOVYW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-st9CDcotGL4IOVYW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-st9CDcotGL4IOVYW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

原始文档PDF/Word/MD/HTML…

ExtractDocumentReader读取文档

TransformDocumentTransformer分割、增强、格式化

LoadDocumentWriter写入向量数据库

向量数据库Vector Store

AI 检索增强生成

用一句大白话总结:ETL 就是"读取 → 拆分加工 → 存入向量库"的流水线,是 RAG 系统的数据入口。


二、Spring AI ETL 三大核心接口

Spring AI 用三个极简的 Java 接口定义了 ETL 的三个阶段,每个接口都用到了 Java 函数式编程的思想,非常优雅。

#mermaid-svg-jV25FQZBShFgosZy{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jV25FQZBShFgosZy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jV25FQZBShFgosZy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jV25FQZBShFgosZy .error-icon{fill:#552222;}#mermaid-svg-jV25FQZBShFgosZy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jV25FQZBShFgosZy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jV25FQZBShFgosZy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jV25FQZBShFgosZy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jV25FQZBShFgosZy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jV25FQZBShFgosZy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jV25FQZBShFgosZy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jV25FQZBShFgosZy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jV25FQZBShFgosZy .marker.cross{stroke:#333333;}#mermaid-svg-jV25FQZBShFgosZy svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jV25FQZBShFgosZy p{margin:0;}#mermaid-svg-jV25FQZBShFgosZy .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-jV25FQZBShFgosZy .cluster-label text{fill:#333;}#mermaid-svg-jV25FQZBShFgosZy .cluster-label span{color:#333;}#mermaid-svg-jV25FQZBShFgosZy .cluster-label span p{background-color:transparent;}#mermaid-svg-jV25FQZBShFgosZy .label text,#mermaid-svg-jV25FQZBShFgosZy span{fill:#333;color:#333;}#mermaid-svg-jV25FQZBShFgosZy .node rect,#mermaid-svg-jV25FQZBShFgosZy .node circle,#mermaid-svg-jV25FQZBShFgosZy .node ellipse,#mermaid-svg-jV25FQZBShFgosZy .node polygon,#mermaid-svg-jV25FQZBShFgosZy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jV25FQZBShFgosZy .rough-node .label text,#mermaid-svg-jV25FQZBShFgosZy .node .label text,#mermaid-svg-jV25FQZBShFgosZy .image-shape .label,#mermaid-svg-jV25FQZBShFgosZy .icon-shape .label{text-anchor:middle;}#mermaid-svg-jV25FQZBShFgosZy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jV25FQZBShFgosZy .rough-node .label,#mermaid-svg-jV25FQZBShFgosZy .node .label,#mermaid-svg-jV25FQZBShFgosZy .image-shape .label,#mermaid-svg-jV25FQZBShFgosZy .icon-shape .label{text-align:center;}#mermaid-svg-jV25FQZBShFgosZy .node.clickable{cursor:pointer;}#mermaid-svg-jV25FQZBShFgosZy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jV25FQZBShFgosZy .arrowheadPath{fill:#333333;}#mermaid-svg-jV25FQZBShFgosZy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jV25FQZBShFgosZy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jV25FQZBShFgosZy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jV25FQZBShFgosZy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jV25FQZBShFgosZy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jV25FQZBShFgosZy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jV25FQZBShFgosZy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jV25FQZBShFgosZy .cluster text{fill:#333;}#mermaid-svg-jV25FQZBShFgosZy .cluster span{color:#333;}#mermaid-svg-jV25FQZBShFgosZy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jV25FQZBShFgosZy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jV25FQZBShFgosZy rect.text{fill:none;stroke-width:0;}#mermaid-svg-jV25FQZBShFgosZy .icon-shape,#mermaid-svg-jV25FQZBShFgosZy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jV25FQZBShFgosZy .icon-shape p,#mermaid-svg-jV25FQZBShFgosZy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jV25FQZBShFgosZy .icon-shape .label rect,#mermaid-svg-jV25FQZBShFgosZy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jV25FQZBShFgosZy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jV25FQZBShFgosZy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jV25FQZBShFgosZy :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

ETL Pipeline 三大组件

read() / get()

transform() / apply()

write() / accept()

DocumentReaderextendsSupplier<List<Document>>

DocumentTransformerextendsFunction<List<Document>, List<Document>>

DocumentWriterextendsConsumer<List<Document>>

向量数据库

在这里插入图片描述

2.1 DocumentReader ——“搬运工”

public interface DocumentReader extends Supplier<List<Document>> {
default List<Document> read() {
return get();
}
}

这个接口极其简单,继承自 Supplier,核心任务就是返回一个 Document 列表。Spring AI 内置了多种实现:

实现类支持的格式大白话解释
JsonReader JSON 从 JSON 文件中提取指定字段
TextReader 纯文本 读取 .txt 文件
MarkdownReader Markdown 按标题、段落、代码块拆分 MD
PagePdfDocumentReader PDF(按页) 把 PDF 按页码拆分
ParagraphPdfDocumentReader PDF(按段落) 根据 PDF 目录结构拆分
JsoupDocumentReader HTML 用 CSS 选择器提取网页内容
TikaDocumentReader 1000+ 种格式 万能解析器,基于 Apache Tika

用 JsonReader 举例,它还能用 JSON Pointer 精准提取嵌套数据:

// 基本用法:读取整个 JSON
JsonReader jsonReader = new JsonReader(resource);
List<Document> docs = jsonReader.get();

// 精准提取:只看 items 数组里的内容
List<Document> docs = jsonReader.get("/items");

// 指定字段:只取 description 和 features
JsonReader jsonReader = new JsonReader(resource, "description", "features");

2.2 DocumentTransformer ——“加工车间”

public interface DocumentTransformer extends Function<List<Document>, List<Document>> {
default List<Document> transform(List<Document> documents) {
return apply(documents);
}
}

它继承自 Function,输入一堆 Document,输出加工后的一堆 Document。这是 ETL 中最关键的一环,直接影响 RAG 效果。Spring AI 提供了三大类 Transformer:

(1)TextSplitter 文本分割器

把大文档切成小块。TokenTextSplitter 是最常用的实现:

// 默认参数
TokenTextSplitter splitter = new TokenTextSplitter();

// 自定义参数
TokenTextSplitter splitter = new TokenTextSplitter(
1000, // defaultChunkSize: 每块目标大小(token)
400, // minChunkSizeChars: 每块最小字符数
10, // minChunkLengthToEmbed: 最小嵌入长度
5000, // maxNumChunks: 最多生成块数
true // keepSeparator: 是否保留分隔符
);

它的工作原理很聪明:

#mermaid-svg-2dZYQWA8IB1lRlO8{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2dZYQWA8IB1lRlO8 .error-icon{fill:#552222;}#mermaid-svg-2dZYQWA8IB1lRlO8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2dZYQWA8IB1lRlO8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .marker.cross{stroke:#333333;}#mermaid-svg-2dZYQWA8IB1lRlO8 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2dZYQWA8IB1lRlO8 p{margin:0;}#mermaid-svg-2dZYQWA8IB1lRlO8 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster-label text{fill:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster-label span{color:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster-label span p{background-color:transparent;}#mermaid-svg-2dZYQWA8IB1lRlO8 .label text,#mermaid-svg-2dZYQWA8IB1lRlO8 span{fill:#333;color:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .node rect,#mermaid-svg-2dZYQWA8IB1lRlO8 .node circle,#mermaid-svg-2dZYQWA8IB1lRlO8 .node ellipse,#mermaid-svg-2dZYQWA8IB1lRlO8 .node polygon,#mermaid-svg-2dZYQWA8IB1lRlO8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .rough-node .label text,#mermaid-svg-2dZYQWA8IB1lRlO8 .node .label text,#mermaid-svg-2dZYQWA8IB1lRlO8 .image-shape .label,#mermaid-svg-2dZYQWA8IB1lRlO8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-2dZYQWA8IB1lRlO8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .rough-node .label,#mermaid-svg-2dZYQWA8IB1lRlO8 .node .label,#mermaid-svg-2dZYQWA8IB1lRlO8 .image-shape .label,#mermaid-svg-2dZYQWA8IB1lRlO8 .icon-shape .label{text-align:center;}#mermaid-svg-2dZYQWA8IB1lRlO8 .node.clickable{cursor:pointer;}#mermaid-svg-2dZYQWA8IB1lRlO8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .arrowheadPath{fill:#333333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2dZYQWA8IB1lRlO8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2dZYQWA8IB1lRlO8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2dZYQWA8IB1lRlO8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster text{fill:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 .cluster span{color:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2dZYQWA8IB1lRlO8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2dZYQWA8IB1lRlO8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-2dZYQWA8IB1lRlO8 .icon-shape,#mermaid-svg-2dZYQWA8IB1lRlO8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2dZYQWA8IB1lRlO8 .icon-shape p,#mermaid-svg-2dZYQWA8IB1lRlO8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2dZYQWA8IB1lRlO8 .icon-shape .label rect,#mermaid-svg-2dZYQWA8IB1lRlO8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2dZYQWA8IB1lRlO8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2dZYQWA8IB1lRlO8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2dZYQWA8IB1lRlO8 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

输入文本

1. CL100K_BASE 编码成 Token

2. 按 defaultChunkSize 切块

3. 在句号/问号/换行处找断点

4. 保留语义完整的文本块

输出 Document 列表

大白话:它不是死板地每 500 字切一刀,而是切完后会"回头看看"——如果正好切在句子中间,就往前或往后挪到最近的句号处。这样保证每块都是完整的话。

(2)MetadataEnricher 元数据增强器

给文档"贴标签",方便后续精准检索:

// 自动提取关键词标签
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 5);
List<Document> enrichedDocs = enricher.apply(documents);

// 自动生成摘要(还能关联前后文档)
SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(
chatModel,
List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT)
);

大白话:就像图书馆给每本书贴标签(“科技类”“2025年”“AI”),以后找书时先看标签就能快速筛掉不相关的。

(3)ContentFormatter 内容格式化工具

统一文档格式,控制哪些元数据跟着内容一起喂给 AI。通过 DefaultContentFormatter 的 Builder 模式灵活配置:

DefaultContentFormatter formatter = DefaultContentFormatter.builder()
.withMetadataTemplate("{key}: {value}")
.withMetadataSeparator("\\n")
.withTextTemplate("{metadata_string}\\n\\n{content}")
.withExcludedInferenceMetadataKeys("embedding", "vector_id")
.build();

2.3 DocumentWriter ——“入库员”

public interface DocumentWriter extends Consumer<List<Document>> {
default void write(List<Document> documents) {
accept(documents);
}
}

它继承自 Consumer,负责把处理好的文档存到目标位置。Spring AI 提供了两种内置实现:

  • FileDocumentWriter:写入文件系统(调试用)
  • VectorStore:写入向量数据库(生产用)

VectorStore 支持的向量数据库一览:

#mermaid-svg-ZSMC4f9sHHyf8rbl{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZSMC4f9sHHyf8rbl .error-icon{fill:#552222;}#mermaid-svg-ZSMC4f9sHHyf8rbl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZSMC4f9sHHyf8rbl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZSMC4f9sHHyf8rbl .marker.cross{stroke:#333333;}#mermaid-svg-ZSMC4f9sHHyf8rbl svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZSMC4f9sHHyf8rbl p{margin:0;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge{stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 text{fill:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon–1{font-size:40px;color:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge–1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth–1{stroke-width:17;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section–1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-0{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-0{stroke-width:14;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-1{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-1{stroke-width:11;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 text{fill:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-2{stroke-width:8;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-3{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-3{stroke-width:5;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-4{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-4{stroke-width:2;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-5{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-5{stroke-width:-1;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-6{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-6{stroke-width:-4;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-7{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-7{stroke-width:-7;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-8{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-8{stroke-width:-10;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-9{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-9{stroke-width:-13;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 polygon,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 text{fill:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .node-icon-10{font-size:40px;color:black;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge-depth-10{stroke-width:-16;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:lightgray;}#mermaid-svg-ZSMC4f9sHHyf8rbl .disabled text{fill:#efefef;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root rect,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root path,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root circle,#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root text{fill:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-root span{color:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .section-2 span{color:#ffffff;}#mermaid-svg-ZSMC4f9sHHyf8rbl .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-ZSMC4f9sHHyf8rbl .edge{fill:none;}#mermaid-svg-ZSMC4f9sHHyf8rbl .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-ZSMC4f9sHHyf8rbl :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

VectorStore

Milvus

Redis

PGVector

Elasticsearch

MongoDB Atlas

Weaviate

Qdrant

Pinecone

阿里云 DashScope


三、完整 ETL 流水线实战

把三大组件串起来,一个完整的 ETL 流程就是:

// 抽取:从 PDF 读取
PDFReader pdfReader = new PagePdfDocumentReader("knowledge_base.pdf");
List<Document> documents = pdfReader.read();

// 转换:分割 + 添加摘要
TokenTextSplitter splitter = new TokenTextSplitter(500, 50);
List<Document> splitDocs = splitter.apply(documents);
SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(chatModel,
List.of(SummaryType.CURRENT));
List<Document> enrichedDocs = enricher.apply(splitDocs);

// 加载:写入向量库
vectorStore.write(enrichedDocs);

// 或者用函数式链式调用,一行搞定!
vectorStore.write(enricher.apply(splitter.apply(pdfReader.read())));

#mermaid-svg-kQD1GwrZMjxNJ9fY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kQD1GwrZMjxNJ9fY .error-icon{fill:#552222;}#mermaid-svg-kQD1GwrZMjxNJ9fY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kQD1GwrZMjxNJ9fY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .marker.cross{stroke:#333333;}#mermaid-svg-kQD1GwrZMjxNJ9fY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kQD1GwrZMjxNJ9fY p{margin:0;}#mermaid-svg-kQD1GwrZMjxNJ9fY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster-label text{fill:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster-label span{color:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster-label span p{background-color:transparent;}#mermaid-svg-kQD1GwrZMjxNJ9fY .label text,#mermaid-svg-kQD1GwrZMjxNJ9fY span{fill:#333;color:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .node rect,#mermaid-svg-kQD1GwrZMjxNJ9fY .node circle,#mermaid-svg-kQD1GwrZMjxNJ9fY .node ellipse,#mermaid-svg-kQD1GwrZMjxNJ9fY .node polygon,#mermaid-svg-kQD1GwrZMjxNJ9fY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .rough-node .label text,#mermaid-svg-kQD1GwrZMjxNJ9fY .node .label text,#mermaid-svg-kQD1GwrZMjxNJ9fY .image-shape .label,#mermaid-svg-kQD1GwrZMjxNJ9fY .icon-shape .label{text-anchor:middle;}#mermaid-svg-kQD1GwrZMjxNJ9fY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .rough-node .label,#mermaid-svg-kQD1GwrZMjxNJ9fY .node .label,#mermaid-svg-kQD1GwrZMjxNJ9fY .image-shape .label,#mermaid-svg-kQD1GwrZMjxNJ9fY .icon-shape .label{text-align:center;}#mermaid-svg-kQD1GwrZMjxNJ9fY .node.clickable{cursor:pointer;}#mermaid-svg-kQD1GwrZMjxNJ9fY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .arrowheadPath{fill:#333333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQD1GwrZMjxNJ9fY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kQD1GwrZMjxNJ9fY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQD1GwrZMjxNJ9fY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster text{fill:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY .cluster span{color:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kQD1GwrZMjxNJ9fY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kQD1GwrZMjxNJ9fY rect.text{fill:none;stroke-width:0;}#mermaid-svg-kQD1GwrZMjxNJ9fY .icon-shape,#mermaid-svg-kQD1GwrZMjxNJ9fY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQD1GwrZMjxNJ9fY .icon-shape p,#mermaid-svg-kQD1GwrZMjxNJ9fY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kQD1GwrZMjxNJ9fY .icon-shape .label rect,#mermaid-svg-kQD1GwrZMjxNJ9fY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQD1GwrZMjxNJ9fY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kQD1GwrZMjxNJ9fY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kQD1GwrZMjxNJ9fY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

完整 ETL 流程

knowledge_base.pdf

PagePdfDocumentReader按页读取

List<Document>(原始文档)

TokenTextSplitter按 Token 智能切分

List<Document>(分割后)

SummaryMetadataEnricherAI 生成摘要元数据

List<Document>(增强后)

VectorStore.write()向量化 + 入库

向量数据库


四、Spring AI Alibaba 的"外挂"扩展

如果说 Spring AI 提供了 ETL 的"标配",那 Spring AI Alibaba 社区 就是给它装上了"豪华大礼包"。它扩展了大量的 DocumentReader 和 DocumentParser,几乎覆盖了你日常开发中能遇到的所有数据源。

4.1 DocumentReader 扩展

模块支持的数据源一句话解释
POI Word/PPT/Excel 解析 Office 全家桶
GitHub GitHub 仓库 直接读代码仓库
GitLab GitLab 仓库 直接读代码仓库
Notion Notion 页面 同步 Notion 笔记
飞书 飞书文档 同步飞书文档
语雀 语雀文档 同步语雀文档
Bilibili B 站视频 提取视频信息和字幕
YouTube YouTube 视频 提取视频信息和字幕
Email 邮件文件 解析 .eml/.mbox
MySQL MySQL 数据库 数据库变知识库
MongoDB MongoDB 数据库变知识库
Elasticsearch ES 索引 从 ES 拉文档
腾讯云 COS 对象存储 读取云上文件
ArXiv 学术论文 读论文摘要

4.2 DocumentParser 扩展

Parser 与 Reader 的区别:Reader 负责"从哪读",Parser 负责"怎么解析格式"。

模块支持的格式
Tika 1000+ 格式(PDF/Word/HTML 等)
Apache PDFBox PDF
Markdown Markdown
YAML YAML 配置
BibTeX 学术引用
Multi-Modality 图像 OCR + 语音转文字
PDF Tables PDF 表格提取
Directory 批量解析目录中所有文件

4.3 Reader + Parser 配合使用

Reader 和 Parser 经常搭档出场。比如从语雀读取一篇 PDF 附件:

// Parser 负责解析 PDF 格式
TikaDocumentParser parser = new TikaDocumentParser();

// Reader 负责从语雀获取文档,并用 Parser 解析
YuQueResource resource = YuQueResource.builder()
.yuQueToken("your-token")
.resourcePath("your-path")
.build();
YuQueDocumentReader reader = new YuQueDocumentReader(resource, parser);

// 读取
List<Document> documents = reader.get();

大白话:Reader 是"快递员"(负责从各种地方取件),Parser 是"拆包员"(负责把包裹里的东西解析出来)。有的 Reader 自带拆包能力,有的则需要外挂 Parser。


五、ETL 最佳实践

文档质量决定了 AI 回答能力的上限,其他优化策略只是让 AI 回答能力不断逼近上限。

5.1 文档处理三原则

(1)内容结构化

原始文档排版清晰、标题层次分明、列表不要嵌套太深。建议使用 Markdown 作为知识库文档的首选格式——它天生结构清晰,解析效果好。

(2)内容规范化

  • 语言统一:中文场景用中文文档,别中英混杂
  • 表述统一:同一概念用同一说法("机器学习"别一会儿叫 ML,一会儿叫 Machine Learning)
  • 减少噪音:去掉水印、复杂表格等干扰元素

(3)格式标准化

优先使用 Markdown、DOCX 等文本格式。PDF 解析效果相对较差,可以先用百炼 DashScopeParse 工具转成 Markdown 再处理。

5.2 文档切片技巧

切片是 ETL 中最考验经验的环节:

问题原因解决方案
检索不到相关内容 切片太短,语义不完整 增大切片尺寸
返回大量无关内容 切片太长,包含噪音 减小切片尺寸
关键信息被截断 固定长度切分破坏语义 使用智能分块算法

最佳策略:智能分块 + 人工二次校验。先用算法自动切分,再人工抽查几篇,确认语义完整性。

// 调整切片参数
TokenTextSplitter splitter = new TokenTextSplitter(
200, // 减小块大小
100, // 降低最小字符数
10, // 最小嵌入长度
5000,
true
);

5.3 元数据标注策略

给你的知识碎片打上丰富的标签,形成多维索引:

// 方式1:手动添加
new Document("案例内容…", Map.of(
"type", "interior",
"year", "2025",
"style", "modern"
));

// 方式2:AI 自动提取关键词
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 5);
List<Document> enriched = enricher.apply(documents);

// 方式3:批量为文档添加来源标签
MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()
.withAdditionalMetadata("source", "codefather.cn")
.withAdditionalMetadata("status", "已审核")
.build();

5.4 批处理策略

当文档量很大时,别一次性全塞给嵌入模型——可能触发 API 限制。Spring AI 提供了 BatchingStrategy 来智能分批:

// 自定义分批策略
@Bean
public BatchingStrategy customTokenCountBatchingStrategy() {
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE, // 编码类型
8000, // 最大 token 数
0.1 // 保留百分比(余量)
);
}

大白话:就像搬家时不能把整个房间的东西塞进一个箱子,得分批打包。每批不能超过搬运工(嵌入模型)的承重上限。


六、总结

#mermaid-svg-8AhEiZqUthZGUkkJ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8AhEiZqUthZGUkkJ .error-icon{fill:#552222;}#mermaid-svg-8AhEiZqUthZGUkkJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8AhEiZqUthZGUkkJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8AhEiZqUthZGUkkJ .marker.cross{stroke:#333333;}#mermaid-svg-8AhEiZqUthZGUkkJ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8AhEiZqUthZGUkkJ p{margin:0;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge{stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 text{fill:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon–1{font-size:40px;color:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge–1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth–1{stroke-width:17;}#mermaid-svg-8AhEiZqUthZGUkkJ .section–1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-0{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-0{stroke-width:14;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-1{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-1{stroke-width:11;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 text{fill:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-2{stroke-width:8;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-3{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-3{stroke-width:5;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-4{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-4{stroke-width:2;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-5{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-5{stroke-width:-1;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-6{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-6{stroke-width:-4;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-7{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-7{stroke-width:-7;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-8{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-8{stroke-width:-10;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-9{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-9{stroke-width:-13;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 polygon,#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 text{fill:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .node-icon-10{font-size:40px;color:black;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .edge-depth-10{stroke-width:-16;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled circle,#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:lightgray;}#mermaid-svg-8AhEiZqUthZGUkkJ .disabled text{fill:#efefef;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-root rect,#mermaid-svg-8AhEiZqUthZGUkkJ .section-root path,#mermaid-svg-8AhEiZqUthZGUkkJ .section-root circle,#mermaid-svg-8AhEiZqUthZGUkkJ .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-8AhEiZqUthZGUkkJ .section-root text{fill:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-root span{color:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .section-2 span{color:#ffffff;}#mermaid-svg-8AhEiZqUthZGUkkJ .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-8AhEiZqUthZGUkkJ .edge{fill:none;}#mermaid-svg-8AhEiZqUthZGUkkJ .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-8AhEiZqUthZGUkkJ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Spring AI ETL

Extract 抽取

DocumentReader

JsonReader

TextReader

MarkdownReader

PDFReader

HtmlReader

TikaDocumentReader

Alibaba 扩展

POI / GitHub / Notion

飞书 / 语雀 / B站

MySQL / MongoDB / ES

Transform 转换

TextSplitter

TokenTextSplitter

MetadataEnricher

KeywordMetadataEnricher

SummaryMetadataEnricher

ContentFormatter

DefaultContentFormatter

Load 加载

DocumentWriter

FileDocumentWriter

VectorStore

PGVector 实战

阿里云 PostgreSQL

pgvector 插件

这篇文章我们系统地学习了 Spring AI 的 ETL Pipeline:

  • ETL 就是"读 → 拆 → 存"的流水线,是 RAG 系统的数据基础设施
  • 三大接口各司其职:DocumentReader 负责读取、DocumentTransformer 负责加工、DocumentWriter 负责入库
  • Spring AI Alibaba 社区提供了丰富的扩展,几乎覆盖所有常见数据源
  • 文档质量决定 RAG 上限,好的切片策略和元数据标注能让检索效果质的飞跃
  • 掌握了 ETL,你就掌握了 RAG 系统的"任督二脉"。接下来就可以搭建自己的知识库,让 AI 真正"读懂"你的专属数据了。


    参考文档:

    • Spring AI 官方文档 – ETL Pipeline
    • Spring AI Alibaba – ETL Pipeline
    • Spring AI Alibaba – Document Reader 使用指南
    • Spring AI Alibaba – Document Parser 使用指南
    赞(0)
    未经允许不得转载:171主机测评 » RAG核心特性详解:ETL流水线
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址