ETL 流水线
提取、转换和加载 (ETL) 框架是检索增强生成 (RAG) 用例中数据处理的骨干。
ETL 流水线协调从原始数据源到结构化向量存储的流程,确保数据处于供 AI 模型检索的最佳格式。
RAG 用例是通过从数据体中检索相关信息来增强生成模型的能力,从而提升生成输出的质量和相关性。
API概述
ETL 流水线创建、转换并存储 Document 个实例。
Document 类包含文本、元数据,以及可选的其他媒体类型(如图像、音频和视频)。
ETL 流水线主要有三个组成部分,
-
DocumentReader实现Supplier<List<Document>> -
DocumentTransformer实现Function<List<Document>, List<Document>> -
DocumentWriter实现Consumer<List<Document>>
Document 类的内容由 DocumentReader 协助从 PDF、文本文件及其他文档类型创建。
要构建一个简单的 ETL 管道,您可以将每种类型的实例链接在一起。
假设我们有以下三种 ETL 类型的实例
-
PagePdfDocumentReader的一个DocumentReader实现 -
TokenTextSplitter的一个DocumentTransformer实现 -
VectorStore的一个DocumentWriter实现
要在向量数据库中执行基本的数据加载以用于检索增强生成模式,请在 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);
}
}
文档读取器
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 提供了多种构造函数选项:
-
JsonReader(Resource resource) -
JsonReader(Resource resource, String… jsonKeysToUse) -
JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String… jsonKeysToUse)
参数
-
resource:一个指向 JSON 文件的 SpringResource对象。 -
jsonKeysToUse:来自 JSON 的键数组,这些键将用作结果Document对象中的文本内容。 -
jsonMetadataGenerator: 一个可选的JsonMetadataGenerator,用于为每个Document创建元数据。
行为
JsonReader 按以下方式处理 JSON 内容:
-
它可以处理 JSON 数组和单个 JSON 对象。
-
对于每个 JSON 对象(无论是在数组中还是单个对象):
-
它根据指定的
jsonKeysToUse提取内容。 -
如果未指定任何键,则使用整个 JSON 对象作为内容。
-
它使用提供的
JsonMetadataGenerator(如果未提供则使用空值)生成元数据。 -
它创建一个带有提取内容和元数据的
Document对象。
-
使用 JSON 指针
JsonReader 现在支持使用 JSON Pointer 检索 JSON 文档的特定部分。此功能让您能够轻松地从复杂的 JSON 结构中提取嵌套数据。
示例 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”字段的值。
text
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();
}
}
配置
-
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抽象,使其能够从各种来源(类路径、文件系统、URL 等)进行读取。 -
可以使用
getCustomMetadata()方法将自定义元数据添加到读取器创建的所有文档中。
HTML (JSoup)
JsoupDocumentReader 处理 HTML 文档,使用 JSoup 库将其转换为 Document 对象列表。
依赖项
使用 Maven 或 Gradle 将依赖项添加到您的项目中。
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-jsoup-document-reader</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-jsoup-document-reader'
}
例举
@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>© 2024 John Doe</p>
</footer>
</body>
</html>
行为:
JsoupDocumentReader 处理 HTML 内容,并根据配置创建 Document 对象:
-
selector决定了哪些元素用于文本提取。 -
如果
allElements为true,则<body>内的所有文本将被提取到单个Document中。 -
如果
groupByElement为true,则每个匹配selector的元素都会创建一个独立的Document。 -
如果
allElements和groupByElement都不是true,则使用separator将匹配selector的所有元素的文本连接起来。 -
文档标题、来自指定
<meta>标签的内容,以及(可选的)链接 URL 会被添加到Document元数据中。 -
用于解析相对链接的基础 URI 将从 URL 资源中提取。
读取器会保留所选元素的文本内容,但会移除其中的任何 HTML 标签。
Markdown
MarkdownDocumentReader 处理 Markdown 文档,将其转换为 Document 对象列表。
依赖项
使用 Maven 或 Gradle 将依赖项添加到您的项目中。
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-markdown-document-reader'
}
例举
@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 对象:
-
头信息成为文档对象中的元数据。
-
段落成为文档对象的内容。
-
代码块可以分离为独立的文档对象,或与周围文本一起包含。
-
引用块可以分离为独立的文档对象,或与周围文本一起包含。
-
水平规则可用于将内容分割为独立的文档对象。
阅读器会保留文档对象内容中的格式,如内联代码、列表和文本样式。
PDF 页面
PagePdfDocumentReader 使用 Apache PdfBox 库来解析 PDF 文档。
依赖项
使用 Maven 或 Gradle 将依赖项添加到您的项目中。
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
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 目录(例如目录树)信息将输入 PDF 拆分为文本段落,并为每个段落输出一个 Document。
注意:并非所有 PDF 文档都包含 PDF 目录。
依赖项
使用 Maven 或 Gradle 将依赖项添加到您的项目中。
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
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 文档。
依赖项
使用 Maven 或 Gradle 将依赖项添加到您的项目中。
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
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();
}
}
转换器
TokenTextSplitter
TokenTextSplitter 是 TextSplitter 的一个实现,它根据Tokens数量将文本分割成块,使用 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);
}
}
使用构建器模式
创建 TokenTextSplitter 的推荐方式是使用构建器模式,它提供了更易读且灵活的 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) {
// Use Chinese punctuation marks
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(800)
.withMinChunkSizeChars(350)
.withPunctuationMarks(List.of('。', '?', '!', ';')) // Chinese punctuation
.build();
return splitter.apply(documents);
}
public List<Document> splitWithCustomMarks(List<Document> documents) {
// Mix of English and other punctuation marks
TokenTextSplitter splitter = TokenTextSplitter.builder()
.withChunkSize(800)
.withPunctuationMarks(List.of('.', '?', '!', '\n', ';', ':', '。'))
.build();
return splitter.apply(documents);
}
}
构造函数选项
TokenTextSplitter 提供了三种构造函数选项:
-
TokenTextSplitter(): 使用默认设置创建分割器。 -
TokenTextSplitter(boolean keepSeparator): 创建一个具有自定义分隔符行为的分割器。 -
TokenTextSplitter(int chunkSize, int minChunkSizeChars, int minChunkLengthToEmbed, int maxNumChunks, boolean keepSeparator, List<Character> punctuationMarks): 包含所有自定义选项的完整构造函数。
| 建造者模式(如上所示)是创建具有自定义配置实例的推荐方法。 |
参数
-
chunkSize: 每个文本块的目标大小(以Tokens为单位)(默认值:800)。 -
minChunkSizeChars: 每个文本块的最小字符数(默认值:350)。 -
minChunkLengthToEmbed:要包含的块的最小长度(默认值:5)。 -
maxNumChunks: 从文本中生成的最大块数(默认值:10000)。 -
keepSeparator:是否在块中保留分隔符(如换行符)(默认值:true)。 -
punctuationMarks: 用作句子边界以进行分割的字符列表(默认值:.、?、!、\n)。
行为
TokenTextSplitter 按以下方式处理文本内容:
-
它使用 CL100K_BASE 编码将输入文本编码为Tokens。
-
它根据
chunkSize将编码后的文本分割成块。 -
对于每个块:
-
它将数据块解码回文本。
-
仅当总Tokens数超过分块大小时,它才会尝试在
minChunkSizeChars之后找到一个合适的断点(使用配置的punctuationMarks)。 -
如果找到断点,它会在该点截断块。
-
它会根据
keepSeparator设置修剪代码块,并可选择性地移除换行符。 -
如果生成的块长度大于
minChunkLengthToEmbed,则将其添加到输出中。
-
-
此过程会持续进行,直到所有Tokens处理完毕或达到
maxNumChunks。 -
任何剩余文本如果长度大于
minChunkLengthToEmbed,将作为最后一个块添加。
| 基于标点的拆分仅在Tokens数量超过块大小时适用。完全匹配或小于块大小的文本将作为单个块返回,不会进行基于标点的截断。这可避免对小型文本进行不必要的拆分。 |
例举
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(默认行为),原始文档中的内容格式化器(如果已设置)也会被复制到派生的块中。 -
此分割器特别适用于为具有Tokens限制的大型语言模型准备文本,确保每个块都在模型的处理能力范围内。
-
自定义标点符号:默认标点符号(
.、?、!、\n)适用于英文文本。对于其他语言或专业内容,请使用构建器的withPunctuationMarks()方法自定义标点符号。 -
性能考虑:虽然分割器可以处理任意数量的标点符号,但为了获得最佳性能,建议将列表保持在合理的小规模(少于 20 个字符),因为每个块都会检查每个标记。
-
可扩展性:
getLastPunctuationIndex(String)方法是protected,允许子类重写标点检测逻辑以满足特定用例。 -
小文本处理:自 2.0 版本起,小文本(Tokens数量等于或低于分块大小)不再在标点符号处拆分,从而避免了对已符合大小限制的内容进行不必要的碎片化。
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 = KeywordMetadataEnricher.builder(chatModel)
.keywordCount(5)
.build();
// Or use custom templates
KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
.keywordsTemplate(YOUR_CUSTOM_TEMPLATE)
.build();
return enricher.apply(documents);
}
}
构造函数选项
KeywordMetadataEnricher 提供了两种构造函数选项:
-
KeywordMetadataEnricher(ChatModel chatModel, int keywordCount): 使用默认模板并提取指定数量的关键词。 -
KeywordMetadataEnricher(ChatModel chatModel, PromptTemplate keywordsTemplate): 使用自定义模板进行关键词提取。
行为
KeywordMetadataEnricher 按以下方式处理文档:
-
对于每个输入文档,它都会使用该文档的内容创建一个提示。
-
它将此提示发送到提供的
ChatModel以生成关键词。 -
生成的关键词会以键 "excerpt_keywords" 添加到文档的元数据中。
-
返回已增强的文档。
自定义
您可以使用默认模板,或通过 keywordsTemplate 参数自定义模板。 默认模板为:
\{context_str}. Give %s unique keywords for this document. Format as comma separated. Keywords:
其中 {context_str} 将被替换为文档内容,%s 将被替换为指定的关键词数量。
例举
ChatModel chatModel = // initialize your chat model
KeywordMetadataEnricher enricher = KeywordMetadataEnricher.builder(chatModel)
.keywordCount(5)
.build();
// Or use custom templates
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);
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 提供了两个构造函数:
-
SummaryMetadataEnricher(ChatModel chatModel, List<SummaryType> summaryTypes) -
SummaryMetadataEnricher(ChatModel chatModel, List<SummaryType> summaryTypes, String summaryTemplate, MetadataMode metadataMode)
参数
-
chatModel:用于生成摘要的 AI 模型。 -
summaryTypes: 一个包含SummaryType个枚举值的列表,用于指示要生成哪些摘要(PREVIOUS、CURRENT、NEXT)。 -
summaryTemplate: 用于生成摘要的自定义模板(可选)。 -
metadataMode: 指定在生成摘要时如何处理文档元数据(可选)。
行为
SummaryMetadataEnricher 按以下方式处理文档:
-
对于每个输入文档,它会根据文档内容和指定的摘要模板创建一个提示。
-
它将此提示发送到提供的
ChatModel以生成摘要。 -
根据指定的
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 = // 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匹配。 -
第一个文档的
next_section_summary与第二个文档的section_summary匹配。
作者
file
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 提供了三个构造函数:
-
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)。
行为
FileDocumentWriter 按以下方式处理文档:
-
它为指定的文件名打开一个 FileWriter。
-
对于输入列表中的每个文档:
-
如果
withDocumentMarkers为真,则写入一个包含文档索引和页码的文档标记。 -
它根据指定的
metadataMode写入文档的格式化内容。
-
-
所有文档写入完成后,文件将被关闭。
文档标记
当 withDocumentMarkers 设置为 true 时,写入器会按以下格式为每个文档包含标记:
### Doc: [index], pages:[start_page_number,end_page_number]
向量存储
提供与各种向量存储的集成。 请参阅 向量数据库文档 获取完整列表。