「社内文書を 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つを質問します。
- 「6月にアプリで起きた二重購入の問題と、ベンダーのコネクトワークス社にはどんな関係がある?」
- 「この半年で繰り返し起きた問題に共通する要因は?」
どちらも、人間が文書を全部読めば答えられます。しかしベクトル検索の RAG は、どちらも苦手です。下の図で、文書のどこに答えがあり、なぜ拾えないのかを追ってみてください。
質問①の答えは「4/8 のベンダーメモ → 5/20 の報告書 → 6/12 の報告書」と3本にまたがり、質問②の答えは8本の報告書を読み比べないと出ない。どちらも「質問に似た断片」を探すだけでは届かない
ベクトル検索 RAG の仕組みは「質問文を数値化し、意味が近いチャンク(文書の断片)を上位 k 件だけ LLM に渡す」です。質問①では、「二重購入」に似た断片は拾えますが、原因側の「ライブラリの既定値が変わった」というメモは質問文と似ていないので上位に入りません。質問②は、個々の報告書には答えが書かれておらず、複数の報告書を比べて初めて分かる内容です。
Microsoft Research はこの2つを、ベースライン RAG の典型的な失敗として挙げています。「点在する情報を共通の属性でつないで答える」ことと、「大きなデータ集合を俯瞰して要約する」ことです。GraphRAG はこの2つに答えるために作られました。
GraphRAG とは何か:一般名詞の「グラフRAG」と Microsoft GraphRAG
「グラフRAG」という言葉は、実は2つの意味で使われます。混乱しやすいので先に整理します。
一般名詞のグラフ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 を呼びます。ここが費用の源泉なので、どの工程で何をしているかを押さえておくと、あとの費用の話が理解しやすくなります。
紫のラベルが LLM を呼ぶ工程。公式ドキュメントでは索引作成の費用の約75%が工程2〜3(グラフ抽出)にかかるとされる
- チャンクに分割(TextUnit)。文書を一定トークンごとに切ります。今回は34文書が63チャンクになりました
- エンティティと関係を抽出。各チャンクを LLM に読ませ、「人・組織・製品・インシデント…」と、その間の関係を説明文つきで書かせます。取りこぼしを拾う gleaning(追加の問いかけ)が既定で1回入るので、1チャンクにつき LLM を2回呼びます
- 統合して知識グラフに。同じ名前のエンティティをまとめ、複数のチャンクから集まった説明文を LLM で1つに要約します
- コミュニティ検出(Leiden)。つながりの濃いノード群を自動でグループ化し、階層を作ります
- コミュニティ要約を生成。グループごとに LLM が「レポート」を書きます。上の階層ほど抽象度の高い要約になります
- 埋め込みを作る。エンティティの説明文、チャンク、要約をベクトル化します
工程4の Leiden アルゴリズムは聞き慣れない言葉だと思うので、たとえで説明します。学校のクラスで「誰と誰がよく話すか」を線で結ぶと、線が密集している部分(部活仲間、同じ塾のグループ)が見えてきます。Leiden は、名簿や所属を一切見ずに、この「線の密集具合」だけから仲良しグループを見つけ、さらにグループをまとめて「学年」のような上の階層を作ります。
3つ目の「中で本当につながっているか点検する」工程が、前身の Louvain にはなかった Leiden の特徴。GraphRAG はこうしてできた各階層のまとまりに要約を書く
検索:質問の種類で4つのモードを使い分ける
索引ができたら、質問に応じて検索モードを選びます。公式には Global・Local・DRIFT の3つに加え、比較用の 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 はこの統合作業を、質問のたびではなく索引作成のときに前倒ししています。
左は「二重購入」に似たチャンクばかりが上位に来て、原因側の文書が切り捨てられる様子。右は「二重購入」のエンティティから関係のエッジを2〜3ホップたどる様子(いずれも概念図)
GraphRAG を使ったほうがいいケース
結論から言うと、社内 FAQ やマニュアル検索のように答えが特定の箇所にあるなら、ベクトル検索 RAG(ハイブリッド検索+リランク)で十分です。GraphRAG が効くのは、調査レポート群・議事録・インシデント記録・訴訟資料のように、横断的な傾向分析や関係の把握をしたい場合です。
「いいえ」が続いて左下に落ちるほどベクトル検索で済む。右下に行くほど GraphRAG の索引コストを払う価値がある
判断の軸は3つです。
- 質問の性質: 「〜はどこに書いてある?」が中心か、「全体として」「共通して」「関係は」が多いか
-
文書の更新頻度: 毎日追加・改訂されるナレッジは相性が悪い。増分更新の仕組み(
graphrag update)はありますが、コミュニティ構造が変わると要約の再生成が発生します。凍結された文書群(過去の議事録、終わったプロジェクトの記録)に向いています - 抽出品質の手当てができるか: 既定の抽出プロンプトは汎用的なので、業務文書ではエンティティ種別やプロンプトのチューニングがほぼ必須です。ここが悪いと下流がすべて劣化します
実務では、全面的に置き換えるのではなく、質問タイプでルーティングして併用する構成が現実的です。これは後半の検証結果からも裏付けられます。
GraphRAG を使う場合の費用
費用は3つの場面で発生します。どこで、何に比例して増えるかを知っておけば、見積もりができます。
索引作成は「最初に1回」だが文書量に比例する。質問ごとの費用は Global Search で跳ね上がる
- 索引作成(最初に1回): 全チャンクに抽出(gleaning で2回)、説明文の要約、コミュニティ要約が走ります。文書量に比例して LLM 呼び出しが増え、元の文書の数十倍の LLM トークンを消費します(今回の実測では約30倍)。公式 README も「索引作成は高くつくので、小さく始めて」と注意しています
- 質問ごと(毎回): Local は LLM 1〜2回で済みますが、Global はコミュニティ要約の数だけ map の呼び出しが走ります。今回の検証では、同じ質問でも Global はベクトル検索の約35倍のトークンを使いました(数字は後述)
- 文書の更新: 変わったチャンクだけ埋め込み直せばよいベクトル検索と違い、グラフの統合とコミュニティ要約の再生成が絡みます
費用が課題なら、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 は使いません。
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本(オフィス移転、健康診断など)です。
正解を採点できるように、文書には次の「答えの構造」を仕込んであります。
赤枠がインシデント報告書。仕込み①は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回と、呼び出しが積み上がるためです。
右は記録したトークン数に 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移行」のように、人間が見ても納得できるまとまりになっています。無関係な社内連絡(オフィス移転、健康診断など)は本体とつながらない小さな成分として分離されました。
各コミュニティのラベルは 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段階です。採点は私が回答を読んで行い、全回答は記事末尾のフォルダに残しています。
右端の数字は合計点(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 だけが正解でした。実際の回答を並べると違いがはっきりします。
同じ 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件あたりのコストです。
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 が効く、という元の整理どおりの結果でした。であれば、全面的に置き換える理由はありません。質問のタイプを判定して経路を振り分けるのが現実的です。
ルーターの分類が外れても、安い経路で「記載なし」と返ったら上の経路へ落とす設計にしておけば、大半の質問は安い経路で済む
ルーターは小さなモデルで十分です。次は 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つ挙げます。
-
抽出プロンプトのチューニングは必須。既定のプロンプトは英語ニュース向けの汎用品です。今回は「日本語で出す」「固有名詞を原文どおりに保つ」「エンティティ種別を業務文書向けに」の3点を直しただけで実用になりましたが、ここを怠ると知識グラフの質が下がり、Local も Global も劣化します。公式には
graphrag prompt-tuneという自動チューニングのコマンドもあります -
更新頻度の高い文書には向かない。
graphrag updateで増分更新はできますが、コミュニティ構造が変わると要約の再生成が走ります。「終わった案件の記録」「過去の議事録」のように凍結された文書群で真価を発揮します - 日本語でも動くが、トークン数は英語より増える。日本語は英語よりトークン効率が悪く、同じ文字数でも 1.5〜2 倍のトークンになります。費用の試算は必ず自分のコーパスで行ってください
トラブルシューティング:ローカル LLM で動かすときに踏んだ点
今回の検証で実際に踏んだ順に、確認する手順を図にしました。
②の思考モードが最重要。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 呼び出しが走ります。まず小さなサブセットで索引を作ってトークン数を測り、質問タイプでルーティングして併用するのが現実的です
次のステップとしては、自分の手元にある「終わった案件の議事録」や「過去のインシデント記録」で同じことを試してみるのがおすすめです。この記事の設定ファイルとスクリプトはそのまま流用できます。
参考リソース
- Microsoft Research ブログ「GraphRAG: Unlocking LLM discovery on narrative private data」(2024-02-13): https://www.microsoft.com/en-us/research/blog/graphrag-unlocking-llm-discovery-on-narrative-private-data/
- 論文 "From Local to Global: A Graph RAG Approach to Query-Focused Summarization"(arXiv:2404.16130): https://arxiv.org/abs/2404.16130
- 公式ドキュメント(Indexing Methods / Query Overview / Configuration): https://microsoft.github.io/graphrag/
- GitHub microsoft/graphrag: https://github.com/microsoft/graphrag
- Microsoft Research ブログ「LazyGraphRAG: Setting a new standard for quality and cost」(2024-11-25): https://www.microsoft.com/en-us/research/blog/lazygraphrag-setting-a-new-standard-for-quality-and-cost/
- Traag, Waltman, van Eck "From Louvain to Leiden: guaranteeing well-connected communities"(2019): https://www.nature.com/articles/s41598-019-41695-z
- Dify ドキュメント「Setting the Indexing Method」: https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods
- OpenAI の料金ページ(換算に使用): https://developers.openai.com/api/docs/pricing

















