次の方法で共有


セマンティック キャッシュの概要

大規模言語モデル (LLM) は、ユーザー プロンプトに基づいて入力候補またはテキスト応答を生成する能力に優れています。 他のサービスと同様に、コンピューティング コストが発生します。 LLM の場合、これは通常トークンで表されます。

セマンティック キャッシュを使用すると、以前のユーザー プロンプトと LLM 入力候補を使用し、ベクトル類似性検索を使用して、同様のユーザー プロンプトに対処できます。 LLM への呼び出しは GenAI アプリケーションでコストが最も高く、待機時間が最も長いサービスであることが多いため、セマンティック キャッシュを使用することで GenAI アプリケーションの待機時間を短縮し、コストを節約できます。

LLM が単純なプロンプトを処理するシナリオでは、このコンピューティング コストは低くなります。 ただし、LLM ではプロンプトと入力候補の間のコンテキストは保持されません。 最新のプロンプトを送信する際は、コンテキストを提供するために LLM にチャット履歴の一部を送信して処理させる必要があります。 多くの場合、このメカニズムはコンテキスト ウィンドウと呼ばれ、ユーザーと LLM の間のプロンプトと入力候補のスライディング ウィンドウの役割を果たします。 この追加のテキストにより、要求の処理に必要なコンピューティング コスト (トークン) が増加します。 また、テキストの量が増えるにつれて、入力候補を生成するための待機時間も増加します。

取得拡張生成 (RAG) パターンと呼ばれるパターンでは、データベースなどの外部ソースからのデータがユーザー プロンプトおよびコンテキスト ウィンドウと共に送信され、LLM の強化または根拠付けを行います。 外部ソースからのデータは、入力候補を生成するための追加情報を提供します。 多くの場合、LLM への RAG パターンのペイロードのサイズはかなり大きくなることがあります。 入力候補を生成するために、数千のトークンを消費し、何秒間も待機することも珍しくありません。 ミリ秒単位の時間が重視される世界では、多くの場合、何秒間も待機することは許容できないユーザー エクスペリエンスになります。 また、大量のデータを使用することで、コストも高額になります。

一般的に、高いコンピューティング コストと長い待機時間が必要な要求に対処するために使用されるソリューションは、キャッシュの採用です。 このシナリオも同様ですが、セマンティック キャッシュの動作と実装方法に違いがあります。

セマンティック キャッシュのしくみ

文字列の等価一致を使用してキャッシュ キーのキャッシュ検索を行う従来のキャッシュ セマンティック キャッシュは、ベクトルとして保存されているキャッシュ キーに対してベクトル クエリを使用します。 キャッシュ検索を行うためにベクトル検索クエリを実行するには、テキストをベクトル埋め込みに変換し、これを使用してキャッシュのキーで最も類似性の高いベクトルを検索します。

キー値検索に比べてベクトル クエリの使用には、いくつかの利点があります。 従来のキャッシュは通常、キャッシュ ヒットの結果を 1 つだけ返します。 セマンティック キャッシュはクエリを使用するため、必要に応じて複数の結果をユーザーに返すことができます。 選択肢を増やすことで、コンピューティング コストをさらに削減することができます。 キャッシュ ミスが原因で LLM が生成する必要がある項目の数を減らすことで、キャッシュ サイズを小さく保つことができます。

類似度スコア

すべてのベクトル クエリは、高次元空間でのベクトルの類似度を示す類似度スコアと呼ばれるものを返します。 値の範囲は 0 (類似性なし) から 1 (完全一致) です。

ベクトル クエリでは、返される結果の類似性スコアは、WHERE 句で渡されたデータに対する、単語またはユーザーの意図の類似性を表します。 クエリは複数の結果を返す可能性があるため、ユーザーが選択できるように、キャッシュ結果の可能性が高い順に結果を並べ替えることができます。

類似性スコアは、ベクトル クエリのフィルターとして使用され、ユーザーの意図に一致する可能性が高いアイテムのみを返すように結果を制限します。 実際には、ベクトル クエリに対する類似性スコア値を設定するには、試行錯誤が必要になる場合があります。 値が高すぎると、キャッシュ ミスが繰り返されるため、同様の質問に対する複数の応答でキャッシュはすぐにいっぱいになります。 値が低すぎると、ユーザーの意図と一致しない無関係な応答がキャッシュから返されます。

コンテキスト ウィンドウ

大規模言語モデルでは、要求間のコンテキストは維持されません。 LLM と会話を行うには、コンテキスト ウィンドウ (チャット履歴) を維持し、各要求の LLM にそれを渡して、コンテキストに関連する応答を提供できるようにする必要があります。

セマンティック キャッシュを有効にするには、そのコンテキストも必要です。 つまり、セマンティック キャッシュでは、個々のプロンプトのテキストをキーとして使用するだけでなく、チャット履歴のプロンプトの一部も使用する必要があります。 これにより、LLM によって生成された場合と同様に、キャッシュから返される内容もコンテキスト的に正しくなります。 チャット履歴のコンテキストがキャッシュに含まれていない場合、ユーザーは予期しない、そして許容できない可能性が高い応答を受け取ることになります。

この理由を説明するため、簡単な頭の体操をしてみましょう。 最初に LLM に "北米最大の湖は何ですか?" と尋ねると、いくつかの事実と数字を挙げて "スペリオル湖" と応答し、ベクトル化されたユーザー プロンプトと入力候補からのテキストをキャッシュします。

その後、"2 番目に大きいのは何ですか?" と尋ねると、LLM は前のプロンプトと入力候補のコンテキスト ウィンドウが後続の質問と共に渡され、"ヒューロン湖" と正しく応答します。 次に、2 番目のプロンプト "2 番目に大きいのは何ですか?" と生成された入力候補 "ヒューロン湖" をキャッシュします。

その後、別のセッションの別のユーザーが "北米最大のスタジアムは何ですか?" と尋ねると、LLM はいくつかの事実と数字を挙げて "ミシガン スタジアム" と応答します。 その後、そのユーザーが "2 番目に大きいのは何ですか?" と尋ねると、キャッシュはそのプロンプトとの完全一致を見つけて "ヒューロン湖" と返しますが、これは正しくありません。

このため、セマンティック キャッシュはコンテキスト ウィンドウ内で動作する必要があります。 コンテキスト ウィンドウは、LLM が関連する入力候補を生成するために必要な情報をすでに提供しています。 このため、キャッシュの動作方法としても論理的な選択になります。

これを実装するには、まずコンテキスト ウィンドウと最後のプロンプトからプロンプトの配列をベクトル化する必要があります。 次に、ベクトルは、キャッシュ キーのベクトル クエリ内の WHERE 句で使用されます。 返される内容は、別のユーザーが以前に尋ねたのと同じ、一連の質問からの入力候補です。 コンテキスト ウィンドウが会話内で継続的に前方にスライドしていくため、類似性の高い一連のプロンプトは LLM によって再生成されるのではなく、キャッシュによって返されます。

管理

他のキャッシュと同様に、サイズが膨大になる可能性があります。 セマンティック キャッシュを保持するには、同様のメンテナンスが必要です。 キャッシュされたアイテムの有効期限 (TTL) の使用、最大サイズの制限、キャッシュ内の項目数の制限など、サイズを維持する方法は複数あります。

類似性スコアを使用することで、キャッシュをスリムに保つためのメカニズムも提供されます。 キャッシュに対するベクトル検索の WHERE 句の類似性スコアが低いほど、キャッシュ ヒットの数が増える可能性があり、類似性の高いユーザー プロンプトに対する入力候補の生成とキャッシュの必要性を減らすことができます。 ただし、関連性の低い結果が返される可能性があります。

TTL を使用しながら、キャッシュ ヒットの頻度を維持するその他の手法としては、項目のキャッシュ ヒット スコアを保持し、キャッシュ ヒット スコアに基づいてキャッシュを取り除くメカニズムを実装する方法があります。 これは、キャッシュ項目のヒット数プロパティを増やすパッチ操作を使用して実装できます。 次に、事前に決定されたキャッシュ ヒットのしきい値に達した場合に、その項目の TTL をオーバーライドしてキャッシュ内に保持します。

また、効率性以外の観点からキャッシュを維持するその他の考慮事項もあります。 開発者はユーザーのチャット履歴を使用し、LLM を使用して入力候補を生成するアプリケーションを調整できることが広く知られています。 また、チャット履歴は、ユーザーとこれらの種類のアプリケーションとのやりとりに関する貴重なデータを提供し、感情や行動に関する重要な分析情報を生み出す可能性があります。 キャッシュの使用についても同様です。

キャッシュの全内容を保持して、詳細な分析に使用することが推奨されますが、ユーザーには最新のキャッシュ エントリのみを表示されるようにする必要があります。 このようなシナリオでは、キャッシュに対するベクトル クエリの WHERE 句で追加のフィルターを使用し、最新のキャッシュ項目をフィルター処理したり、データの新しさに基づいて並べ替えたりする手法が考えられます。 たとえば、WHERE c.lastUpdated > @someDate ORDER BY c.lastUpdated DESC のように指定します。

Azure Cosmos DB を使用したセマンティック キャッシュの実装

複数のサンプルで、Azure Cosmos DB を使用して独自のセマンティック キャッシュを構築する方法を理解できます。

この C# サンプルでは、Azure Cosmos DB for NoSQL を使用して Azure で独自の Copilot アプリケーションを構築するために必要な多くの概念について説明しています。 このサンプルにはハンズオンラボも付属しており、ユーザーにこれらの概念 (セマンティック キャッシュの実装方法など) を順を追って説明しています。

この C# サンプルでは、Azure Cosmos DB for MongoDB を使用して Azure で独自の Copilot アプリケーションを構築するために必要な多くの概念について説明しています。 このサンプルにはハンズオンラボも付属しており、ユーザーにこれらの概念 (セマンティック キャッシュの実装方法など) を順を追って説明しています。