CDKプロジェクトのAIエージェント設計 (2) — Context: 何を読ませ、何を考えさせないか
はじめに
統合運用サービス課の石井です。
前回の記事では、AIエージェントが書いたCDKコードのセキュリティ準拠を「仕組みで守る」ためのHarness設計 ― L3コンストラクト(Guide)とcdk-nagカスタムルールパック(Sensor)の二重構造 ― を紹介しました。
しかし Harness は単体では機能しません。AIが正しいコンストラクトに辿り着けなければ、Sensorがエラーを出し続け、AIが試行錯誤を繰り返すことになります。Harnessが機能するには、その前段として AIに正しい文脈を届ける仕組み が必要です。
本記事では、AIコーディングにおける3層設計(Spec → Context → Harness)のうち Context 層 ― 「AIに何を見せるか」の設計 ― について、私たちのCDKプロジェクトでの実践を紹介します。
Spec について(本記事では深入りしない理由)
3層のうち Spec(何を作るか)も本来なら大きなテーマですが、インフラ構築の Spec はアプリケーション開発のそれとは性質が異なります。
- セキュリティ要件: 「暗号化必須」「VPC内配置」のようなリスト
- 通信・権限要件: 「AからBへのポート443を許可」の列挙
アプリケーション開発の Spec(ビジネスロジック、状態遷移、UI仕様)と比べると、形式的で箇条書きに落とし込みやすいものが中心です。そのため私たちのプロジェクトでは、セキュリティ要件の原文を専用ディレクトリに配置する・要件シートに整理するといった素直な管理で回せており、Context と Harness の設計に注力する余地が生まれました。
本記事は Context の設計に絞ります。Spec の設計論(要件の構造化・ステークホルダ調整等)は本シリーズでは扱いません。
失敗から学んだこと
失敗1: 「全部読め」問題
最初に私たちがやったのは、AIの設定ファイルに「社内セキュリティ要件は最重要テーマである。構築作業時はセキュリティ要件フォルダの内容を把握してから作業に取り組むこと」と書くことでした。
結果、AIはセッション開始直後にセキュリティ要件のドキュメントを 全サービス分 読み込みました。ECS、RDS、S3、CloudFront、Lambda ― まだ何を構築するか指示すらしていないのに・・・
セッションのコンテキストウィンドウの30%が、まだ使う予定のない情報で埋まりました。
例えるなら、離婚の裁判をするのに、弁護士が「法律は全部重要なので」と言って不動産登記法や会社法まで勉強してきたようなものです。
失敗2: 「全部書く」問題
次に試したのは、AIが常時読み込む設定ファイルにありったけの情報を詰め込むことでした。
以前の設定ファイルはこんな構造でした:
# モード選択ガイド(常時読み込み) ## キーワード検出ルール - CDK関連キーワード(CDK、Lambda、API Gateway、CloudFront...)を検出したら開発モード起動 - 調査関連キーワード(調査、AWS CLI、レポート...)を検出したら調査モード起動 ## 開発モードの動作フロー 1. 前提チェック 2. 関連ガイドの読み込み 3. 要件確認 4. サービス別標準の適用 5. ...(以下、詳細な手順が続く) ## 調査モードの動作フロー 1. 調査環境準備 2. ガイドライン参照 3. ...(以下、詳細な手順が続く)
全モードの動作フロー、キーワード検出ロジック、詳細な手順 ― すべてが1ファイルに詰まっており、セッション開始時に常時読み込まれる設定になっていました。
これも失敗でした。情報が多すぎて、本当に重要な指示が埋もれてしまいます。AIは大量のテキストの中から関連する部分を拾おうとしますが、ノイズが多いほど精度は下がります。
失敗3: 「考えさせる」問題
上記の設定にはもう一つ問題がありました。AIにキーワードを検出させ、モードを判断させ、手順を組み立てさせる ― つまり AIに考えさせる 設計になっていたことです。
「CDKというキーワードを検出したら開発モードを起動せよ」という指示は一見明確ですが、実際にはAIの解釈に委ねる部分が大きく、同じ入力に対して毎回微妙に異なる挙動をしていました。
具体例を挙げます。「アカウント初期設定をやって」と3回頼んだところ、初回はAWS CLIで直接リソースを作成し、2回目はCloudFormationテンプレートを書き始め、3回目はCDKで実装しようとしました。どれも「アカウント初期設定」には違いありませんが、アプローチが毎回違います。さらに同じCLI方式でも、リソース作成の順序やエラーハンドリングの有無がセッションごとに変わりました。
共通する構造
3つの失敗に共通するのは:
- 「量を渡せば質が上がる」は必ずしも成立しない — 関係ない情報が多いほど、関係ある情報の効果が薄まる
- 「AIに判断させる」とばらつく — 推論のたびに結果が変わる
必要なのは「何を渡すか」ではなく「何を渡さないか」、そして「何を考えさせるか」ではなく「何を考えさせないか」の設計でした。
解決: 階層型ドキュメント + ルーティング
エントリーポイントは軽く
現在のエントリーポイントファイル(AIがセッション開始時に最初に読むファイル)は、コンテキスト消費が約3%に収まっています。書いてあるのは:
- プロジェクトの全体像(何のリポジトリか、スタック構成)
- 絶対に守るべきルール(「このコンストラクトを使え」等)
- 作業ガイドテーブル(後述)
詳細な手順や要件の原文は一切含みません。
実際のエントリーポイントファイル(約270行・19KB)の章立てはこうなっています:
# CLAUDE.md — AI Agent Context ## プロジェクト概要 ← 3行で「何のリポジトリか」 ## 2層スタック構成 ← パイプライン / サービスの役割分担 ## 設定ファイル ← 案件カスタマイズ時に触る箇所 ## セキュリティ準拠 ← 「このコンストラクトを使え」ルール ## AI向け作業ガイド ← ★ ルーティングテーブル(後述) ## 開発ワークフロー ← synth必須、コミットフォーマット ## 品質保証の3層構造 ← Spec / Context / Harness の対応表
ポイントは、各セクションが 「何をすべきか」のルール であって 「どうやるか」の手順 ではないことです。手順は docs/ 配下に分離し、ルーティングテーブル経由で必要なときだけ読ませます。
※ 多くのAIコーディングツールには、プロジェクトのエントリーポイントとなるファイルの仕組みがあります(Claude Code の CLAUDE.md、Cursor の
.cursor/rules/等)。私たちのプロジェクトでは複数のAIツール利用者が混在するため AGENTS.md という共通エントリーポイントを採用しています(実体は CLAUDE.md に置き、AGENTS.md はそのシンボリックリンク。どのツールから読んでも同じファイルに辿り着きます)。AGENTS.md は 2026年現在、OpenAI Codex や Cline 等のツールも認識する de facto 標準として広がりつつある形式ですが、この選択の背景については次回記事で補足します。
作業ガイドテーブル = ルーティングテーブル
エントリーポイントファイルの中核にあるのが、以下のようなテーブルです:
AI向け作業ガイド(作業前に該当ドキュメントを読むこと)
| 作業内容 | 事前に読むファイル |
|---|---|
| サービスリソースの追加・修正 | docs/service-stack/README.md |
| CI/CDパイプラインの編集 | docs/pipeline-stack/README.md |
| アーキテクチャ・命名規則の確認 | docs/ARCHITECTURE.md |
| L3コンストラクトの確認 | docs/service-stack/CODEARTIFACT-CATALOG.md |
| 要件ヒアリング | tools/requirements/construction_template.md |
| セキュリティ準拠コンストラクトの開発 | docs/development/CONSTRUCT-DEVELOPMENT.md |
| AWS構成図の自動生成 | docs/architecture-diagram/AI-AGENT-SPEC.md |
これはネットワークのルーティングテーブルと同じ発想です。パケット(作業指示)の宛先に応じて、どの経路(ドキュメント)に転送するかを定義しています。
AIは作業指示を受けたとき、このテーブルを参照して 該当するドキュメントだけ を読みに行きます。ECSの構築を頼まれたらサービススタックのドキュメントだけ読む。パイプラインの修正ならパイプラインのドキュメントだけ読む。
以前の「キーワードを検出してモードを判断する」設計との違いは明確です:
| 以前 | 現在 | |
|---|---|---|
| 判断主体 | AIがキーワードから推論 | テーブルが明示的に指定 |
| 読み込み範囲 | モード全体の手順を常時ロード | 該当ドキュメントだけ遅延ロード |
| ばらつき | AIの解釈次第で変わる | テーブルの定義通りに動く |
遅延ロード
この設計のポイントは 遅延ロード です。
- セッション開始時: エントリーポイントファイルだけ読む(3%)
- 作業指示を受けた時: 該当ドキュメントを読む(必要な分だけ追加)
- 別の作業に移った時: 別のドキュメントを読む
プログラミングの遅延評価と同じで、「使うときまで評価しない」ことでリソースを節約しています。
Spec との接続
ここで導入で触れた Spec の話と繋がります。
セキュリティ要件の原文はファイルとしてリポジトリに存在します。しかし ファイルとして存在するだけでは、AIにとっては存在しないのと同じ です。
ルーティングテーブルに「セキュリティ要件の確認 → docs/security/README.md」という導線があって初めて、Spec が Context として機能します。逆に言えば、ルーティングテーブルに載っていない情報は、AIの判断に影響を与えません。
これは意図的な設計です。「全部読め」で失敗した経験から、何を読ませないか を明示的に制御する仕組みが必要でした。
なお、ルーティングテーブル自体の更新は通常のコード変更と同じフローで管理しています。新しい作業カテゴリが増えたとき(例: 新しいAWSサービスの採用)、担当者がテーブルに行を追加し、PRレビューを通す。テーブルの変更履歴は git log で追跡できるため、「いつ・誰が・何を追加したか」は常に明確です。
もう一つの原則: 「考えさせない」設計
問題: 自律判断型の定義はばらつく
失敗3で触れた通り、「AIに考えさせる」設計はばらつきを生みます。この問題は作業手順の設計でも同じ構造で現れました。
当初、作業手順を自律判断型で定義していました。「アカウント初期設定の作業」「パイプライン監視の作業」のように、目的とゴールだけ示してAIが状況に応じてやり方を考える前提の設計です。
しかしこれだと 同じ作業を頼んでも、毎回微妙に違う手順で実行される 問題が起きました。AIは文脈から「最適な手順」を推論しようとしますが、推論のたびに結果がばらつきます。
解決: スクリプト化とパッケージ化
私たちが辿り着いたのは、AIに考えさせない という発想です。
- 作業手順はスクリプトとして固定する(シェルスクリプト、Python CLI)
- 手順書は「判断材料」ではなく「実行手順」として書く
- AIの役割は「手順を考える」ではなく「手順を実行する」に限定する
これらのスクリプトは tools/ 配下に作業テーマごとに整理しています:
tools/ ├── construction/ # 構築(アカウント初期設定、CLI、ドキュメント生成) │ ├── account-init/ # 初期設定スクリプト群(VPC作成、SecurityHub設定等) │ └── src/ # 構築CLI(Python) ├── operations/ # 運用(監視、障害調査、手順書作成) │ ├── incident-research/ # 障害調査スキル(Datadog + AWS MCP連携) │ ├── create-manual/ # 運用手順書テンプレート │ └── security-check/ # セキュリティ準拠チェック ├── requirements/ # 要件ヒアリング └── utility/ # ユーティリティ(Atlassian連携、プロファイル管理等)
AIは指示を受けたら該当カテゴリのツールを実行するだけで済むようにしています。例えば「パイプライン監視」であれば以下のようなスクリプトです:
#!/bin/bash
# tools/operations/poll-pipeline.sh — パイプライン監視
# Usage: bash tools/operations/poll-pipeline.sh <pipeline-name> <profile> [interval]
PIPELINE=$1; PROFILE=$2; INTERVAL=${3:-25}
while true; do
STATE=$(aws codepipeline get-pipeline-state --name "$PIPELINE" --profile "$PROFILE" --region ap-northeast-1 --output json 2>/dev/null)
echo "$STATE" | jq -r '.stageStates[] |
"\(.stageName): \(.latestExecution.status // "N/A")"'
# 全ステージ成功なら終了
if echo "$STATE" | jq -e '[.stageStates[].latestExecution.status] | all(. == "Succeeded")' > /dev/null 2>&1; then
echo "✅ Pipeline succeeded"; exit 0
fi
# 失敗ステージがあればエラー詳細を出力
FAILED=$(echo "$STATE" | jq -r '.stageStates[] |
select(.latestExecution.status == "Failed") |
.actionStates[] | select(.latestExecution.status == "Failed") |
" ❌ \(.actionName): \(.latestExecution.errorDetails.message // "unknown")"')
[ -n "$FAILED" ] && echo "$FAILED" && exit 1
sleep "$INTERVAL"
done
AIに「パイプラインの状態を確認して」と頼むと、bash tools/operations/poll-pipeline.sh cp-myproject-dev-pipeline saml 25 を実行するだけです。「どうやって確認するか」を考える余地がありません。
さらに、各作業パッケージには最後に検証スクリプトを実行するステップを組み込んでいます。アカウント初期設定であれば設定値の確認テスト、セキュリティ要件であれば準拠チェックスクリプトの実行です。作業の実行だけでなく、結果の検証までスクリプト化することで、「実行→検証→完了」の一連の流れからAIの判断を排除しています。
これは単に判定を自動化しているだけではありません。人間があるべき姿を テストという形で事前に定義しておく ことで、AI は振り回されず、成否判定も曖昧にならずに済みます。AI と協業する上では、人間の役割が「AI の出力を事後に判定する」から「事前に到達すべき姿を示す」方向にシフトしつつある、とも言えます。
Context の二面性
この経験から、Context の役割には二面性があることが分かりました:
- 判断材料を渡す — 「このセキュリティ要件を満たせ」(AIが考えて実装する)
- 判断させない仕組みを渡す — 「この手順で実行しろ」(AIは実行するだけ)
どちらを使うかは作業の性質で決まります:
| 作業の性質 | Context の渡し方 | 例 |
|---|---|---|
| 創造的判断が必要 | 判断材料を渡す | リソース設計、アーキテクチャ検討 |
| 再現性が必要 | 手順を渡す | デプロイ、初期設定、監視 |
100回やってほぼ100回同じ結果が欲しい作業に、AIの「創造性」は不要です。むしろ結果のばらつきを招く要因になります。
ただし、すべてをスクリプト化すればよいわけではありません。仕様が固まる前にスクリプト化すると、変更のたびに書き直しが発生します。「いつ固定度を上げるか」のタイミング判断は第3回で詳しく扱います。
まとめ
AIのコンテキストウィンドウは有限であり、「量を渡せば質が上がる」は必ずしも成立しません。
私たちが実践しているContext設計の原則は3つです:
- エントリーポイントは軽く — 全体像とルールだけ。詳細は持たない
- ルーティングテーブルで遅延ロード — 作業テーマに応じて必要なドキュメントだけ読ませる
- 再現性が必要な作業は考えさせない — スクリプト化・パッケージ化で判断の余地を排除する
前回記事の Harness(Guide + Sensor)と合わせると、全体像はこうなります:
- Context が正しい情報を正しいタイミングで届け
- Guide(L3コンストラクト)が正解の型を提供し
- Sensor(cdk-nag)が逸脱を検出する
この3つが揃うことで、AIの出力が「正しい方向に」「短いループで」収束します。
次回予告
次回は、ここまで紹介したHarnessとContextの設計を前提に、人間が介在しない自律運用 ― ダークファクトリー ― をどう設計するかについて紹介します。「人間は疲れないがトークンが疲れる」問題、MCP vs SKILL vs CLIのトレードオフ、そして複数AIが同じリポジトリで作業する環境での知識共有と追跡の仕組みを掘り下げます。
参考文献
- 前回記事: 「CDK × Harness Engineering — AIが書いたインフラコードのセキュリティ準拠を仕組みで守る」(本シリーズ第1回)