0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Microsoft GraphRAG は何が違う? ベクトル検索RAGと同じ社内文書で比べてみた

0
Posted at

Microsoft GraphRAG は何が違う? ベクトル検索RAGと同じ社内文書で比べてみた

「社内文書を RAG で検索できるようにしたのに、『この半年で繰り返し起きている問題は何?』と聞くと的外れな答えが返ってくる」。Dify などでナレッジ検索を作ったことがある人なら、一度はぶつかる壁だと思います。

この記事では、Microsoft が公開している GraphRAG が「ふつうのベクトル検索 RAG」と何が違うのかを仕組みから整理し、そのうえで 同じ34本の社内文書・同じ10問 を、素のベクトル検索 RAG と GraphRAG の両方に投げて答えを比べます。LLM は手元の Mac で動かした Qwen3.8-27B(LM Studio)だけを使い、外部 API は呼びません。そのかわり LLM の呼び出し回数とトークン数をすべて記録して、「クラウドの API でやったらいくらか」も換算します。

想定読者は、ベクトル検索の RAG を触ったことがあり、GraphRAG という名前は聞いたが「結局いつ使うものなのか」「いくらかかるのか」が分からない人です。仕組みの節は非エンジニアの方にも読めるように書いています。

この記事の確認範囲

  • 検証日: 2026年10月6日。GraphRAG は 3.2.0(pip install graphrag)、LM Studio の qwen/qwen3.8-27b(MLX 4bit)と text-embedding-nomic-embed-text-v1.5 を使用
  • 公式情報は Microsoft Research のブログ(2024年2月13日)、論文 arXiv:2404.16130、公式ドキュメント microsoft.github.io/graphrag を参照
  • 検証コーパスは、この記事のために作った架空の会社の社内文書です。実在の組織・人物とは関係ありません

はじめに:ベクトル検索RAGが落とす2種類の質問

まず、何が問題なのかを例で見てください。架空の EC 企業の社内文書(インシデント報告書・議事録・月次振り返りなど34本)があり、次の2つを質問します。

  1. 「6月にアプリで起きた二重購入の問題と、ベンダーのコネクトワークス社にはどんな関係がある?」
  2. 「この半年で繰り返し起きた問題に共通する要因は?」

どちらも、人間が文書を全部読めば答えられます。しかしベクトル検索の RAG は、どちらも苦手です。下の図で、文書のどこに答えがあり、なぜ拾えないのかを追ってみてください。

ベクトル検索RAGが苦手な2種類の質問。離れた文書をつなぐ質問と、全体を見渡す質問は、質問文に似た断片だけを拾う仕組みでは落ちる

質問①の答えは「4/8 のベンダーメモ → 5/20 の報告書 → 6/12 の報告書」と3本にまたがり、質問②の答えは8本の報告書を読み比べないと出ない。どちらも「質問に似た断片」を探すだけでは届かない

ベクトル検索 RAG の仕組みは「質問文を数値化し、意味が近いチャンク(文書の断片)を上位 k 件だけ LLM に渡す」です。質問①では、「二重購入」に似た断片は拾えますが、原因側の「ライブラリの既定値が変わった」というメモは質問文と似ていないので上位に入りません。質問②は、個々の報告書には答えが書かれておらず、複数の報告書を比べて初めて分かる内容です。

Microsoft Research はこの2つを、ベースライン RAG の典型的な失敗として挙げています。「点在する情報を共通の属性でつないで答える」ことと、「大きなデータ集合を俯瞰して要約する」ことです。GraphRAG はこの2つに答えるために作られました。

GraphRAG とは何か:一般名詞の「グラフRAG」と Microsoft GraphRAG

「グラフRAG」という言葉は、実は2つの意味で使われます。混乱しやすいので先に整理します。

ふつうのベクトルRAG、一般名詞のグラフRAG、Microsoft GraphRAG の3段階の比較。右に行くほど答えられる質問の幅が広がるが索引コストも増える

一般名詞のグラフRAGは「エンティティと関係をグラフにして検索に使う方式」の総称。Microsoft 版はそれに加えて「Leiden によるコミュニティ分割」と「コミュニティごとの階層的な要約」を事前に作る

一般名詞としてのグラフRAGは、文書から「人・組織・製品・出来事」などのエンティティ(entity、固有の対象)と、その間の関係(relationship)を取り出し、ノードとエッジのグラフにして検索に使う方式の総称です。Neo4j のようなグラフデータベースと LLM を組み合わせた構成や、LightRAG のような OSS がこれにあたります。多くは「質問に近いエンティティを見つけて、隣をたどる」ところまでで、文書全体の要約は持ちません。

Microsoft GraphRAG は、2024年2月に Microsoft Research が公開した OSS(MIT ライセンス、GitHub の microsoft/graphrag)で、論文「From Local to Global: A Graph RAG Approach to Query-Focused Summarization」の実装です。グラフを作るところまでは一般のグラフRAGと同じですが、そのあとに次の2つを足しています。

  • Leiden アルゴリズムでグラフを「つながりの濃いまとまり(コミュニティ)」に階層的に分ける
  • 各コミュニティについて LLM で要約レポートを事前に書いておく

この「コミュニティ要約」があるおかげで、「全体の傾向は?」のような俯瞰の質問に答える Global Search が可能になります。これが Microsoft 版の最大の特徴です。なお GitHub の README によると、プロジェクトは現在「概ねメンテナンスモード」で、新機能の追加は止まっています。それでも「グラフRAGの考え方を一通り試せる実装」としては今でも最も手軽です。

Microsoft GraphRAG の仕組み

索引作成:質問が来る前に文書群の構造を作る

GraphRAG の本体は、索引作成(インデックス)のパイプラインです。6つの段階があり、そのうち3つで LLM を呼びます。ここが費用の源泉なので、どの工程で何をしているかを押さえておくと、あとの費用の話が理解しやすくなります。

Microsoft GraphRAG の索引作成の6段階。チャンク分割、エンティティと関係の抽出、知識グラフへの統合、Leiden によるコミュニティ検出、コミュニティ要約の生成、埋め込みの作成

紫のラベルが LLM を呼ぶ工程。公式ドキュメントでは索引作成の費用の約75%が工程2〜3(グラフ抽出)にかかるとされる

  1. チャンクに分割(TextUnit)。文書を一定トークンごとに切ります。今回は34文書が63チャンクになりました
  2. エンティティと関係を抽出。各チャンクを LLM に読ませ、「人・組織・製品・インシデント…」と、その間の関係を説明文つきで書かせます。取りこぼしを拾う gleaning(追加の問いかけ)が既定で1回入るので、1チャンクにつき LLM を2回呼びます
  3. 統合して知識グラフに。同じ名前のエンティティをまとめ、複数のチャンクから集まった説明文を LLM で1つに要約します
  4. コミュニティ検出(Leiden)。つながりの濃いノード群を自動でグループ化し、階層を作ります
  5. コミュニティ要約を生成。グループごとに LLM が「レポート」を書きます。上の階層ほど抽象度の高い要約になります
  6. 埋め込みを作る。エンティティの説明文、チャンク、要約をベクトル化します

工程4の Leiden アルゴリズムは聞き慣れない言葉だと思うので、たとえで説明します。学校のクラスで「誰と誰がよく話すか」を線で結ぶと、線が密集している部分(部活仲間、同じ塾のグループ)が見えてきます。Leiden は、名簿や所属を一切見ずに、この「線の密集具合」だけから仲良しグループを見つけ、さらにグループをまとめて「学年」のような上の階層を作ります。

Leiden アルゴリズムの4段階。1人グループから始めて隣に移ると濃くなるなら移し、中でつながっているか点検し、グループを1点とみなして繰り返す

3つ目の「中で本当につながっているか点検する」工程が、前身の Louvain にはなかった Leiden の特徴。GraphRAG はこうしてできた各階層のまとまりに要約を書く

検索:質問の種類で4つのモードを使い分ける

索引ができたら、質問に応じて検索モードを選びます。公式には Global・Local・DRIFT の3つに加え、比較用の Basic があります。

GraphRAG の4つの検索モードの比較。Global はコミュニティ要約を map-reduce で全部読む、Local はエンティティから関係をたどる、DRIFT は両者の折衷、Basic はふつうのベクトル検索

Global は「全部読む」ので取りこぼしが少ないが LLM 呼び出しが多い。Local は入口のエンティティを外すと弱い

  • Global Search: コミュニティ要約を全部読みます。各要約から質問に関係する要点を抜き出し(map)、集めて最終回答にまとめます(reduce)。「全体の傾向は」「共通する課題は」向けです
  • Local Search: 質問に近いエンティティをベクトル検索で見つけ、グラフをたどって隣のエンティティ・関係・元のチャンク・所属コミュニティの要約を集めて答えます。「A について詳しく」「A と B の関係は」向けです
  • DRIFT Search: 両者の折衷です。コミュニティ要約で当たりをつけ、追加の質問を自分で作りながら Local で掘り下げます
  • Basic Search: グラフも要約も使わない、ふつうのベクトル検索です。比較のベースラインとして同梱されています

Global Search の map-reduce も、たとえで押さえておきましょう。1000枚のアンケートから「お客様の主な不満」を調べるとき、10人に100枚ずつ配って各自がメモを作り(map)、リーダーが10枚のメモから結論をまとめる(reduce)やり方です。LLM には一度に読める量の上限があるので、全文書を丸ごと渡すことはできません。map-reduce なら上限を超える量を踏まえて答えられます。そのかわり、要約の数だけ LLM を呼ぶので費用と時間がかかります。

ちなみに、この「仕事を分けて並列に処理し、結果をまとめる」という形は、エージェントのサブエージェント(親が子に仕事を振る仕組み)と似ています。ただし map-reduce は「全員が同じ作業を1回ずつする固定の手順」で、サブエージェントは「各自が別の仕事を自律的に進める実行単位」です。GraphRAG の map は素の LLM 呼び出しを並べているだけで、途中で「この方向をもっと掘ろう」とは判断しません。そのぶん挙動が予測しやすく、費用も見積もりやすい設計です。

ベクトル検索RAG(Dify のナレッジ検索など)との違い

Dify のナレッジベースを例にすると、「高品質」インデックスではチャンクを埋め込みモデルでベクトル化し、検索時はベクトル検索・全文検索・ハイブリッド検索から選んで、上位 k 件(既定 3 件)を取り、必要ならリランクをかけます。これが現在の「ふつうの RAG」の標準形です。GraphRAG との違いを観点ごとに並べます。

観点 ベクトル検索RAG Microsoft GraphRAG
検索の単位 チャンク エンティティ・関係・コミュニティ要約・チャンク
得意な質問 答えが特定の箇所に書いてある質問 文書横断の俯瞰・集約、複数文書をまたぐ関係
苦手な質問 「全体の傾向は」「共通する課題は」 単純な FAQ(過剰投資になる)
索引作成の費用 埋め込みだけで安い 全チャンクに LLM が走り、高い
質問ごとの費用 低い Local は低め、Global は多数の LLM 呼び出しで高く遅い
更新 チャンク単位で容易 グラフと要約の再計算が絡み、重い

本質的な差は、ベクトル検索では top-k に入らなかった情報は存在しないのと同じになる点です。ハイブリッド検索やリランクは「似ている」の精度を上げてくれますが、「因果の鎖をたどる」「全部を読み比べる」仕組みではありません。GraphRAG はこの統合作業を、質問のたびではなく索引作成のときに前倒ししています。

top-k に入らなかった情報は存在しないのと同じ。同じ質問に対して、ベクトル検索は上位 k 件で切るが、GraphRAG の Local はエンティティから関係をたどって原因側の文書に到達する

左は「二重購入」に似たチャンクばかりが上位に来て、原因側の文書が切り捨てられる様子。右は「二重購入」のエンティティから関係のエッジを2〜3ホップたどる様子(いずれも概念図)

GraphRAG を使ったほうがいいケース

結論から言うと、社内 FAQ やマニュアル検索のように答えが特定の箇所にあるなら、ベクトル検索 RAG(ハイブリッド検索+リランク)で十分です。GraphRAG が効くのは、調査レポート群・議事録・インシデント記録・訴訟資料のように、横断的な傾向分析や関係の把握をしたい場合です。

GraphRAG を使うべきかの判断フロー。答えが1か所にある質問が中心ならベクトル検索で十分、俯瞰や関係の質問が多く文書が頻繁に更新されないなら GraphRAG、混在するなら質問タイプでルーティングして併用

「いいえ」が続いて左下に落ちるほどベクトル検索で済む。右下に行くほど GraphRAG の索引コストを払う価値がある

判断の軸は3つです。

  • 質問の性質: 「〜はどこに書いてある?」が中心か、「全体として」「共通して」「関係は」が多いか
  • 文書の更新頻度: 毎日追加・改訂されるナレッジは相性が悪い。増分更新の仕組み(graphrag update)はありますが、コミュニティ構造が変わると要約の再生成が発生します。凍結された文書群(過去の議事録、終わったプロジェクトの記録)に向いています
  • 抽出品質の手当てができるか: 既定の抽出プロンプトは汎用的なので、業務文書ではエンティティ種別やプロンプトのチューニングがほぼ必須です。ここが悪いと下流がすべて劣化します

実務では、全面的に置き換えるのではなく、質問タイプでルーティングして併用する構成が現実的です。これは後半の検証結果からも裏付けられます。

GraphRAG を使う場合の費用

費用は3つの場面で発生します。どこで、何に比例して増えるかを知っておけば、見積もりができます。

GraphRAG の費用が発生する3つの場面。索引作成は文書量に比例して LLM 呼び出しが増え、質問ごとの費用は Global で大きく、更新は要約の再生成が絡む。軽量版の LazyGraphRAG も紹介

索引作成は「最初に1回」だが文書量に比例する。質問ごとの費用は Global Search で跳ね上がる

  1. 索引作成(最初に1回): 全チャンクに抽出(gleaning で2回)、説明文の要約、コミュニティ要約が走ります。文書量に比例して LLM 呼び出しが増え、元の文書の数十倍の LLM トークンを消費します(今回の実測では約30倍)。公式 README も「索引作成は高くつくので、小さく始めて」と注意しています
  2. 質問ごと(毎回): Local は LLM 1〜2回で済みますが、Global はコミュニティ要約の数だけ map の呼び出しが走ります。今回の検証では、同じ質問でも Global はベクトル検索の約35倍のトークンを使いました(数字は後述)
  3. 文書の更新: 変わったチャンクだけ埋め込み直せばよいベクトル検索と違い、グラフの統合とコミュニティ要約の再生成が絡みます

費用が課題なら、LazyGraphRAG(2024年11月発表)という派生があります。索引時の LLM 要約をやめて NLP の名詞句抽出に置き換え、LLM の仕事を質問時に寄せる設計で、Microsoft Research は「索引コストはベクトル RAG と同等(GraphRAG の 0.1%)」「Global Search 相当の品質を 700 分の 1 のクエリコストで」と報告しています。ただし OSS の graphrag ライブラリには含まれていません。ライブラリで近いのは graphrag index --method fast(抽出を NLP で代替する FastGraphRAG)です。

見積もりの最も確実な方法は、小さなサブセットで実際に索引を作ってトークン数を測ることです。この記事でもそれをやります。

検証:同じ34文書・同じ10問で「素のベクトル検索」と GraphRAG を比べる

ここからが実測です。公式のチュートリアルは英語の小説(『クリスマス・キャロル』)を使いますが、それでは「仕事で使えるか」が分かりません。そこで日本語の社内文書を用意し、「正解が分かっている質問」を10問作って、答えを採点しました。

検証環境

すべて手元の MacBook Pro(Apple M5 Max、ユニファイドメモリ 128GB)の中で動かします。LLM は LM Studio で動かした Qwen3.8-27B(MLX 4bit、約15GB)、埋め込みは nomic-embed-text-v1.5 です。外部 API は使いません。

検証構成。1台の Mac の中で、検証コーパス、素のベクトル検索RAG、GraphRAG 3.2.0、LM Studio の Qwen3.8-27B と nomic-embed を接続し、時間とトークンを記録する

GraphRAG は LiteLLM 経由、ベースラインは openai ライブラリで、どちらも LM Studio の OpenAI 互換 API(localhost:1234)を叩く

項目 内容
GraphRAG 3.2.0(pip install graphrag、Python 3.12)
LLM qwen/qwen3.8-27b(LM Studio、MLX 4bit、思考モードは停止、temperature 0)
埋め込み text-embedding-nomic-embed-text-v1.5(768次元)
LM Studio 並列 4(lms load --parallel 4)。GraphRAG 側は concurrent_requests: 6 だが LM Studio の並列数で頭打ちになる
チャンク 600トークン、重なり100(o200k_base)。34文書 → 63チャンク
比較対象 ①自作のベクトル検索RAG(同じチャンク・同じ埋め込み・同じ LLM、top-k=5 と 10)、②GraphRAG の Basic / Local / Global / DRIFT(DRIFT は追加質問 5・深さ 1 に削減)

検証コーパス:架空の会社の社内文書34本

コーパスは、架空の EC 企業「株式会社ミナトテック」の2026年4〜9月の社内文書34本(約3.5万字)です。インシデント報告書8本、週次定例の議事録8本、月次振り返り5本、ポストモーテム2本、ベンダー連絡メモ3本、仕様メモ2本、それに検索のノイズになる無関係な社内連絡6本(オフィス移転、健康診断など)です。

正解を採点できるように、文書には次の「答えの構造」を仕込んであります。

検証コーパスに仕込んだ答えの構造。4/8 のライブラリ導入から 6/12 の二重購入までの因果の鎖、8件のインシデントに散らした3つの繰り返し要因、件数と方針変更の時系列

赤枠がインシデント報告書。仕込み①は3〜4本の文書をたどる必要があり、仕込み②は8本を読み比べる必要がある

  • 仕込み①「つなぐ」: ベンダーのライブラリ更新(4/8)→ 通知遅延(5/20)→ 設定が staging にしか反映されない(5/27)→ アプリの二重購入(6/12)という因果の鎖
  • 仕込み②「見渡す」: 8件のインシデントに「リリース前チェックリスト未実施」×3、「監視閾値が実態と不一致」×3、「staging と本番の設定差分」×2 を散らす
  • 仕込み③「数える・並べる」: インシデント8件の原因分類と重大度、方針変更8つの時系列
  • 仕込み④「ない」: 資料に書いていない質問(iOS の最低対応バージョン)

文書は Claude に書かせたもので、仕込んだ数値・日付・固有名詞が一字一句入っていることを確認してあります。元データと仕様書は記事末尾のフォルダに置いています。

10問の内訳

# タイプ 質問
Q1 ピンポイント 決済 API のタイムアウト値は、いつ、何秒から何秒に変更された?
Q2 ピンポイント 2026年8月の MAU は何万人?
Q3 エンティティ中心 高橋美咲さんはこの半年でどんな出来事や仕事に関わった?
Q4 マルチホップ 6月の二重購入と、コネクトワークス社にはどんな関係がある?
Q5 マルチホップ CW-Link v2.3 の導入はその後どんな影響を及ぼした?(時系列で)
Q6 全体の傾向 4〜9月に繰り返し起きた問題に共通する要因は?
Q7 集計 インシデントは全部で何件? 原因分類と重大度ごとの件数は?
Q8 全体の傾向 複数のチームに共通する課題は?
Q9 時系列の集約 会社が決めた主な方針変更を時系列で挙げて
Q10 資料にない ハーバーアプリがサポートする iOS の最低バージョンは?

環境構築の手順

GraphRAG を入れ、設定ファイルを作ります。graphrag init は対話式で既定のモデル名を聞いてくるので、Enter で流してから settings.yaml を書き換えます。

# 作業フォルダと Python 3.12 の仮想環境(uv を使用)
mkdir -p ~/graphrag-lab && cd ~/graphrag-lab
uv venv --python 3.12 .venv && source .venv/bin/activate
uv pip install graphrag==3.2.0 openai pandas pyarrow tiktoken

# プロジェクトの雛形(settings.yaml・prompts/・input/ ができる)
mkdir rag && cd rag
printf '\n\n' | graphrag init --root .

LM Studio 側は、モデルを並列 4 で読み込んでおきます(lms は LM Studio 付属の CLI です)。

lms server start
lms load qwen/qwen3.8-27b --parallel 4 -y
lms load text-embedding-nomic-embed-text-v1.5 -y

settings.yaml の要点は次のとおりです(全文は記事末尾のフォルダにあります)。ポイントは3つ。LM Studio を model_provider: openai + api_base で OpenAI 互換として指定すること、思考モードを切る指定を extra_body に書くこと、トークン使用量を metrics でファイルに記録することです。

concurrent_requests: 6

completion_models:
  default_completion_model:
    model_provider: openai            # OpenAI 互換 API として LiteLLM 経由で呼ぶ
    model: qwen/qwen3.8-27b
    api_base: http://localhost:1234/v1
    auth_method: api_key
    api_key: lm-studio                # 空にはできないのでダミーを入れる
    call_args:
      temperature: 0
      max_tokens: 4000
      extra_body:                     # LiteLLM は未知の引数を落とすので extra_body で素通しにする
        reasoning_effort: none        # Qwen3.8 の思考モードを切る
    metrics:
      writer: file                    # 呼び出し回数とトークン数を metrics/*.jsonl に書く
      base_dir: metrics

embedding_models:
  default_embedding_model:
    model_provider: openai
    model: text-embedding-nomic-embed-text-v1.5
    api_base: http://localhost:1234/v1
    auth_method: api_key
    api_key: lm-studio

chunking:
  type: tokens
  size: 600                           # 既定 1200。短い社内文書なので小さめに
  overlap: 100
  encoding_model: o200k_base

extract_graph:
  entity_types: [organization, person, product, system, incident, project, policy]
  max_gleanings: 1

snapshots:
  graphml: true                       # グラフを描くために GraphML も出力

extra_body の件は、私が最初にハマった点です。call_args に reasoning_effort: none と素直に書くと、LiteLLM が OpenAI 公式に無い値として黙って落とし、Qwen が思考モードのまま走ります。思考に数千トークンを使うので、63チャンクの抽出が何十分たっても1件も終わりません。LM Studio のサーバーログに reasoning_content が出ていたら、これが原因です。

既定のプロンプトは「Return output in English」と書かれているので、日本語で出すように直します。差分は記事末尾のフォルダに prompts-japanese.patch として置きましたが、やったことは単純で、抽出プロンプトの「English」を「Japanese」に変え、「固有名詞は原文どおりに保つ」と足し、要約・レポート・回答の各プロンプトに「日本語で書く」を足しただけです。entity_types は既定の [organization, person, geo, event] から、社内文書向けに incident・system・product・project・policy を入れた7種類に変えました。

文書を input/ に置いて、索引を作ります。

# 文書(UTF-8 のテキスト)を input/ に置く
cp ~/corpus/*.txt input/

# 設定の検証だけ(LLM は呼ばない)
graphrag index --root . --dry-run

# 索引作成。進み具合は logs/indexing-engine.log に出る
graphrag index --root .

索引作成の実測:26,000トークンの文書に、79万トークンの LLM 処理

索引作成は 1時間29分 かかりました。内訳は、エンティティと関係の抽出が約50分、コミュニティ要約の生成が約39分で、この2つでほぼ全部です。LLM の呼び出し回数とトークン数は metrics/ の記録から次のとおりでした。

項目 GraphRAG(索引作成) ベクトル検索RAG(索引作成)
所要時間 1時間29分16秒 1.1秒
LLM 呼び出し 369回 0回
LLM 入力トークン 582,565 0
LLM 出力トークン 205,130 0
埋め込みトークン(推定) 約155,900(チャンク+エンティティ説明文+コミュニティ要約) 約29,200(チャンクのみ)
できたもの エンティティ 266、関係 693、コミュニティ 55(3階層)、要約レポート 55本 チャンク 63 件の埋め込み

元の文書は全部で約 26,300 トークンです。つまり GraphRAG は、文書の約30倍の LLM 入力トークンを索引作成に使いました。1チャンクにつき抽出と gleaning(取りこぼし確認)で2回、さらに抽出した説明文の統合要約が数百回、最後にコミュニティ要約が55回と、呼び出しが積み上がるためです。

索引作成の実測と外部 API 換算。LLM 呼び出し 369回、入力 58万・出力 21万トークン。同じ処理を OpenAI の API でやった場合の目安

右は記録したトークン数に OpenAI の公開単価を掛けた目安。gpt-4.1 で約3ドル、gpt-4.1-mini や gpt-5-mini なら1ドル未満。今回は34文書だが、文書量に比例して増える

外部 API に換算すると、gpt-4.1 で約 2.8 ドル、gpt-4.1-mini で約 0.56 ドルです。34文書でこの金額なので、数千文書なら数百ドル規模になります。「まず小さく試す」という公式の注意は、この比例関係を踏まえたものです。

できあがった知識グラフも見ておきましょう。Leiden が見つけたレベル0のコミュニティは9個で、「決済チーム・ペイブリッジ社・決済API」「ハーバーアプリと二重購入」「本番DB移行」のように、人間が見ても納得できるまとまりになっています。無関係な社内連絡(オフィス移転、健康診断など)は本体とつながらない小さな成分として分離されました。

GraphRAG が作った知識グラフ。ノード 266、エッジ 659。色は Leiden のレベル0コミュニティ 9個、大きさはつながりの数

各コミュニティのラベルは LLM が書いた要約レポートのタイトルから。左上の灰色は、コミュニティに属さない無関係文書の小さな成分

一方で、抽出の弱点も見えました。同じ人物が「佐伯」と「佐伯 蓮」、「高橋」と「高橋 美咲」のように別のエンティティとして登録されています。同じインシデントが「INC-2026-03」と「INC-03」、同じ環境が「本番」「本番環境」「本番DB」「本番 DB」に分かれる例もありました。GraphRAG は表記が完全に一致したものしかまとめないので、実務では抽出プロンプトに「正式名称に揃える」ルールを足すか、後処理で名寄せする必要があります。

10問の結果:ピンポイントはベクトル検索、「つなぐ」質問は Global、「数える」質問は全滅

同じ10問を、自作のベクトル検索(top-k=5 と 10)と、GraphRAG の Basic / Local / Global / DRIFT に投げました。採点は、仕込んだ正解と照らして ○(正解・2点)、△(部分的・1点)、×(不正解または「記載なし」・0点)の3段階です。採点は私が回答を読んで行い、全回答は記事末尾のフォルダに残しています。

10問×6手法の採点グリッド。ピンポイント質問は全手法が正解、マルチホップ質問は Global だけが正解、集計の質問は全手法が不正解

右端の数字は合計点(20点満点)。DRIFT の行は実行時間の都合で追加質問の数を既定の20から5、深さを3から1に減らしている

手法 合計 得意だった質問 落とした質問
ベクトル検索(k=5) 10/20 ピンポイント(Q1, Q2)、資料にない質問(Q10) マルチホップ(Q4)、集計・俯瞰(Q7〜Q9)
ベクトル検索(k=10) 14/20 k=5 より人物・傾向の質問が改善 集計(Q7)、時系列(Q9)
GraphRAG Basic 15/20 ベクトル検索と同じ傾向で、要約が丁寧 集計(Q7)
GraphRAG Local 12/20 エンティティ中心(Q3)、因果の鎖(Q5) ピンポイント(Q2)を「記載なし」、集計(Q7)
GraphRAG Global 13/20 マルチホップ(Q4)で唯一の正解、俯瞰(Q6) ピンポイント(Q2)、集計(Q7)、年号の誤り
GraphRAG DRIFT 18/20 ピンポイントもマルチホップも俯瞰も正解。6手法で最高点 集計(Q7)。1問あたり6分以上かかる

合計点だけ見ると、DRIFT が18点で最高、次がふつうのベクトル検索と変わらない Basic の15点で、Local と Global は k=10 のベクトル検索を下回りました。「GraphRAG なら何でも良くなる」わけではありません。質問のタイプごとに見ると、きれいに得意・不得意が分かれています。

ピンポイントの質問(Q1・Q2)は、ベクトル検索で十分でした。「8月の MAU は?」のような質問は、該当する月次振り返りのチャンクがそのまま上位に来ます。むしろ GraphRAG の Local と Global は Q2 を「データに含まれていない」と答えました。Local はエンティティの説明文から入るため、「42万」という数字を含むチャンクに到達できず、Global はコミュニティ要約に月ごとの MAU が書かれていなかったためです。要約に残らなかった細かい数値は、Global では見えなくなるという弱点です。

マルチホップの質問(Q4)は、Global と DRIFT だけが正解でした。実際の回答を並べると違いがはっきりします。

マルチホップ質問 Q4 への4手法の回答の抜粋。ベクトル検索は「記載なし」、Local は鎖はたどれるが会社名を結べず、Global だけがコネクトワークス社と CW-Link と二重購入の連鎖を説明した

同じ LLM でも、渡す根拠が違うと答えが変わる。Global は55本のコミュニティ要約を全部読むので、「コネクトワークス社=CW-Link の提供元」という対応を拾えた

ベクトル検索(k=5)は、「二重購入」に似た断片ばかりを拾い、オフィス移転や社員旅行の連絡までが上位5件に入りました。原因側の文書は質問文と似ていないので届きません。これは冒頭で説明した「top-k に入らなかった情報は存在しないのと同じ」が、そのまま起きた形です。興味深いのは GraphRAG Local も落としたことです。知識グラフには「コネクトワークス社」のノードがちゃんとあるのに、入口のエンティティ検索(質問文の埋め込みとエンティティ説明文の類似度)で拾えず、「データに存在しない」と答えました。Local は入口を外すと弱い、という仕組みどおりの結果です。

一方、同じマルチホップでも Q5(「CW-Link v2.3 の導入はどんな影響を?」)は全手法が正解でした。質問文に「CW-Link v2.3」という固有名詞が入っているので、ベクトル検索でも原因側の文書が直接ヒットするからです。つまり「マルチホップだから GraphRAG」ではなく、質問文に出てこない中間の文書をたどる必要があるときに GraphRAG が効く、というのが正確な言い方です。

俯瞰の質問(Q6・Q8)は、GraphRAG がやや有利でした。Q6(繰り返し起きた問題の共通要因)は、Local と Global が3つの要因をすべて INC 番号つきで挙げました。ただし、ここは正直に書いておくと、このコーパスでは8月のポストモーテム文書に集計結果が書かれているため、k=10 のベクトル検索でもその文書を拾えば答えられました。本当に「全部を読み比べないと分からない」質問は次の Q7 です。

集計の質問(Q7)は、全手法が不正解でした。「インシデントは何件? 原因分類ごとと重大度ごとの件数は?」に対し、ベクトル検索は上位に入った報告書だけを数えて「2件」、Local は「7件」、Global は「2件、文脈によっては4件か7件」と答えました。Global が外した理由は、コミュニティ要約が「どのインシデントが何件」という形では書かれておらず、要約の粒度で数が失われているからです。GraphRAG は「数える」仕事には向きません。件数が欲しければ、構造化データ(表)にしてから SQL で数えるべきです。

時系列の集約(Q9)は、Global と Basic が部分点でした。Global は8つの方針変更のうち7つを拾いましたが、一部の日付を「2024年」と書く誤りがありました。元の文書に2024年という記述はないので、コミュニティ要約を書く段階で LLM が年を取り違え、それが回答に伝播したものです。要約を事前に作る方式は、要約の誤りがそのまま答えに乗るという、GraphRAG 固有のリスクです。

**資料にない質問(Q10)は、全手法が正しく「記載なし」**と答えました。ハルシネーションの抑制については、どの手法も問題ありませんでした。

DRIFT が最高点だった理由も書いておきます。DRIFT は、まずコミュニティ要約で当たりをつけてから、自分で追加の質問を5つ作って Local Search を繰り返し、最後にまとめます。Q2(8月の MAU)では、Local 単体は「記載なし」でしたが、DRIFT は追加質問の中で月次振り返りのチャンクに到達して「42万」と答えました。Q4 では Global と同じく会社名とライブラリの対応を拾い、Q9 では年号の誤りもありませんでした。「入口を1回外しても、質問を変えてもう一度探す」ので取りこぼしが減る、という仕組みどおりの結果です。そのかわり、今回の縮小設定(追加質問5・深さ1)でも1問に平均6分20秒かかりました。既定の設定(追加質問20・深さ3)では、さらに数倍の時間と費用がかかります。

質問1件あたりの費用と時間

採点と並べて見たいのが、質問1件あたりのコストです。

質問1件あたりの LLM トークンと所要時間。ベクトル検索は約2,500トークン・16秒、GraphRAG Global は約85,000トークン・195秒

Basic と Local の入力トークンは、ストリーミング応答で使用量が記録されないため、LLM を呼ばずにコンテキストを再構築して数えた推定値。DRIFT は9回の呼び出しのうち6回がストリーミングで未計上のため、記録できた3回分(約11,600)だけを載せている。未計上分を Local 相当(1回約8,000)とみなすと1問あたり5〜6万トークンになる

手法 1問あたりの LLM トークン 1問あたりの時間 LLM 呼び出し
ベクトル検索(k=5) 約2,450 16秒 1回
ベクトル検索(k=10) 約4,440 22秒 1回
GraphRAG Basic 約5,940 46秒 1回
GraphRAG Local 約8,350 52秒 1回
GraphRAG Global 約84,600 195秒 12〜13回
GraphRAG DRIFT(縮小設定) 記録できた分で約11,600(推定 5〜6万) 380秒 9回

Global は、ベクトル検索の約35倍のトークンと約12倍の時間を毎回使います。コミュニティ要約55本を8万トークン分まとめて map に渡し、reduce で統合するためです。外部 API なら、gpt-4.1 で1問あたり約 0.2 ドル、gpt-4.1-mini でも約 0.04 ドルです。DRIFT は時間がさらに長く(約24倍)、既定設定ならもっとかかります。全部の質問を Global や DRIFT に流す設計は、費用と待ち時間の面で現実的ではありません。

実務での使い分け:ルーティングして併用する

検証結果をまとめると、ピンポイントの質問はベクトル検索で十分で、関係や俯瞰の質問で GraphRAG が効く、という元の整理どおりの結果でした。であれば、全面的に置き換える理由はありません。質問のタイプを判定して経路を振り分けるのが現実的です。

質問タイプでルーティングして併用する構成。ピンポイントはベクトル検索、関係・マルチホップは Local/DRIFT、俯瞰・集約は Global へ振り分け、どの経路でも資料にないことは答えない

ルーターの分類が外れても、安い経路で「記載なし」と返ったら上の経路へ落とす設計にしておけば、大半の質問は安い経路で済む

ルーターは小さなモデルで十分です。次は Qwen に分類させる最小の例で、GraphRAG の Python API(graphrag.api)と自作のベクトル検索を切り替えます。

# router.py: 質問タイプを判定して検索経路を選ぶ最小例
from openai import OpenAI
client = OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio")

ROUTE_PROMPT = """次の質問を1語で分類してください。
- pinpoint: 特定の数値・日付・担当者など、答えが1か所に書いてある質問
- relation: 2つ以上の事柄の関係や経緯、因果を聞く質問
- global: 全体の傾向・共通点・一覧・集計を聞く質問
質問: {q}
分類:"""

def route(q: str) -> str:
    r = client.chat.completions.create(
        model="qwen/qwen3.8-27b", temperature=0, max_tokens=5,
        messages=[{"role": "user", "content": ROUTE_PROMPT.format(q=q)}],
        extra_body={"reasoning_effort": "none"})
    label = r.choices[0].message.content.strip().lower()
    return {"pinpoint": "vector", "relation": "local", "global": "global"}.get(label, "vector")

# 使い方: route("繰り返し起きた問題の共通要因は?") -> "global"
#   "vector" なら自作のベクトル検索、"local"/"global" なら
#   graphrag query --method local|global を呼ぶ(Python API は graphrag.api.local_search など)

運用面で押さえておきたい注意点を3つ挙げます。

  1. 抽出プロンプトのチューニングは必須。既定のプロンプトは英語ニュース向けの汎用品です。今回は「日本語で出す」「固有名詞を原文どおりに保つ」「エンティティ種別を業務文書向けに」の3点を直しただけで実用になりましたが、ここを怠ると知識グラフの質が下がり、Local も Global も劣化します。公式には graphrag prompt-tune という自動チューニングのコマンドもあります
  2. 更新頻度の高い文書には向かない。graphrag update で増分更新はできますが、コミュニティ構造が変わると要約の再生成が走ります。「終わった案件の記録」「過去の議事録」のように凍結された文書群で真価を発揮します
  3. 日本語でも動くが、トークン数は英語より増える。日本語は英語よりトークン効率が悪く、同じ文字数でも 1.5〜2 倍のトークンになります。費用の試算は必ず自分のコーパスで行ってください

トラブルシューティング:ローカル LLM で動かすときに踏んだ点

今回の検証で実際に踏んだ順に、確認する手順を図にしました。

ローカル LLM で GraphRAG が動かないときの診断フロー。設定エラー、抽出が進まない(思考モード)、並列で止まる(メモリ)、埋め込みの次元、抽出が英語になる、の順に確認する

②の思考モードが最重要。LM Studio のサーバーログに reasoning_content が出ていたら、思考を切る指定が届いていない

症状 原因 対処
graphrag index が設定エラーで止まる api_key が空 LM Studio はキー不要だが、ダミーの文字列を入れる。--dry-run で先に検証
抽出が始まったのに何十分も 0 件のまま 思考モードが切れていない(reasoning_effort が LiteLLM に落とされる) call_args.extra_body.reasoning_effort: none に書く
1件ずつは速いのに並列だと止まる 並列数ぶんの KV キャッシュでメモリ不足、スワップ lms load --parallel 4 と concurrent_requests を合わせる。sysctl vm.swapusage で確認
埋め込みで vector_size の警告 既定 3072(text-embedding-3-large)と nomic の 768 が違う 3.2.0 は自動で合わせて続行する。古い版は vector_store.vector_size: 768 を明示
抽出結果が英語になる、名前が揺れる 既定プロンプトが英語出力 「日本語で」「固有名詞は原文どおり」をプロンプトに足す
graphrag init が止まる 対話式でモデル名を聞いている printf '\n\n' の出力をパイプで graphrag init --root . に渡して流す

まとめ

  • GraphRAG は、文書からエンティティと関係を抽出して知識グラフを作り、Leiden でコミュニティに分け、コミュニティごとの要約を事前に作っておく RAG です。Microsoft 版の特徴は「階層的なコミュニティ要約」と、それを map-reduce で全部読む Global Search にあります
  • ベクトル検索 RAG との本質的な差は、top-k に入らなかった情報は存在しないのと同じになるかどうかです。GraphRAG は「離れた文書をつなぐ」「全体を読み比べる」作業を索引作成のときに前倒ししています
  • 今回の検証(34文書・10問・Qwen3.8-27B)では、ピンポイントの質問はベクトル検索で十分、質問文に出てこない中間の文書をたどるマルチホップの質問で GraphRAG の Global と DRIFT が有利、件数を数える質問はどの手法も不正解、という結果でした。合計点は DRIFT が最高(18/20)でしたが、1問に6分以上かかります
  • 費用は索引作成が文書量に比例し、Global Search は質問ごとに多数の LLM 呼び出しが走ります。まず小さなサブセットで索引を作ってトークン数を測り、質問タイプでルーティングして併用するのが現実的です

次のステップとしては、自分の手元にある「終わった案件の議事録」や「過去のインシデント記録」で同じことを試してみるのがおすすめです。この記事の設定ファイルとスクリプトはそのまま流用できます。

参考リソース

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?