← ブログに戻る

Neo4jで3週間、7ステップで組んだナレッジグラフの実測メモ

Neo4jとTree-sitterを使って、週末ゼロの状態から3週間でコードベース用のナレッジグラフを組みました。

想定より安く、想定より速く、想定より地味に効きました。ナレッジグラフというと大企業案件、GraphRAG論文、数千万円のPoC、そういう匂いがしますよね。私も最初は「触ってみたいけどROIどうなん?」と2年ほど寝かせていました。今回、腹をくくって組んでみたので、7ステップとその実測値をまとめます。この記事の内容を深く追いたい方は、まずは書籍側の walkthrough を先に読んでもいいです → ナレッジグラフ実践ガイド

この記事で分かること

  • ナレッジグラフ7ステップの中で、どこで詰まるか (答え: Step 3)
  • トークン削減率の中央値 (Tree-sitter抽出との比較で実測 8-49倍)
  • ビルドコスト実測 (10,000ドキュメント換算で $50-200レンジ、Microsoft GraphRAG系pipeline時)
  • Neo4j 5.x + vector-2026.06 provider の使い分け

書籍側では14章に分けて丁寧に扱っています → ナレッジグラフ実践ガイド

Step 1: ユースケースを絞る (これで週末が消える)

最も重要なステップです。

ここで「社内データを全部グラフにしたい」と言い出す人は、3ヶ月後に空のNeo4jインスタンスを持て余します。私も1回目は「iris-hub全ファイルの関係性を可視化する」と壮大な設計をして、Step 3で燃え尽きました。

良いユースケース:

「あるMCP tool定義を変更したときに、影響を受けるハーネスファイルを30秒以内で列挙する」

これなら必要なノード・エッジ・クエリが自ずと決まります。ユースケースは1つのクエリに絞る。これが週末2回を消さないコツです。

Step 2: データソースを特定する

私の場合はコードベースだったので、Tree-sitterで抽出したAST + Git logの2種類だけにしました。非構造化データをLLMで抽出する方針も考えたのですが、Step 1のクエリには不要と判断してカットしました。

「取り込めるものは全部取り込む」は禁物です。

Step 3: オントロジー設計 (ここで一番悩む)

私が組んだ最小オントロジーはこれです。

ノード:
  - File (path, language, loc)
  - Function (name, signature, complexity)
  - MCPTool (name, schema_hash)
  - HarnessConfig (path, section)

エッジ:
  - CALLS: Function -> Function
  - DEFINES: File -> Function
  - REGISTERS: HarnessConfig -> MCPTool
  - CONFIGURED_BY: MCPTool -> HarnessConfig

ノード4種、エッジ4種、それだけ。

ここを「Class, Method, Interface, Trait, Module…」と広げ始めた瞬間に、Step 4のデータ取り込みで自分の首を絞めます。

最小オントロジーで先にStep 7まで通す、これに尽きます。

Step 4: データモデリング

Neo4j 5.x + Python ドライバでモデリングしました。インデックスを最初に作ることだけは忘れないでください。作らないと、Step 6のクエリで秒単位の待ちが発生し、開発体験が一気にダレます。

CREATE INDEX FOR (f:File) ON (f.path);
CREATE INDEX FOR (fn:Function) ON (fn.name);
CREATE INDEX FOR (t:MCPTool) ON (t.name);

インデックスを忘れていると、後で「なんかクエリ遅いな」と思ってから気付いて、既に入れた10万ノードに対して張り直すことになります。

あの気まずい沈黙、二度と味わいたくないですね。

Step 5: データの取り込み

Tree-sitterで各言語 (TypeScript/Python/Shell) をパースし、AST → Cypher CREATE文への変換パイプラインを書きました。ここが本記事のヘッドラインの数字が出るところです。

Tree-sitter抽出とLLM直接読み込みのトークン比較

  • LLMに直接ファイルを渡した場合: 平均 47,000 tokens / query
  • Tree-sitterでシンボル抽出後にグラフから引いた場合: 平均 960〜5,800 tokens / query
  • 削減率の中央値: 約12倍、最大49倍

「8-49倍」レンジの意味は、単純なコードジャンプ系クエリでは12倍前後、複雑な影響範囲分析では49倍近くになる、ということです。ファイル全文をLLMに読ませていた頃と比べると、コストは1桁小さくなります。参考: Microsoft GraphRAG系のフルパイプライン (エンティティ抽出 + 関係マッピング + コミュニティ要約) を10,000ドキュメントに適用した場合、$50-200レンジと最近のベンチマークで報告されています。純粋なvector indexingが$5前後なので、GraphRAG側は10-40倍のindexing premiumを払う構造です。私の場合はコードベース特化で、LLM抽出をスキップしたので費用感はもっと軽く、月$20以下に収まりました。

Step 6: クエリとAPIの構築

Step 1で決めた1つのクエリだけを書きます。

MATCH (t:MCPTool {name: $tool_name})<-[:REGISTERS]-(h:HarnessConfig)
      <-[:CONFIGURED_BY]-(dep:MCPTool)
MATCH (dep)<-[:REGISTERS]-(other:HarnessConfig)
RETURN DISTINCT other.path AS affected_harness_file

Cypher 25 の SEARCH 句を使う場合は Neo4j 2026.06 の vector-2026.06 provider が必要ですが、私の初期構築では純粋なグラフトラバーサルで十分でした。ベクトル検索が要るのは、ノードのプロパティに自然言語のdescriptionが入る場合だけです。自然言語のharnessとナレッジグラフを組み合わせる話は、Natural Language Agent Harness (arXiv)の実装メモ にも通じるところがあります。

Step 7: 運用と拡張

3週間目の最終週はここに丸ごと使いました。

  • 鮮度: Git postcommit hookで差分ファイルだけ再抽出、Neo4jへ差分UPDATE
  • 監視: 孤立ノード検出をnightly cronで
  • 拡張: ユースケースを2つ目に増やす前に、既存クエリで1週間運用して痛みを見る

「Step 7が終わる=完成」ではありません。「Step 1に戻れる状態=完成」だと考えています。

実際に効いた3つの数字

3週間の実測でうれしかった数字を並べます。

指標Before (LLM直接)After (Neo4j + Tree-sitter)
MCP tool影響範囲クエリ47,000 tokens960 tokens
ハーネス設定の一貫性チェック手動30分Cypher 1本 (0.4秒)
月間LLM API cost$180$22

トークン削減は書籍で予告した通り8-49倍レンジに収まりました。一番効いたのは実は月間コスト側で、想定の3割で済みました。理由はシンプルで、以前は「とりあえずファイル全部渡す」をやめられなかったから。ナレッジグラフを組んだ副作用で、LLMに渡すコンテキストを設計する癖がつきました。

まとめ

ステップやること詰まりポイント
1ユースケース1つに絞る「全部グラフ化」の誘惑
2データソース特定取り込みすぎ
3最小オントロジーここで週末が2回消える
4モデリングインデックス忘れ
5データ取り込みTree-sitter抽出で8-49倍削減
6クエリ構築まず1本だけ
7運用Step 1に戻れる状態を作る

3週間、正確には土日 x 3 + 平日夜 x 12日で組めました。書籍を書いた時期に一度手を動かしていたのが効いたので、初見だと4週間見た方が安全だと思います。ここまで手を動かして、コードベースにナレッジグラフを重ねる感覚がやっと腹落ちしました。詳細な14章分の実装ガイド (第4章の7ステップを含む) は書籍側で扱っています。

関連する書籍: ナレッジグラフ実践ガイド