数据引入是收集、读取和准备来自不同源(如文件、数据库、API 或云服务)的数据的过程,以便在下游应用程序中使用它。 实际上,此过程遵循 Extract-Transform-Load (ETL) 工作流:
- 从其原始源(无论是 PDF、Word 文档、音频文件还是 Web API)中提取数据。
- 通过清理、分块、扩充或转换格式来转换数据。
- 将数据加载到目标(如数据库、矢量存储或 AI 模型)中,以便检索和分析。
对于 AI 和机器学习场景(尤其是检索增强生成(RAG)),数据引入不仅仅是将数据从一种格式转换为另一种格式。 它用于使数据可用于智能应用程序。 这意味着,以保留其结构和含义的方式表示文档,将其拆分为可管理的区块,使用元数据或嵌入内容丰富文档,并存储文档,以便快速准确地检索它们。
为什么数据引入对于 AI 应用程序很重要
假设你正在构建一个 RAG 驱动的聊天机器人,以帮助员工查找公司大量文档集合中的信息。 这些文档可能包括 PDF、Word 文件、PowerPoint 演示文稿和分散在不同系统中的网页。
聊天机器人需要了解并搜索数千个文档,以提供准确的上下文答案。 但原始文档不适用于 AI 系统。 你需要将它们转换为保留含义的格式,同时使其可搜索和可检索。
这是数据引入变得至关重要的地方。 你需要从不同的文件格式中提取文本,将大型文档分解为适合 AI 模型限制的较小区块,使用元数据丰富内容,生成语义搜索的嵌入内容,以及以启用快速检索的方式存储所有内容。 每个步骤都需要仔细考虑如何保留原始含义和上下文。
Microsoft.Extensions.DataIngestion 库
📦 Microsoft.Extensions.DataIngestion 包提供用于数据引入的基础 .NET 构建基块。 它使开发人员能够读取、处理和准备 AI 和机器学习工作流的文档,尤其是增强检索生成(RAG)方案。
使用这些构建基块,可以创建针对应用程序需求定制的可靠、灵活、智能的数据引入管道:
- 统一文档表示形式: 表示任何文件类型(例如 PDF、图像或 Microsoft Word),格式一致,适用于大型语言模型。
- 灵活的数据摄取: 使用多个内置读取器,从云服务和本地源读取文档,使从各个来源摄取数据更加简便。
- 内置 AI 增强功能: 使用摘要、情绪分析、关键字提取和分类自动丰富内容,为智能工作流准备数据。
- 可自定义的分块策略: 使用基于令牌、基于节或语义感知的方法将文档拆分为区块,以便可以针对检索和分析需求进行优化。
- 生产就绪存储: 在常用矢量数据库和文档存储中存储已处理的区块,支持嵌入生成,使管道可供实际方案使用。
- 端到端管道组合: 将读取器、处理器、区块器和编写器与 IngestionPipeline<T> API 链接在一起,减少样本,并使其易于生成、自定义和扩展完整的工作流。
- 性能和可伸缩性: 这些组件专为可缩放的数据处理而设计,可以高效地处理大量数据,使其适合企业级应用程序。
所有这些组件都按设计开放且可扩展。 可以添加自定义逻辑和新连接器,并扩展系统以支持新兴的 AI 方案。 通过标准化文档的表示、处理和存储方式,.NET 开发人员可以生成可靠、可缩放且可维护的数据管道,而无需为每个项目“重塑方向盘”。
在稳固的基础上构建
这些数据引入构建基块基于 .NET 生态系统中经过验证的可扩展组件构建,可确保可靠性、互作性和与现有 AI 工作流的无缝集成:
- Microsoft.ML.Tokenizers: Tokenizer 为基于令牌分块文档提供了基础。 这样就可以精确拆分内容,这对于准备大型语言模型的数据和优化检索策略至关重要。
- Microsoft.Extensions.AI: 这组库使用大型语言模型为扩充转换提供支持。 它支持汇总、情绪分析、关键字提取和嵌入生成等功能,以便通过智能见解轻松增强数据。
- Microsoft.Extensions.VectorData: 这组库提供了一个一致的接口,用于将处理区块存储在各种矢量存储中,包括 Qdrant、Azure SQL、CosmosDB、MongoDB、ElasticSearch 等。 这可确保数据管道可供生产使用,并且可以跨不同的存储后端进行缩放。
除了熟悉的模式和工具,这些抽象还基于已扩展的组件构建。 插件功能和互作性至关重要,因此,随着 .NET AI 生态系统的其余部分的发展,数据引入组件的功能也随之增长。 此方法使开发人员能够轻松集成新的连接器、扩充和存储选项,使管道的未来就绪且适应不断发展的 AI 方案。
数据摄取构建模块
Microsoft.Extensions.DataIngestion 库是围绕多个关键组件构建的,这些组件共同创建完整的数据处理管道。 本部分介绍每个组件及其组合方式。
文档和文档阅读器
在库的基础是 IngestionDocument 类型,它提供了一种统一的方式来表示任何文件格式,而不会丢失重要信息。
IngestionDocument 以 Markdown 为中心,因为大型语言模型最适合 Markdown 格式。
IngestionDocumentReader抽象层负责从各种来源加载文档,无论是本地文件还是流。 有一些读卡器可供使用:
将来将添加更多读者(包括 LlamaParse 和 Azure 文档智能)。
此设计意味着你可以使用同一一个一致的 API 处理来自不同源的文档,使代码更易于维护且更灵活。
文档处理
文档处理器在文档级别应用转换以增强和准备内容。 该库提供ImageAlternativeTextEnricher类作为内置处理器,利用大型语言模型为文档中的图像生成描述性替代文本。
区块和分块策略
加载文档后,通常需要将其分解为称为区块的较小部分。 区块表示可由 AI 系统有效处理、存储和检索的文档的子节。 此分块过程对于检索扩充的生成方案至关重要,需要快速查找最相关的信息片段。
该库提供了多个分块策略来适应不同的用例:
- 用于拆分标头的基于标头的分块。
- 基于分区的分块 ,用于按分区进行拆分(例如页面)。
- 语义感知分块 以保留完整的想法。
这些分块策略基于 Microsoft.ML.Tokenizers 库构建,以智能地将文本拆分为适合大型语言模型的适当大小的片段。 正确的分块策略取决于文档类型和计划检索信息的方式。
Tokenizer tokenizer = TiktokenTokenizer.CreateForModel("gpt-4");
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.Abstractions,该库提供了 VectorStoreWriter<T> 支持将区块存储在 Microsoft.Extensions.VectorData 支持的任何向量存储中的类。
矢量存储包括常用的选项,如 Qdrant、 SQL Server、 CosmosDB、 MongoDB、 ElasticSearch 等。 编写器还可以使用 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>来实现部分成功的原因。 调用方负责处理任何失败(例如,通过重试失败的文档或在第一个错误时停止处理)。