
open-code-reviewをCIに組み込もうと調べ始めると、「ハイブリッドアーキテクチャ」「行レベルコメント」「Alibaba社内で実戦投入済み」という言葉が並んでいます。
実際に手を動かす前に把握しておきたいのは2点——なぜそのアーキテクチャが必要なのか、そしてCIに組み込んだ後にどこで手間がかかるか。
その2点を実装レベルで掘り下げます。
diffをLLMに丸投げすると何が起きるか
PRのdiffをそのままLLMに投げるアプローチは、直感的でシンプルに見えます。
でも実際に使い始めると、じわじわと問題が積み上がってきます。
コンテキスト不足 の問題があります。
diffには「何が変わったか」しか映っていません。
変更されたメソッドの呼び出し元や、プロジェクト全体のアーキテクチャ上の制約はdiffだけでは見えません。
「このnullチェックは不要では?」とLLMがコメントしても、呼び出し元で保証されているかどうかはdiffだけでは判断できないわけです。
もう一つが position drift(位置ずれ)です。
GitHub Pull Request Review APIでは、コメントの位置を「ファイルの絶対行番号」ではなく「diffハンク内のposition」で指定しなければなりません。
LLMが「42行目に問題がある」と答えても、そのままAPIに渡すとコメントがずれたりエラーになったりします。
diffをパースしてpositionを計算する実装を持たないツールは、ここで詰まりがちです。
大きいPRになると、さらに別の問題が出てきます。
ファイル数が増えるとLLMのコンテキストウィンドウが圧迫されて、後半のファイルがまともにレビューされなくなります。
NPEやSQLインジェクションのような「決まったパターンがある」脆弱性は、LLMに毎回うまく思い出してもらうしかなく、モデルのバージョンや設定によって検出結果が変わります。
PR-AgentやCodeRabbitも、基本的にはdiff+LLMという構造の上に工夫を積み重ねています。
open-code-reviewが採用したのは、そもそもその構造を変えるというアプローチです。
「ルールエンジンが先、LLMが後」という順序の意味
open-code-reviewの設計の核心は、処理の 順序 にあります。
決定論的なルールエンジンが先に走り、LLMエージェントがその結果を踏まえて補完する役割で登場する二段構えです。
ルールエンジンが担う検出クラスは次のとおりです。
- NPE(NullPointerException):nullチェックなしのメソッド呼び出しパターン
- スレッド安全性:共有状態へのアクセスで同期が欠けているパターン
- XSS:ユーザー入力をエスケープなしにDOM操作へ渡しているパターン
- SQLインジェクション:クエリ文字列に変数を直接結合しているパターン
これらは確率に依存しません。
検出結果は毎回同じです。
LLMエージェントが補完するのは、ルールエンジンが見つけられなかった複雑な論理的問題や、コードベース全体の文脈を踏まえた判断が必要な箇所です。
エージェントはdiffだけを見るのではなく、 file_read や code_search といったツール呼び出しでリポジトリ全体のコンテキストを参照できます。
「変更された関数がリポジトリ内のどこから呼ばれているか」を確認しながらレビューできる設計です。
公式READMEのAACR-Bench(50のOSS・200件のPR・10言語・80名以上のシニアエンジニアによる1,505件のアノテーション)では、同じモデルを使ったClaude Codeとの比較でトークン消費が約 1/9 に抑えられ、PrecisionとF1スコアが上回っています。
その代わりRecallは意図的に低く設定されています。
AIレビューツールが嫌われる最大の理由は「的外れなコメントが多すぎて重要な指摘が埋もれる」ことです。
open-code-reviewは「見逃しが出てもいい、その代わり指摘したものは正確に」という方向に振り切っています。
ルール検出と行コメントの仕組みを理解する
ルールエンジンの基本的な発想は「差分の追加行を舐めながら、問題パターンを捕まえる」というものです。
open-code-reviewの実装はGoで書かれていますが、概念を把握するために擬似コードで示します。
# NPE検出の概念的なサンプル(擬似コード。実際の実装はGoで書かれています)
def detect_npe_risk(diff_lines):
issues = []
for i, line in enumerate(diff_lines):
if not line.startswith('+'): # 追加行のみ対象
continue
if re.search(r'\.(\w+)\(', line):
context = diff_lines[max(0, i-5):i]
has_null_check = any(
'!= null' in c or 'Objects.requireNonNull' in c
for c in context
)
if not has_null_check:
issues.append({
'diff_position': i,
'type': 'NPE_RISK',
'message': 'Potential NPE: null check not found before method call'
})
return issues
XSSも同様の発想で、ユーザー入力をエスケープなしにinnerHTMLへ渡しているパターンを追います。
「ルールで確実に拾えるもの」と「モデルに聞かなければわからないもの」を最初から分けているのが、この設計の肝です。
検出結果をGitHubのPRに付ける部分が、もう一つの設計上のポイントです。
GitHub Pull Request Review APIでは、コメントの位置を position という値で指定します。
ファイルの絶対行番号ではなく、diffのハンク内での相対的な位置です。
{
"body": "Potential NPE: null check not found before method call",
"commit_id": "abc123def456",
"path": "src/main/java/com/example/UserService.java",
"position": 12
}
positionが1つずれるだけでAPIはエラーを返します。
diffをそのまま投げるツールで行番号ズレが起きやすい原因はここにあります。
open-code-reviewはdiffをきちんとパースして追加行・削除行・コンテキスト行を1行ずつカウントしながらpositionを計算する処理をツール側で持っています。
GitHub Actionsへの組み込み:最小構成のYAMLと必要なシークレット
公式アクション(alibaba/open-code-review@main)を使えば、インストールステップは不要です。
ocrのインストール・PR情報の取得・diffの計算・コメント投稿まで、アクション側で一通り処理します。
name: AI Code Review
on:
pull_request_target:
types: [opened, synchronize, reopened]
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: alibaba/open-code-review@main
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
llm_api_key: ${{ secrets.LLM_API_KEY }}
llm_model: anthropic/claude-sonnet-4-5
llm_url: https://openrouter.ai/api/v1
トリガーに pull_request_target を使うのは、forkからのPRでもシークレットにアクセスできるようにするためです。
pull_requestトリガーではforkリポジトリのシークレットが使えず、LLMのAPIキーを渡せなくなります。
CLIで手動構成する場合、OpenRouter経由とAnthropic nativeでコマンドが変わります。
# OpenRouter(OpenAI互換)経由
ocr config set llm.url https://openrouter.ai/api/v1
ocr config set llm.auth_token sk-or-xxxxxxxxxxxx
ocr config set llm.model anthropic/claude-sonnet-4-5
# Anthropic native
ocr config set llm.url https://api.anthropic.com
ocr config set llm.auth_token sk-ant-xxxxxxxxxxxx
ocr config set llm.model claude-sonnet-4-5
シークレットはリポジトリの Settings → Secrets and variables → Actions から登録します。
GitHub Appを使う場合はApp IDとPrivate Keyも別途必要です。
書き忘れやすいのが、permissionsの pull-requests: write です。
これがないと、レビュー処理が走っても最後のコメント投稿でパーミッションエラーになります。
最初に組み込む際に引っかかりやすいポイントです。
実運用で最初につまずくポイント
CIに組み込んだ直後に気になりやすいのは、ルールエンジンの 誤検知 です。
検出は確定的で毎回同じ結果が出る一方、コンテキストを考慮しない静的解析なので「この変数は上位レイヤーで必ずnullでないことが保証されている」といったケースは素直に誤検知になります。
ルールを全部有効にして1〜2週間ほど運用し、「このルールは自分たちのコードベースでは雑音が多い」と判断したものを個別に無効化していくのが現実的なアプローチです。
最初から全ルールを細かくカスタマイズしようとすると、設定の手間と得られる恩恵のバランスが崩れます。
コストについては、実際に動かしてみるまで感覚がつかみにくいのが正直なところです。
トークン消費が約1/9というのは数字だけ見ると優秀ですが、「同じモデルを使った場合」の比較です。
claude-sonnet系をそのまま使えばコストはそれなりにかかります。
2週間ほどデフォルト設定で動かして実際のコストを計測してから、軽量モデルへの切り替えを検討するのが一番無駄がないアプローチです。
チームへの展開で忘れがちなのが、 Recallを低く抑えた設計 であることの共有です。
「このツールが何も言わなければ安全」という受け取り方をされると困ります。
AIレビューは追加の安全網であって、人間のレビューを置き換えるものではない——この認識を最初に宣言しておくだけで、ツールへの過剰な期待や失望をかなり減らせます。
「AIのコメントはnon-blockingとして扱い、マージ判断は人間が行う」と運用ルールを最初に決めておくと、開発者が余計なプレッシャーを感じずに使い始められます。
株式会社ホコサキは山口県宇部市を拠点に、Web制作・業務システム開発・AI活用支援・DX推進に取り組んでいます。
open-code-reviewのようなツールのCIへの組み込みや、チームへのAI導入支援についてもご相談を承っています。
お気軽に お問い合わせページ からご連絡ください。

