こんにちは。大規模金融システムでSREをやっているshungineerです。
AIエージェントにターミナルを触らせると、コードを書くだけでなく、テストやデプロイ、エラー調査までかなり任せられるようになってきました。
とはいえ、毎回「次はこのファイルを直して」「今度はデプロイして」とチャットで指示していると、結局こちらが張り付くことになります。便利なんだけど、思っていたほど楽ではない。
そこで今回は、Git初期化直後の空っぽのリポジトリに、要件と制約を書いたMarkdownの計画書を1枚だけ置いて、どこまで自走できるか試しました。
利用したモデルはGemini CLIのGemini-3.5-flashです。安くて速いのでトイルや軽い検証を任せるときはお勧めです。
題材にしたのは、CloudflareのIP登録をセルフサービス化するPoCです。私たちのチームでは基盤にGoogle Cloudを使っているので、Google Forms、Pub/Sub、Cloud Run、GitLab、Google Sheetsをつないだ小さな仕組みを作らせました。
ここでいう「計画書1枚」は、AIへの入力が1ファイルだったという意味です。実行環境までゼロから用意したわけではありません。AIエージェントから run_shell_command と replace を使え、gcloud、Terraform、Git、各APIやMCPを呼び出せる状態は用意しています。
結果として、コード生成、単体テスト、Terraformでのデプロイ、Cloud Runのエラー調査、Google Sheetsの更新、最後のConfluence報告書まで、1日で一通り動かせました。
特に楽だったのは、コードを書かせる部分より、失敗したあともログを調べて修正し、再デプロイまで続けて任せられたことです。
Cloudflare申請の自動化
これまで、アプリチームからCloudflareのIPアドレス追加・削除を依頼されるたびに、SRE側で次の作業をしていました。
- 申請内容を確認してリリース判定資料を作る
- TerraformのIPオブジェクトと説明文を書き換え、GitLabにMRを作る
- 変更後にGoogle Sheetsの設計書を更新する
正直、あまり面白い仕事ではありません。
SREとしては手を引きたい。一方で、Cloudflareに詳しくないアプリチームへTerraform編集まで渡すのも怖い。IP制限を間違えればアクセス制御にそのまま影響しますし、入力ミスで意図しない範囲を許可するような事故は避けたいところです。
そこで、アプリチームにはGoogle Formsだけを触ってもらい、その後ろを自動化する構成にしました。
- アプリ担当者がGoogle FormsからIP追加・削除を申請する
- Google Apps Script(GAS)が入力を受け取り、Pub/Subへメッセージを送る
- Cloud RunのPythonコンテナがメッセージを受けて処理する
- Cloud Runが対象リポジトリをcloneし、Terraformの対象箇所を編集してGitLab APIからMRを作る
- 同じ処理の中でGoogle Sheetsの設計書も更新する
この構成であれば、アプリチームは使い慣れたGoogleフォームに入力するだけで、自動でGitLab上にMRまでが起票されます。さらに、入力された値はPythonで厳密にバリデーション・整形パースした上でTerraformに反映されるため、アプリチームが自力でコードを編集して壊してしまう心配もありません。
この自動化を実証するため、Gitリポジトリの中は「コードも、Dockerfileも、Terraformコードも何一つ存在しない、完全に空の更地」の状態から、この要件とセキュリティ制約をまとめた「計画書(md)」を1枚用意し、AIエージェントによる検証をスタートさせました。
サブエージェントの分担
リポジトリにはコードもDockerfileもTerraformもありません。そこに要件と制約を書いた計画書を置き、実行側のAIエージェントにはそのファイルだけを読ませました。
計画書には、少なくとも次の内容を書きました。
- 作る仕組みの要件
- 変更してよい範囲(
terraform/main.tfと自分のPythonコード。variables.tfなど、PoCに必要なファイルの新規作成は可) - 受け入れ条件(重複IP、複数IP、不正なIP形式、説明文不足の扱い)
- CIDRの入力ミス、同時実行等のリスク洗い出し
今回は、計画、実行、RV(レビュー)の工程ごとにサブエージェントを呼び出し、それぞれ別セッションで実施しました。
まず計画用のサブエージェントに要件や制約を渡して計画書を作らせます。次に実行用のサブエージェントを別セッションで呼び出し、計画時の会話履歴は渡さず、計画書とリポジトリ内のファイルを入力として実装やコマンド実行を任せました。実装後のRVも、さらに別のサブエージェントを呼び出して行っています。
狙いは、実行側が何を根拠に作業したのかを追いやすくすることです。計画時の会話は引き継がず、入力を計画書とリポジトリ内のファイルに絞りました。RVも、実装したサブエージェントとは別のセッションから確認させています。
同一のコンテキストで実行させてしまうと、計画段階の思い込みやバイアスを実行側がそのまま引き継いでしまい、客観的な検証やデバッグができずに暴走するリスクがあるからです。
さらに技術的な理由として、過去の対話履歴など余計な情報が蓄積される(コンテキストが長くなる)ほど、AIの注意(Attention)が散漫になり、指示の正確性やコード生成の精度が落ちるという問題もあります。常にコンテキストをクリーンに保つことが、AIエージェントのパフォーマンスを引き出す最大の鍵です。
同様に、「変更コードを適用するAI(実行者)」と「その変更内容をレビューするAI(レビュアー)」のコンテキストを完全に分けることも大切です。同一コンテキストで自己の変更をレビューさせると自作自演の形骸化したチェックに陥るため、完全に情報の共有を持たない別のAIインスタンスに相互チェック(レビュー)させなければなりません。
今回は、完全に空のクリーンなコンテキストから実行側のAIを立ち上げ、客観的なデータとして計画書(md)だけを渡して実装を開始させました。
実行用のサブエージェントは、最初に必要なディレクトリを作り、Terraformの配列構造を書き換えるPythonスクリプトを実装しました。そのあと、計画書に書いていた受け入れ条件から単体テストも作っています。
今回入れたのは、たとえばこのあたりです。
- すでに登録済みのIPは追加しない
- カンマ区切りで渡された複数IPを処理できる
- 不正なIP形式をTerraformへ書き込まない
誤ったIP形式や変な記述が入ってきても、スクリプト側で徹底的に弾く、あるいは整形する。このバリデーションをクリアして、初めて綺麗なHCLフォーマットのTerraformコードが生成されるロジックになっています。テストで落ちたところは、自分でコードを直してもう一度テストを実行していました。
続いて、スプレッドシート設計書との同期を行うための、API クライアントロジックの実装に入りました。ローカルの認証を用いて、模擬 tfplan.json のパースから実機スプレッドシート設計書の特定行を書き換えるスクリプトを作り、ローカル検証の段階で、実際にスプレッドシート設計書が正しくアップデートされることを確認。目の前でスプレッドシートのセルが勝手に書き換わったのを見たときは、普通に感動しました。
GCPへのデプロイ
ローカルで一通り動いたので、次はGoogle Cloudへ持っていきます。
AIエージェントは、許可していた範囲で variables.tf や main.tf を作り、Cloud RunやPub/Subなど、PoCに必要なリソースをTerraformで作成しました。
cd terraform
terraform init
terraform apply -auto-approve
今回は検証環境でのPoCだったので -auto-approve まで許可しています。本番環境であればもちろんapplyは厳禁です。
デプロイ自体は通りましたが、テスト用のPub/Subメッセージを送るとCloud RunがHTTP 500で落ちました。
ここからがAIエージェントの本領発揮です。
AIは gcloud logging read でCloud Runのログを検索し、GitLabのclone時に403 Forbiddenになっていることを見つけました。
ここで面白かったのは、その後です。
同じGCPプロジェクト内で正常に動いている別のCloud Runサービスを gcloud run services describe で参照し、GitLabへ出ていく通信が共有VPCコネクタ経由になっていることを見つけました。その設定を参考に、自分の main.tf へ vpc_access を追加しました。
以下のプロジェクト名とコネクタ名は、公開用のダミー値です。
vpc_access {
connector = "projects/example-host-project/locations/asia-northeast1/connectors/example-vpc-connector"
egress = "ALL_TRAFFIC"
}
ここで、AIエージェントに「自ら実行」させてデバッグを任せるにあたり、「修正してよい対象範囲(スコープ)」を事前に絶対的なルールとして計画書に明示しておくことが不可欠です。
エラーを解消するためだからといって、AIが勝手に関係のない他チームの共通リソース設定や、セキュリティポリシー用のファイルを直そうとする(スコープを逸脱する)のを防ぐためです。今回は「修正してよいのは terraform/main.tfなどのPoC用資材および自身のPythonコードのみであり、他は一切変更してはならない」と、変更可能な対象範囲を明確に定義して実行させました。
Cloud Runの認証
ローカルで動いたスプレッドシート同期用のコードを Cloud Run 環境へ持っていくにあたり、認証方法を切り替える必要がありました。
ローカルでの個人用 gcloud 認証から、サービスアカウントの ADC(Application Default Credentials)によるキーレス認証 への切り替えも, AIエージェントにコードを改変させ、安全に設定を完了させました。
秘密鍵をコンテナに持たせることなく、サービスアカウントの権限を利用してGitlab APIおよびSheets API 認証情報をロードする Python コードが生成されました。
これにより、GAS からの申請、Pub/Sub 経由の Cloud Run 起動、GitLab への MR 自動起票、およびスプレッドシート設計書の自動更新まで、コードを手動で書き換えることなくシームレスに連携させることができました。
Confluenceへの報告書作成
最後に、MCP経由でConfluenceへ検証報告書も作らせました。
検証MRのリンク、テスト結果、実装した仕様、残っているリスクなどをまとめてページにしています。Confluenceの画面を開いて、結果をコピペして整形する作業がなくなったのはかなり楽でした。
計画書には、CIDRの入力ミスや同時実行などのリスクを洗い出すよう書いていました。
生成された報告書を見ていたら、トークン期限切れへの対策が「SREチームが定期的に手動でローテーションする」になっていました。
あれだけ自動化にこだわっておきながら、結局そこは「人間の気合い(手作業)」でカバーする結論を導き出しており、人間の妥協や現実的な諦めをそのまま見透かされて引き継がれたようで、妙に人間味があって笑ってしまいました。
ともあれ、人間が Confluence 画面を開いてチマチマとエディタをいじることなく、見栄えの良い報告書が最初から揃った状態で自動で起票されたのは、素真面目にものすごく便利です。
まとめ:AIエージェントに仕事を丸投げするための3つの割り切り
更地の状態から、AIエージェントにCLIを握らせてシステム全体を立ち上げ、スプレッドシート設計書を更新し、Confluenceの報告書作成までの一連の流れを、わずか1日で終えることができました。
今回の検証を通じて、AIエージェントを現場の「優秀なアシスタント」として使いこなすためには、3つの重要な割り切り(操縦のツボ)があると感じました。
1. 細かい指示をチャットで送るのをやめ、計画書(md)を最初に叩き込む
AIエージェントに対する指示は、その都度の細かい命令(「次はここを直して」「このコマンドを実行して」)ではなく、システム構成、最終的なゴール、制約事項を明確にした「1枚の計画書(md)」を最初に提示するのが一番スムーズです。
計画書の作成自体は、人間が要件を箇条書きのメモレベルでまとめて、AIに作成させる方法で十分うまくいきます。
もちろん不明点を勝手に推測させずにこちらへ質問するよう促しましょう。
2. コードの提案だけに留めず、自ら実行してデバッグさせる
AIを「コードを提案するだけの存在」に留めるのはもったいないです。run_shell_command(ターミナル実行)やファイル編集の権限を丸投げし、実際にコマンドを動かし、エラーログを読み込み、自らパッチを当ててデバッグのループをAI自身に回させることで、開発速度は劇的に向上します。
ただし、AIが自ら実行して修正・編集してよい対象範囲(ファイル名やディレクトリの境界)を、事前に絶対的なルールとして明示することが不可欠です。この境界線を引いておかないと、AIは目の前のエラーを消すためだけに、関係のない共通のインフラやセキュリティ設定を勝手に書き換え、重大な波及障害を引き起こす恐れがあります。
3. 「計画者」「実行者」「レビュワー」のコンテキストは完全に分ける
AIエージェントを安全に本番運用に載せるための最大の鉄則です。計画書を作成するAI、実行するAI、そして変更をチェックするAIのコンテキストをサブエージェントの呼び出しで完全に分け、情報(履歴やメモリ)を共有させないことは非常に有効です。
コンテキストを共有したままだと、計画側の思い込みや自己の変更に対する甘えを実行・レビュー側が無批判に引き継いでしまう可能性があります。また、過去の対話履歴など余計な情報が蓄積される(履歴が長くなる)ほどAIの注意(Attention)が散漫になり、コード生成や判断の精度が低下する可能性があります。安全な自律運用のために、各ロールごとに完全にクリーンなコンテキストを新規に割り当てる設計にすることが大切です。
🏁 最後に
検証終了後、不要になったインフラを terraform destroy で完全に元の更地に戻すまで、すべてをスムーズに終えることができました。
AIエージェントにCLIを握らせてインフラを自動化する時代、私たちは「AIエージェントの爆発的なスピード」を享受しつつも、「暴走を防ぐためのブレーキ」をセットで設計していくことが求められています。
最後までお読みいただき、ありがとうございました!