数据引入是收集、读取和准备来自不同源(如文件、数据库、API 或云服务)的数据的过程,以便在下游应用程序中使用它。 实际上,此过程遵循 Extract-Transform-Load (ETL) 工作流:
- 从其原始源(无论是 PDF、Word 文档、音频文件还是 Web API)中提取数据。
- 通过清理、分块、扩充或转换格式来转换数据。
- 将数据加载到目标(如数据库、矢量存储或 AI 模型)中,以便检索和分析。
对于 AI 和机器学习方案(尤其是检索扩充生成(RAG),数据引入不仅仅是将数据从一种格式转换为另一种格式。 它用于使数据可用于智能应用程序。 这意味着,以保留其结构和含义的方式表示文档,将其拆分为可管理的区块,使用元数据或嵌入内容丰富文档,并存储文档,以便快速准确地检索它们。
为什么数据引入对于 AI 应用程序很重要
假设你正在构建一个 RAG 驱动的聊天机器人,以帮助员工查找公司大量文档集合中的信息。 这些文档可能包括 PDF、Word 文件、PowerPoint 演示文稿和分散在不同系统中的网页。
聊天机器人需要了解并搜索数千个文档,以提供准确的上下文答案。 但原始文档不适用于 AI 系统。 你需要将它们转换为保留含义的格式,同时使其可搜索和可检索。
这是数据引入变得至关重要的地方。 你需要从不同的文件格式中提取文本,将大型文档分解为适合 AI 模型限制的较小区块,使用元数据丰富内容,生成语义搜索的嵌入内容,以及以启用快速检索的方式存储所有内容。 每个步骤都需要仔细考虑如何保留原始含义和上下文。
数据摄取构建模块
Microsoft.Extensions.DataIngestion 库是围绕多个关键组件构建的,这些组件共同创建完整的数据处理管道。 本部分介绍每个组件及其组合方式。
文档和文档阅读器
在库的基础是 IngestionDocument 类型,它提供了一种统一的方式来表示任何文件格式,而不会丢失重要信息。
IngestionDocument 以 Markdown 为中心,因为大型语言模型最适合 Markdown 格式。
IngestionDocumentReader抽象层负责从各种来源加载文档,无论是本地文件还是流。 有一些读卡器可供使用:
将来将添加更多读者(包括 LlamaParse 和 Azure 文档智能)。
此设计意味着你可以使用同一一个一致的 API 处理来自不同源的文档,使代码更易于维护且更灵活。
文档处理
文档处理器在文档级别应用转换以增强和准备内容。 该库提供ImageAlternativeTextEnricher类作为内置处理器,利用大型语言模型为文档中的图像生成描述性替代文本。
区块和分块策略
加载文档后,通常需要将其分解为称为区块的较小部分。 区块表示可由 AI 系统有效处理、存储和检索的文档的子节。 此分块过程对于检索扩充的生成方案至关重要,需要快速查找最相关的信息片段。
该库提供了多个分块策略来适应不同的用例:
- 用于拆分标头的基于标头的分块。
- 基于分区的分块 ,用于按分区进行拆分(例如页面)。
- 语义感知分块 以保留完整的想法。
这些分块策略基于 Microsoft.ML.Tokenizers 库构建,以智能地将文本拆分为适合大型语言模型的适当大小的片段。 正确的分块策略取决于文档类型和计划检索信息的方式。
Tokenizer tokenizer = TiktokenTokenizer.CreateForModel("gpt-5");
IngestionChunkerOptions options = new(tokenizer)
{
MaxTokensPerChunk = 2000,
OverlapTokens = 0
};
IngestionChunker<string> chunker = new HeaderChunker(options);
区块处理和扩充
将文档拆分为区块后,可以应用处理器来增强和丰富内容。 区块处理器处理各个部分,可以执行以下作:
-
内容扩充 包括自动摘要(
SummaryEnricher)、情绪分析(SentimentEnricher)和关键字提取(KeywordEnricher)。 - 基于预定义类别()自动内容分类的
ClassificationEnricher。
这些处理器使用 Microsoft.Extensions.AI.Abstractions 利用大型语言模型进行智能内容转换,使区块更适用于下游 AI 应用程序。
文档编写器和存储
IngestionChunkWriter<T> 将已处理的区块存储在数据存储中供以后检索。 使用Microsoft.Extensions.AI和Microsoft.Extensions.VectorData的库提供VectorStoreWriter<T>类。 此编写器支持将区块存储在受支持的任何Microsoft.Extensions.VectorData中。
矢量存储包括常用的选项,如 Qdrant、 SQL Server、 CosmosDB、 MongoDB 和 ElasticSearch。 有关提供程序的详细信息,请参阅现成的矢量存储提供程序。 (尽管包名称中包含“SemanticKernel”,但这些提供程序与语义内核无关,并且可用于 .NET 中的任何位置,包括 Agent Framework)。
编写器还可以用Microsoft.Extensions.AI自动为您的数据块生成嵌入式向量,从而为语义搜索和检索方案做好准备。
OpenAIClient openAIClient = new(
new ApiKeyCredential(Environment.GetEnvironmentVariable("GITHUB_TOKEN")!),
new OpenAIClientOptions { Endpoint = new Uri("https://models.github.ai/inference") });
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator =
openAIClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
using SqliteVectorStore vectorStore = new(
"Data Source=vectors.db;Pooling=false",
new()
{
EmbeddingGenerator = embeddingGenerator
});
// The writer requires the embedding dimension count to be specified.
// For OpenAI's `text-embedding-3-small`, the dimension count is 1536.
using VectorStoreWriter<string> writer = new(vectorStore, dimensionCount: 1536);
文档处理管道
API IngestionPipeline<T> 允许将各种数据引入组件链接到完整的工作流中。 可以组合:
- 读取器 从各种源加载文档。
- 用于转换和扩充文档内容的处理器。
- 分块器 将文档分解为可管理的部分。
- 用于将最终结果存储在所选数据存储中的编写器。
此管道方法可减少样本代码,并可轻松生成、测试和维护复杂的数据引入工作流。
using IngestionPipeline<string> pipeline = new(reader, chunker, writer, loggerFactory: loggerFactory)
{
DocumentProcessors = { imageAlternativeTextEnricher },
ChunkProcessors = { summaryEnricher }
};
await foreach (var result in pipeline.ProcessAsync(new DirectoryInfo("."), searchPattern: "*.md"))
{
Console.WriteLine($"Completed processing '{result.DocumentId}'. Succeeded: '{result.Succeeded}'.");
}
单个文档引入失败不应导致整个管道失败。 这就是IngestionPipeline<T>.ProcessAsync通过返回IAsyncEnumerable<IngestionResult>来实现部分成功的原因。 调用方负责处理任何失败(例如,通过重试失败的文档或在第一个错误时停止处理)。