件名:DevOps Agent のスキル定義におけるマルチ環境展開時のファイル構成について
■背景
現在、負荷試験時のテナント側障害調査を目的とした DevOps Agent のスキルを開発環境で
構築しています。今後、検証環境および商用環境へ同じスキルを展開する予定です。
現状のファイル構成は以下の通りです。
skills
│
└─ load-test-tenant-incident-investigation
│
├── SKILL.md 目次
│
├── references/ 症状別(What)
│ │
│ ├── task-startup-failure.md タスクが立ち上がらない・すぐ落ちる
│ ├── connection-failure.md 通信が通らない(疎通不良)
│ ├── alb-5xx-and-unhealthy.md ALB がエラー・Unhealthy
│ ├── slow-response-high-load.md 遅い(アプリ層が処理しきれない)
│ ├── aurora-serverless-bottleneck.md 遅い(DB の応答待ちで詰まっている)
│ └── autoscaling-not-scaling.md 台数が増えない
│
└── tools/ 道具別(How)
│
├── log-locations.md ログの一覧
├── athena-alb-access-logs.md Athena(ALB アクセスログ)
├── athena-vpc-flow-logs.md Athena(VPC Flow Logs)
├── athena-cloudtrail-logs.md Athena(CloudTrail)
└── cloudwatch-logs-insights.md CloudWatch Logs Insights(ECS ログ)
調査対象は ECS/Fargate + ALB 構成のマルチテナント環境です。
スキルは参照専用(read-only)で、リソースの変更操作は行いません。
■実現したいこと
現在の構成が DevOps Agent のスキルとして適切に機能することを確認したい
開発環境で作成したスキルを、検証環境・商用環境へ流用したい
記述の重複を可能な限り発生させたくない
メンテナンス効率のよい構造にしたい
■質問
Q1. ファイル構成の妥当性について
上記のファイル構成は、症状別(references)と手段別(tools)に分割し、SKILL.md を
目次として各ファイルへ誘導する設計としています。
(1) Agent は SKILL.md 以外のファイルをどのように扱うのでしょうか。
ファイルの選択基準、読み込みのタイミング、および references/ 配下から
tools/ 配下を参照するような相対パスによる相互参照の可否をご教示ください。
(2) 分割せず単一の SKILL.md にまとめる構成と比較した場合、Agent の処理に
どのような違いが生じますか。(読み込むトークン量、参照の確実性、応答時間など)
(3) ファイル数、1ファイルあたりのサイズ、階層の深さについて、上限や推奨値などの
制約がありましたらご教示ください。
Q2. 環境依存値の分離方法について
アカウント ID、リソース名、S3 バケット名、Athena のデータベース/テーブル名など、
環境ごとに異なる値があります。これらをスキル本体から分離し、環境固有の
定義ファイルのみを差し替える構成を検討しています。
(1) スキル定義内で変数や外部ファイルを参照する仕組みはありますか。
(2) 仕組みがない場合、環境依存値を扱う際に推奨される方法をご教示ください。
Q3. スキルの共有・再利用について
複数の Agent Space(環境ごとに分離を想定)で同一のスキル定義を共有する仕組みは
ありますか。環境ごとに複製する必要がある場合、更新時の同期に推奨される運用方法が
あればご教示ください。
■課題
①【済】 ソース管理がローカル(CLAUDE.md、SKILL.md)
⇒ CloudCode のレポジトリでソース管理
②【済】skills / athena-log-search が Claude Code側にある
⇒ クエリー結果をS3からマネージドに変更することで、DevOps Agent側で実行可能に
③【初回】CLAUDE.md のサイズが大きい(表現圧縮、外部化)
⇒ サイズ 474行 ⇒ 368 行 (22%削減)
④【済】DevOps Agent のファイル構成の妥当性をQAに確認する
⇒ Amazon QA にファイル構成の妥当性を質問
⑤【提案】調査フローをスラッシュコマンド化する(≒ステアリングファイル)
/investigate-triage 事象・影響+判定(quick / deep)
/investigate-quick 原因・対応
/investigate-deep-cause 原因
/investigate-deep-response 対応
investigation/ <TEST_ID>-<PREFIX>/
├── triage.json # 判定フラグ(構造化)
├── triage.md # 事象・影響
├── cause.md # 原因(quick、deep 共通)
└── response.md # 対応(quick、deep 共通)
⑥【提案】 Claude Code の依頼契約(CLAUDE.md)と Agent の受領前提(SKILL.md)
⇒ /investigate-triage 入力契約、出力契約を作成
/investigate-quick 入力契約、出力契約を作成
/investigate-deep-cause 未作成
/investigate-deep-response 未作成
⑦ NRIノウハウのスキル化(既知の障害の調査手順のスキル化)
⇒ Redmineチケットで調査依頼
⑧【説明】SKILLに人間が考える障害対応フローの動作をさせる(性能、障害対応で分ける)
⇒ 障害対応フローを整理
------------------------------------------------------------
⑧ SKILLが狙い通りに選ばれるか
⑨ Container Insight の導入(既存メトリクスでコンテナ、タスク単位の情報取得が可能)
⑩ Terrafromソース、仕様書のRAG化
■■■ DevOps Agent
■ 依頼として受け取る前提の情報(= 入力契約)
■ ファイル構造
skills
│
└─ load-test-tenant-incident-investigation
│
├── SKILL.md 目次
│
├── references/ 症状別(What)
│ │
│ ├── task-startup-failure.md タスクが立ち上がらない・すぐ落ちる
│ ├── connection-failure.md 通信が通らない(疎通不良)
│ ├── alb-5xx-and-unhealthy.md ALB がエラー・Unhealthy
│ ├── slow-response-high-load.md 遅い(アプリ層が処理しきれない)
│ ├── aurora-serverless-bottleneck.md 遅い(DB の応答待ちで詰まっている)
│ └── autoscaling-not-scaling.md 台数が増えない
│
└── tools/ 道具別(How)
│
├── log-locations.md ログの一覧
├── athena-alb-access-logs.md Athena(ALB アクセスログ)
├── athena-vpc-flow-logs.md Athena(VPC Flow Logs)
├── athena-cloudtrail-logs.md Athena(CloudTrail)
└── cloudwatch-logs-insights.md CloudWatch Logs Insights(ECS ログ)
■ 障害切り分けロジック
------------------------------------------------------------
[区分の判定]
起動系 判定:running < desired(数が足りない)
意味:タスクが上がらない/落ちる/配置できない
応答系 判定:running == desired(数は揃っている)
意味:上がってはいるが、遅い・エラー・スケールしない
------------------------------------------------------------
[A]起動系
症状・シグナル :タスクが立ち上がらない・すぐ落ちる
開始ファイル(What):task-startup-failure.md
補助(How) :cloudwatch-logs-insights.md
------------------------------------------------------------
[B]起動系
症状・シグナル :通信が通らない(疎通不良)
開始ファイル(What):connection-failure.md
補助(How) :log-locations.md
tools/athena-vpc-flow-logs.md(§0-A)
------------------------------------------------------------
[C]応答系
症状・シグナル :ALB がエラー・Unhealthy
開始ファイル(What):alb-5xx-and-unhealthy.md
補助(How) :cloudwatch-logs-insights.md §3-5
tools/athena-alb-access-logs.md(§0-A)
------------------------------------------------------------
[D]応答系
症状・シグナル :遅い(アプリ層が処理しきれない)
開始ファイル(What):slow-response-high-load.md
補助(How) :cloudwatch-logs-insights.md
------------------------------------------------------------
[E]応答系
症状・シグナル :遅い(DB の応答待ちで詰まっている)
開始ファイル(What):aurora-serverless-bottleneck.md
補助(How) :cloudwatch-logs-insights.md
------------------------------------------------------------
[F]応答系
症状・シグナル :台数が増えない
開始ファイル(What):autoscaling-not-scaling.md
補助(How) :describe-scaling-activities
------------------------------------------------------------
■ alb-5xx-and-unhealthy.md
------------------------------------------------------------
DLT ──▶ ALB ──▶ ECS/アプリ
│ │
│ └ アプリが返すコード
│
└ ALB 自身が返すコード
elb_status_code(ALB がクライアントに返したコード= DLT が見た値)
target_status_code(アプリが ALB に返したコード)
■一次振り分け表
DLT の responseCode = elb_status_code
[1] 4xx / 5xx(503 除く) 当たり: アプリ由来
初手: 失敗 URL のパスでロググループ選択(不明なら ①、②のロググループを選択)
① iolt-frnt-idfr-net
② libra-front
確定:
・①②のロググループでヒット → アプリ由来で確定
・空振り → ALB ログを引く
・actions_executed … ALB が何をしたか(fixed-response 等)
・matched_rule_priority … どのルールで止まったか
・target_status_code … '-' ならアプリ未到達
[2] 503 当たり: ALB 由来
初手: 5xx の発生源切り分け(メトリクス)
ALB 由来 / アプリ由来の比率を把握
確定: ALB ログの target_status_code で分岐
・'-' → ALB 由来 → 503 の深掘り(target_ip → コンテナ特定)
・'503' → アプリ由来 → 転送先のサービスのロググループへ
[3] Non HTTP response code 当たり: ALB より手前
初手: なし
確定:
・ALB ログにも残らないことあり
・メトリクスで裏取り
------------------------------------------------------------
失敗 URL のパス … JTL でエラーになったリクエストの URL パス
URLパス ECSサービス
-------------------------------------------------
ia01(画面系)
/wmn036/* → iolt-frnt-idfr-net
/wmn052/* → dmnd-anpf-scia-net
default → libra-front
ia02(API 系・9本収容)
/wma018/* → dmnd-idpf-attr-api
/wma019/* → dmnd-anpf-lgin-api
/wma024/* → dmnd-anpf-pswd-api
/wma028/* → dmnd-azpf-lbad-api
/wma032/* → iolt-anbl-idan-api
/wma034/* → iolt-idbl-idaa-api
/wma055/* → dmnd-anpf-scia-api
/wma056/* → iolt-adbl-idad-api
/dmnd-idpf-relt-api/* → dmnd-idpf-relt-api
default → iolt-idbl-idaa-api
ia03
default → iolt-adbl-idad-ol
ia04
/wma022/* → dmnd-anpf-otpw-api
default → libra-idrepo
ia05
default → libra-management
ia06
default → libra-authlete
------------------------------------------------------------
5xx の発生源切り分け(メトリクス)
HTTPCode_ELB_5XX_Count
⇒ ターゲット不在、タイムアウト
HTTPCode_Target_5XX_Count
⇒ アプリ内エラー
------------------------------------------------------------
503 の深掘り(target_ip → コンテナ特定)
-(ターゲット無し)
⇒ その瞬間 TG に正常なタスクが 0
特定 IP
⇒ そのタスク 1 本の不調
複数 IP
⇒ TG 全体の問題
※)ECSタスク停止後、少なくとも 1 時間は DescribeTasks で取得できる
------------------------------------------------------------
<ご参考>
libra-front 【画面】フロント
libra-management 【画面】管理コンソール
libra-idrepo 【API】Idrepository
libra-authlete 【API】authlete
iolt-adbl-idad-ol 【画面】IDaaS管理BL画面
iolt-frnt-idfr-net 【画面】IDaaSフロント
iolt-anbl-idan-api 【API】IDaaS認証BL
iolt-idbl-idaa-api 【API】IDaaS属性管理BL
iolt-adbl-idad-api 【API】IDaaS管理BL
dmnd-anpf-scia-net 【画面】ソーシャルIDP集約
dmnd-azpf-lbad-api 【API】Libraアダプター
dmnd-idpf-relt-api 【API】IDリレーション管理
dmnd-idpf-attr-api 【API】ID属性管理
dmnd-anpf-lgin-api 【API】ログイン
dmnd-anpf-otpw-api 【API】OTP認証
dmnd-anpf-pswd-api 【API】パスワード
dmnd-anpf-scia-api 【API】ソーシャルIDP集約
・スケーリングポリシー(libra / iolt、dmnd)
CPU 60%
memory 80%
ALB 200リクエスト / 1200リクエスト
クールダウンタイム 180s / 120s
■■■ Claude Code
■ ファイル構造(スコープ:プロジェクト)
/home/sagemaker-user/
│
├─ .aws/
│ │
│ └── config
│
├─ .claude.json
│
└─ dlt-dev-idaas-test-tky-codecommit-lipla/
│
├── CLAUDE.md
│
├── .mcp.json
│
├── .gitignore
│
└── .claude/
│
├── settings.json
│
├── references/
│ │
│ ├ report-format.md
│ │
│ └ devops-agent-mcp.md
│
└── skills/
│
└── load-test-dlt-results-investigation/
│
└── SKILL.md
■ DevOps Agent への依頼
============================================================
入力契約(現時点)
① TEST_ID [必須]
② 症状 [必須]
③ 調査時間帯 [必須]
④ 対象アカウント [必須]
⑤対象テナントID [必須]
⑥ 分母/分子のテナント一覧 [必須]
⑦ 負荷プロファイル + responseCode 内訳 [必須]
⑧ X-Amzn-Trace-Id [任意]
⑨ 総リクエスト数 [必須]
⑩ Athena で特に見てほしい点 [任意]
============================================================
/investigate-triage 事象・影響+判定(quick / deep)
【入力契約】
① 試験パターン[必須:ユーザが指定]
⇒ 以下の文言のどれか
t998(通常)の試験
wjoh(通常)の試験
t998(高負荷)の試験
wjoh(高負荷)の試験
t998(高負荷)、wjoh(通常)の試験
wjoh(高負荷)、t998(通常)の試験
② 調査識別子 [必須:ユーザが指定]
⇒ テナント数分
<TEST_ID>-<PREFIX>
ユーザは、<TEST_ID> <STARTED AT>を指定
③ 症状 [必須]
⇒ テナント数分
複数行。悪化区間の異常を機械的に列挙する
④ 負荷実績 [必須]
⇒ テナント数分
- 総リクエスト数(成功+失敗)
- JTL に出たステータスコードをそのまま全部
- label 別 p50/p95/p99
- 失敗したlabel / URL(多い順)
⑤ 調査時間帯 [必須]
⇒ UTC ISO8601 の開始 / 終了、および悪化のピーク時刻
複数テナントの場合は全テナントの悪化区間を包含する範囲
<事前に決めること>
定常値 = ramp-up 完了後、最初の3分の中央値
判定指標
err_rate = 失敗数 / サンプル数
p95 = elapsed(応答時間) の 95 パーセンタイル
閾値
err_rate: 定常値 × 3 を超える(ただし定常が 0 の場合は絶対値 1% で判定)
p95: 定常値 × 2 を超える
継続条件(ノイズ除去)
開始 = 閾値超えが 連続2ビン 続いた最初のビン
回復 = 閾値以下が 連続3ビン 続いた最初のビン
前後マージン
窓 = 悪化開始 −5分 〜 回復 +2分
------------------------------------------------------------
【出力契約】
⑥ 本依頼の位置づけ [必須]
⇒ 本依頼は triage である。原因の特定は次フェーズで行う。
⑦ 調査範囲の制約 [必須]
⇒ - Athena(ALB アクセスログ / VPC Flow Logs / CloudTrail)は
実施しないこと。本フェーズは CloudWatch Metrics / Logs と
ECS・ELB・RDS の API 参照のみで回答する
- Athena を実施していない旨を見出し 5 に明記すること
- IDaaS を起点に確認し、IDaaS 側で説明がつかない場合のみ
JWL(アプリ層 → データ層)まで確認する
- JWL データ層まで降りる場合、Aurora は mysql / postgresql の
両エンジンを確認すること(片方のみで「異常なし」と結論しない)
⑧ 結論の扱い [必須]
⇒ - 原因を断定しないこと。根拠が不足する場合は「未確定」と明記する
- 対立仮説がある場合は、棄却せず併記すること
- 原因の推定は本フェーズでは行わない
- 単一テナントの試験では、テナント横断の同時性による層の切り分けが
使えないため、共有層/テナント固有の断定をしないこと
⑨ 回答の形式 [必須]
⇒ 以下の見出し 1〜6 で回答し、末尾に判定 JSON を付すこと。
1. 事象
観測された異常の姿。テナント別・時系列で。
ALB の ELB 5xx / Target 5xx、レイテンシ、ECS のタスク数を含む
2. 影響範囲
エラー率・継続時間・影響を受けたパス/エンドポイント
全断か部分縮退か
3. テナント横断の比較
テナント別の症状の有無と、悪化タイミングの前後関係
単一テナント試験の場合は「判定不可」と記載
4. API で確認した事実
根拠となるメトリクス名・実測値・stoppedReason の原文を保持する
5. Athena の実施状況
本フェーズでは未実施である旨を明記する
6. 未確認
確認できなかった項目と、その理由
(記録なし/権限外/保持期間切れ/メトリクス欠損)
末尾の判定 JSON(下記の形式)
{
"time_window_resolved": true | false,
"error_type": "elb_5xx" | "target_5xx" | "latency_only" | "mixed" | "none",
"path_skewed": true | false,
"ecs_anomaly": true | false,
"config_change_suspected": true | false,
"tenant_divergence": "single" | "multiple" | "unknown",
"next_step": "quick" | "deep",
"reason": "<次フェーズの判断根拠を1〜2文>"
}
⑩ 併記義務 [必須]
⇒ - すべての事実に対象アカウントとテナントID を併記すること
- 数値は実測値をそのまま記載し、要約・丸めをしないこと
(API 名・メトリクス名・stoppedReason の原文を保持する)
- 確認できなかった項目は「無かった」ではなく「確認できない」と
記載し、その理由(記録なし/権限外/保持期間切れ)を明示する
============================================================
quick /deep / STOP 判定
上から順に評価し、最初に一致したものを採用します。
【判定ルール】
0. JSON が欠損・不正、または必須キーが揃わない
→ STOP(triage をやり直す。取得内容に穴がある可能性)
1. time_window_resolved == false
→ STOP(窓がずれている。⑤を絞り直して triage を再実行)
2. error_type == "none"
→ STOP(受け側に異常なし。負荷側/ネットワーク経路を疑う。
DevOps Agent への依頼ではなく DLT 側の再確認へ)
3. error_type == "latency_only"
→ deep
4. path_skewed == true
→ deep
5. config_change_suspected == true
→ deep
6. ecs_anomaly == true
→ quick
7. 上記いずれにも該当しない
→ deep
============================================================
/investigate-quick 原因・対応
【入力契約】
変更なし
① 試験パターン[必須]
② 調査識別子 [必須]
③ 症状 [必須]
④ 負荷実績 [必須]
修正
⑤ 調査時間帯 [必須]
⇒ triage で確定した窓をそのまま使用する(再計算しない)
UTC ISO8601 の開始 / 終了、および悪化のピーク時刻
複数テナントの場合は全テナントの悪化区間を包含する範囲
追加
⑥ triage の確定事実 [必須]
⇒ 前フェーズで Agent が API 参照により確定した事実を、
根拠(メトリクス名・実測値・stoppedReason の原文)ごと転記する。
要約しないこと。
⑦ triage の判定 [必須]
⇒ triage 末尾の判定 JSON をそのまま転記する。
特に tenant_divergence の値と、その根拠となった
テナント別の症状・悪化タイミングの前後関係を明記する。
⑧ 未確認として残った項目 [必須]
⇒ triage の見出し 6 に記載された内容を転記する。
本フェーズでも追えないものは再調査しないこと。
------------------------------------------------------------
【出力契約】
============================================================
【出力契約】
------------------------------------------------------------
⑨ 本依頼の位置づけ [必須]
⇒ 本依頼は quick(原因・対応)である。triage で ECS 等に明確な異常が
確認されているため、メトリクスと API 参照で原因を特定し、
暫定対応まで提示する。
⑩ 調査範囲 [必須]
⇒ - ⑥の確定事実を起点とし、その原因まで掘り下げること
- ⑥で確定済みの事実は再調査せず、掘り下げに時間を使うこと
- ⑧に挙がった未確認項目は再調査しないこと
(誰が引いても追えないものとして確定している)
- Athena(ALB アクセスログ / VPC Flow Logs / CloudTrail)は
原因の特定に必要と判断した場合のみ実施してよい。
実施した場合は、その理由と結果を見出し 4 に記載すること
- IDaaS を起点に確認し、IDaaS 側で説明がつかない場合のみ
JWL(アプリ層 → データ層)まで確認する
- JWL データ層まで降りる場合、Aurora は mysql / postgresql の
両エンジンを確認すること(片方のみで「異常なし」と結論しない)
⑪ 原因の扱い [必須]
⇒ - 最有力の推定原因と、その根拠(メトリクス名・実測値・
stoppedReason の原文)を紐付けて提示すること
- 対立仮説と、それを棄却した根拠を必ず併記すること。
棄却できない仮説は残したまま提示する
- 断定できない場合は「未確定」と明記し、確定に必要な
追加調査(何を、どのデータソースで)を挙げること
- ⑦の tenant_divergence が "unknown"(単一テナント試験)の場合、
テナント横断の同時性による層の切り分けは使えない。
共有層/テナント固有の断定をしないこと
- ⑦の tenant_divergence が "single" の場合は
IDaaS のテナント固有層を、"multiple" の場合は
JWL(共有層)を優先的に検討すること
⑫ 対応の扱い [必須]
⇒ - 推奨対応には、リスクと副作用を必ず併記すること
- 原因が未確定の場合は、仮説ごとに条件分岐の形で提示すること
(断定を避けるために対応を省略しない)
- 暫定対応と恒久対策を分けて記載すること。
恒久対策は方向性の提示にとどめ、設計判断は行わない
- 本調査は read-only である。提案のみとし、実行・代行はしないこと。
すべての対応案に「未実施の提案」であることを明記する
⑬ 回答の形式 [必須]
⇒ 以下の見出し 1〜7 で回答すること。判定 JSON は不要。
1. 事象
観測された異常の姿。テナント別・時系列で
2. テナント横断の比較
テナント別の症状の有無と、悪化タイミングの前後関係
単一テナント試験の場合は「判定不可」と記載
3. API で確認した事実
根拠となるメトリクス名・実測値・stoppedReason の原文を保持する
⑥から引き継いだ事実と、本フェーズで新たに確認した事実を区別すること
4. Athena の実施状況
実施した場合はその理由・クエリ対象・結果
実施しなかった場合はその旨と、必要と判断しなかった理由
5. 推定原因
最有力の候補と根拠、対立仮説と棄却根拠
未確定の場合はその旨と、確定に必要な追加調査
6. 推奨対応
暫定対応(リスク・副作用つき)/恒久対策の方向性
原因が未確定の場合は仮説ごとに条件分岐で
すべて「未実施の提案」である旨を明記
7. 未確認
本フェーズでも確認できなかった項目と、その理由
⑧から引き継いだものと、本フェーズで新たに判明したものを区別すること
⑭ 併記義務 [必須]
⇒ - すべての事実に対象アカウントとテナントID を併記すること
- 数値は実測値をそのまま記載し、要約・丸めをしないこと
(API 名・メトリクス名・stoppedReason の原文を保持する)
- 確認できなかった項目は「無かった」ではなく「確認できない」と
記載し、その理由(記録なし/権限外/保持期間切れ)を明示する
- Athena を実施した場合、IDaaS と JWL で DB・テーブル名が同名のため、
どちらのアカウントに対するクエリかを必ず併記すること
============================================================
/investigate-deep-cause 原因
============================================================
/investigate-deep-response 対応
============================================================
◆ 送り方 / MCP ツール
実測(ログ・メトリクスを引くこと)が要るかどうか
------------------------------------------------------------
[経路 1]障害調査・疎通テスト(ログやメトリクスを実際に引くもの全部)
ツール:create_investigation
【必須】title 1行の要約
【必須】description
triage: 入力契約 ①〜⑤ + 出力契約 ⑥〜⑩
quick: 入力契約 ①〜⑧ + 出力契約 ⑨〜⑭
【必須】agent_space_id エージェントのスペースID
【任意】priority CRITICAL / HIGH / MEDIUM / LOW(デフォルト) / MINIMAL
【任意】reference system / referenceId / referenceUrl / associationId
⇒ 削除
※)スキーマ上は title のみ必須
特性 :15分以内の非同期。get_task でポーリング
------------------------------------------------------------
[経路 2]コスト / 構成 / トポロジ / サービス一覧の「質問」
ツール:chat
message
特性 :1 回で完結。⛔ 調査は実行しない(実測しない)
------------------------------------------------------------
============================================================