← ブログに戻る

Tree-sitter+MCPでレビュートークンを8〜49倍削った実測: コードベースは既に巨大なグラフだった

「AI コードレビューが毎回リポジトリ全体を舐めてトークンの 80% を食う」問題を、Tree-sitter で AST に切り分けて MCP ツール経由で渡すように書き換えたら、削減幅が 8 倍のケースと 49 倍のケースの両方が出ました。両方本当の数字で、最初は自分の計測スクリプトのバグを疑って 3 回叩き直したうえでの結果です。

平均値で語ると誤解を招くので、タスク種別ごとに分解します。私が過去 3 週間で計測した 30 本の PR の結果です。

8 倍と 49 倍の間に何が起きているか

タスク種別別の削減倍率を並べます。列は「全ファイルを Anthropic 公式 filesystem MCP で渡していた頃のトークン量 ÷ Tree-sitter で刈った後のトークン量」、つまり「何倍節約できたか」。

タスク種別PR 数平均削減倍率特徴
小規模 refactor(単一関数のリネーム系)8 本49x影響を受けるのは blast radius 内の 5-15 関数のみ
N+1 SQL fix(ORM の eager loading)4 本32x呼び出しチェーン + テスト + マイグレーション
type refactor(共通型の追加・変更)6 本18x型を import している全ファイル + テスト
API endpoint 追加(ルーティング + handler + テスト)5 本12x関連 middleware + 認可 + fixtures を辿る必要
microservice 間境界の変更(protobuf 修正)4 本8x全サービスの schema import 箇所を横断
全体アーキ変更(DI コンテナ差し替え)3 本1.4xほぼ全ファイルを触るので、そもそも刈れない

真ん中付近が 12-18 倍で落ち着いていて、両端に外れ値がある形です。刈り込みが効くのは「変更の影響範囲がコードベース全体の一部分に閉じている」ケースで、閉じていないほど倍率は 1 に近付きます。当たり前の話ですが、実測すると「じゃあ何倍まで落とせるか」の期待値が具体的になります。

タスク種別ごとの削減倍率: 49倍(refactor)から1.4倍(全体アーキ変更)まで

「毎回 80% トークン喰う」の内訳

Tree-sitter に置き換える前の私の構成は、Claude Code に Anthropic 公式の filesystem MCP サーバを繋いで、レビュー対象の PR を read_multiple_files で丸ごと読ませていました。中規模リポ(Python + TypeScript、約 300 ファイル、6.8 万行)で 1 レビューあたり平均 118,000 トークン。その内訳がこうです。

  • 変更ファイル本体: 約 8,000 トークン(6.8%)
  • 変更ファイルが import している依存ファイル群: 約 46,000 トークン(39%)
  • テストファイル(関連しそうなもの全部): 約 38,000 トークン(32%)
  • 設定・型定義・スキーマ: 約 26,000 トークン(22%)

「変更ファイル本体」に相当する 6.8% 以外は、レビューの判断のために「たぶん要る」ファイルをまとめて詰めていたぶんです。合計 93.2% が「保険で読ませた」トークンで、そこにモデルの注意が薄く広がって、肝心の変更差分に対する指摘の質が下がります。middle-lost problem の教科書事例をやっていました。

Tree-sitter で何を刈れるようになるか

Tree-sitter は Max Brunsfeld らが Atom の構文解析基盤として開発したパーサジェネレータで、公式のツリーは 23 言語の grammar を保守しています。コミュニティ拡張の tree-sitter-language-pack まで含めると 306 言語超。私の実務では Python / TypeScript / Go / Rust / Java / Ruby の 6 言語しか使わないので、公式 23 で完全に足りています。

AST を取り出せるだけなら Tree-sitter でなくてもよくて、LSP や ctags でも近いことはできます。Tree-sitter を第一選択にしたのは 3 つの実務的な理由でした。

1 つ目、19 言語超に同一 API で AST 抽出できる基盤が他にありません。ast-grep もこの層に乗っています。 2 つ目、構文エラーを含むコードでも部分 AST を返します。PR ブランチが未完成で壊れていてもレビューは進みます。 3 つ目、インクリメンタルパース対応。差分ビルドが数百 ms で回ります。

3 つ目が地味に効きます。私の 6.8 万行リポでフル AST 抽出は約 4 秒、差分だけなら約 200 ms。CI で PR フックに埋め込んでも遅延になりません。

MCP ツールの粒度を 5 本に絞る

MCP(Model Context Protocol) 経由で Tree-sitter が抽出したグラフを Claude Code に露出させる部分は、ツール数の設計が全部でした。CodeGraph の 22 ツールをそのまま模倣したときは Claude Code が呼び出し先を選び切れず、同じ質問に対して blast_radius と get_callers を二重に叩いたり、search_symbols で済むものに get_function を挟んだりして、逆にトークンが増えました。

5 ツールまで削ったら選択精度が安定しました。

@tool
async def get_function(name: str) -> dict:
    """関数のシグネチャ、行範囲、所属クラスを返す"""

@tool
async def get_callers(name: str, max_hops: int = 1) -> list:
    """指定関数の呼び出し元 1 階層。設計判断より軽い質問向け"""

@tool
async def blast_radius(name: str, max_hops: int = 3, min_confidence: float = 0.8) -> dict:
    """変更影響範囲。hop 距離で groupby した dict を返す"""

@tool
async def search_symbols(query: str, kind: str = "function|class") -> list:
    """シンボル横断検索。fuzzy 対応"""

@tool
async def get_file_summary(path: str) -> dict:
    """ファイル単位の関数・クラス・import 一覧。ファイル全読み込みの代替"""

5 本で PR レビュー質問の 8 割は捌けます。残り 2 割はget_tests_callingget_complexityを追加していけば良い、というのが今のところの結論。命名で意図を区別することが、AI 側での選択エラーを一番減らします。

49 倍が出た PR の話

一番削減率が高かった PR は、Django の 1 メソッドをリネームするだけの変更でした。差分は 3 行。全ファイル方式では 128,000 トークンを消費して、Tree-sitter+MCP 方式では 2,600 トークンで済んだので、比率としては 49.2 倍。

Tree-sitter+MCP 側で何が呼ばれたかログを見ると、こう並んでいます。

  1. get_function(name="UserRepository.find_by_email") - 変更前のシグネチャ確認
  2. blast_radius(name="UserRepository.find_by_email", max_hops=3) - 影響範囲 12 関数 + 関連テスト 4 本
  3. search_symbols(query="find_by_email") - 文字列参照の残存確認

必要な情報だけ取って、必要ないファイルは開きません。人間のシニアレビュアーが blame と grep で同じ判断をするときの動きに近くて、当たり前と言えば当たり前です。

一方で 8 倍しか出なかった microservice 境界の PR は、7 サービスの schema import を全部辿る必要があって、blast_radius の結果集合がもともと大きくなります。構造で刈るのが効きにくい形をしています。ここで「49 倍出るはず」と期待して構造を無理に絞ると、レビュー精度が落ちます。倍率は目的ではなく結果です。

追試手順

私の構成を最小で再現する場合、以下の順で組みます。

  1. pip install tree-sitter tree-sitter-python で 1 言語だけ AST 抽出を走らせて、__str__ で S 式が返ることを確認
  2. nx.DiGraph に function/class をノード、call/import をエッジとして 500 行程度で書く(初手は Neo4j や Kuzu を使わなくていい)
  3. FastMCP で上記 5 ツールを露出、Claude Code の settings.json に MCP サーバとして登録
  4. 直近 5 本の PR で claude -p "review this PR" を実行して、トークン消費量を旧構成と比較

私の実測は Python + TypeScript の 2 言語、初期グラフ構築が 500 行未満で組めました。手が動きやすい規模です。

コードKG実装ガイド: Tree-sitter+MCP+Kuzu で AI コードレビューを 8-49 倍削る本 では、上記 5 ツール実装から 22 ツールへの拡張、Kuzu へのグラフ移行、GitHub Action への埋め込みまでを 15 章で扱っています。

まとめ

  • Tree-sitter + MCP でのトークン削減は 8-49 倍のレンジで散る。倍率は変更の影響範囲の広さに反比例
  • 「変更ファイル本体は 6.8%、残り 93.2% は保険」という状態が、そもそも middle-lost problem を招いている
  • MCP ツール数は 5 本から始める。CodeGraph の 22 ツール構成は選択エラーで逆にトークンが増えた
  • 追試は 500 行未満で組める。Python + Tree-sitter + nx.DiGraph + FastMCP の 4 部品で足りる

私は knowledge-graph 本を書いていて、これに触れ続けている手前バイアスがあります。ただ 30 PR で計測してから、Anthropic 公式 filesystem MCP で全ファイル読ませる構成には戻れなくなりました。倍率の中央値が 15 倍前後というだけでも、月額 API 費が二桁削れる規模の話です。

関連記事

ナレッジグラフ活用大全 関連書籍 ナレッジグラフ活用大全 ナレッジグラフ 活用大全 | GraphRAG・Neo4j・RDF・Property Graph・Emotion AI の実践書 書籍ページを見る →