個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Microsoft MVP for Developer Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

C# だけで Azure OpenAI の RAG を試してみたい (7)インデックスへのドキュメント登録

 
前の記事
hiro128.hatenablog.jp
 

ドキュメントの登録

作成したソースコードの詳細は以下を参照ください。
github.com
 

Embedding の取得

チャンクしたコンテンツから Embedding (1536次元の数値ベクトル表現)を取得します。

var embedings = await GenerateEmbeddingsAsync(openAIClient, openAIEmbeddingsDeproymentName, chunk);

openAIEmbeddingsDeproymentName は Embedding のデプロイ名です。Azure AI Studio で確認できます。

 

ドキュメントのアップロード

SearchDocument オブジェクトを生成してアップロードすることでインデックスにドキュメントを登録できます。
アップロード済みドキュメントがあれば削除してからアップロードするようにしています。

var searchClient = searchIndexClient.GetSearchClient(aiSerchIndexeName);
await DeleteDocumentByUrlAsync(searchClient, url);
await searchClient.UploadDocumentsAsync(documents);

 

ドキュメントの削除時の注意点

ドキュメントは、key 属性が設定されたフィールドの値指定でしか削除できないので、特定の記事のドキュメントを url フィールドで検索してドキュメントを取得し、 id フィールドの値を取得して、DeleteDocumentsAsyncに指定して削除します。

 

        // url フィールドでインデックスデータを取得し、id フィールドで削除する
        async Task DeleteDocumentByUrlAsync(SearchClient searchClient, string url)
        {
            SearchOptions options = new SearchOptions()
            {
                Filter = $"url eq '{url}'",
                Size = 100
            };

            var response = searchClient.Search<SearchDocument>("*", options);

            foreach (var result in response.Value.GetResults())
            {
                var id = result.Document["id"].ToString() ?? string.Empty;
                await searchClient.DeleteDocumentsAsync("id", new List<string>() { id });
            }
        }

 

ソースコード全体

作成したソースコードの詳細は以下を参照ください。
github.com
 
主要な処理部分は以下の通りです。

            BobyContentChunker chunker = new();
            var chunks = chunker.ChunkText(bodyText);

            List<SearchDocument> documents = new();
            foreach (var (chunk, index) in chunks.Select((chunk, index) => (chunk, index)))
            {
                var id = Guid.NewGuid().ToString();
                var lastUpdatedText = DateTimeOffset.Now.ToString();
                var embedings = await GenerateEmbeddingsAsync(openAIClient, openAIEmbeddingsDeproymentName, chunk);
                
                documents.Add(new SearchDocument
                {
                    ["id"] = id,
                    ["lastUpdated"] = lastUpdatedText,
                    ["content"] = chunk,
                    ["title"] = title,
                    ["filePath"] = url,
                    ["url"] = url,
                    ["metadata"] = "{\"chunk_id\": \"" + id + "\"}",
                    ["contentVector"] = embedings
                });

                //Console.WriteLine($"Uploading documents : {(index + 1).ToString("000000")}/{chunks.Count.ToString("000000")}");
            }

            var searchClient = searchIndexClient.GetSearchClient(aiSerchIndexeName);
            await DeleteDocumentByUrlAsync(searchClient, url);
            await searchClient.UploadDocumentsAsync(documents);
        }

 
ここまでで、「はてなブログの記事を関数アプリで10分ごとにクロールし、Blob に html として保存し、Blob にアイテムが追加されると、Event Grid の Blob Trigger の関数アプリで AI Search にベクトルを含むドキュメントを登録する」アプリが完成しましたので、チャットがこのインデックスの内容を含んだ回答を返してくれるか確認しましょう。

 
次の記事
hiro128.hatenablog.jp