📒

GitHub Actions + LLM での自動レビューフローを構築する過程で気づいた Context Engineering の本質

に公開

はじめに

自動レビューの仕組み作りの過程で Context Engineering を知る

2025年2月、私たちのチームは GitHub Actions を使ってコードレビューを自動化する 「deep-review」 という自動レビューの仕組みを作り始めました。自社のプロダクトのコードレビューで使う弊社独自の仕組みです。

目的はとてもシンプルで、リーダークラスのエンジニアが PR レビューに費やす時間を減らすためです。(要するに早く帰りたかったのです)

1 PR あたり 15 分かかっているレビューを、仮に半分にできれば、10人規模のチームで月に 300〜400 PR を扱う我々にとっては、大きな効率化になります。

しかし、このシステムを進化させていく中で、私は単なるプロンプト改善やモデル選定とは異なる、より本質的な課題に直面しました。

その過程で行き着いたのが、Context Engineering という考え方です。

この記事では、deep-review (チーム独自にカスタマイズした自動レビュー機構) を 3 つのバージョンで進化させる過程を通じて得られた学びを共有します。


Context Engineering とは何か

Context Engineering は一般に、
AI が適切に推論できるよう、AIに渡す情報を構造化し、設計・制御する考え方を指します。

Anthropicは、Context Engineering を次のような問題として扱っています。

コンテキスト=LLMが出力を生成する時に投入されるトークンの集合
工学的課題=その限られた枠の中に、望ましい振る舞いに最も効く情報を キュレーション(取捨選択)し続けること

ここで重要なのは、コンテキストは“無限ストレージ”ではなく、有限の資源だという前提です。
入力が増えるほど良くなるとは限らず、むしろ長くなるほど信頼性が落ちたり、重要情報が埋もれたりします。

AIに支持する際に必要な情報をなんでも渡せば良いというわけではなく、人間が取捨選択し、構造化された情報を渡すことが必要です。

Prompt Engineeringとの違い

Prompt Engineering:主に「指示文(特にsystem prompt)をどう書くか」を最適化する
Context Engineering:指示文に限らず、履歴・外部データ・ツール結果などを含む “その時点のコンテキスト全体”をどう構成するかを最適化する


deep-review の試行錯誤

Version 1:diff だけの世界

最初のバージョンは、非常に素朴なものでした。

PR の diff をそのまま Claude API に渡し、構文エラーや明らかなミスをチェックさせる。それだけの仕組みです。

# GitHub Actions(簡略化)
- name: Get diff
  run: git diff origin/main...HEAD > diff.txt

- name: Review
  run: |
    curl -X POST https://api.anthropic.com/v1/messages \
      -d '{"messages": [{"role": "user", "content": "この diff をレビューしてください: ..."}]}'

前提として Github Actions での自動テストや、lintによる構文チェックはプロジェクトの初期から導入しており、安定して動作していました。我々は初歩的なバグや構文エラーの検出を AI レビューに期待していたわけではありません。

deep-review Version 1 が主に拾っていたのは、テストではカバーしづらく、人によって判断が揺れやすい領域でした。
動作は問題ないが、フレームワークの標準機能を使ってないコードや、実行効率の悪いコード、メソッド名が実態とずれてないか(パラメータ追加した結果、責務がわかりづらくなっている)など、コード品質をあげることをレビューの目的としていました。

deep-review Version 1 は、Rails Way から外れた命名や単純なタイポ、N+1 の可能性など、コード品質のベースラインを底上げする用途としては十分に機能していました。

ただし、Version 1にも限界がありました。
「動作は問題ないが、プロジェクトの既存コードを知っていれば書かない余計なコード」までは検出できません。

# PRのdiff
@users = User.where(status: 'active', deleted_at: nil)

このコード自体に問題はありません。しかし、user.rb を見ると

scope :active, -> { where(status: 'active', deleted_at: nil) }

同じ条件の scope が既に存在しています。User.active と書くべきでした。
こうした「車輪の再発明」は、既存コードという Context がないと指摘できません。

このような問題は、diff だけではそのコードが動作する 文脈 を把握できないため、検出できませんでした。

一方で、いくつかの問題に関しては、AI レビューならではの価値もありました。

例えば、Bullet(N+1を検出するパッケージ) が「実際に発生した N+1」を実行時に検出するのに対し、AI は diff から新しく追加されたアソシエーションアクセスを読み取り、将来的に index で使われる可能性を考慮したうえで、includes に追加されているかを確認するよう促します。

Bullet が事後検知であるのに対し、AI は予防的に指摘できる点は、明確なメリットでした。

コストは日次で $5 以下と非常に安価で、当初は十分に満足していました。
しかし同時に、もっと踏み込んだ品質改善の提案までできるはずだという確信も芽生え始めていました。


Version 2:力技で Context を集める

「情報が足りないのであれば、ありったけの情報を渡せばよい」

そのように考えて、Version 2 では 2 段構えのアーキテクチャを採用しました。
Version 1 で物足りなかった既存コードという Context がないと指摘できないことを、AI自動レビューでできるようにしたかったのです。

Step 1:関連ファイルの探索

変更ファイルごとに、関連が深いファイルを最大10個選ばせます。PRに10ファイルの変更があれば、10回の探索API呼び出しが発生します。

diff + 全てのファイルのリストから、Claude API が関連ファイルを選択してリストで送り返す

Step 2:個別レビュー

変更ファイルごとにレビューを実行します。10ファイルなら、さらに10回のAPI呼び出し。
つまり、10ファイルのPRで20回のAPI呼び出し。

Step 3: 集約

10個のレビュー結果 → 1つのコメントにまとめてPRに投稿
このアプローチにより、レビュー精度は飛躍的に向上したと感じました。

  • 関連モデル間のロジック矛盾
  • 既存のscopeやヘルパーとの重複実装

Version 1 では見逃していた問題を検出できるようになりました。
しかし、その代償は小さくありませんでした。

コストの爆発

関連ファイル最大 10 個の全文を毎回読み込むため、トークン消費量が急増しました。

  • 2025年7月の月額コスト:約 $794
  • 日次で $30〜50 が常態化

リーダーエンジニアの工数削減効果を考えれば、まだペイはしますが、やや負担が大きいと感じていました。


もっと効率的に関連ファイルを見つけられないか?

「この探索は、本当に毎回必要なのだろうか?」
PR を作成する開発者は、実装の時点ですでに次のことを把握しています。

  • なぜこの変更が必要なのか
  • どのファイルを変更するのか
  • 影響範囲はどこか
  • 想定されるリスクは何か

つまり、最も情報密度が高い文脈は、実装前の時点ですでに存在しているのです。
それを捨てて、レビュー時に AI に再発見させているのは、二度手間だと感じていました。


「Plan(実装計画)を書く能力」との出会い

ちょうどその頃、Claude は 実装前に計画を書かせる能力をすでに備えていました。
明示的な「Plan Mode」という機能があったわけではありませんが、プロンプトと運用を工夫すれば、

  • 変更対象ファイル
  • 設計方針
  • 影響範囲
  • 注意点やリスク

といった内容を Markdown として残すことは十分に可能でした。

それらは docs/plans/ 以下に保存され、PR から参照されます。

Plan には、すでに探索済みの文脈が凝縮されているということに気づきました。


Version 3:Plan-driven Review

Version 3 では、レビューの前提そのものを根本から見直しました。

Before(Version 2)

Input: diff + AI が探索した関連ファイル(最大 10 個の全文)

After(Version 3)

Input: diff + Plan + Plan に明記された必要ファイル(2〜3 個の全文)

重要な変更点

Plan は単なる補足情報ではありません。

レビュー時には「実装が Plan と一致しているか」そのものを検証対象にしました。

  • Plan に書かれていない変更が含まれていないか
  • Plan で宣言された変更が実装されているか
  • 実装の振る舞いが Plan の設計意図と矛盾していないか

つまり、Plan を 仕様(Contract) として扱うようにしたのです。


結果

Version 2(7月) Version 3(11月)
月額コスト $794 $87
1 PR あたり 約 $2.3 約 $0.25
削減率 - 約 90% 減
レビュー精度 高い 同等以上

探索フェーズが不要になり、トークン消費が安定しました。

しかも精度は落ちていませんでした。
それどころか、Plan と実装の不整合という、人間でも見落としがちな問題を検出できるようになりました。


Context Engineering の本質

Version 2 と Version 3 の違いは明確です。

アプローチ 特徴 コスト 精度
都度探索 AI が毎回文脈を発見する 高い 探索精度に依存する
文脈の資産化 人間の意思決定を記録する 低い 人間の知識を活用する

重要なのは、意思決定の瞬間が最も情報密度が高いという事実です。

その文脈を捨てるのか、それとも資産として残すのか。
この選択が、AI 活用のスケールを大きく左右します。


Plan Stack へ

deep-review での学びは、Plan Stack の設計思想の原点の一つになりました。

  • Plan を第一級の成果物として扱う
  • Plan を仕様としてレビュー・検証に使う
  • Plan を将来参照可能な資産として残す

これにより、

  1. レビューが高速化します
  2. AI レビューのコストが下がります
  3. 設計意図が失われません
  4. AI との協業が安定します

詳細については、以下を参照してください。

https://plan-stack.ai


まとめ

  • AI の性能向上を待つより、Context の設計を見直すべきです
  • Context は「探すもの」ではなく「残すもの」です
  • Plan を仕様として扱ったとき、AI レビューは安定します
  • Context Engineering は、AI 時代のエンジニアリングそのものです

月 $800 の API コストという痛みがあったからこそ、この気づきに至ることができました。

同じ課題を感じている方にとって、この記事が一つのヒントになれば幸いです。

補足

最近は、Claude Code のローカル実行したレビュー機能で十分かもしれません。
ローカルでレビューしたかはレビュワーは検出できないので、Github Actions でのレビューは必須にしています。

Discussion