Pozyskiwanie danych

Pozyskiwanie danych to proces zbierania, odczytywania i przygotowywania danych z różnych źródeł, takich jak pliki, bazy danych, interfejsy API lub usługi w chmurze, dzięki czemu może być używany w aplikacjach podrzędnych. W praktyce ten proces jest zgodny z procesem Wyodrębnianie, Transformacja, Ładowanie (ETL):

  • Wyodrębnij dane z oryginalnego źródła, niezależnie od tego, czy jest to plik PDF, dokument programu Word, plik audio, czy internetowy interfejs API.
  • Przekształć dane, czyszcząc, fragmentując, wzbogacając lub konwertując formaty.
  • Załaduj dane do miejsca docelowego, takiego jak baza danych, magazyn wektorów lub model sztucznej inteligencji na potrzeby pobierania i analizy.

W przypadku scenariuszy sztucznej inteligencji i uczenia maszynowego, szczególnie w przypadku generowania rozszerzonego pobierania (RAG) pozyskiwanie danych nie polega tylko na konwertowaniu danych z jednego formatu na inny. Chodzi o to, aby dane można było używać dla inteligentnych aplikacji. Oznacza to reprezentowanie dokumentów w sposób, który zachowuje ich strukturę i znaczenie, dzieląc je na możliwe do zarządzania fragmenty, wzbogacając je metadanymi lub osadzanymi oraz przechowując je tak, aby można je było szybko i dokładnie pobrać.

Dlaczego pozyskiwanie danych ma znaczenie dla aplikacji sztucznej inteligencji

Wyobraź sobie, że tworzysz czatbota opartego na technologii RAG, aby ułatwić pracownikom znajdowanie informacji w ogromnej kolekcji dokumentów firmy. Te dokumenty mogą obejmować pliki PDF, pliki programu Word, prezentacje programu PowerPoint i strony internetowe rozproszone w różnych systemach.

Twój czatbot musi zrozumieć i przeszukać tysiące dokumentów, aby zapewnić dokładne, kontekstowe odpowiedzi. Jednak nieprzetworzone dokumenty nie są odpowiednie dla systemów sztucznej inteligencji. Należy przekształcić je w format, który zachowuje znaczenie, jednocześnie umożliwiając ich wyszukiwanie i pobieranie.

W tym miejscu pozyskiwanie danych staje się krytyczne. Musisz wyodrębnić tekst z różnych formatów plików, podzielić duże dokumenty na mniejsze fragmenty, które mieszczą się w granicach modelu sztucznej inteligencji, wzbogacić zawartość o metadane, wygenerować osadzanie na potrzeby wyszukiwania semantycznego i przechowywać wszystko w sposób umożliwiający szybkie pobieranie. Każdy krok wymaga starannego rozważenia sposobu zachowania oryginalnego znaczenia i kontekstu.

Bloki konstrukcyjne pozyskiwania danych

Biblioteka Microsoft.Extensions.DataIngestion jest oparta na kilku kluczowych składnikach, które współpracują ze sobą w celu utworzenia kompletnego potoku przetwarzania danych. W tej sekcji opisano poszczególne składniki i sposób ich dopasowania.

Dokumenty i czytniki dokumentów

Podstawą biblioteki jest IngestionDocument typ, który zapewnia ujednolicony sposób reprezentowania dowolnego formatu pliku bez utraty ważnych informacji. IngestionDocument jest skoncentrowany na języku Markdown, ponieważ duże modele językowe działają najlepiej z formatowaniem języka Markdown.

IngestionDocumentReader Abstrakcja obsługuje ładowanie dokumentów z różnych źródeł, czy to pliki lokalne, czy strumienie. Dostępnych jest kilka czytelników:

Więcej czytelników (w tym LlamaParse i Azure Document Intelligence) zostanie dodanych w przyszłości.

Ten projekt oznacza, że możesz pracować z dokumentami z różnych źródeł przy użyciu tego samego spójnego interfejsu API, dzięki czemu kod jest bardziej czytelny i elastyczny.

Przetwarzanie dokumentów

Procesory dokumentów stosują przekształcenia na poziomie dokumentu, aby ulepszyć i przygotować zawartość. Biblioteka udostępnia klasę ImageAlternativeTextEnricher jako wbudowany procesor, który używa dużych modeli językowych do generowania opisowego tekstu alternatywnego dla obrazów w dokumentach.

Strategie podziału na fragmenty i fragmenty

Po załadowaniu dokumentu zazwyczaj trzeba podzielić go na mniejsze fragmenty nazywane fragmentami. Fragmenty reprezentują podsekcje dokumentu, które mogą być efektywnie przetwarzane, przechowywane i pobierane przez systemy sztucznej inteligencji. Ten proces fragmentowania jest niezbędny w scenariuszach generowania wspomaganego wyszukiwaniem, w których trzeba szybko znaleźć najbardziej odpowiednie informacje.

Biblioteka udostępnia kilka strategii fragmentowania, które pasują do różnych przypadków użycia:

  • Fragmentowanie oparte na nagłówkach w celu podzielenia na podstawie nagłówków.
  • Fragmentowanie oparte na sekcjach do dzielenia na sekcje (na przykład strony).
  • Fragmentowanie z obsługą semantyczną w celu zachowania pełnych myśli.

Te strategie fragmentowania opierają się na bibliotece Microsoft.ML.Tokenizers, aby inteligentnie podzielić tekst na odpowiednie rozmiary elementów, które dobrze współpracują z dużymi modelami językowymi. Właściwa strategia fragmentowania zależy od typów dokumentów i sposobu pobierania informacji.

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

Przetwarzanie i wzbogacanie kawałków

Po podzieleniu dokumentów na fragmenty można zastosować procesory w celu ulepszenia i wzbogacania zawartości. Procesory fragmentów działają na poszczególnych elementach i mogą wykonywać następujące operacje:

  • Wzbogacanie zawartości , w tym automatyczne podsumowania (SummaryEnricher), analiza tonacji (SentimentEnricher) i wyodrębnianie słów kluczowych (KeywordEnricher).
  • Klasyfikacja do automatycznej kategoryzacji zawartości według zdefiniowanych wcześniej kategorii (ClassificationEnricher).

Te procesory używają Microsoft.Extensions.AI.Abstractions do wykorzystania dużych modeli językowych do inteligentnej transformacji treści, co sprawia, że elementy są bardziej przydatne dla dalszych aplikacji sztucznej inteligencji.

Moduł zapisywania i przechowywania dokumentów

IngestionChunkWriter<T> przechowuje przetworzone fragmenty w magazynie danych na potrzeby późniejszego pobierania. Biblioteka, która używa Microsoft.Extensions.AI i Microsoft.Extensions.VectorData, udostępnia klasę VectorStoreWriter<T>. Ten składnik zapisywania obsługuje przechowywanie fragmentów w dowolnym magazynie wektorów obsługiwanym przez Microsoft.Extensions.VectorDataprogram .

Magazyny wektorowe obejmują popularne opcje, takie jak Qdrant, SQL Server, CosmosDB, MongoDB i ElasticSearch. Aby uzyskać więcej informacji na temat dostawców, zobacz Out-of-the-box Vector Store providers (Dostawcy out-of-the-box Vector Store). (Pomimo włączenia "SemanticKernel" w nazwach pakietów, ci dostawcy nie mają nic wspólnego z semantycznym jądrem i mogą być używane w dowolnym miejscu na platformie .NET, w tym w programie Agent Framework).

Autor może również automatycznie generować embeddingi dla fragmentów przy użyciu metody Microsoft.Extensions.AI, przygotowując je do semantycznego wyszukiwania i pobierania scenariuszy.

OpenAIClient openAIClient = new(
    new ApiKeyCredential(Environment.GetEnvironmentVariable("OPENAI_API_KEY")!));

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

Potok przetwarzania dokumentów

Interfejs IngestionPipeline<T> API umożliwia łączenie różnych składników pozyskiwania danych w kompletny przepływ pracy. Możesz połączyć:

  • Czytelnicy ładują dokumenty z różnych źródeł.
  • Procesory do przekształcania i wzbogacania zawartości dokumentu.
  • Fragmentatory umożliwiające podzielenie dokumentów na elementy, którymi można zarządzać.
  • Autorzy do przechowywania końcowych wyników w wybranym magazynie danych.

Podejście do potoków danych zmniejsza kod szablonowy i ułatwia tworzenie, testowanie oraz utrzymanie złożonych przepływów danych.

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

Awaria pozyskiwania jednego dokumentu nie powinna spowodować awarii całego potoku. Dlatego IngestionPipeline<T>.ProcessAsync implementuje częściowy sukces, zwracając IAsyncEnumerable<IngestionResult>. Obiekt wywołujący jest odpowiedzialny za obsługę wszelkich błędów (na przykład ponowne próby przetwarzania nieudanych dokumentów lub zatrzymanie się przy pierwszym napotkanym błędzie).