1
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?

自律型PRレビュー基盤「Reviewers Forest」のアーキテクチャ

1
Posted at

1. はじめに:予告していた「レビュー自動化」の裏側をすべて明かします

前回の記事『AIを実装役とレビュー役に分けてローテーションし、コード品質を上げる』では、AIにコードを書かせたときに発生する数々の問題(テストの削除や弱体化、勝手な機能追加、エッジケース抜け)を取り上げました。

それらの元凶は「書いた本人(AI)が自分の成果物をセルフチェックしていること(セルフレビューのバイアス)」にあります。人間でも自分のバグを見つけるのは難しいのに、直前の推論コンテキストに支配された単一のAIセッションが客観的な批判などできるはずがありません。

前回は、この解決策として「実装役(Claude Code)とレビュー役(Codex CLI)に役割を分離し、人間が監督として手動でレビューサイクルを回すプロトコル」を紹介しました。

そして、記事の末尾でこう予告していました。

発展:レビューの自動化
慣れてきたら、PR作成→レビュー→指摘対応→再レビューのサイクルを自動化することもできます。私は自作のツールで、レビュー役のコメント投稿や、指摘への対応・再レビュー依頼までをスキルとして組み込んで回しています。このあたりはまた別の記事で紹介できればと思います。

大変お待たせしました。今回はその続編です!

前回は「手動でプロンプトやCLIを叩く運用ノウハウ」を中心にお話ししましたが、今回は概念的な話にとどまらず、「裏側で動いている自律レビュー基盤のアーキテクチャ」をがっつり解説します。

手動運用の段階から一歩進み、「PR作成 → CI待機 → 独立Reviewer起動 → インライン指摘 → 修正 → スレッドresolve → 再レビュー → 独立APPROVED判定」という一連のサイクルを完全自動化しようとすると、単なるプロンプト調整では絶対に太刀打ちできない分散システム特有の難問が立ちはだかります。

  • 実装側AIとレビュー側AIをどうやって安全に通信・連携させるのか?
  • 実装側エージェントが「レビュー待ち」の間、無駄にトークンを浪費しながらポーリングするのをどう防ぐか?
  • レビュー中にコードが更新されたり、AIが嘘の完了報告(ハルシネーション)をしたりするのをどう機械的に防ぐのか?

本稿では、これらの課題を泥臭く解決し、現在20以上のリポジトリで実際に稼働している自律型レビューインフラ「Reviewers Forest」の6つのマイクロコンポーネント構成と、Model Context Protocol(MCP)を駆使した自律レビューサイクルを徹底解説します。


2. 全体像:6つのマイクロリポジトリが織りなす「Reviewers Forest」

Reviewers Forestは、単一の巨大なモノリスツールではありません。各責務を極限まで純化し、独立して更新・デプロイ可能な6つのリポジトリ(マイクロコンポーネント)で構成されています。

一目で分かるように、サイクルは「実装側 → オーケストレーション → 独立レビュー → 実装側」という明確な循環構造を持っています。

コンポーネントの責務境界

コンポーネント 役割 厳密な責務境界
review-raven 実装側(reviewed-side) 指摘の取得、インライン返信、スレッドのresolve、修正サマリの投稿、再レビュー依頼。レビュー自体(合否判定)は絶対に行わない。
thread-owl レビュー側(reviewer-side) コード差分の客観的検証、インライン指摘の投稿、レビューVerdict(APPROVED / CHANGES_REQUESTED)の確定。依頼側の修正ワークフローには関与しない。
squirrel-notifier オーケストレーション イベント受信、CI完了待機、トースト通知、独立reviewerエージェントの起動、ローカル進捗状態(review-status.json)の公開。レビュー結果の正本は持たない。
resource-bridge-cli
(mcp-resource-subscriber)
イベント同期ブリッジ MCP Resource(review://status/...)を購読し、更新があるまでブロッキングしてCLIに結果を返す。業務判断や状態を持たない純粋な通信土管。
mcp-gateway 接続・ルーティング クライアント認証、GitHub Appトークンの中継、MCPリクエストのルーティング。
Mcp-Docker 環境配布・ゲート検証 DockerコンテナによるMCPサーバー群のホスト、エージェント用Skillの配布、完了記録の機械的検証(reviewgate validate)。

このように役割を分断することで、「実装エージェントが自分の書いたコードを勝手に承認する」余地を物理的・プロトコル的に完全に排除しています。


3. 完全自律レビューサイクルのシーケンス

では、開発者が実装エージェントに「Issue #123 を実装して」と命じたあと、どのようなシーケンスで自律レビューサイクルが回るのかを追ってみましょう。

このシーケンスの真髄は、「人間の介在を一切必要とせず、かつAIの嘘や馴れ合いを許さないチェック&バランス」が完全に自動で完結する点にあります。


4. アーキテクチャの核心:泥臭くも堅牢な5つの設計思想

このサイクルを実運用に耐えうるものにするため、Reviewers Forestには数々の泥臭くも合理的な設計が組み込まれています。特に重要な5つのポイントを紹介します。

① LLMにポーリングさせない「MCP Resource Bridge CLI」

AIエージェントに「レビューが終わるまで待って」と指示すると、初心者が作りがちなのが次のようなプロンプトやスクリプトです。

# やってはいけない実装:LLMによるポーリング地獄
while true; do
  STATUS=$(gh pr view --json reviewDecision)
  if [ "$STATUS" = "APPROVED" ]; then break; fi
  sleep 15
done

これをLLM環境で実行すると、エージェントは15秒ごとにツールを実行し、そのたびにコンテキスト履歴が膨れ上がり、レビューを待っているだけで数千〜数万トークンが溶けて消えます。最悪の場合、コンテキストウィンドウの上限に達してクラッシュします。

Reviewers Forestでは、これを解決するために専用の外部CLI resource-bridge-cli(TypeScript製)を開発しました。

実装エージェントは、PR作成後に以下のコマンドを1回叩くだけで済みます。

resource-bridge-cli review://status/scottlz0310/my-repo/42

このコマンドはOSレベルの標準的なプロセスとして待機し、MCPサーバーからのStreamable HTTP経由の更新通知(notifications/resources/updated)を受け取るまでブロックします。結果が返ってきた瞬間に1行の構造化JSONを出力して正常終了するため、LLM側のトークン消費は実質ゼロで安全に同期待ちができます。


② GitHub PRそのものを通信バスにする「投稿者の身元検証」

「実装エージェントとレビューエージェントを連携させる」と聞いたとき、多くのエンジニアは「専用のRedisやRabbitMQ、あるいは内部連携用のREST APIやDBサーバーを作ろう」と考えがちです。実は私たちも当初はそのような内部連携台帳を設計していました。

しかし、それは巨大な技術負債の始まりでした。

  • エージェント間の認証トークンはどう管理する?
  • 内部DBとGitHub上のPR状態がズレたら誰が同期する?
  • マシンユーザーアカウントの課金や権限管理はどうする?

私たちはこの複雑さをすべて捨て去り、「GitHub PRそのものを唯一無二のメッセージバス(Single Source of Truth)にする」というアーキテクチャに回帰しました。

GitHub App による厳密な身元証明

コメントや指摘の投稿は、個人のアクセストークンではなく、専用のGitHub App(thread-owl[bot] および review-raven[bot])の名義で行われます。

これにより、実装エージェントは「誰が書いたコメントなのか」を検証する際、GitHubのAPIから返ってくる author.login が正当な thread-owl[bot] であるかを確認するだけで済みます。人間や悪意あるスクリプトが偽造したコメントに騙される余地はありません。


③ 起動前CI待機ゲート:壊れたコードをレビューさせない

どれだけ高性能なLLMであっても、ビルドが通っていないコードや単体テストが落ちているコードをレビューさせるのは時間とトークンの完全な無駄遣いです。「〇〇行目でシンタックスエラーが出ています」という指摘をもらうために高価なLLMを動かす必要はありません。

常駐オーケストレーターである Squirrel Notifier は、レビューリクエストを受信すると、即座にreviewerエージェントを起動するのではなく、まずGitHub ActionsのCIステータスを監視するゲートに入ります。

[Squirrel Notifier: 起動前CIゲート]
  ├── PR #42 のコミット HEAD を取得
  ├── CIチェックを開始 (30秒間隔で確認、最大12分)
  │     ├── run 1: Pending... 待機
  │     ├── run 2: Pending... 待機
  │     └── run 3: SUCCESS (Green) 🎉
  └── すべてのCIが成功したことを確認して初めてReviewerを起動

※ ここでの確認はLLMではなく常駐アプリ(Squirrel Notifier)が行う機械的な処理なので、トークンは消費しません。

もしCIがコケた場合、Reviewerは起動されず、レビューサイクルは保留(holdReason: ciPending)されます。テストがすべてグリーンになって初めて、LLMによる高度な意味論的レビュー(設計の妥当性、エッジケース、回帰リスクの検証)が開始されます。


④ HEAD SHA による決定論的整合性(競合の排除)

分散環境で最も恐ろしいのが、「レビュー対象が途中で動いてしまうこと(レースコンディション)」です。

例えば、Reviewerがコードを読んでいる最中に、実装側が焦って追加のコミットをpushしたり、force-pushしたりしたら何が起きるでしょうか?Reviewerは古いコードに対して指摘を出し、PR上の行番号はズレ、レビュー結果は破綻します。

Reviewers Forestでは、サイクル全体で徹底して headSha(Gitコミットハッシュ)の一致 を検証します。

  1. Enqueue時: 実装エージェントが待機を開始した時点の headSha を記録。
  2. Reviewer実行時: レビュー対象のコミットSHAが待機中の headSha と完全に一致していることを検証。
  3. Verdict投稿時: Verdictのメタデータに対象の headSha を焼き込む。
  4. 待機解除時: resource-bridge-cli が受信した完了ステータスの headSha と、自分がpushしたHEADが一致しているかを照合。

もし途中でHEADが動いた場合、古いレビュー結果は無効化され、新しいHEADに対して再度CIゲートからやり直しになります。


⑤ reviewgate validate:AIの虚偽申告を許さない決定論的バリデータ

AIエージェントに「レビュー結果はどうでしたか?」と尋ねると、時に「問題なくAPPROVEDされました!」とハルシネーション(嘘の報告)をすることがあります。

私たちはLLMの「言葉」を決して信用しません。サイクルの完了判定には、Goで書かれた決定論的CLIツール reviewgate validate を必須関門として設けています。

# レビュー完了を機械的に証明するバリデーション
mcp-docker reviewgate validate --completion-file ./completion.json

このコマンドは以下の項目をGitHub APIと直接通信して冷徹にチェックします。

  • PR上の最新Verdictが真に APPROVED であるか?
  • そのVerdictを投稿したのが正規の thread-owl[bot] であるか?
  • Verdictが対象としているコミットSHAが、PRの最新HEADと1文字の狂いもなく一致しているか?
  • 未解決のインラインスレッド(Unresolved Threads)が 0件 であるか?
  • 関連するCIチェックがすべて成功しているか?

このバリデータが exit code 0 を返さない限り、実装エージェントはマージ準備完了(READY_TO_MERGE)の宣言を出すことが許されません。


5. リアルな開発裏話:AIの半ば暴走による「過剰実装」を人間が叩き落とした話

ここまで美しく整理されたアーキテクチャを解説してきましたが、実を言うと、この基盤を構築する過程で「AIエージェントの半ば暴走による過剰設計(Over-engineering)」という壮大な落とし穴にハマりかけました。

AIと日常的に開発している方なら痛感していると思いますが、AIは「コードを生成すること」に何の躊躇も痛みも感じません。そのため、手綱を少しでも緩めると、勝手に複雑怪奇なシステムを錬成し始めます。

AIが勝手に突き進もうとした「大掛かりな内部連携構想」

コンポーネント間の連携についてAIエージェントと設計を進めていた際、AIは次のような壮大で大掛かりな提案を自ら組み立て、コードを実装し始めました。

  • サービス間通信用の「専用GitHubマシンユーザーアカウント」を新規取得する
  • レビュー依頼と進捗を中央集権的に管理する「専用の内部依頼台帳APIサーバー」を構築する
  • 各エージェントの実行ログをリアルタイム中継する「観測中継ストリーミングサーバー」を新設する

「マイクロサービス同士を疎結合につなぐエンタープライズなアーキテクチャ」っぽく見えますが、個人開発〜小規模環境の視点で見ればただの悪夢です。

人間(現場監督)のツッコミと一刀両断の撤去

実装が肥大化し始めたところで、人間(現場監督)として猛烈なブレーキを踏みました。

現場監督(人間):
「おい待て。誰がその専用マシンアカウントのOAuthトークン失効や課金をメンテするんだ?」
「目の前にGitHub PRという世界最強の台帳があるのに、なんで新しく自作の『依頼台帳』を作って状態の二重管理に苦しまなきゃいけないんだ?」
「開発者のローカルPCで動いている常駐アプリ(Squirrel Notifier)がJSON(review-status.json)を吐いて、それをローカルCLIが読めば、新しい通信サーバーなんて1行も立てずに完結するだろ!」

結果として、2026年11月1日、AIが作りかけた専用台帳や内部連携コードはすべて「廃案(撤去)」と決定し、不要なコードを一掃しました。

現場監督の教訓:AIの「足し算の暴走」に人間が「引き算」を突きつける
AIエージェントは「コードを書くこと(足し算)」は天才的ですが、「コードを書かない、既存の仕組みで済ませる(引き算・YAGNI原則)」という判断は致命的に苦手です。
放っておくと、頼んでもいない内部APIや専用アカウントをどんどん増やして自らを首絞めにかかります。
前回の記事で「人間は現場監督に集中する」と書きましたが、AIが興奮して作り始めた過剰なアーキテクチャを冷徹に叩き落とすことこそ、人間にしかできない最重要の役割です。

既存のプラットフォーム(GitHub PR)とOSネイティブの仕組み(ローカルファイル・CLIパイプ)という「枯れた土台」に立ち返ったことで、Reviewers Forestは何倍もシンプルで、保守コストのかからない頑丈な基盤へと着地することができました。


6. おわりに:自律型マルチエージェント協調のリアル

昨今のAI界隈では、「ひとつの超巨大で賢いLLMがあらゆるタスクを完璧にこなす」という幻想が語られがちです。

しかし、実際のソフトウェアエンジニアリングの現場では、どれだけ賢いモデルであっても「権限の分離」「チェック&バランス」「決定論的ガードレール」がなければ、品質を担保することはできません。人間社会が三権分立やピアレビューによってガバナンスを維持しているのと同じです。

Reviewers Forestが示したのは、以下のアーキテクチャの有効性です。

  1. 実装とレビューの主権分離: 別プロセス・別エージェントによる客観的査読
  2. イベント駆動による省トークン設計: MCP Resource Subscription による待機の外部化
  3. GitHub Appによる身元確認: GitHub App名義とPRをバスにした通信
  4. 決定論的バリデーション: LLMの出力ではなく、CLIツール(reviewgate)による厳密な合否検証

単一エージェントによる「一人芝居」を卒業し、制約とプロトコルによって自律的に自浄作用が働くマルチエージェントの生態系(Forest)を構築する ── これこそが、真にスケールするAIネイティブなソフトウェア開発の未来だと確信しています。


関連リポジトリ(GitHub)

  • review-raven 🐦‍⬛:実装側ワークフロー・修正・再レビュー依頼窓口
  • thread-owl 🦉:レビュー側MCPサーバー・差分検証・Verdict投稿
  • squirrel-notifier 🐿️:WinUI 3製オーケストレーター・トースト通知
  • mcp-resource-subscriber ⚡:MCPリソース購読・CLI同期待ちブリッジ
  • mcp-gateway 🛡️:認証・ルーティングゲートウェイ
  • Mcp-Docker 🐳:MCP環境構築・Skill配布・Reviewgateバリデータ
1
0
2

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
1
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?