normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Semantic Kernel を利用して Azure Cognitive Search のインデックスにベクトル検索してみる(失敗編)

以前に Azure Cognitive Search がベクトル検索に対応した件、python でベクトル検索を実施した件をそれぞれ試しました。
normalian.hatenablog.com
normalian.hatenablog.com
Azure OpenAI とベクトル検索を組み合わせてどの様に動くかはご理解いただけたと思いますが、これらはどちらも Python コードで実行されており、C# 等になじみのある方々にとって自身のアプリに組み込むのは少しハードルがある状況だと思います。

こちらに対して、Python 側で主要なライブラリである LangChain 相当のことを目指す Sentiment Kernel と呼ばれるライブラリが既に発表されており、既に Azure Cognitive Search 向けのコネクタも提供されていることが分かりました。
github.com

今回は実際にソースコードを書いて&実行して Azure Cognitive Search のインデックスにベクトル検索をしてみました。が、結果から言うと「Semantic Kernel の Azure Cognitive Search 向け Connector がベクトル検索に対応していない」という理由で失敗しました(あくまで2023年7月7日現在の話)。ここまでアレコレしたので、せっかくなので途中経過だろうがまとめようと思ったのが今回の記事になります

Semantic Kernel で Azure Cognitive Search を利用する

Semantic Kernel で Azure Cognitive Search を利用する場合は以下の様に Microsoft.SemanticKernel と Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch のライブラリを nuget 経由でインストールする必要があります。

この際に include prerelease にチェックを入れるのを忘れないようにしましょう。

以下が実際に利用したコードですが、実行前に Azure Cognitive Search のインデックス側にデータを格納する必要があります。Azure Cognitive Search という「ベクトル化データのデータストア」にどの様にデータを格納するかは Azure OpenAI での Embedding 時にパラメータ弄って観察する - normalian blog を参照ください。

using Microsoft.SemanticKernel;

namespace MyOpenAITest
{
    class Program
    {
        public static async Task Main(string[] args)
        {
            string deploymentName = "text-davinci-003";
            string endpoint = "https://xxxxxxxxxxxxxx.openai.azure.com/";
            string openAiKey = "your-openai-key";

            string deploymentName_embedding = "text-embedding-ada-002";
            string azuresearchEndpoint = "https://xxxxxxxxxxxxx-koreasouth.search.windows.net";
            string azuresearchKey = "your-azuresearch-key";
            string azuresearchIndexname = "your-index-name";

            Console.WriteLine("== Start Applicaiton ==");

            var builder = new KernelBuilder();
            builder.WithAzureTextCompletionService(
                     deploymentName, // Azure OpenAI Deployment Name
                     endpoint,       // Azure OpenAI Endpoint
                     openAiKey);

            IKernel kernel = Kernel.Builder
                .WithOpenAITextCompletionService(deploymentName, openAiKey)
                .WithOpenAITextEmbeddingGenerationService(deploymentName_embedding, openAiKey)
                .WithAzureCognitiveSearchMemory(
                    azuresearchEndpoint,
                    azuresearchKey)
                .Build();

            var searchResult = kernel.Memory.SearchAsync(azuresearchIndexname,
                "Please let me know Azure subscription structure");

            await foreach (var result in searchResult) 
            {
                Console.Write($"id ={result.Metadata.Id}, text={result.Metadata.Text}");
            }

            Console.WriteLine("== End Application ==");
        }
    }
}

こちらを実行すると残念ながら以下の結果が返ってきます。値の中身が全く入っていません。

なんで検索が上手くいかないの?

その答えは Semantic Kernel のソースコード自体を読み込むことで理解ができました。以下を参照ください。
github.com
以下のソースコード周辺で "// TODO: use vectors" という記載があり、今の時点ではベクトル検索にライブラリ自体が対応していないことが見受けられます(これは多少弄った程度だとどうにもならなそうでした)。

ハマったところ① - Semantic 検索がオフにできない

最初に出くわしたエラーは以下の「Semantic 検索を有効にしてないぞ」です。

こちらは困った問題で、現時点(2023年7月7日現在)では Japan East/Japan West ともに Azure Cognitive Search は Semantic 検索 に対応しておりません。
azure.microsoft.com
仕方ないので Korea South で Azure Cognitive Search のリソースを作り直して回避しました。
Korea South リージョンで Azure Cognitive Search のリソースを作ると以下の様に左側のメニューに「Semantic Search (preview)」が表示されるので、ここで有効化します。

ハマったところ② - Semantic 検索用の設定を作る

Azure Cognitive Search のインデックスにて Semantic 検索用の設定をしない場合、今度は以下のエラーが発生します。

こちらに関しては以下の様にポータル側で設定しようとしたのですが、何故か Save リンク(ボタン?)が有効にならずにうまくいきませんでした

仕方がないので上記スクリーンショットでの "Edit JSON" リンクを押下し、以下の設定を追記しました。

"semantic": {
      "configurations": [
        {
          "name": "default",
          "prioritizedFields": {
            "titleField": {
                  "fieldName": "title"
                },
            "prioritizedContentFields": [
              {
                "fieldName": "content"
              }
            ],
            "prioritizedKeywordsFields": [
              {
                "fieldName": "tag"
              }
            ]
          }
        }
      ]
    }

加えて、この設定名は必ず default にする必要があります。間違えると以下のエラーが発生します。

そこについては以下のソースコードを参照すると分かりますが、直接ハードコードされています。
github.com

結論

あくまで2023年7月7日現在となりますが、Azure Cognitive Search に対しては Semantic Kernel はまだ未成熟なようです。その一方で別のベクトル化データのストアは当然あるので、そういったものをアレコレ調べるのも面白そうです。