Document 加载与切分
约 539 字大约 2 分钟
布欧-Lewyon
2026-05-15
RAG 的第一步是处理源文档——加载、清洗、切分、向量化。
DocumentReader
// 文本文件
TxtReader txtReader = new TxtReader("classpath:/docs/faq.txt");
List<Document> docs = txtReader.get();// JSON 文件
JsonReader jsonReader = new JsonReader(
new FileSystemResource("/data/products.json"),
"name", "description", "category" // 提取的 JSON 字段
);
List<Document> docs = jsonReader.get();PDF 文档加载
// PDF 文件(需要添加 Tika 或 PDFBox 依赖)
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>// 使用 Apache Tika 解析 PDF
TikaDocumentReader pdfReader = new TikaDocumentReader(
new FileSystemResource("/data/manual.pdf")
);
List<Document> documents = pdfReader.get();
// 读取目录下所有 PDF
Path dir = Paths.get("/data/docs/");
List<Document> allDocs = Files.walk(dir)
.filter(p -> p.toString().endsWith(".pdf"))
.flatMap(path -> {
TikaDocumentReader reader = new TikaDocumentReader(
new FileSystemResource(path.toFile()));
return reader.get().stream();
})
.toList();DocumentSplitter
LLM 有上下文窗口限制,长的文档需要切分成小块:
// Token 文本切分器(推荐)
TokenTextSplitter tokenSplitter = TokenTextSplitter.builder()
.withChunkSize(500) // 每块 500 Token
.withChunkOverlap(50) // 重叠 50 Token(保留上下文)
.build();
List<Document> chunks = tokenSplitter.apply(documents);// 句子切分器
SentenceSplitter sentenceSplitter = SentenceSplitter.builder()
.withChunkSize(300)
.withChunkOverlap(30)
.build();// 自定义切分
public class CustomSplitter implements DocumentSplitter {
@Override
public List<Document> split(List<Document> documents) {
List<Document> result = new ArrayList<>();
for (Document doc : documents) {
String[] paragraphs = doc.getContent().split("\\n\\n");
for (int i = 0; i < paragraphs.length; i++) {
Document chunk = new Document(
doc.getId() + "-" + i,
paragraphs[i].trim(),
doc.getMetadata()
);
result.add(chunk);
}
}
return result;
}
}完整处理流水线
@Service
public class DocumentPipelineService {
private final VectorStore vectorStore;
public void processDocument(Resource resource, String category) {
log.info("Processing: {}", resource.getFilename());
// 1. 加载
TikaDocumentReader reader = new TikaDocumentReader(resource);
List<Document> documents = reader.get();
log.info("Loaded {} pages", documents.size());
// 2. 添加元数据
documents.forEach(doc ->
doc.getMetadata().put("category", category));
// 3. 切分
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(500)
.withChunkOverlap(50)
.build();
List<Document> chunks = splitter.apply(documents);
log.info("Split into {} chunks", chunks.size());
// 4. 向量化并存储
vectorStore.add(chunks);
log.info("Successfully stored in vector store");
}
// 批量处理目录
public void processDirectory(String directoryPath, String category) {
try {
Files.walk(Paths.get(directoryPath))
.filter(p -> p.toString().endsWith(".pdf") ||
p.toString().endsWith(".txt") ||
p.toString().endsWith(".md"))
.forEach(path -> processDocument(
new FileSystemResource(path.toFile()), category));
} catch (IOException e) {
throw new RuntimeException("Failed to process directory", e);
}
}
}小结
TikaDocumentReader支持 PDF、DOCX、TXT、HTML 等多种格式。JsonReader从 JSON 中提取指定字段。TokenTextSplitter按 Token 切分(推荐),SentenceSplitter按句子切分。- Chunk Overlap 保留段落间的上下文过渡。
- 流水线:加载 → 清洗 → 切分 → 向量化 → 存入 VectorStore。
上一节:VectorStore 与 PGVector 下一节:RAG 检索增强生成
