はじめに
本記事は、以下のLlamaIndexガイドの意訳をしたものです。
クエリ変換
クエリ変換とは、ユーザーから提供された検索クエリを、特定の情報検索システムが理解しやすく処理しやすい形式に変更するプロセスです。これにより、LLMがより関連性の高い結果を返すことが可能になります。
クエリ変換の内部処理
クエリ変換は一般に以下のような手法を含みます。
-
自然言語処理(NLP):
クエリ内の意図や文脈を理解するために、自然言語処理技術を使用します。これは、クエリがあいまいであったり、特定のキーワードに依存していない場合に特に有用です。 -
シノニムの使用:
クエリの意図を保ちつつ、同義語や関連語を用いてクエリを拡張します。これにより、異なる単語を使用しているが同じ意味を持つ文書を検索することが可能になります。 -
クエリの分解:
複雑なクエリをより小さく、シンプルな部分クエリに分けます。これにより、各サブクエリに対して最適な情報源を判別し、より精度の高い情報を取得することができます。 -
クエリの再構成:
ユーザーの質問をより明確にし、情報検索の精度を高めるために、クエリに含まれる言葉を書き換えたり、追加したりします。 -
ステップバイステップの変換:
特に複雑なクエリの場合、クエリを段階的に変換し、それぞれのステップで得られる情報を次のステップの入力として使用することがあります。
変換手法
クエリ変換には複数の使用例があります。
- 最初のクエリ(=ユーザの質問文)を、より簡単に埋め込める形に変換する(HyDEなど)
- シングルステップ・クエリ変換:最初のクエリを、データからより簡単に回答できるサブクエリに変換する
- マルチステップ・クエリ変換:最初のクエリを、より簡単に回答できる複数のサブクエリに分割する
HyDE (仮説的な答えを一時的につくる)
HyDEは、ユーザーからの質問に基づき、仮想的な文書や答えを生成する技術です。
この生成された仮想的な文書は、生のクエリではなく、埋め込み検索プロセスに利用されます。
このアプローチにより、より精度の高い検索結果を得ることが可能になります。
「こういう質問には、こんな答えがほしいよね」を先に考えて、答えから逆算して質問のための文章を作り直す、といったイメージです。
以下は、LlamaIndexを使用して、HyDEクエリ変換を利用した文書検索のサンプルです。
from llama_index import VectorStoreIndex, SimpleDirectoryReader
from llama_index.indices.query.query_transform.base import HyDEQueryTransform
from llama_index.query_engine.transform_query_engine import (
TransformQueryEngine,
)
# ドキュメントを読み込み、インデックスを構築
documents = SimpleDirectoryReader("../paul_graham_essay/data").load_data()
index = VectorStoreIndex(documents)
# HyDEクエリ変換を用いてクエリを実行
query_str = "what did paul graham do after going to RISD"
hyde = HyDEQueryTransform(include_original=True)
query_engine = index.as_query_engine()
query_engine = TransformQueryEngine(query_engine, query_transform=hyde)
response = query_engine.query(query_str)
print(response)
シングルステップ・クエリ変換
ユーザーの質問をより小さなステップに分割することで、複雑な質問に対してより良い回答をさせる手法です。
シングルステップクエリ分解機能は、データ収集のプロセス中に複雑な質問をより単純なものに変換し、元の質問に対するサブアンサーを提供することで、質問への対応を支援します。
この手法は、構造化されたグラフ内で特に有効です。構造化グラフ内では、クエリを複数のサブインデックスにルーティングすることが可能で、各サブインデックスは知識コーパス全体のサブセットを代表しています。クエリの分解により、任意のインデックスに対してより適切な質問へとクエリを変換することが可能になります。このプロセスは、複雑な質問への対応能力を高め、より精度の高い回答を導出する助けとなります。
この図は、ヒューストンとボストンのスポーツ環境を比較し対照するためのクエリ分解プロセスを説明しています。
サンプルコードです。
from llama_index.indices.query.query_transform.base import (
StepDecomposeQueryTransform,
)
# GPT-4を用いたステップごとのクエリ分解変換の初期化
step_decompose_transform = StepDecomposeQueryTransform(llm, verbose=True)
# クエリエンジンの初期化
query_engine = index.as_query_engine()
query_engine = MultiStepQueryEngine(
query_engine, query_transform=step_decompose_transform
)
# 複雑なクエリの実行
response = query_engine.query(
"著者が始めたアクセラレータープログラムの最初のピッチにいた人は誰ですか?",
)
print(str(response))
マルチステップ・クエリ変換
マルチステップ・クエリ変換は、クエリを解析し、段階的に処理することで、複雑な情報要求に対してより洗練された応答を生成する、既存のシングルステップ・クエリ変換手法の進化形です。
この手法では、初めに与えられた複雑なクエリを、実行可能なより小さなステップに変換します。そして、各ステップはインデックスに対して個別に実行されます。一つの応答が得られると、その応答は次のクエリの実行に使用されることがあります。つまり、最初の応答が次の質問の文脈を形成し、より洗練された、または関連する情報を求めるために使用されるのです。
このプロセスは、ある質問に対する応答が次の質問に影響を与えることを可能にし、結果としてクエリが終了するまで続けられます。このようにして、単一の知識ソースから複数のクエリを通じて情報を引き出すことができ、クエリの各ステップが前のステップの応答に基づいています。マルチステップ・クエリ変換は、特に大規模なデータセットや複雑な情報源を扱う際に、より精度の高い情報提供を可能にします。
この図はマルチステップ・クエリ変換の一例を示しています。
-
クエリ分解:
元の質問「著者が始めたアクセラレータープログラムの最初のピッチにいた人は誰ですか?」はまず、「著者が始めたアクセラレータープログラムは何ですか?」という質問に分解されます。 -
情報の取得:
著者に関するデータソースから、アクセラレータープログラムが「Y Combinator (YC)」であることを明らかにします。 -
サブクエリの生成:
さらに、この情報を元に新しいサブクエリ「Y Combinatorのアクセラレータープログラムの最初のピッチにいた人は誰ですか?」が生成されます。 -
情報の取得:
Y Combinatorの最初のピッチが2005年に開始され、Reddit(スティーブ・ハフマンとアレクシス・オハニアンによって設立された)、Loopt、Weebly、Twitch(ジャスティン・カンによって設立された)などのスタートアップが含まれていたことを明らかにします。 -
最終回答の合成:
これらの情報を基に、最終的な回答が構築され、「Y Combinatorのアクセラレータープログラムの最初のピッチにはReddit、Loopt、Weebly、Twitchなどのスタートアップが含まれていました」という応答をします。