ETL 管道

提取、轉換和載入 (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 型別的例項:

  • PagePdfDocumentReader,一個 DocumentReader 的實現。

  • TokenTextSplitter,一個 DocumentTransformer 的實現。

  • VectorStore,一個 DocumentWriter 的實現。

要執行將資料載入到向量資料庫中用於檢索增強生成模式的基本操作,可以使用以下 Java 函式式語法程式碼。

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

或者,您可以使用在該領域更自然地表達的方法名稱。

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

ETL 介面

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

DocumentReaders

JSON

JsonReader 處理 JSON 文件,將它們轉換為 Document 物件列表。

示例

@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 中的鍵陣列,應將其用作生成的 Document 物件的文字內容。

  • jsonMetadataGenerator: 可選的 JsonMetadataGenerator,用於為每個 Document 建立元資料。

行為

JsonReader 按如下方式處理 JSON 內容:

  • 它可以處理 JSON 陣列和單個 JSON 物件。

  • 對於每個 JSON 物件(無論是陣列中的還是單個物件):

    • 它根據指定的 jsonKeysToUse 提取內容。

    • 如果未指定鍵,則使用整個 JSON 物件作為內容。

    • 它使用提供的 JsonMetadataGenerator(如果未提供,則使用空的)生成元資料。

    • 它使用提取的內容和元資料建立 Document 物件。

使用 JSON Pointers

JsonReader 現在支援使用 JSON Pointers 檢索 JSON 文件的特定部分。此功能允許您輕鬆從複雜的 JSON 結構中提取巢狀資料。

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

此方法允許您使用 JSON Pointer 檢索 JSON 文件的特定部分。

引數
  • pointer: JSON Pointer 字串(如 RFC 6901 中定義),用於在 JSON 結構中定位所需的元素。

返回值
  • 返回包含從由指標定位的 JSON 元素解析的文件的 List<Document>

行為
  • 該方法使用提供的 JSON Pointer 在 JSON 結構中導航到特定位置。

  • 如果指標有效並指向現有元素:

    • 對於 JSON 物件:它返回包含單個 Document 的列表。

    • 對於 JSON 陣列:它返回 Document 列表,陣列中的每個元素對應一個 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."
  }
]

在此示例中,如果 JsonReader 使用 `"description"` 作為 jsonKeysToUse 進行配置,它將建立 Document 物件,其中內容是陣列中每輛腳踏車的 "description" 欄位的值。

注意事項

  • JsonReader 使用 Jackson 進行 JSON 解析。

  • 透過對陣列使用流式處理,它可以高效地處理大型 JSON 檔案。

  • 如果在 jsonKeysToUse 中指定了多個鍵,內容將是這些鍵對應值的連線。

  • 透過自定義 jsonKeysToUseJsonMetadataGenerator,該讀取器具有靈活性,可以適應各種 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(): 返回一個可變對映,您可以在其中為文件新增自定義元資料。

行為

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);
  • 該讀取器使用 Spring 的 Resource 抽象,允許從各種來源(classpath、檔案系統、URL 等)讀取。

  • 可以使用 getCustomMetadata() 方法將自定義元資料新增到讀取器建立的所有文件中。

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 選擇器,用於指定從中提取文字的元素(預設為 "body")。

  • separator: 用於連線從多個選定元素中提取的文字的字串(預設為 "\n")。

  • allElements: 如果為 true,則提取 <body> 元素中的所有文字,忽略 selector(預設為 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 決定哪些元素用於文字提取。

  • 如果 allElementstrue,則將 <body> 內的所有文字提取到一個單獨的 Document 中。

  • 如果 groupByElementtrue,則每個與 selector 匹配的元素都會建立一個單獨的 Document

  • 如果 allElementsgroupByElement 都不是 true,則將所有與 selector 匹配的元素中的文字使用 separator 連線起來。

  • 文件標題、指定 <meta> 標籤中的內容以及(可選地)連結 URL 會新增到 Document 的元資料中。

  • 用於解析相對連結的基礎 URI 將從 URL 資源中提取。

讀取器保留選定元素的文字內容,但刪除其中的任何 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 物件。

讀取器保留內聯程式碼、列表和文字樣式等格式,這些格式位於 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 (DOCX, 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();
    }
}

轉換器

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(): 使用預設設定建立分割器。

  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. 它將塊解碼迴文本。

    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 模型相容。

  • 分割器嘗試透過在句子邊界處(如果可能)斷開來建立語義上有意義的塊。

  • 原始文件中的元資料會被保留並複製到從該文件派生的所有塊。

  • 如果 copyContentFormatter 設定為 true(預設行為),則原始文件中的內容格式器(如果設定)也會複製到派生的塊。

  • 此分割器對於準備用於具有 token 限制的大型語言模型的文字特別有用,確保每個塊都在模型的處理容量範圍內。

ContentFormatTransformer

確保所有文件的內容格式統一。

KeywordMetadataEnricher

KeywordMetadataEnricher 是一個 DocumentTransformer,它使用生成式 AI 模型從文件內容中提取關鍵詞並將其新增為元資料。

用法

@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. 對於每個輸入文件,它使用文件內容建立一個 prompt。

  2. 它將此 prompt 傳送給提供的 ChatModel 以生成關鍵詞。

  3. 生成的關鍵詞將以鍵 "excerpt_keywords" 新增到文件的元資料中。

  4. 返回經過增強的文件。

自定義

可以透過修改類中的 KEYWORDS_TEMPLATE 常量來自定義關鍵詞提取 prompt。預設模板是:

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

Where {context_str} is replaced with the document content, and %s is replaced with the specified keyword count.

示例

ChatModel chatModel = // initialize your 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

SummaryMetadataEnricher 是一個 DocumentTransformer,它使用生成式 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 模型。

  • summaryTypes: 一個 SummaryType 列舉值列表,指示要生成哪些摘要(PREVIOUS、CURRENT、NEXT)。

  • summaryTemplate: 用於摘要生成的自定義模板(可選)。

  • metadataMode: 指定生成摘要時如何處理文件元資料(可選)。

行為

SummaryMetadataEnricher 按如下方式處理文件:

  1. 對於每個輸入文件,它使用文件內容和指定的摘要模板建立一個 prompt。

  2. 它將此 prompt 傳送給提供的 ChatModel 以生成摘要。

  3. 根據指定的 summaryTypes,它為每個文件新增以下元資料:

    • section_summary: 當前文件的摘要。

    • prev_section_summary: 上一個文件的摘要(如果可用且已請求)。

    • next_section_summary: 下一個文件的摘要(如果可用且已請求)。

  4. 返回經過增強的文件。

自定義

可以透過提供自定義 summaryTemplate 來定製摘要生成 prompt。預設模板是:

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

Summarize the key topics and entities of the section.

Summary:
"""

Summarize the following text. Text: {text}.

ChatModel chatModel = // initialize your 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));

// Check the metadata of the enriched documents
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 匹配。

注意事項

  • SummaryMetadataEnricher 需要一個正常工作的 ChatModel 來生成摘要。

  • 增強器可以處理任意大小的文件列表,並正確處理第一個和最後一個文件的邊緣情況。

  • 此增強器對於建立上下文感知的摘要特別有用,有助於更好地理解序列中文件之間的關係。

  • MetadataMode 引數允許控制如何將現有元資料合併到摘要生成過程中。

寫入器

檔案

FileDocumentWriter 是一個 DocumentWriter 實現,它將 Document 物件列表的內容寫入檔案。

用法

@Component
class MyDocumentWriter {

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

建構函式

FileDocumentWriter 提供三個建構函式

  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. 如果 withDocumentMarkers 為 true,它會寫入一個文件標記,包括文件索引和頁碼。

    2. 它根據指定的 metadataMode 寫入文件的格式化內容。

  3. 所有文件寫入完成後,檔案將被關閉。

文件標記

withDocumentMarkers 設定為 true 時,寫入器會為每個文件包含以下格式的標記

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

元資料處理

寫入器使用兩個特定的元資料鍵

  • page_number: 表示文件的起始頁碼。

  • end_page_number: 表示文件的結束頁碼。

這些在寫入文件標記時使用。

示例

List<Document> documents = // initialize your documents
FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, true);
writer.accept(documents);

這將把所有文件寫入 "output.txt",包括文件標記,使用所有可用的元資料,如果檔案已存在則追加寫入。

注意

  • 寫入器使用 FileWriter,因此它以作業系統的預設字元編碼寫入文字檔案。

  • 如果在寫入過程中發生錯誤,將丟擲 RuntimeException,其原因包含原始異常。

  • metadataMode 引數允許控制如何將現有元資料併入寫入的內容。

  • 此寫入器特別適用於除錯或建立文件集合的可讀輸出。

向量儲存

提供與各種向量儲存的整合。請參閱 向量資料庫文件 以獲取完整列表。