AI アプリケーションのカスタム データを処理する

このクイック スタートでは、AI アプリケーションのカスタム データを処理および準備するためのデータ インジェスト パイプラインを作成する方法について説明します。 アプリでは、 Microsoft.Extensions.DataIngestion ライブラリを使用して、ドキュメントの読み取り、AI によるコンテンツのエンリッチ、意味的なチャンク テキスト、セマンティック検索用のベクター データベースへの埋め込みの格納を行います。

データ インジェストは、大量の非構造化データを処理し、AI アプリケーションを検索できるようにする必要がある、取得拡張生成 (RAG) シナリオに不可欠です。

前提条件

アプリを作成する

.NET コンソール アプリを作成するには、次の手順を実行します。

  1. コンピューター上の空のディレクトリで、dotnet new コマンドを使用して新しいコンソール アプリを作成します。

    dotnet new console -o ProcessDataAI
    
  2. ディレクトリをアプリ フォルダーに変更します。

    cd ProcessDataAI
    
  3. 必要なパッケージをインストールします。

    dotnet add package Azure.AI.OpenAI
    dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
    dotnet add package Microsoft.Extensions.Configuration
    dotnet add package Microsoft.Extensions.Configuration.UserSecrets
    dotnet add package Microsoft.Extensions.DataIngestion --prerelease
    dotnet add package Microsoft.Extensions.DataIngestion.Markdig --prerelease
    dotnet add package Microsoft.Extensions.Logging.Console
    dotnet add package Microsoft.ML.Tokenizers.Data.O200kBase
    dotnet add package Microsoft.SemanticKernel.Connectors.SqliteVec --prerelease
    

AI サービスを作成する

  1. Azure OpenAI サービスとモデルをプロビジョニングするには、 Azure OpenAI サービス リソースの作成とデプロイ に関する記事の手順を完了します。 このクイック スタートでは、 gpt-5text-embedding-3-smallの 2 つのモデルをプロビジョニングする必要があります。

  2. ターミナルまたはコマンド プロンプトから、プロジェクト ディレクトリのルートに移動します。

  3. 次のコマンドを実行して、サンプル アプリの Azure OpenAI エンドポイントと API キーを構成します。

    dotnet user-secrets init
    dotnet user-secrets set AZURE_OPENAI_ENDPOINT <your-Azure-OpenAI-endpoint>
    dotnet user-secrets set AZURE_OPENAI_API_KEY <your-Azure-OpenAI-API-key>
    

エディターでアプリを開く

Visual Studio Code (または任意のエディター) でアプリを開きます。

code .

サンプル データを作成する

  1. sample.md ファイルをプロジェクト ディレクトリ内の data という名前のフォルダーにコピーします。
  2. このファイルを出力ディレクトリにコピーするようにプロジェクトを構成します。 Visual Studio を使用している場合は、ソリューション エクスプローラーでファイルを右クリックし、[ プロパティ] を選択し、[ 出力ディレクトリにコピー ] を [新しい場合はコピー] に設定します。

アプリ コードを追加する

データ インジェスト パイプラインは、ドキュメントを処理するために連携するいくつかのコンポーネントで構成されます。

  • ドキュメント リーダー: ディレクトリから Markdown ファイルを読み取ります。
  • ドキュメント プロセッサ: AI によって生成された代替テキストを使用して画像をエンリッチします。
  • Chunker: 埋め込みを使用して、ドキュメントをセマンティック チャンクに分割します。
  • チャンク プロセッサ: 各チャンクの AI の概要を生成します。
  • ベクター ストア ライター: SQLite データベースに埋め込まれたチャンクを格納します。
  1. Program.cs ファイルで、既存のコードを削除し、次のコードを追加してドキュメント リーダーを構成します。

    // Configure document reader.
    IngestionDocumentReader reader = new MarkdownReader();
    

    MarkdownReader クラスは Markdown ドキュメントを読み取り、大規模な言語モデルで適切に動作する統合形式に変換します。

  2. パイプラインのログ記録を構成するコードを追加します。

    using ILoggerFactory loggerFactory =
        LoggerFactory.Create(builder => builder.AddSimpleConsole());
    
  3. エンリッチメントとチャット用に AI クライアントを構成するコードを追加します。

    // Configure IChatClient to use Azure OpenAI.
    IConfigurationRoot config = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .Build();
    
    string endpoint = config["AZURE_OPENAI_ENDPOINT"];
    string apiKey = config["AZURE_OPENAI_API_KEY"];
    string chatModel = "gpt-5";
    string embeddingModel = "text-embedding-3-small";
    
    AzureOpenAIClient azureClient = new(
        new Uri(endpoint),
        new AzureKeyCredential(apiKey));
    
    IChatClient chatClient =
        azureClient.GetChatClient(chatModel).AsIChatClient();
    
  4. AI によって生成された説明を使用してイメージをエンリッチするドキュメント プロセッサを構成するコードを追加します。

    // Configure document processor.
    EnricherOptions enricherOptions = new(chatClient)
    {
        // Enricher failures should not fail the whole ingestion pipeline,
        // as they are best-effort enhancements.
        // This logger factory can create loggers to log such failures.
        LoggerFactory = loggerFactory
    };
    
    IngestionDocumentProcessor imageAlternativeTextEnricher =
        new ImageAlternativeTextEnricher(enricherOptions);
    

    ImageAlternativeTextEnricherでは、大きな言語モデルを使用して、ドキュメント内の画像の説明的な代替テキストを生成します。 そのテキストを使用すると、アクセシビリティが向上し、セマンティックな意味が向上します。

  5. ベクター表現を作成するための埋め込みジェネレーターを構成するコードを追加します。

    // Configure embedding generator.
    IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator =
        azureClient.GetEmbeddingClient(embeddingModel).AsIEmbeddingGenerator();
    

    埋め込み とは、テキストのセマンティックの意味を数値で表したものです。これにより、ベクトルの類似性検索が可能になります。

  6. ドキュメントをセマンティックな意味のチャンクに分割するチャンカーを設定するコードを追加します。

    // Configure chunker to split text into semantic chunks.
    IngestionChunkerOptions chunkerOptions = new(TiktokenTokenizer.CreateForModel(chatModel))
    {
        MaxTokensPerChunk = 2000,
        OverlapTokens = 0
    };
    
    IngestionChunker<string> chunker =
        new SemanticSimilarityChunker(embeddingGenerator, chunkerOptions);
    

    SemanticSimilarityChunkerでは、文間のセマンティック類似性を分析してドキュメントをインテリジェントに分割し、関連するコンテンツが一緒に残っていることを確認します。 このプロセスでは、単純な文字またはトークンベースのチャンクよりも意味とコンテキストを保持するチャンクが生成されます。

  7. 概要を生成するチャンク プロセッサを構成するコードを追加します。

    // Configure chunk processor to generate summaries for each chunk.
    IngestionChunkProcessor<string> summaryEnricher = new SummaryEnricher(enricherOptions);
    

    SummaryEnricherは、各チャンクの簡潔な概要を自動的に生成します。これによって、コンテンツの概要を提供することで、取得の精度を向上させることができます。

  8. 埋め込みを格納するための SQLite ベクター ストアを構成するコードを追加します。

    // Configure SQLite Vector Store.
    using SqliteVectorStore vectorStore = new(
        "Data Source=vectors.db;Pooling=false",
        new()
        {
            EmbeddingGenerator = embeddingGenerator
        });
    
    // The writer requires the embedding dimension count to be specified.
    using VectorStoreWriter<string> writer = new(
        vectorStore,
        dimensionCount: 1536,
        new VectorStoreWriterOptions { CollectionName = "data" });
    

    ベクター ストアは、チャンクとその埋め込みを格納し、高速なセマンティック検索機能を有効にします。

  9. すべてのコンポーネントを完全なパイプラインに作成するコードを追加します。

    // Compose data ingestion pipeline
    using IngestionPipeline<string> pipeline =
        new(reader, chunker, writer, loggerFactory: loggerFactory)
    {
        DocumentProcessors = { imageAlternativeTextEnricher },
        ChunkProcessors = { summaryEnricher }
    };
    

    IngestionPipeline<T>は、すべてのコンポーネントを結合して、ドキュメントを最初から最後まで処理するまとまりのあるワークフローにします。

  10. ディレクトリからドキュメントを処理するコードを追加します。

    await foreach (IngestionResult result in pipeline.ProcessAsync(
        new DirectoryInfo("./data"),
        searchPattern: "*.md"))
    {
        Console.WriteLine($"Completed processing '{result.DocumentId}'. " +
            $"Succeeded: '{result.Succeeded}'.");
    }
    

    パイプラインは、 ./data ディレクトリ内のすべての Markdown ファイルを処理し、各ドキュメントの状態を報告します。

  11. 処理されたドキュメントの対話型検索を有効にするコードを追加します。

    // Search the vector store collection and display results
    VectorStoreCollection<object, Dictionary<string, object?>> collection =
        writer.VectorStoreCollection;
    
    while (true)
    {
        Console.Write("Enter your question (or 'exit' to quit): ");
        string? searchValue = Console.ReadLine();
        if (string.IsNullOrEmpty(searchValue) || searchValue == "exit")
        {
            break;
        }
    
        Console.WriteLine("Searching...\n");
        await foreach (VectorSearchResult<Dictionary<string, object?>> result in
            collection.SearchAsync(searchValue, top: 3))
        {
            Console.WriteLine($"Score: {result.Score}\n\tContent: {result.Record["content"]}");
        }
    }
    

    検索機能は、ユーザー クエリを埋め込みに変換し、ベクトル ストア内で最も意味的に似たチャンクを検索します。

アプリを実行する

  1. dotnet run コマンドを使用してアプリを実行します。

    dotnet run
    

    アプリは、 ./data ディレクトリ内のすべての Markdown ファイルを処理し、各ドキュメントの処理状態を表示します。 処理が完了したら、自然言語の質問を入力して、処理されたコンテンツを検索できます。

  2. プロンプトでデータを検索するための質問を入力します。

    Enter your question (or 'exit' to quit): What is data ingestion?
    

    アプリは、ドキュメントから最も関連性の高いチャンクとその類似性スコアを返します。

  3. exit 」と入力して、アプリケーションを終了します。

リソースをクリーンアップする

不要になった場合は、Azure OpenAI リソースとモデルのデプロイを削除します。

  1. Azure portalで、Azure OpenAI リソースに移動します。
  2. Azure OpenAI リソースを選択し、[削除] を選択します。

次のステップ