Ingestão de dados

A ingestão de dados é o processo de recolher, ler e preparar dados de diferentes fontes, como ficheiros, bases de dados, APIs ou serviços cloud, para que possam ser usados em aplicações posteriores. Na prática, este processo segue o fluxo de trabalho Extract-Transform-Load (ETL):

  • Extrair dados da sua fonte original, seja um PDF, documento Word, ficheiro áudio ou API web.
  • Transforme os dados limpando, fragmentando, enriquecendo ou convertendo formatos.
  • Carregue os dados num destino como uma base de dados, armazenamento vetorial ou modelo de IA para recuperação e análise.

Para cenários de IA e aprendizagem automática, especialmente geração aumentada por recuperação (RAG), a ingestão de dados não se resume apenas a converter dados de um formato para outro. Trata-se de tornar os dados utilizáveis para aplicações inteligentes. Isto significa representar documentos de forma a preservar a sua estrutura e significado, dividindo-os em partes geríveis, enriquecendo-os com metadados ou embeddings, e armazenando-os para que possam ser recuperados rápida e precisamente.

Porque a ingestão de dados é importante para aplicações de IA

Imagine que está a construir um chatbot alimentado por RAG para ajudar os colaboradores a encontrar informação na vasta coleção de documentos da sua empresa. Estes documentos podem incluir PDFs, ficheiros Word, apresentações PowerPoint e páginas web espalhadas por diferentes sistemas.

O seu chatbot precisa de compreender e pesquisar milhares de documentos para fornecer respostas precisas e contextuais. Mas documentos brutos não são adequados para sistemas de IA. Precisas de os transformar num formato que preserve o significado enquanto os torna pesquisáveis e recuperáveis.

É aqui que a ingestão de dados se torna crítica. É necessário extrair texto de diferentes formatos de ficheiro, dividir documentos grandes em blocos mais pequenos que se encaixem dentro dos limites do modelo de IA, enriquecer o conteúdo com metadados, gerar embeddings para pesquisa semântica e armazenar tudo de forma a permitir uma recuperação rápida. Cada passo exige uma consideração cuidadosa sobre como preservar o significado e o contexto originais.

Blocos de construção para ingestão de dados

A biblioteca Microsoft.Extensions.DataIngestion é construída em torno de vários componentes-chave que trabalham em conjunto para criar um pipeline completo de processamento de dados. Esta secção explora cada componente e como se encaixam.

Documentos e leitores de documentos

Na base da biblioteca está o IngestionDocument tipo, que proporciona uma forma unificada de representar qualquer formato de ficheiro sem perder informação importante. IngestionDocument é centrado no Markdown porque os grandes modelos de linguagem funcionam melhor com a formatação Markdown.

A IngestionDocumentReader abstração trata do carregamento de documentos de várias fontes, sejam ficheiros locais ou fluxos. Estão disponíveis alguns leitores:

Mais leitores (incluindo LlamaParse e Azure Document Intelligence) serão adicionados no futuro.

Este design significa que pode trabalhar com documentos de diferentes fontes usando a mesma API consistente, tornando o seu código mais fácil de manter e flexível.

Processamento de documentos

Os processadores de documentos aplicam transformações ao nível do documento para melhorar e preparar o conteúdo. A biblioteca fornece a ImageAlternativeTextEnricher classe como um processador incorporado que utiliza grandes modelos de linguagem para gerar texto descritivo alternativo para imagens dentro de documentos.

Fragmentos e estratégias de chunking

Depois de carregares um documento, normalmente precisas de o dividir em partes mais pequenas chamadas blocos. Os chunks representam subsecções de um documento que podem ser processadas, armazenadas e recuperadas de forma eficiente por sistemas de IA. Este processo de divisão em fragmentos é essencial para cenários de geração de informações aumentada por recuperação, onde é necessário encontrar rapidamente as informações mais relevantes.

A biblioteca fornece várias estratégias de fragmentação para se adaptar a diferentes casos de uso:

  • Divisão baseada em cabeçalhos para dividir nos cabeçalhos.
  • Fragmentação baseada em secções para dividir em secções (por exemplo, páginas).
  • Fragmentação semântica consciente para preservar pensamentos completos.

Estas estratégias de fragmentação baseiam-se na biblioteca Microsoft.ML.Tokenizers para dividir inteligentemente o texto em partes de tamanho adequado que funcionam bem com grandes modelos de linguagem. A estratégia correta de fragmentação depende dos tipos de documentos e de como planeia recuperar a informação.

Tokenizer tokenizer = TiktokenTokenizer.CreateForModel("gpt-5");
IngestionChunkerOptions options = new(tokenizer)
{
    MaxTokensPerChunk = 2000,
    OverlapTokens = 0
};
IngestionChunker<string> chunker = new HeaderChunker(options);

Processamento e enriquecimento de fragmentos

Depois de os documentos serem divididos em partes, pode usar processadores para enriquecer e enriquecer o conteúdo. Os processadores em blocos funcionam em peças individuais e podem executar:

  • Enriquecimento de conteúdo incluindo resumos automáticos (SummaryEnricher), análise de sentimento (SentimentEnricher) e extração de palavras-chave (KeywordEnricher).
  • Classificação para categorização automática de conteúdos com base em categorias pré-definidas (ClassificationEnricher).

Estes processadores utilizam Microsoft.Extensions.AI.Abstractions para aproveitar grandes modelos de linguagem para transformação inteligente de conteúdos, tornando os seus blocos mais úteis para aplicações de IA a jusante.

Escritor e armazenamento de documentos

IngestionChunkWriter<T> armazena os chunks processados num repositório de dados para recuperação posterior. A biblioteca, que utiliza Microsoft.Extensions.AI e Microsoft.Extensions.VectorData, fornece a classe VectorStoreWriter<T>. Este escritor suporta o armazenamento de chunks em qualquer armazenamento vetorial suportado por Microsoft.Extensions.VectorData.

As lojas vetoriais incluem opções populares como Qdrant, SQL Server, CosmosDB,MongoDB e ElasticSearch. Para mais informações sobre os fornecedores, consulte fornecedores da Vector Store prontos a utilizar. (Apesar da inclusão de "SemanticKernel" nos nomes dos pacotes, estes fornecedores nada têm a ver com o Kernel Semântico e são utilizáveis em qualquer parte do .NET, incluindo o Agent Framework.)

O escritor pode gerar automaticamente embeddings para os seus fragmentos usando Microsoft.Extensions.AI, preparando-os para cenários de pesquisa semântica e recuperação.

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

Pipeline de processamento de documentos

A IngestionPipeline<T> API permite-lhe encadear os vários componentes de ingestão de dados num fluxo de trabalho completo. Pode combinar:

  • Leitores para carregar documentos de várias fontes.
  • Processadores para transformar e enriquecer o conteúdo do documento.
  • Fragmentadores para dividir documentos em partes manejáveis.
  • Escritores para armazenar os resultados finais no armazenamento de dados escolhido.

Esta abordagem de pipeline reduz o código padrão e facilita a construção, testagem e manutenção de fluxos de trabalho complexos de ingestão de dados.

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}'.");
}

Uma falha na ingestão de um único documento não deve comprometer todo o algoritmo do pipeline. É por isso que IngestionPipeline<T>.ProcessAsync implementa sucesso parcial ao devolver IAsyncEnumerable<IngestionResult>. O chamador é responsável por tratar de quaisquer falhas (por exemplo, reprocessando documentos com falhas ou interrompendo na primeira falha).