收藏本站,收获最前沿的人工智能与编程资讯!!

Spring AI ETL 流水线

技术文档 20℃ 0

抽取、转换与加载(ETL)框架是检索增强生成(RAG)应用场景中数据处理的核心支柱。

ETL 流水线统筹管理从原始数据源到结构化向量库的数据流,确保数据以最优格式供 AI 模型检索使用。

RAG 应用场景通过从数据集中检索相关信息来增强生成式模型的能力,以此提升生成输出的质量和相关性。

API 概述

ETL 流水线负责创建、转换并存储文档实例。

Spring AI 消息 API

文档类包含文本、元数据,以及可选的图片、音频、视频等其他媒体类型。

ETL 流水线包含三大核心组件:

  • 文档读取器,实现了 Supplier<List<Document>> 接口

  • 文档转换器,实现了 Function<List<Document>, List<Document>> 接口

  • 文档写入器,实现了 Consumer<List<Document>> 接口

借助文档读取器,可从 PDF、文本文件及其他文档类型中创建文档类的内容。

构建一条简单的 ETL 流水线,你可以将这三类组件的实例串联使用。

ETL 流水线

假设我们拥有以下三种 ETL 类型的实例:

  • 分页 PDF 文档读取器:文档读取器的一种实现

  • 令牌文本分割器:文档转换器的一种实现

  • 向量库:文档写入器的一种实现

若要按照检索增强生成模式将数据基础加载到向量数据库中,可使用以下 Java 函数式语法代码:

vectorStore.accept(tokenTextSplitter.apply(pdfReader.get()));

你也可以使用更贴合业务领域的自然表达方法名:

vectorStore.write(tokenTextSplitter.split(pdfReader.read()));

ETL 接口

ETL 流水线由以下接口和实现类组成。详细的 ETL 类图见 ETL 类图章节。

文档读取器

从多种来源提供文档数据。

public interface DocumentReader extends Supplier<List<Document>> {

    default List<Document> read() {
		return get();
	}
}

文档转换器

作为处理工作流的一部分,批量转换文档。

public interface DocumentTransformer extends Function<List<Document>, List<Document>> {

    default List<Document> transform(List<Document> transform) {
		return apply(transform);
	}
}

文档写入器

管理 ETL 流程的最终阶段,为文档存储做准备。

public interface DocumentWriter extends Consumer<List<Document>> {

    default void write(List<Document> documents) {
		accept(documents);
	}
}

文档读取器

JSON 格式

JSON 读取器用于处理 JSON 文档,将其转换为文档对象列表。

示例

@Component
class MyJsonReader {

	private final Resource resource;

    MyJsonReader(@Value("classpath:bikes.json") Resource resource) {
        this.resource = resource;
    }

	List<Document> loadJsonAsDocuments() {
        JsonReader jsonReader = new JsonReader(this.resource, "description", "content");
        return jsonReader.get();
	}
}

构造方法选项

JSON 读取器提供多种构造方法:

  • JsonReader(Resource resource)

  • JsonReader(Resource resource, String… jsonKeysToUse)

  • JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String… jsonKeysToUse)

参数

  • resource:指向 JSON 文件的 Spring 资源对象

  • jsonKeysToUse:JSON 中需作为结果文档对象文本内容的键数组

  • jsonMetadataGenerator:可选的 JSON 元数据生成器,用于为每个文档创建元数据

行为

JSON 读取器处理 JSON 内容的规则如下:

  • 可同时处理 JSON 数组和单个 JSON 对象

  • 对每个 JSON 对象(数组内或单个对象):

  • 根据指定的 jsonKeysToUse 提取内容

  • 若未指定键,则使用整个 JSON 对象作为内容

  • 通过提供的 JSON 元数据生成器生成元数据(未提供则生成空元数据)

  • 使用提取的内容和元数据创建文档对象

使用 JSON 指针

JSON 读取器现已支持通过 JSON 指针获取 JSON 文档的指定部分。该功能可轻松从复杂 JSON 结构中提取嵌套数据。

get(String pointer) 方法

public List<Document> get(String pointer)

该方法允许使用 JSON 指针获取 JSON 文档的指定部分。

参数

  • pointer:符合 RFC 6901 规范的 JSON 指针字符串,用于定位 JSON 结构中的目标元素

返回值

返回由 JSON 指针定位元素解析得到的文档列表。

行为

  • 该方法通过传入的 JSON 指针导航至 JSON 结构的指定位置

  • 若指针有效且指向存在的元素:

  • JSON 对象:返回包含单个文档的列表

  • JSON 数组:返回与数组元素一一对应的文档列表

  • 若指针无效或指向不存在的元素,抛出非法参数异常

示例

JsonReader jsonReader = new JsonReader(resource, "description");
List<Document> documents = this.jsonReader.get("/store/books/0");

示例 JSON 结构

[
  {
    "id": 1,
    "brand": "Trek",
    "description": "A high-performance mountain bike for trail riding."
  },
  {
    "id": 2,
    "brand": "Cannondale",
    "description": "An aerodynamic road bike for racing enthusiasts."
  }
]

本示例中,若 JSON 读取器配置 "description" 为 jsonKeysToUse,会为数组中每辆自行车创建文档对象,内容为 "description" 字段的值。

注意事项

  • JSON 读取器基于 Jackson 解析 JSON

  • 通过流式处理数组,可高效处理大型 JSON 文件

  • 若 jsonKeysToUse 指定多个键,内容为这些键对应值的拼接结果

  • 通过自定义 jsonKeysToUse 和 JSON 元数据生成器,可适配多种 JSON 结构

纯文本格式

文本读取器用于处理纯文本文档,将其转换为文档对象列表。

示例

@Component
class MyTextReader {

    private final Resource resource;

    MyTextReader(@Value("classpath:text-source.txt") Resource resource) {
        this.resource = resource;
    }

	List<Document> loadText() {
		TextReader textReader = new TextReader(this.resource);
		textReader.getCustomMetadata().put("filename", "text-source.txt");

		return textReader.read();
    }
}

构造方法选项

文本读取器提供两种构造方法:

  • TextReader(String resourceUrl)

  • TextReader(Resource resource)

参数

  • resourceUrl:表示待读取资源 URL 的字符串

  • resource:指向文本文件的 Spring 资源对象

配置

  • setCharset(Charset charset):设置读取文本文件的字符集,默认为 UTF-8

  • getCustomMetadata():返回可变映射,可添加文档的自定义元数据

行为

文本读取器处理文本内容的规则如下:

  • 将文本文件全部内容读取到单个文档对象中

  • 文件内容作为文档的内容

  • 自动为文档添加元数据:

  • charset:读取文件使用的字符集(默认:UTF-8)

  • source:源文本文件的文件名

  • 通过 getCustomMetadata() 添加的自定义元数据也会包含在文档中

注意事项

  • 文本读取器会将文件全部内容加载到内存,不适合超大文件

  • 若需将文本分割为更小片段,读取文档后可使用令牌文本分割器:

List<Document> documents = textReader.get();
List<Document> splitDocuments = new TokenTextSplitter().apply(this.documents);
  • 读取器基于 Spring 资源抽象,可读取多种来源(类路径、文件系统、URL 等)

  • 可通过 getCustomMetadata() 方法为读取器创建的所有文档添加自定义元数据

HTML 格式(基于 JSoup)

JSoup 文档读取器基于 JSoup 库处理 HTML 文档,将其转换为文档对象列表。

依赖

使用 Maven 或 Gradle 为项目添加依赖。

Maven

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-jsoup-document-reader</artifactId>
</dependency>

示例

@Component
class MyHtmlReader {

    private final Resource resource;

    MyHtmlReader(@Value("classpath:/my-page.html") Resource resource) {
        this.resource = resource;
    }

    List<Document> loadHtml() {
        JsoupDocumentReaderConfig config = JsoupDocumentReaderConfig.builder()
            .selector("article p") // 提取 article 标签内的段落
            .charset("ISO-8859-1")  // 使用 ISO-8859-1 编码
            .includeLinkUrls(true) // 在元数据中包含链接 URL
            .metadataTags(List.of("author", "date")) // 提取作者和日期元标签
            .additionalMetadata("source", "my-page.html") // 添加自定义元数据
            .build();

        JsoupDocumentReader reader = new JsoupDocumentReader(this.resource, config);
        return reader.get();
    }
}

JSoup 文档读取器配置可自定义读取器行为:

  • charset:指定 HTML 文档的字符编码,默认 UTF-8

  • selector:JSoup CSS 选择器,指定提取文本的元素,默认 body

  • separator:拼接多个选中元素文本的字符串,默认换行符

  • allElements:若为 true,提取 body 内所有文本,忽略选择器,默认 false

  • groupByElement:若为 true,选择器匹配的每个元素创建独立文档,默认 false

  • includeLinkUrls:若为 true,提取绝对链接 URL 并加入元数据,默认 false

  • metadataTags:需提取内容的 meta 标签列表,默认 ["description", "keywords"]

  • additionalMetadata:为所有创建的文档对象添加自定义元数据

示例文档:my-page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Web Page</title>
    <meta name="description" content="A sample web page for Spring AI">
    <meta name="keywords" content="spring, ai, html, example">
    <meta name="author" content="John Doe">
    <meta name="date" content="2024-01-15">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>Welcome to My Page</h1>
    </header>
    <nav>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/about">About</a></li>
        </ul>
    </nav>
    <article>
        <h2>Main Content</h2>
        <p>This is the main content of my web page.</p>
        <p>It contains multiple paragraphs.</p>
        <a href="https://www.example.com">External Link</a>
    </article>
    <footer>
        <p>&copy; 2024 John Doe</p>
    </footer>
</body>
</html>

行为

JSoup 文档读取器处理 HTML 内容并根据配置创建文档对象:

  • 选择器决定提取文本的元素

  • 若 allElements 为 true,body 内所有文本提取到单个文档

  • 若 groupByElement 为 true,选择器匹配的每个元素创建独立文档

  • 若两者均为 false,选择器匹配的所有元素文本通过分隔符拼接

  • 文档标题、指定 meta 标签内容、(可选)链接 URL 加入文档元数据

  • 解析相对链接的基础 URI 从 URL 资源中提取

  • 读取器保留选中元素的文本内容,移除内部 HTML 标签

Markdown 格式

Markdown 文档读取器用于处理 Markdown 文档,将其转换为文档对象列表。

依赖

使用 Maven 或 Gradle 为项目添加依赖。

Maven

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>

示例

@Component
class MyMarkdownReader {

    private final Resource resource;

    MyMarkdownReader(@Value("classpath:code.md") Resource resource) {
        this.resource = resource;
    }

    List<Document> loadMarkdown() {
        MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()
            .withHorizontalRuleCreateDocument(true)
            .withIncludeCodeBlock(false)
            .withIncludeBlockquote(false)
            .withAdditionalMetadata("filename", "code.md")
            .build();

        MarkdownDocumentReader reader = new MarkdownDocumentReader(this.resource, config);
        return reader.get();
    }
}

Markdown 文档读取器配置可自定义读取器行为:

  • horizontalRuleCreateDocument:为 true 时,Markdown 中的水平分隔线创建新文档对象

  • includeCodeBlock:为 true 时,代码块与周围文本包含在同一文档;为 false 时,代码块创建独立文档

  • includeBlockquote:为 true 时,引用块与周围文本包含在同一文档;为 false 时,引用块创建独立文档

  • additionalMetadata:为所有创建的文档对象添加自定义元数据

示例文档:code.md

This is a Java sample application:

```java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
```

Markdown also provides the possibility to `use inline code formatting throughout` the entire sentence.

---

Another possibility is to set block code without specific highlighting:

```
./mvnw spring-javaformat:apply
```

行为

Markdown 文档读取器处理 Markdown 内容并根据配置创建文档对象:

  • 标题转为文档对象的元数据

  • 段落转为文档对象的内容

  • 代码块可分离为独立文档或与周围文本合并

  • 引用块可分离为独立文档或与周围文本合并

  • 水平分隔线可将内容分割为独立文档

  • 读取器保留文档内容中的行内代码、列表、文本样式等格式

PDF 分页格式

分页 PDF 文档读取器基于 Apache PdfBox 库解析 PDF 文档。

依赖

使用 Maven 或 Gradle 为项目添加依赖。

Maven

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>

示例

@Component
public class MyPagePdfDocumentReader {

	List<Document> getDocsFromPdf() {

		PagePdfDocumentReader pdfReader = new PagePdfDocumentReader("classpath:/sample1.pdf",
				PdfDocumentReaderConfig.builder()
					.withPageTopMargin(0)
					.withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
						.withNumberOfTopTextLinesToDelete(0)
						.build())
					.withPagesPerDocument(1)
					.build());

		return pdfReader.read();
    }

}

PDF 段落格式

段落 PDF 文档读取器利用 PDF 目录(如目录)信息将输入 PDF 分割为文本段落,每个段落输出一个文档。注意:并非所有 PDF 文档都包含目录。

依赖

使用 Maven 或 Gradle 为项目添加依赖。

Maven

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>

示例

@Component
public class MyPagePdfDocumentReader {

	List<Document> getDocsFromPdfWithCatalog() {

        ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader("classpath:/sample1.pdf",
                PdfDocumentReaderConfig.builder()
                    .withPageTopMargin(0)
                    .withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
                        .withNumberOfTopTextLinesToDelete(0)
                        .build())
                    .withPagesPerDocument(1)
                    .build());

	    return pdfReader.read();
    }
}

Tika 格式(DOCX、PPTX、HTML 等)

Tika 文档读取器基于 Apache Tika 从多种文档格式提取文本,包括 PDF、DOC/DOCX、PPT/PPTX、HTML 等。完整支持格式列表参考 Tika 官方文档。

依赖

使用 Maven 或 Gradle 为项目添加依赖。

Maven

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

示例

@Component
class MyTikaDocumentReader {

    private final Resource resource;

    MyTikaDocumentReader(@Value("classpath:/word-sample.docx")
                            Resource resource) {
        this.resource = resource;
    }

    List<Document> loadText() {
        TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(this.resource);
        return tikaDocumentReader.read();
    }
}

转换器

文本分割器

文本分割器是抽象基类,用于分割文档以适配 AI 模型的上下文窗口。

令牌文本分割器

令牌文本分割器是文本分割器的实现类,基于令牌数量分割文本,使用 CL100K_BASE 编码。

用法

基础用法
@Component
class MyTokenTextSplitter {

    public List<Document> splitDocuments(List<Document> documents) {
        TokenTextSplitter splitter = new TokenTextSplitter();
        return splitter.apply(documents);
    }

    public List<Document> splitCustomized(List<Document> documents) {
        TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true, List.of('.', '?', '!', '\n'));
        return splitter.apply(documents);
    }
}
使用建造者模式

推荐使用建造者模式创建令牌文本分割器,API 更易读、更灵活:

@Component
class MyTokenTextSplitter {

    public List<Document> splitWithBuilder(List<Document> documents) {
        TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withChunkSize(1000)
            .withMinChunkSizeChars(400)
            .withMinChunkLengthToEmbed(10)
            .withMaxNumChunks(5000)
            .withKeepSeparator(true)
            .build();

        return splitter.apply(documents);
    }
}
自定义标点符号

可自定义用于将文本分割为语义片段的标点符号,对国际化场景尤为实用:

@Component
class MyInternationalTextSplitter {

    public List<Document> splitChineseText(List<Document> documents) {
        // 使用中文标点符号
        TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withChunkSize(800)
            .withMinChunkSizeChars(350)
            .withPunctuationMarks(List.of('。', '?', '!', ';'))  // 中文标点
            .build();

        return splitter.apply(documents);
    }

    public List<Document> splitWithCustomMarks(List<Document> documents) {
        // 中英文标点混合
        TokenTextSplitter splitter = TokenTextSplitter.builder()
            .withChunkSize(800)
            .withPunctuationMarks(List.of('.', '?', '!', '\n', ';', ':', '。'))
            .build();

        return splitter.apply(documents);
    }
}

构造方法选项

令牌文本分割器提供三种构造方法:

  • TokenTextSplitter():使用默认配置创建分割器

  • TokenTextSplitter(boolean keepSeparator):自定义分隔符行为创建分割器

  • TokenTextSplitter(int chunkSize, int minChunkSizeChars, int minChunkLengthToEmbed, int maxNumChunks, boolean keepSeparator, List<Character> punctuationMarks):全参数自定义构造方法

推荐使用建造者模式创建自定义配置的实例。

参数

  • chunkSize:每个文本片段的目标令牌大小,默认 800

  • minChunkSizeChars:每个文本片段的最小字符数,默认 350

  • minChunkLengthToEmbed:需纳入的片段最小长度,默认 5

  • maxNumChunks:单段文本生成的最大片段数,默认 10000

  • keepSeparator:是否在片段中保留分隔符(如换行符),默认 true

  • punctuationMarks:用于句子边界分割的字符列表,默认 . ? ! 换行符

行为

令牌文本分割器处理文本内容的规则如下:

  • 通过 CL100K_BASE 编码将输入文本转为令牌

  • 根据 chunkSize 将编码后的文本分割为片段

  • 对每个片段:

  • 将片段解码为文本

  • 仅当总令牌数超过 chunkSize 时,在 minChunkSizeChars 后通过配置的标点符号寻找合适分割点

  • 找到分割点则在该位置截断片段

  • 修剪片段,并根据 keepSeparator 设置可选移除换行符

  • 若结果片段长度大于 minChunkLengthToEmbed,加入输出列表

  • 重复流程直至所有令牌处理完成或达到 maxNumChunks

  • 剩余文本长度大于 minChunkLengthToEmbed 时,作为最终片段加入

仅当令牌数超过片段大小时,才基于标点分割。大小等于或小于片段大小的文本直接作为单个片段返回,避免小文本无意义分割。

示例

Document doc1 = new Document("This is a long piece of text that needs to be split into smaller chunks for processing.",
        Map.of("source", "example.txt"));
Document doc2 = new Document("Another document with content that will be split based on token count.",
        Map.of("source", "example2.txt"));

TokenTextSplitter splitter = new TokenTextSplitter();
List<Document> splitDocuments = this.splitter.apply(List.of(this.doc1, this.doc2));

for (Document doc : splitDocuments) {
    System.out.println("Chunk: " + doc.getContent());
    System.out.println("Metadata: " + doc.getMetadata());
}

注意事项

  • 令牌文本分割器使用 jtokkit 库的 CL100K_BASE 编码,兼容新版 OpenAI 模型

  • 分割器尽可能在句子边界分割,创建语义完整的片段

  • 原文档的元数据会保留并复制到所有派生片段

  • 若 copyContentFormatter 设为 true(默认行为),原文档的内容格式化器会复制到派生片段

  • 该分割器适合为有令牌限制的大语言模型准备文本,确保片段在模型处理能力范围内

  • 自定义标点符号:默认标点适配英文文本,其他语言或专业内容可通过建造者的 withPunctuationMarks 方法自定义

  • 性能考量:分割器可处理任意数量标点,但为优化性能,建议列表长度控制在 20 个字符以内

  • 可扩展性:getLastPunctuationIndex 方法为保护类型,子类可重写标点检测逻辑适配特殊场景

  • 小文本处理:2.0 版本起,令牌数小于等于片段大小的小文本不再按标点分割,避免符合大小限制的内容无意义碎片化

内容格式转换器

确保所有文档的内容格式统一。

关键词元数据增强器

关键词元数据增强器是一种文档转换器,使用生成式 AI 模型从文档内容提取关键词并作为元数据添加。

用法

@Component
class MyKeywordEnricher {

    private final ChatModel chatModel;

    MyKeywordEnricher(ChatModel chatModel) {
        this.chatModel = chatModel;
    }

    List<Document> enrichDocuments(List<Document> documents) {
        KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
                .keywordCount(5)
                .build();

        // 或使用自定义模板
        KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
               .keywordsTemplate(YOUR_CUSTOM_TEMPLATE)
               .build();

        return enricher.apply(documents);
    }
}

构造方法选项

关键词元数据增强器提供两种构造方法:

  • KeywordMetadataEnricher(ChatModel chatModel, int keywordCount):使用默认模板提取指定数量关键词

  • KeywordMetadataEnricher(ChatModel chatModel, PromptTemplate keywordsTemplate):使用自定义模板提取关键词

行为

关键词元数据增强器处理文档的规则如下:

  • 为每个输入文档基于内容创建提示词

  • 将提示词发送给指定的对话模型生成关键词

  • 生成的关键词以 "excerpt_keywords" 为键加入文档元数据

  • 返回增强后的文档

自定义

可使用默认模板或通过 keywordsTemplate 参数自定义模板。默认模板:

{context_str}. Give %s unique keywords for this document. Format as comma separated. Keywords:

其中 {context_str} 替换为文档内容,%s 替换为指定的关键词数量。

示例

ChatModel chatModel = // 初始化对话模型
KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
                .keywordCount(5)
                .build();

// 或使用自定义模板
KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
                .keywordsTemplate(new PromptTemplate("Extract 5 important keywords from the following text and separate them with commas:\n{context_str}"))
                .build();

Document doc = new Document("This is a document about artificial intelligence and its applications in modern technology.");

List<Document> enrichedDocs = enricher.apply(List.of(this.doc));

Document enrichedDoc = this.enrichedDocs.get(0);
String keywords = (String) this.enrichedDoc.getMetadata().get("excerpt_keywords");
System.out.println("Extracted keywords: " + keywords);

注意事项

  • 关键词元数据增强器需要可用的对话模型生成关键词

  • 关键词数量必须大于等于 1

  • 增强器为每个处理后的文档添加 "excerpt_keywords" 元数据字段

  • 生成的关键词以逗号分隔字符串返回

  • 该增强器可提升文档检索性,用于生成文档标签或分类

  • 建造者模式中,若设置 keywordsTemplate 参数,keywordCount 参数会被忽略

摘要元数据增强器

摘要元数据增强器是一种文档转换器,使用生成式 AI 模型为文档生成摘要并作为元数据添加。可生成当前文档及相邻文档(上一个、下一个)的摘要。

用法

@Configuration
class EnricherConfig {

    @Bean
    public SummaryMetadataEnricher summaryMetadata(OpenAiChatModel aiClient) {
        return new SummaryMetadataEnricher(aiClient,
            List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));
    }
}

@Component
class MySummaryEnricher {

    private final SummaryMetadataEnricher enricher;

    MySummaryEnricher(SummaryMetadataEnricher enricher) {
        this.enricher = enricher;
    }

    List<Document> enrichDocuments(List<Document> documents) {
        return this.enricher.apply(documents);
    }
}

构造方法

摘要元数据增强器提供两种构造方法:

  • SummaryMetadataEnricher(ChatModel chatModel, List<SummaryType> summaryTypes)

  • SummaryMetadataEnricher(ChatModel chatModel, List<SummaryType> summaryTypes, String summaryTemplate, MetadataMode metadataMode)

参数

  • chatModel:用于生成摘要的 AI 模型

  • summaryTypes:摘要类型枚举列表,指定生成哪些摘要(上一个、当前、下一个)

  • summaryTemplate:摘要生成自定义模板(可选)

  • metadataMode:生成摘要时处理文档元数据的方式(可选)

行为

摘要元数据增强器处理文档的规则如下:

  • 为每个输入文档基于内容和指定摘要模板创建提示词

  • 将提示词发送给指定的对话模型生成摘要

  • 根据指定的 summaryTypes,为每个文档添加以下元数据:

  • section_summary:当前文档摘要

  • prev_section_summary:上一个文档摘要(可用且请求时)

  • next_section_summary:下一个文档摘要(可用且请求时)

  • 返回增强后的文档

自定义

可通过提供自定义 summaryTemplate 定制摘要生成提示词。默认模板:

"""
Here is the content of the section:
{context_str}

Summarize the key topics and entities of the section.

Summary:
"""

示例

ChatModel chatModel = // 初始化对话模型
SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(chatModel,
    List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));

Document doc1 = new Document("Content of document 1");
Document doc2 = new Document("Content of document 2");

List<Document> enrichedDocs = enricher.apply(List.of(this.doc1, this.doc2));

// 检查增强后文档的元数据
for (Document doc : enrichedDocs) {
    System.out.println("Current summary: " + doc.getMetadata().get("section_summary"));
    System.out.println("Previous summary: " + doc.getMetadata().get("prev_section_summary"));
    System.out.println("Next summary: " + doc.getMetadata().get("next_section_summary"));
}

示例展示预期行为:

  • 两个文档的列表中,两个文档均获得 section_summary

  • 第一个文档获得 next_section_summary,无 prev_section_summary

  • 第二个文档获得 prev_section_summary,无 next_section_summary

  • 第一个文档的 section_summary 与第二个文档的 prev_section_summary 一致

  • 第一个文档的 next_section_summary 与第二个文档的 section_summary 一致

注意事项

  • 摘要元数据增强器需要可用的对话模型生成摘要

  • 增强器可处理任意长度的文档列表,正确处理首尾文档的边界情况

  • 该增强器适合创建上下文感知摘要,更好理解序列中文档的关联关系

  • MetadataMode 参数可控制现有元数据如何纳入摘要生成流程

写入器

文件写入

文件文档写入器是文档写入器的实现类,将文档列表内容写入文件。

用法

@Component
class MyDocumentWriter {

    public void writeDocuments(List<Document> documents) {
        FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, false);
        writer.accept(documents);
    }
}

构造方法

文件文档写入器提供三种构造方法:

  • FileDocumentWriter(String fileName)

  • FileDocumentWriter(String fileName, boolean withDocumentMarkers)

  • FileDocumentWriter(String fileName, boolean withDocumentMarkers, MetadataMode metadataMode, boolean append)

参数

  • fileName:写入文档的目标文件名

  • withDocumentMarkers:是否在输出中包含文档标记,默认 false

  • metadataMode:指定写入文件的文档内容,默认 MetadataMode.NONE

  • append:为 true 时数据追加到文件末尾,否则覆盖开头,默认 false

行为

文件文档写入器处理文档的规则如下:

  • 为指定文件名打开文件写入器

  • 对输入列表中的每个文档:

  • 若 withDocumentMarkers 为 true,写入包含文档索引和页码的文档标记

  • 根据指定的 metadataMode 写入格式化后的文档内容

  • 所有文档写入完成后关闭文件

文档标记

withDocumentMarkers 设为 true 时,写入器为每个文档添加以下格式标记:

### Doc: [index], pages:[start_page_number,end_page_number]

元数据处理

写入器使用两个特定元数据键:

  • page_number:文档的起始页码

  • end_page_number:文档的结束页码

写入文档标记时使用这两个键。

示例

List<Document> documents = // 初始化文档
FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, true);
writer.accept(documents);

该代码将所有文档写入 output.txt,包含文档标记、所有元数据,文件已存在时追加内容。

注意事项

  • 写入器使用文件写入器,以操作系统默认字符编码写入文本文件

  • 写入过程出错时,抛出运行时异常并封装原始异常

  • metadataMode 参数可控制现有元数据如何纳入写入内容

  • 该写入器适合调试或创建文档集合的人类可读输出

向量库

提供与多种向量库的集成。完整列表参考向量数据库文档。

相关推荐