どうやら私はGraphRAGを勘違いしていたらしい[1/2]

2025/01/28に公開

はじめに

この記事は情報検索・検索技術 - Qiita Advent Calendar 2024 - Qiitaの8日目の記事となります。
大遅刻ですみません💦

普段は全文検索をメインにやっている人間なのですが、最近のLLMブームによって検索システムの在り方にも影響が出てきています。
RAGやベクトル検索の台頭によって、これまで検索エンジンに触れてこなかった方々も続々と検索システムに参入してきてくれている印象です。

私も検索エンジニアの端くれ、これらについて聞かれることが増えてきました。
今回はその中でも最近話題となっているGraphRAGについて調べてみました。
なかなか興味深く複雑なので長くなってしまいました。

検索エンジニアの視点から見た解釈がみなさんのお役にたてば幸いです。

忙しい方のためのサマリー

  • 「この文書の主題」のような直接的に書かれていない問いかけに答えられるようになったのが新規点
  • 今話題になっているのは特にMicrosoftが提案しているGraphRAGで、一般的なGraphRAGとは異なる
  • MicrosoftのGraphRAGはグラフクエリ言語は使わないし、そもそも検索をしていない(と思う)

RAGのおさらい

ChatGPTの登場によって、世界的に生成AIの注目度は飛躍的に上がりました。
LLMはWikipediaなどの膨大な公開情報を使って学習されています。
そのため、幅広い情報ソースに基づいた従来よりも実用に足る回答が可能になりました。

しかし、社内ドキュメントなど非公開の情報に関しては同然ながら含まれていません。
業務においては、そのような秘匿かつ自社ナイズされた情報を使ってこそ、有益な回答となります。
そこで、LLMへの入力に外部からの検索結果を組み合わせるRetrival-Agumented Generation(RAG)が登場しました。
RAGよって検索と情報整理を同時に行えるようになり、不慣れな新人であっても効率よく所望の社内情報にたどり着きやすくなりました。
RAGの詳細については、多くの方が記事投稿されていたり、私の過去記事でも紹介しているのでそちらをご覧ください。
https://zenn.dev/sashimimochi/articles/be1122c813d989

従来のRAGとGraphRAGの違い...?

RAGによって現場でのLLM活用は加速しましたが、もちろん万能ではありませんでした。
従来のRAGの欠点として、複雑な関係性を考慮した回答が難しいと言われています。
たとえば、次のような人物相関があったとします。

このとき「AさんとBさんの関係は?」という問いかけを考えます。
私たちは迷うことなく、AさんとBさんは兄弟(姉妹)と答えられるでしょう。

もし、先の問いかけに対して「AさんとBさんは兄弟(姉妹)である」などの直接的な文章を検索ヒットさせることができれば、LLMも正しく回答できることでしょう。
ですが、そのように都合の良い1文が情報ソースの時点で用意できている保証はありませんよね。
もしかしたら、複数の文章(チャンク)を組み合わせて初めて分かる情報の可能性もあります。
たとえば、「Aさんは母が最初にお腹を痛めて産んだ子だ」と「Bさんのときは母も出産には慣れたものだ」のような書き方がされているかもしれません。2文合わせてはじめてLLMは正しい回答ができます。

加えて、従来のRAGは検索時に質問内容の文意は考慮されません。
文章ごとに類似性の高い文章を検索ヒットさせるだけです。
たとえば、「AさんとBさんは小さいころから友達のように遊んでいた」という1文が検索システムにインデックスされていたとします。
1文の中にAさんとBさんの両方が登場しています。
キーワード検索やベクトル検索で検索した場合、先の2文よりこちらの1文の方が類似性としては高くなる可能性があります。
となると、LLMはRAGによって「AさんとBさんは友達である」といった誤った回答をしてしまいかねません。
また、質問文によって検索ヒットするドキュメントも変化するので、プロンプト次第で正しく回答できる/できないが分かれることもあります。

このように、文章という非構造化データを検索によって取得した後に、LLMが構造化して回答生成をします。
このプロセスがRAGでは複雑な関係性を加味した回答が難しいと言われる一因であり、純粋なRAG[1]だけではハルシネーションは完全にはなくならないと言われています[2]
そうした中で今注目を集めているのがGraphRAGです。

そこで、プロセスを逆転させて、検索インデックス作成時に情報を構造化(グラフ)したのちに、検索、回答生成とすれば高精度でLLMが正しい回答ができるようになるだろうというのがGraphRAGの発想です[3]
情報を構造化したグラフは知識グラフと呼ばれます。

グラフデータベース(以下、グラフDB)という専用データベースを使えば、知識グラフの保存や検索ができるようになります。
知識グラフの主流な表現方法であるResource Description Framework(RDF)では、「主語(Subject)」と「述語(Predicate)」と「目的語(Object)」の3つ組み(トリプル)で情報間の関係が表されます。
RDFでは、このトリプルのうち2つを指定すると、残りの1つの情報が検索できます。
先の例でいうならば、あらかじめ知識グラフを作っておけば、AさんとBさんを指定して2人の関係性を抽出できます。
以下はCypherと呼ばれるグラフクエリ言語での検索例です。

MATCH (a:Person {id: 'A'})-[r]-(b:Person {id: 'B'}) RETURN r

戻り値として、「兄弟(姉妹)」が得られるので、LLMは2人は兄弟であるという検索結果を踏まえて回答生成ができるようになります。

このようにグラフをたどることで情報同士のつながりを理解し、より正確な回答をできるようにするのがGraphRAGです。
ほかにも、病気と薬およびその副作用の関係性や会社の組織図など関係性が重要な問いかけに対して、より高精度な回答生成ができるようになることが期待されています。

というのが私の初見のGraphRAGの理解でした。
とすれば、従来のRAGとは以下のような違いがあると考えられます。

ベクトル検索との違い

先に述べた通り、GraphRAGを行うにはあらかじめ知識グラフを作成しておく必要があります。
しかし、膨大な非構造テキストから人物などを抽出して、さらにその間の関係値まで人力で登録するのは途方もない労力がかかります[4]
そのため、元のテキストを入力して、LLMに構造情報を抽出させます。

これを聞いたときに思ったのは、「非構造データから構造データをLLMで抽出できるなら、グラフ検索いらないのでは?」という疑問でした。
構造化というLLMの苦手な処理を外部で行うための手法がGraphRAGだと思っていたので、LLMで知識グラフが作れるなら、ベクトル検索で十分だと感じました。

確かにLLMで構造化ができるので一見ベクトル検索で事足りるようにも思えるのですが、先に述べた通りベクトル検索では、毎回必要十分な内容が記載されている文章がヒットするとは限りません。
ドンピシャな文章がヒットしないと関係性の抽出しようがないので、検索→構造化→回答生成の順番だと検索結果の時点で詰みが起こり得ます。
また、クエリによってヒット文章が変わってしまうベクトル検索では回答内容の安定性に欠けます。

GraphRAGであれば、トリプルの要素さえ一致していれば、それ以外の部分がどう変わろうが確実に対象をヒットさせられます。

全文検索(エンジン)との違い

キーワード検索という点においては、全文検索はベクトル検索と同様の弱点を持っています。
「Aさん」、「Bさん」、「関係性」で検索をしても何もヒットせず、「Aさん」、「Bさん」だけで検索すると「AさんとBさんは小さいころから友達のように遊んでいた」がヒットしてしまいます。
どっちに転んでも正しい回答生成はできません。

しかし往々にして、SolrやElasticsearchなどの全文検索エンジンはテキスト以外のフィールド(カラム)を持っています。
RAGの文脈ではメタデータと呼ばれるフィールドです。
このメタデータフィールドに関係値を登録しておけば、わざわざGraphRAGを使う必要はないのではないかと思いました。

たとえば、先ほどの人物相関図をメタデータとしてインデックスすることを考えます。
以下のようにAさんとBさんのsiblings(兄弟姉妹)を事前に登録します。
nameフィールドでAさんを検索して、siblingsで絞り込みをすれば、GraphRAGと同等のことができます。

 [
 	{
 		"name": "a",
 		"siblings": "b"
 	},
 	{
 		"name": "b",
 		"siblings": "a"
 	},
 ]

一見これで解決できそうですが、実際にはぜんぜん現実的ではないことがおわかりでしょう。
というのも、複雑な非構造化テキストからすべてのメタデータを事前に想定できるとは限らないからです。

さきほどの人物相関だけでも、「夫婦」、「父と子」、「母と子」、「兄弟姉妹」の4種類があります。
Aさんとほか3人の関係を検索絞り込みするには、すべての各ドキュメントに対して、この4フィールドを設けるか、各人物ごとのフィールドを設けるかのどちらかになります。
いずれにせよ、フィールドの中身が空だったりフラグが立っていない冗長フィールドが多発することになるので、非常に無駄が出やすいです。

あらかじめ特定少数のフィールドで表現できる関係性のみで足りるなら、メタデータによる検索が有効です。
一方、不特定多数のメタデータを持たせたい場合は、知識グラフ表現の方がスマートと言えるでしょう。

以上のように、確かにいずれにおいても従来の全文検索やベクトル検索では実現できなかったケースをGraphRAGはカバーできています。
しかし、話題になるほどのキラーアイディアとまでは感じられませんでした。
というのも、GraphRAGは固有名詞間の関係性が含まれる文章を確実に検索ヒットさせたいときに使う、厳格な検索手法による回答生成と感じたからです。
ベクトルによる曖昧な検索でもなく、キーワード検索のような片手落ちの検索でもなく、「AさんとBさんは兄弟(姉妹)である」という文章を確実にヒットさせらるのがGraphRAGです[5]
反面、グラフクエリ言語による検索を考えると、キーワード検索以上に表記ゆれには弱いと思います。

総合すると、「ああなんだ、テキストとベクトル以外にハイブリッド検索の手法が1個増えた程度か」と思っていました。
ですがよくよく調べてみると、どうやらGraphRAGの神髄はそんなものではないらしいことがわかりました。

本当のGraphRAGはグラフをたどりたいわけじゃなかった

MS GraphRAGのここがすごい!

ちゃんと調べてみると、今話題になっているGraphRAGはMicrosoft式のGraphRAG(以下、MS GraphRAG)のようです。
MS GraphRAGは一般的なGraphRAGとの違いとして以下のようなものがあります。

  1. グラフクエリ言語は使用せず、意味的なヒットで検索をする。当然、自然言語のクエリをCypherなどのグラフクエリ言語に変換もしない
  2. 「このドキュメントの主題を教えてください」のような抽象度の高い質問に対する回答ができる

特に2ができるというのがMS GraphRAGの最大の特徴です。
小説などにありがちですが、その物語の主題や命題は陽に記載されていません。
象徴的な1文こそあれ、書籍の中の特定の1文を見ただけでは、主題はわからないことがほとんどです。
私たちは文章全体を何度も読み返しながら、整理しまとめていくことでようやくこの物語が伝えたかった主となるテーマを理解することでしょう。
ましてやクエリ自体が非常に抽象的なので、ベクトル検索などで的確な文章群を集めてくるのは困難だというのは想像に難くないと思います。
それができてしまう故、MS GraphRAGは注目を集めているのでしょう。

現に、Microsoftの公式チュートリアルでも「クリスマスキャロルの主題を述べよ」というタスクが例題になっています。
https://microsoft.github.io/graphrag/get_started/

実はMS GraphRAGには2種類の検索方法があります。
2のような抽象度の高い質問への回答生成には、文書全体の流れを俯瞰的に見られるグローバルサーチという検索方法を用います。

一方、先述したようなグラフ上の関係性をたどって対象を見つける方法はMS GraphRAG中ではローカルサーチと呼ばれています。
ユーザークエリの抽象度に応じてグローバルサーチとローカルサーチを使い分けられるのでより応用性の高いGraphRAGになっています。

一般的なGraphRAGとMS GraphRAGの違いは以下のスライドなどでも解説されています。
https://speakerdeck.com/hide212131/the-trending-graphrag-understanding-its-potential-and-challenges

MS GraphRAGの仕組みをちょっとだけ紹介

先述の通り、グローバルサーチがMS GraphRAGが注目を集めた特徴になります。
では、その仕組みを少しだけ見てみましょう。

グローバルサーチのような抽象度の高い質問に回答するには文章全体を見て、かみ砕いて整理した要点要約のようなものが必要になります。
物語全体を一度のプロンプトでLLMに投入出来れば、検索の必要がないので、要点要約を作ったうえで、回答を生成できなくもないでしょう。
しかし入力が長くなれば長くなるほど、処理負荷が増え、時間もかかります。
そもそも、現時点では入力長に制限があるので、文章全体が入力できないというケースもあります。
いずれも将来的には解決できるかもしれませんが、現時点では難しいです。
そこでMicrosoftはグラフ表現を介することで、長大なドキュメントに対して抽象度が高い質問への回答を実現しようとしました。

MS GraphRAGはおおまかに以下の流れで処理されています。


https://arxiv.org/pdf/2404.16130v1 より

  • インデックス作成時
    1. データのチャンク化(テキストユニット)への分割
    2. Entityや付加情報の抽出
    3. Entityの概要生成&リレーション抽出
    4. コミュニティクラスタリング
    5. コミュニティ要約
  • 回答生成時
    1. ユーザークエリの回答に適したコミュニティ要約の検出
      • 各コミュニティ要約を適当なサイズにチャンク分割する
      • 各チャンクを使って1次回答を生成する
      • 各回答に対して有益性を100点満点で評価する
    2. スコアが高いコミュニティ要約を使って最終的な回答を生成

1で膨大なドキュメントを適当な長さに分割します。
次に2で、LLMにテキストユニットを入力してトリプルを抽出します。
抽出されたトリプルのうち、SubjectとObjectに該当するものをEntityと呼びます。
また3にあるように、このとき各Entityに対して簡単な説明文とその埋め込み表現もLLMが作成します。
同時にそのEntityの開始日や終了日など付加要素についても可能なら取り出して結び付けておきます。

続いて4のEntity間の関係性(リレーション)を抽出します。
この関係性についても説明文を生成します。
同時にEntity間の結びつきの強さ(共起頻度)も計算します。
ここまででもLLMを多用して補足情報をガンガン生成している様子がうかがえます。

そして5番からがMS GraphRAGのキモとなるコミュニティの概念が登場します。
MS GraphRAGでは、Leidenというグラフ理論のクラスタリングアルゴリズムを使って、似ているEntityをコミュニティという単位にまとめます。
各Entityには説明文が付いているので、これらを要約することでコミュニティごとのタイトルと説明文を生成します。
ここでコミュニティの要約が作られるからこそ、先に書いたような文章全体を踏まえた抽象度の高い質問への回答が実現できています。

そして、Leidenクラスタリングを多段階で行うことで、より抽象度の高いコミュニティも生成します。
粒度の異なる複数階層のコミュニティを持っておくことで、検索クエリの抽象度に応じて検索対象の粒度をコントロールできるようになっています。

図にすると以下のようになります。

https://graphrag.com/reference/knowledge-graph/lexical-graph-extracted-entities-community-summaries/ より

ちなみにローカルサーチの場合は以下のような流れになります。

  • インデックス作成時
    1. グローバルサーチと同じ
  • 回答生成時
    1. ベクトル検索を使って、ユーザークエリに近いEntityを検出する
    2. 知識グラフをたどって、ヒットしたEntityからと結びついたEntityや関係性、付加情報を回答の候補として取り出す
    3. 回答候補それぞれに対してクエリ内容への回答に使えそうか優先度をつける
    4. 優先度順に情報を取り出して、回答を生成する

ローカルサーチの場合は、コミュニティ要約を使わないのが特徴になります。
また先にも書いた通り、知識グラフこそ使うものの、グラフクエリ言語ではなくベクトル検索を使って該当Entityを探しているのが一般的なGraphRAGとの違いです。

以上が、私なりに勉強し直したうえでのGraphRAGの理解です。
それでも勘違いや不足もあると思うので、詳細はMicrosoftの公式ドキュメントをご覧ください。

また、大変参考になった日本語解説記事も挙げておきます。
https://www.alpha.co.jp/blog/202408_01/
https://qiita.com/nohanaga/items/75305fc63602bd2cdaca

知識グラフは過程であってゴールではない?

MS GraphRAGの最大の特徴はグローバルサーチでした。
グローバルサーチは、コミュニティ要約を生成する過程で、文書全体を踏まえた抽象度の高い情報抽出を実現しています。
そして、コミュニティというまとまりを作るためにグラフ理論のアルゴリズムを利用しています。
つまり、「コミュニティクラスタリング」に都合が良かったからグラフ形式を選んだというのが私の解釈です。
ローカルサーチのような使い方は主目的ではないと思います。

比較していないのでわかりませんが、k-means法などを使ってクラスタリングをしても同じようなコンセプトはできるんじゃないかなと思いました。
もちろん、Entity間の結びつきの強さを考慮してクラスタリングできるので、k-meansなどよりは文脈を意識したクラスタリングはできるので、グラフの形に落とし込むのには意味があると思います。

ただ、グラフクエリ言語を使っていないように、ローカルサーチのような直観的な使い方を意図したものではなさそうです(そりゃ、ちゃんと読まないとわからんわけだ...)。

ということは、巷で言われているようなグラフDBはMS GraphRAGにおいては必須ではない気がします。
実際に、Microsoft公式のGraphRAGチュートリアルを見てもグラフDBは出てきません。
各クラウド基盤でもグラフDBのサービスが出ており、それを使ったGraphRAGのサンプルブログが出始めていて余計に混乱しました[6]
エコシステムが整っていないことも踏まえると、まだ急いでグラフDBに投資する時期ではないのかなと思いました。

また「検索技術」という観点でGraphRAGを見ると、新規性は薄そうに感じました。
ローカルサーチはベクトル検索ですし、グローバルサーチに至っては検索していない気がしますし。
Retrival-Agumented Generationというよりは、Graph-Agumented Generationという印象です。

おわりに

長々書きましたが、「文書の主題」のような抽象度の高い質問に答えられる「グローバルサーチ」がGraphRAGの注目を集めたキラーアイディアのようです。

同時に、GraphRAGと聞いて直観的に思い浮かべる仕組みはローカルサーチの方であり、そのずれがGraphRAGのすごさを勘違いしやすくしていると思いました。

また今回、実装の話はできなかったので、次回の記事ではその辺りの話も書こうかと思います。
実際に使ってみると、これがなかなか面白いです。
ではまた!

脚注
  1. その後の発展形と比較してナイーブRAGやベースラインRAGと呼ばれることもあります。 ↩︎

  2. そもそも伝聞情報やネットの情報ですらあやふやさはあるはずですが。 ↩︎

  3. 後述しますが、これはGraphRAGの一側面に過ぎません。 ↩︎

  4. 実際に人力で頑張っているプロジェクトもあります。 http://shinra-project.info/ ↩︎

  5. 元の文章では言い回しが違ったり、複数文に分かれていたとしても、LLMは情報の構造化をできるということを踏まえると、実質的には「AさんとBさんは兄弟(姉妹)である」という文章をヒットさせられたのと同等と言えます。 ↩︎

  6. 少なくとも、グラフクエリ言語を使っている記事はMSのGraphRAGじゃない気がします。 ↩︎

Discussion