はじめに
鋼材切断計画の B2B SaaS TORIAI を、 人間1人 + AI 3種類で開発・運用しています。 コードを書くAI、 それをレビューするAI、 観点別にQAするAI を 役割で分けたところ、 「AI が自分の書いたコードを自分で『大丈夫です』と太鼓判を押す」 という一番危ない状態を避けられるようになりました。
この記事は、 その分業の組み方と、 実際に効いた/事故った具体例の記録です。 AI に実装を任せたいが品質が不安、 という人の参考になればと思います。
体制: 実装・レビュー・QA・判断 を分ける
| 役割 | 担い手 | やること |
|---|---|---|
| 実装 / 議長 | Claude (Claude Code) | 仕様・実装・全体設計・統合 |
| レビュー / DB | Codex (別ベンダーの coding AI) | 実装の独立レビュー、 DB migration、 重い refactor |
| 観点別 QA | subagent (code-reviewer / security-auditor / migration-checker 等) | commit 前の自動チェック |
| 判断 | 人間 (1人) | 公開可否・価格・本番DB変更・方向性 |
ポイントは 「実装したのと別の主体にレビューさせる」 ことです。 同じAIに「これ大丈夫?」と聞くと、 だいたい「大丈夫です」と返ってきます (自分の出力への確証バイアス)。 実装=Claude / レビュー=Codex や fresh-context の subagent と分けると、 片方が見落とした前提を もう片方が拾えます。
仕組み1: git worktree で実装AIを隔離する
レビューAI(Codex)に実装を任せるとき、 本番ブランチ(main)で直接やらせると事故が怖い。 そこで git worktree で隔離します。
# main とは別のディレクトリに作業ツリーを作る
git worktree add ../proj-cx -b ai/feature-x
# そのツリーで Codex を走らせる (CLI)
cd ../proj-cx
codex exec --dangerously-bypass-approvals-and-sandbox "$(cat /tmp/brief.txt)"
実装が上がったら、 人間(の議長役Claude)が 3-way merge で main に取り込みます。 fast-forward ではなく 3-way にするのは、 隔離中に main 側で進んだ別コミットを保持するためです。
git merge ai/feature-x --no-edit # 3-way。main の進捗を潰さない
git worktree remove ../proj-cx --force
これで「実装AIは隔離ツリーで自由に試す → 検証が通ってから本番へ」 という安全弁ができます。
ハマりどころ: AI CLI に渡す指示文(brief)を インラインのシェル引数に直書きすると、 バッククォートや
$()が シェルに解釈されて壊れます。 必ずファイルに書いて"$(cat brief.txt)"で渡すこと。 これで一度、 指示が無言で失敗して作業ツリーが空のまま、 という事故をやりました。
仕組み2: commit 前に subagent を並列で投げる
コードを書いたら commit 前に、 観点別の subagent を 並列で投入します。
-
code-reviewer: 正確性バグ / 命名 / 既存コードとの不整合 -
security-auditor: 認証 / RLS / 入力描画 (XSS) / 越境 -
migration-checker: DB migration が設計方針に沿うか
それぞれ 独立したコンテキストで動くので、 実装者が「当然そうなってる」と思い込んでいる前提を 容赦なく突きます。
仕組み3: 連携は「掲示板」で非同期に
AI 同士のやり取りは、 チャットで流すと消えるので、 リポジトリ内の AI_BULLETIN.md という1枚に追記していきます。 「Claude → Codex: この migration の越境チェック見て」「Codex → Claude: ここが情報漏れる」 を全部 git 履歴に残す。 後から「なぜこの設計にしたか」 を追えるのが効きます。
効いた例: AIの「それっぽい正論」を実機で潰した
ここが一番伝えたい話です。
残材在庫の登録タイミングを変える、 という変更を Codex に実装させ、 code-reviewer にレビューさせたところ、 「CRITICAL: 再印刷時に登録漏れが起きる」 という指摘が返ってきました。 一見もっともらしい。
でも 鵜呑みにせず、 実機(本番同等環境)で実際に操作して再現を試みました。 計算 → カート追加 → 印刷、 を本物のUIで動かして在庫の数を各段階で確認する。 結果:
- カート追加直後: 在庫は 増えない (狙い通り)
- 印刷後: 端材が 1本だけ登録 され、 カートはクリア
つまり登録は「印刷の確定時に1回だけ」 正しく走っていて、 CRITICAL は誤検知でした (レビューAIは「クリア後に再印刷したら」 という、 実際には起こらない経路を心配していた)。
逆の方向もあります。 別の変更では、 ユニットテストもローカルも全部緑なのに、 本番でだけ動かないバグを実機E2Eで見つけました。 原因は DB の関数の戻り値フィールド名が想定と違った (id ではなく remnant_id だった) こと。 これは 実際にログインして本物のDBを叩かないと絶対に出ない。
教訓はシンプルです。
AIのレビューは「容疑」、 実機の挙動が「判決」。
AIレビューは観点出しには最強ですが、 それ自体が真実ではない。 だから運用ルールに 「subagent の指摘は実機で再現してから直す」 を明文化しています。 誤検知を鵜呑みにして直すと、 動いていたものを逆に壊します。
正直に: AIに任せて事故ったこと
良いことばかりではないので、 やらかしも書きます。
- キャッシュ焼き付き: 変更を出荷した直後、 確認のために本番ファイルを デプロイ伝播の前に 取得してしまい、 CDN が「その時点の古い中身」 を immutable キャッシュに固定。 一瞬ユーザーが旧コードを掴む状態になりました。 すぐ気づいてキャッシュキーを振り直して復旧。 → 「新しい cache-buster URL は、 デプロイ完了まで触らない」 をルール化。
- 死にコードに配線: ある機能を、 既に呼ばれなくなっていた関数(死にコード)に配線してしまい、 実機まで気づけなかった。 → これも実機E2Eで発覚。
どれも 「実機で動かす」 工程があったから捕まえられたもので、 AIの自己申告だけで進めていたら本番に流れていました。
まとめ: 1人 + AIでも「相互監視」は作れる
- 実装するAIと、 それをレビューするAIを分ける (確証バイアスを切る)
- 実装AIは git worktree で隔離 → 検証後に 3-way merge
- commit 前に観点別 subagent を並列投入
- AIの指摘は鵜呑みにせず、 実機の挙動で最終判断する
- 人間は 判断(公開・価格・本番DB・方向性)に専念する
「AIに任せると品質が不安」 の解は、 「もっと賢い1体のAI」 ではなく、 役割を分けて相互監視させる + 最後は実機で殴る、 だと感じています。 1人開発でも、 この相互監視の構造は十分に組めます。
TORIAI について
中小の鉄鋼商社 / 切断加工向けに、 1D 鋼材の切断計画 + 残材在庫 + 営業所共有を 1 ツールで。 登録不要・Free で使えます。