ETL 管道(Pipeline)

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

ETL(提取、转换、加载)框架构成检索增强生成(RAG)用例中数据处理的核心支柱。

ETL 流水线协调从原始数据源到结构化向量存储的完整流程,确保数据最终转换为 AI 模型检索所需的最优格式。

RAG(检索增强生成)用例通过从数据集中检索相关信息来增强生成模型的能力,从而提升输出内容的质量与相关性。

API 概览

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

Spring AI Message API

Document 类包含文本内容、元数据,以及可选的图像/音频/视频等多媒体附件。

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

  • 实现 Supplier<List<Document>> 接口的 DocumentReader 文档读取器

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

  • 实现 Consumer<List<Document>> 接口的 DocumentWriter 文档存储器

通过 DocumentReader 组件,可从 PDF、文本文件等各类文档中提取内容构建 Document 对象。

构建简易 ETL 流水线时,可将各类组件的实例按流程链式组合。

etl pipeline

假设我们已拥有以下三类 ETL 组件的实例:

  • PDF 分页文档读取器 PagePdfDocumentReader(`DocumentReader`的实现类)

  • 文本分块处理器 TokenTextSplitterDocumentTransformer 的实现类)

  • 向量存储器 VectorStoreDocumentWriter 的实现类)

以下 Java 函数式语法代码演示了如何将数据加载至向量数据库,以支持检索增强生成模式的基础实现:

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

亦可采用领域驱动设计中更符合语义的命名方式实现相同功能:

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

ETL 接口

ETL 流水线由以下接口与实现类构成,详细类图参见 ETL 类关系图 章节。

DocumentReader

提供多源异构文档的标准化输入接口。

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

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

DocumentTransformer

对批量文档进行流程化转换处理的组件。

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

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

DocumentWriter

负责 ETL 最终阶段,将文档处理为可存储形态的输出管理器。

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

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

ETL 类关系图

以下类图展示了 ETL 核心接口与实现类的关系架构。

etl class diagram

DocumentReader

JSON

JsonReader 负责解析 JSON 文档,将其转换为 Document 对象列表。

Example

@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();
	}
}

构造函数选项

JsonReader 提供了多个构造函数选项:

  1. JsonReader(Resource resource)

  2. JsonReader(Resource resource, String…​ jsonKeysToUse)

  3. JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String…​ jsonKeysToUse)

参数

  • resource:指向 JSON 文件的 Spring Resource 对象。

  • jsonKeysToUse:指定 JSON 文档中哪些 Key 对应的值应转换为 Document 对象的文本内容。

  • jsonMetadataGenerator:可选的 JsonMetadataGenerator 接口实现,用于为每个 Document 生成元数据。

行为

JsonReader 处理 JSON 内容的逻辑如下:

  • 该组件既能处理 JSON 数组,也能解析单个 JSON 对象。

  • 针对每个 JSON 对象(无论来自数组或独立对象):

    • 根据 jsonKeysToUse 配置提取目标 Key 值作为内容。

    • 若未指定键 Key,则将整个JSON对象作为内容处理。

    • 通过配置的 JsonMetadataGenerator 生成元数据(未配置时使用空元数据)。

    • 最终组合提取内容和元数据构建 Document 对象。

采用 JSON 指针规范

JsonReader 现已支持通过 JSON 指针提取文档特定部分,该特性可便捷地从复杂 JSON 结构中获取嵌套数据。

get(String pointer) 方法
public List<Document> get(String pointer)

该方法支持使用 JSON 指针精准定位 JSON 文档中的目标片段。

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

返回值
  • 返回 List<Document>,包含从指针定位的 JSON 元素解析得到的文档集合。

行为
  • 该方法通过 JSON 指针导航至 JSON 结构中的特定位置。

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

    • JSON 对象:返回含单个 Document 的列表。

    • JSON 数组:为每个数组元素生成对应 Document,返回结果列表。

  • 若指针无效或指向不存在的元素,则抛出 IllegalArgumentException 异常。

示例
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."
  }
]

本示例(一组自行车信息)中,若配置 JsonReaderjsonKeysToUse 为 "description",则会为数组中每辆自行车创建 Document 对象,其内容即为对应 "description" 字段的值。

注意

  • JsonReader 采用 Jackson 库实现 JSON 解析功能。

  • 通过流式解析技术,该组件能高效处理大型 JSON 数组文件。

  • jsonKeysToUse 指定多个键时,最终内容将是这些 Key 对应值的拼接结果。

  • T通过定制 jsonKeysToUseJsonMetadataGenerator,该 Reader 可灵活适配不同 JSON 结构需求。

文本

TextReader 负责解析纯文本文档,将其转换为 Document 对象列表。

示例

@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 提供两种构造方式:

  1. TextReader(String resourceUrl)

  2. TextReader(Resource resource)

参数

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

  • resource:指向文本文件的 Spring Resource 对象。

配置

  • setCharset(Charset charset):设置文本文件的字符编码集,默认采用 UTF-8。

  • getCustomMetadata():返回可变的元数据 Map,用于为文档添加自定义元数据。

行为

TextReader 按以下流程处理文本内容:

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

  • 文件内容直接作为 Document 对象的内容体。

  • 自动为 Document 添加以下元数据:

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

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

  • 通过 getCustomMetadata() 添加的自定义元数据将包含在 Document 中。

注意

  • TextReader 会将整个文件内容读入内存,因此可能不适用于处理超大文件。

  • 如需将文本分割为更小的片段,可在读取文档后使用 TokenTextSplitter 等文本分割器进行处理。

List<Document> documents = textReader.get();
List<Document> splitDocuments = new TokenTextSplitter().apply(this.documents);
  • 该 Reader 采用 Spring 的 Resource 抽象机制,支持从多种来源(类路径、文件系统、URL 等)读取内容。

  • 通过 getCustomMetadata() 方法可为该 Reader 生成的所有文档添加自定义元数据。

HTML(JSoup)

JsoupDocumentReader 利用 JSoup 库处理 HTML 文档,将其转换为 Document 对象列表。

示例

@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") // Extract paragraphs within <article> tags
            .charset("ISO-8859-1")  // Use ISO-8859-1 encoding
            .includeLinkUrls(true) // Include link URLs in metadata
            .metadataTags(List.of("author", "date")) // Extract author and date meta tags
            .additionalMetadata("source", "my-page.html") // Add custom metadata
            .build();

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

JsoupDocumentReaderConfig 支持对 JsoupDocumentReader 的行为进行定制:

  • charset:指定 HTML 文档的字符编码(默认为 "UTF-8")。

  • selector:JSoup CSS 选择器,指定提取文本的 HTML 元素(默认为 "body")。

  • separator:用于连接多个选中元素文本的分隔符(默认为 "\n")。

  • allElements:设为 true 时忽略 selector,提取 <body> 元素内全部文本(默认为 false)。

  • groupByElement:设为 true 时为每个 selector 匹配的元素创建独立 Document(默认为 false)。

  • includeLinkUrls:设为 true 时提取绝对链接 URL 并添加到元数据(默认为 false)。

  • metadataTags:指定要提取内容的 <meta> 标签名称列表(默认为 ["description", "keywords"])。

  • additionalMetadata:允许为所有生成的 Document 对象添加自定义元数据。

示例文档: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>

行为:

JsoupDocumentReader 根据配置将 HTML 内容处理为 Document 对象:

  • selector 决定提取文本的目标 HTML 元素。

  • allElementstrue,则提取 <body> 内全部文本至单个 Document

  • groupByElementtrue,则每个匹配 selector 的元素生成独立 Document

  • allElementsgroupByElement 均为 false,则使用 separator 拼接所有匹配 selector 元素的文本。

  • 文档标题、指定 · 标签内容及(可选)链接 URL 将添加到 Document 元数据中。

  • 用于解析相对链接的基准 URI 将从 URL 资源中自动提取。

该 Reader 保留选中元素的文本内容,但会移除其中的所有 HTML 标签。

Markdown

MarkdownDocumentReader 负责解析 Markdown 文档,将其转换为 Document 对象列表。

示例

@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();
    }
}

MarkdownDocumentReaderConfig 支持对 MarkdownDocumentReader 的行为进行定制:

  • horizontalRuleCreateDocument:设为 true 时,Markdown 中的水平分隔符将生成新 Document 对象。

  • includeCodeBlock:设为 true 时,代码块将与周边文本合并到同一 Document;设为 false 时,代码块生成独立 Document 对象。

  • includeBlockquote:设为 true 时,引用块将与周边文本合并到同一 Document;设为 false 时,引用块生成独立 Document 对象。

  • additionalMetadata:允许为所有生成的 Document 对象添加自定义元数据。

示例文档: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
```

MarkdownDocumentReader 根据配置将 Markdown 内容处理为 Document 对象:

  • 标题内容将转换为 Document 对象的元数据。

  • 段落内容构成 Document 对象的主体文本。

  • 代码块既可分离为独立 Document 对象,也可与周边文本合并处理。

  • 引用块既可分离为独立 Document 对象,也可与周边文本合并处理。

  • 水平分隔符可用于将内容分割为多个独立 Document 对象。

该 Reader 会保留行内代码、列表和文本样式等格式到 Document 对象内容中。

PDF 页

PagePdfDocumentReader 采用 Apache PdfBox 库解析 PDF 文档。

通过 Maven 或 Gradle 添加项目依赖。

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

或添加到 Gradle 的 build.gradle 构建文件。

dependencies {
    implementation 'org.springframework.ai:spring-ai-pdf-document-reader'
}

示例

@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 段落

ParagraphPdfDocumentReader 利用 PDF 目录(如 TOC)信息将输入 PDF 分割为文本段落,每个段落输出为一个独立 Document

注意:并非所有 PDF 文档都包含 PDF 目录结构。

依赖

通过 Maven 或 Gradle 添加项目依赖。

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

或添加到 Gradle 的 build.gradle 构建文件。

dependencies {
    implementation 'org.springframework.ai:spring-ai-pdf-document-reader'
}

示例

@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(OCX, PPTX, HTML…​)

TikaDocumentReader 利用 Apache Tika 从多种文档格式(如 PDF、DOC/DOCX、PPT/PPTX 和 HTML)中提取文本。完整支持的格式列表请参阅 Tika 官方文档

依赖

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

或添加到 Gradle 的 build.gradle 构建文件。

dependencies {
    implementation 'org.springframework.ai:spring-ai-tika-document-reader'
}

示例

@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();
    }
}

Transformer(转换器组件)

TextSplitter

TextSplitter 作为抽象基类,用于分割文档以适应 AI 模型的上下文窗口限制。

TokenTextSplitter

TokenTextSplitterTextSplitter 的实现类,采用 CL100K_BASE 编码按 Token 计数分割文本。

使用方法

@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);
        return splitter.apply(documents);
    }
}

构造器选项

TokenTextSplitter 提供了两个构造函数选项:

  1. TokenTextSplitter():创建采用默认配置的分割器(Splitter)实例。

  2. TokenTextSplitter(int defaultChunkSize, int minChunkSizeChars, int minChunkLengthToEmbed, int maxNumChunks, boolean keepSeparator)

参数

  • defaultChunkSize:每个文本块的目标 Token 数(默认值:800)。

  • minChunkSizeChars:每个文本块的最小字符数(默认值:350)。

  • minChunkLengthToEmbed:可嵌入分块的最小长度要求(默认值:5)。

  • maxNumChunks:单个文本生成的最大分块数限制(默认值:10000)。

  • keepSeparator: 是否在数据块中保留分隔符(如换行符)(默认值: true)。

行为

TokenTextSplitter 按以下流程处理文本内容:

  1. 使用 CL100K_BASE 编码将输入文本转换为 Token 序列。

  2. 根据 defaultChunkSize 将编码后的文本分割成块。

  3. 对于每个分块:

    1. 将分块后的 Token 序列解码还原为文本。

    2. 在达到 minChunkSizeChars 后,尝试寻找合适的分割点(句号、问号、感叹号或换行符)。

    3. 若找到分割点,则在该位置截断分块。

    4. 根据 keepSeparator 设置,对分块进行修剪并可选地移除换行符。

    5. 若结果分块长度大于 minChunkLengthToEmbed,则将其加入输出。

  4. 该过程持续运行,直至处理完所有 Token 或达到 maxNumChunks 限制。

  5. 剩余文本若长度超过 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());
}

注意

  • TokenTextSplitter 采用 jtokkit 库的 CL100K_BASE 编码,该编码与新版 OpenAI 模型兼容。

  • splitter 会尽可能在句子边界处断开,以生成具有语义完整性的文本块。

  • 原始文档的元数据将被保留,并复制到所有派生的文本块中。

  • copyContentFormatter 设为 true(默认行为),原始文档的内容格式化器也会复制到派生文本块。

  • 该 splitter 特别适用于为大语言模型准备文本,通过确保每个分块都在模型的 Token 处理限制内,解决上下文长度约束问题。

ContentFormatTransformer

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

KeywordMetadataEnricher

KeywordMetadataEnricher 作为 DocumentTransformer 的实现,利用生成式 AI 模型从文档内容提取关键词并添加为元数据。

Usage

@Component
class MyKeywordEnricher {

    private final ChatModel chatModel;

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

    List<Document> enrichDocuments(List<Document> documents) {
        KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(this.chatModel, 5);
        return enricher.apply(documents);
    }
}

构造函数

KeywordMetadataEnricher 构造函数接收两个参数:

  1. ChatModel chatModel:用于生成关键词的 AI 模型。

  2. int keywordCount:为每个文档提取的关键词数量。

行为

KeywordMetadataEnricher 按以下方式处理文档:

  1. 对于每个输入文档,它使用文档内容创建提示词。

  2. 将该提示词发送至指定的 ChatModel 以生成关键词。

  3. 生成的关键词以 "excerpt_keywords" 为 Key 添加到文档元数据中。

  4. 返回增强后的文档。

Customization

关键词提取提示词可通过修改类中的 KEYWORDS_TEMPLATE 常量自定义。默认模板如下:

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

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

示例

ChatModel chatModel = // 初始化 chat model
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 5);

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);

注意

  • KeywordMetadataEnricher 需要可用的 ChatModel 来生成关键词。

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

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

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

  • 该增强器对于提升文档可搜索性及生成文档标签/分类特别有用。

SummaryMetadataEnricher

SummaryMetadataEnricherDocumentTransformer 的实现,利用生成式 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 提供两个构造函数:

  1. SummaryMetadataEnricher(ChatModel chatModel, List<SummaryType> summaryTypes)

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

参数

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

  • summaryTypesSummaryType 枚举值列表,指定要生成的摘要类型(PREVIOUS、CURRENT、NEXT)。

  • summaryTemplate: A custom template for summary generation (optional).

  • metadataMode: Specifies how to handle document metadata when generating summaries (optional).

Behavior

SummaryMetadataEnricher 按以下方式处理文档:

  1. 对于每个输入文档,它使用文档内容和指定的摘要模板创建提示词。

  2. 将该提示词发送至指定的 ChatModel 以生成摘要。

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

    • section_summary:当前文档的摘要。

    • prev_section_summary:前一篇文档的摘要(若存在且被请求)。

    • next_section_summary:下一篇文档的摘要(若存在且被请求)。

  4. 返回增强后的文档。

Customization

摘要生成提示词可通过提供自定义的 summaryTemplate 进行修改。默认模板如下:

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

Summarize the key topics and entities of the section.

Summary:
"""

示例

ChatModel chatModel = // 初始化 chat model
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 内容一致。

注意

  • SummaryMetadataEnricher 需要可用的 ChatModel 来生成摘要。

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

  • 该增强器对于创建上下文感知的摘要特别有用,可更好地理解文档序列中的关联关系。

  • MetadataMode 参数用于控制现有元数据如何融入摘要生成过程。

Writer

File

The FileDocumentWriter is a DocumentWriter implementation that writes the content of a list of Document objects into a file.

Usage

@Component
class MyDocumentWriter {

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

Constructors

FileDocumentWriterDocumentWriter 的实现类,用于将 Document 对象列表的内容写入文件。

  1. FileDocumentWriter(String fileName)

  2. FileDocumentWriter(String fileName, boolean withDocumentMarkers)

  3. FileDocumentWriter(String fileName, boolean withDocumentMarkers, MetadataMode metadataMode, boolean append)

参数

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

  • withDocumentMarkers:是否在输出中包含文档标记(默认值:false)。

  • metadataMode:指定写入文件的文档内容类型(默认值:MetadataMode.NONE)。

  • append:若为 true,数据将追加至文件末尾而非开头(默认值:false)。

行为

FileDocumentWriter 按以下方式处理文档:

  1. 为指定文件名创建 FileWriter

  2. 对于输入列表中的每个文档:

    1. withDocumentMarkerstrue,则写入包含文档索引和页码的文档标记。

    2. 根据指定的 metadataMode 写入文档的格式化内容。

  3. 所有文档写入完成后关闭文件。

文档标记

withDocumentMarkers 设为 true 时,Writer 会为每个文档添加如下格式的标记:

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

元数据处理

Writer 使用两个特定的元数据 Key:

  • page_number:表示文档的起始页码。

  • end_page_number:表示文档的终止页码。

这些 Key 用于写入文档标记时使用。

示例

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

将所有文档写入 "output.txt" 文件,包含文档标记,使用全部可用元数据,若文件已存在则追加内容。

注意

  • Writer 使用 FileWriter,因此会采用操作系统的默认字符编码写入文本文件。

  • 若写入过程中发生错误,将抛出包含原始异常的 RuntimeException

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

  • 该 Writer 对于调试或创建文档集合的可读输出特别有用。

VectorStore

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