エンジニア約50名、AWSアカウント約30個を抱える中堅B2B SaaS企業では、週に約40回のオンコール呼び出しが発生し、実際に答えが出るまでに手作業でのコンテキスト収集だけで25分から35分かかる。どのアカウントか、どのダッシュボードか、どのランブックか、そのランブックがまだ正確かどうか。これは診断が始まる前の話であり、診断の代わりではない。本シリーズが構築するのはその解決策だ。この最初の一手を自動でこなし、許可された範囲のすべてを読み、人間の承認なしには何も変更せず、その規律を失った瞬間に価値を失う小さなAIエージェント基盤である。

この会社が実際に払っている「地味な重労働」のコスト

この会社をありのままに呼ぶなら、中堅のB2B SaaS企業、エンジニア約50名、複数のプロダクトラインにまたがるAWSアカウント約30個、それぞれがdev・staging・productionの三点セットを持つ。誰も最初から30アカウントを目指したわけではない。ごく普通の経緯だ。チームが一つずつ分離を求めた結果、AWS Organizationsの構造がアーキテクチャよりも組織図を反映するようになった。

この重労働は派手さがない。じわじわと積み重なるものであり、3か月分のオンコールデータと1回の気まずい振り返りから出てきた4つの数字が、その輪郭をはっきりさせる。

  • 週に約40件の呼び出しがローテーション担当者に降りかかり、30アカウントに不均等に散らばっている。
  • 呼び出しのたびに25分から35分が診断開始前のコンテキスト収集に費やされる。正しいアカウント、正しいダッシュボード、正しいランブック、そしてそのランブックが今も現実と一致しているかどうか。
  • 月次のFinOpsレビューは実際の支出からおよそ3週間遅れて回っているため、設定ミスのAuto Scalingグループやアイドル状態のGPUインスタンスが、誰かが目にするレポートに上がるまで1か月近くコストを垂れ流す。
  • 直近のランブック監査では、約3件に1件の割合でランブックが指すリソース、ARN、コンソールパスがすでに存在しなくなっていた。

この4つはどれも単体では緊急事態ではない。だが合わさるとチームへの定常的な税金になる。週にざっと30から40エンジニア時間が、コンテキスト収集と古い手順の再確認という運用の機械的な部分に費やされている。しかもそれを払っているのは、プロダクトを作るために雇われたはずの人たちだ。

なぜエージェントか、なぜ今か

「なぜ今か」への率直な答えは、必要な部品がようやく誰かが子守をしなくてはならない社内フレームワークではなく、マネージドサービスとして揃ったからだ。BedrockはAgents for Amazon Bedrockという名でマネージドなエージェントオーケストレーションサービスを、2023年11月の一般提供開始以来、改良されたオーケストレーション制御と推論トレースの可視性とともに提供してきた。変わったのはその上の層だ。Amazon Bedrock AgentCoreは2025年10月13日に9リージョンで一般提供を開始し、これまでセッションストア、認証情報ブローカー、トレーシングパイプラインをゼロから構築する必要があった部分を、7つのコンポーネントサービス(Runtime、Memory、Identity、Gateway、Code Interpreter、Browser、Observability)としてパッケージ化した。並行してAWSは2025年5月にStrands Agents SDKをApache 2.0ライセンスでオープンソース化し、2026年5月21日、この投稿のタイムラインが始まるわずか1週間前にPython向けの本番1.0リリースを出した。マネージドインフラとオープンなオーケストレーション層の両方が、同じ数か月のうちに本番運用に耐える水準を超えた。この基盤が構築されるのは、まさにその時期だ。

自作か購入か

チームはまず購入を検討した。それが筋だ。既製のAIOpsやインシデントコパイロット製品なら、もっと早く出荷でき、Terraformを書く必要もなかっただろう。だが3つの理由で見送られた。いずれもエージェント一般の話ではなく、この会社固有の理由だ。

  • 変更操作の境界線は譲れない。修正を実行する主体は誰であれ、対象アカウント内で狭くスコープされたIAMロールを引き受け、社内の承認ステップを通す必要がある。SaaS製品を使えば、幅広いクロスアカウントアクセスを与えるか、後付けで独自の承認フローをこちらの仕組みにねじ込むかのどちらかを迫られる。基盤を自前で持つということは、承認ゲートが最初からネイティブに組み込まれることを意味し、後から統合する必要がない。
  • 30アカウント分の暗黙知はSlackのスレッドやエンジニアの頭の中に生きていて、ベンダーの取り込みパイプラインが理解できる形式にはなっていない。既存のランブック群に対してBedrock Knowledge Baseを構築し、チャンク分割と検索品質をチーム自身が直接コントロールする方が、その知識を第三者にエクスポートして検索精度が十分であることを祈るよりも現実的だ。
  • この会社はすでにこの規模でAWSを運用している。Terraform、CI、オンコールローテーション、アカウント構造、そのすべてがすでに存在する。AWSネイティブなプリミティブの上に構築する限界コストは、2社目のベンダー関係、2本目の請求ライン、2回目のセキュリティレビューを抱えるコストよりも低い。

反論も正当だ。購入の方が速く、重労働が毎週積み上がる状況では速さそのものに価値がある。チームの答えは、これをプラットフォームチームの終わりなきプロジェクトとして扱うのではなく、構築のスコープを厳しく絞り込むことだった(エージェント4体、承認パターン1つ、まずはオンデマンド推論から始める。サイジングの計算式は後の回で扱う)。シリーズ全体のコンパニオンコードはgithub.com/flightlesstux/agents-on-callにあり、この投稿はそのdocs/architecture.mdの起点にあたる。

スタック選定:Bedrockでエージェントを動かす3つの方法

構築すると決めた後、次の判断はどの層の上に構築するかだった。現実的な選択肢は3つあり、そのトレードオフは「一番新しいものを使う」ほど単純ではまったくない。

観点Bedrock Agents(クラシック)AgentCore + StrandsConverse APIで自前構築
自分が所有するものコンソールで定義するアクショングループ、オーケストレーションはAWS側マネージドなランタイム・アイデンティティ・メモリ・ゲートウェイ、エージェントループは自分のPythonコードすべて:ループ、リトライ、メモリ、ツールルーティング、トレーシング
この時点での成熟度2023年11月から一般提供、最長の実績2025年10月13日から一般提供、本番運用の実績は約7か月自分のコードと同程度、それ以上でもそれ以下でもない
モデル・プロバイダの可搬性BedrockモデルのみBedrock、Anthropic直接、Ollama、LiteLLM経由のプロバイダ自分で配線した分だけ
フレームワークへのロックイン高い:オーケストレーションロジックがBedrockのアクショングループ形式の中に存在する低い:StrandsはApache 2.0のPythonであり、AmazonがQ Developer、AWS Glue、VPC Reachability Analyzerで社内的に使っているのと同じSDKロックインなし、その代わり助けもない
ツール統合OpenAPIスキーマで定義されたアクショングループAgentCore GatewayがAPI、Lambda関数、既存サービスをMCP互換ツールに変換する。MCP自体は2024年11月からのオープン標準Converse APIに対する手組みのツール呼び出し
可観測性組み込みの推論トレース、エクスポート方法の制御は限定的OTELトレースをCloudWatch generative AI observabilityへ、自分のダッシュボードで見る自分で計装した分だけ
Terraformカバレッジ実績のあるアクショングループリソース2025年10月16日からネイティブのaws_bedrockagentcore_*リソース、JSON形式の属性マップではなく適切にネストされたHCLブロックサービス固有のリソースは不要、必要なのはIAMとコンピュートのみ
最適な用途シンプルなエージェントが少数、カスタムオーケストレーションを最小限にしたい場合複数のエージェントがループの制御を必要とし、マルチプロバイダの将来を見据える場合どのフレームワークもうまく表現できないほど特殊なオーケストレーション

チームが選んだのはAgentCoreとStrandsの組み合わせだった。自分たちで持ちたくなかったマネージドな部品(セッション分離、認証情報のブローカリング、クロスアカウントゲートウェイ)が、コンソールからリバースエンジニアリングする必要のあるものではなく、自分たちで読んでデバッグできるオーケストレーション層とセットで手に入った。一般提供時点のAgentCore Runtimeは各エージェントセッションに完全な分離と8時間の実行ウィンドウを与え、このプラットフォーム内のエージェントが外部のエージェントと会話する必要が出てきた場合に備えてAgent2Agentプロトコルのサポートも持つ。2026年4月22日にリリースされた@aws/agentcore CLIはcreate、dev、deploy、invoke、logs、tracesという一連のワークフローを追加し、Strandsを直接サポートする(LangGraph、LangChain、Google ADK、OpenAI Agents、独自実装にも対応)。これはオンボーディングの面で効いた。誰もプロジェクトの途中でまったく新しいデプロイツールを覚える必要がなかったからだ。

クラシックなBedrock Agentsはそれ自体の長所で純粋に魅力的なままだった。2年半分の本番実績、所有するカスタムコードの少なさ、アクショングループで用が足りるユースケースにおけるシンプルなメンタルモデル。ここで見送られたのは、ハードなマルチアカウントIAM境界をまたいでスーパーバイザーパターンを共有する4体のエージェントには、アクショングループが露出する以上のループ制御が必要だったからだ。生のConverse APIでの自前構築は逆の理由で却下された。AWSがすでにAgentCore Runtime、Memory、Identity、Observabilityとして提供しているものを、セッションストア、認証情報ブローカー、トレーシングパイプラインとしてゼロから書けば、プロジェクトの最初の2か月をインフラの再発明に費やし、エージェントを書く時間に充てられなかっただろう。

目標アーキテクチャ:組織全体をまたぐハブアンドスポーク

このプラットフォームはマルチアカウント、ハブアンドスポーク構成で、意図的に付加的な設計になっている。停止しても組織はまさに現状維持の状態に戻るだけだ。人間へのページングはこれまで通り機能する。このプラットフォームがクリティカルなアラート経路に座ることは決してない。

graph TD
  MGMT["management account
org root, SCPs, no workloads"] SEC["security account
org CloudTrail, GuardDuty,
Security Hub delegated admin"] OPS["ops-tooling account
the agent platform"] W1["workload account 1"] W2["workload account 2"] WN["workload account N
~30 total"] MGMT -. SCPs .-> SEC MGMT -. SCPs .-> OPS MGMT -. SCPs .-> W1 MGMT -. SCPs .-> W2 MGMT -. SCPs .-> WN W1 -- alarm events --> OPS W2 -- alarm events --> OPS WN -- alarm events --> OPS OPS -- "assume ops-readonly, read-only tools" --> W1 OPS -- "assume ops-readonly, read-only tools" --> W2 OPS -- "assume ops-readonly, read-only tools" --> WN OPS -. "assume ops-mutate, approved executor only" .-> W1

各ワークロードアカウントはops-toolingに対してちょうど2つのロールを公開する。1つはops-readonlyで、あらゆるツールLambdaが引き受けられる。AWSのread-only管理ポリシーをベースに、その上に明示的なdenyを重ねて構築されている。もう1つはops-mutateで、これを引き受けられるLambdaはただ1つ、人間が提案されたアクションを承認した後にだけ実行されるものであり、特定のSSM Automationドキュメントの許可リストにスコープされている。ops-mutateを引き受けられるのは、そのたった1つの承認後実行者だけであり、他のどのエージェントも、他のどのLambdaも、他のどのコードパスもそれはできない。この分離こそが、プロンプトの指示ではなく、read-onlyをデフォルトにしている理由だ。それはIAMによって強制されているのであって、モデルにお願いしているのではない。

ops-toolingの内側

このシリーズの残りが生きる、その1つのアカウントを拡大してみよう。

graph LR
  subgraph entry["Entry"]
    EB["EventBridge bus
cross-account alarms"] SLACK["Slack app
API Gateway + verifier Lambda"] SCHED["EventBridge Scheduler
daily cost sweep"] end subgraph agents["Agent layer"] SUP["supervisor"] TRI["incident-triage"] RUN["runbook"] COST["cost"] MEM["AgentCore Memory"] ID["AgentCore Identity"] end subgraph models["Model layer"] BR["Bedrock, cross-region
inference profiles"] GR["Bedrock Guardrails"] KB["Knowledge Base
runbook corpus"] end subgraph tools["Tool layer"] GW["AgentCore Gateway"] T1["cloudwatch-read"] T2["logs-read"] T3["cost-read"] T4["ssm-execute"] end subgraph gate["Approval gate"] SF["Step Functions
waitForTaskToken"] EXEC["post-approval executor"] end subgraph obs["Observability"] OTEL["OTEL traces to CloudWatch
GenAI observability"] LOG["invocation logs to S3"] BUD["Budgets + Cost
Anomaly Detection"] end EB --> SUP SLACK --> SUP SCHED --> COST SUP --> TRI SUP --> RUN SUP --> COST TRI --> MEM RUN --> MEM COST --> MEM SUP --> ID TRI --> BR RUN --> BR COST --> BR BR --> GR TRI --> KB RUN --> KB SUP --> GW GW --> T1 GW --> T2 GW --> T3 GW --> T4 T4 --> SF SF -- "context + Slack approval" --> SLACK SF -- approved --> EXEC BR --> OTEL GW --> LOG COST --> BUD

4体のStrandsエージェントがスーパーバイザーの背後でAgentCore Runtime上に動く。インシデントトリアージ、ランブック実行、コスト最適化だ。AgentCore Memoryがセッションおよび長期状態を保持するため、スーパーバイザーはホップのたびにコンテキストを専門エージェントへ説明し直す必要がなく、AgentCore Identityがアウトバウンドの認証情報をブローカリングするため、どのエージェントのコードにも長寿命のシークレットは存在しない。モデル呼び出しはすべてクロスリージョン推論プロファイルを経由して信頼性とバースト耐性を確保し、あらゆる呼び出しにBedrock Guardrailsが付き、トリアージエージェントとランブックエージェントの背後にはランブック群に対するKnowledge Baseがある。ツール層は完全にAgentCore Gatewayで構成されている。MCPの背後に最小権限のLambda群がぶら下がり、そのうち3つはread-onlyでスポーク内のops-readonlyを引き受ける。残る1つ、ssm-executeだけが唯一の変更系ツールで、これはスポークアカウントに直接アクセスできない。できるのはStep Functionsに提案を渡すことだけで、Step FunctionsはwaitForTaskTokenで一時停止し、完全なコンテキスト(診断内容、影響範囲、正確なSSMドキュメントとパラメータ)をSlackに投稿し、人間が承認した時だけ再開する。EventBridgeからGatewayに至るすべてのホップはOTELトレーシングをCloudWatch generative AI observabilityへ運び、Bedrockの呼び出しログはS3に収まり、Budgetsおよび Cost Anomaly Detectionがエージェントごとのコスト配分タグでプラットフォーム自体の支出を監視する。

Read-onlyが最優先事項である

このプラットフォーム上のすべてのエージェントは、関連するものを何でも見ることができるが、人間がすでにイエスと言っていない限り何も変更できない。それがこのシリーズの残り全体が守り続けなければならない一文だ。それは1つの気の利いた仕組みとしてではなく、3つの別々の、地味なIAM上の決定として現れる。ツールLambdaはAWS管理ポリシーの上に明示的なdenyを積んで構築されたread-onlyロールを引き受けること、唯一の変更系ツールはスポークアカウント内の何ものも直接引き受けられないこと、そして「エージェントが修正案を提案した」から「その修正が実行された」に至る唯一の経路は、人間のSlackクリックだけが再開できるStep Functionsの待機状態を通ること。

Read-onlyは、モデルに慎重になれと告げるプロンプトの指示ではない。丁寧にお願いされたモデルでも、時に慎重さを欠くことがある。ここでのRead-onlyはIAMの境界であり、侵害されたプロンプトも、幻覚を起こしたツール呼び出しも、単純なバグも、それを越えることはできない。なぜなら越えるための認証情報が、エージェントの手が届くどこにも存在しないからだ。

完成形はどう見えるか

このシリーズの最終回はこれらの数字に立ち返る。上の重労働の棚卸しが設定した、測定可能な形にした数字だ。

  • 呼び出しから充実したSlackサマリー(ログ、ダッシュボード、可能性の高い原因)までの中央値が5分未満。現在の手作業収集にかかる25分から35分から短縮する。
  • Step Functionsに記録された人間の承認なしに実行される変更系アクションはゼロ件。CloudTrailに対して毎週検証する。
  • 月次のFinOpsの遅れが約3週間から即日へと縮む。デイリーのコストスイープが、次の請求サイクルが締まる前に異常を洗い出す。
  • ランブックの陳腐化(壊れたARN、死んだコンソールパス)が約3件に1件から20件に1件未満へと下がる。年1回の監査ではなく継続的に検知される。
  • 四半期ごとのゲームデーがops-toolingを完全に無効化し、ページングと手動でのランブック実行が、このプラットフォームが存在する前とまったく同じように機能することを確認する。静かな依存関係が生まれていないことも合わせて確認する。
  • インシデントトリアージの診断が最終的な根本原因と十分な頻度で一致し(後の回で定義する評価ハーネスの数値しきい値に対して測定する)、オンコール担当者が行動に移す前に手作業で再検証するのをやめる。

初日から注視すべき失敗モード

誰もTerraformに触れる前に見ておくべきことが3つある。シナリオ設計の段階ではなく本番で発見するのは間違った場所だからだ。読み取り系ツールがスポークアカウントに到達できない場合、ロールの引き受けが拒否されたのかサービスが劣化しているのかにかかわらず、エージェントはそれを言葉にして人間に差し戻さなければならない。推測してはいけない。自信満々に述べられた誤った診断は、診断なしよりも悪い。承認ゲート自体が滞留する場合、待機状態とそれを取り巻くステートマシンの両方に明示的なタイムアウトが必要だ。さもなければ行き詰まった提案が大きな失敗音を立てずに静かに古びていく。そしてops-toolingが完全に停止している場合、プラットフォームはまさに今日のプロセスまで劣化しなければならない。それが成立するのは、ops-toolingの外側にある何かが、それが存在することにひっそりと依存し始めていない場合に限る。

次に読む

  • 第2回 基盤編:トークンより先にTerraform。ここまでのアカウント構成が実際のHCLになる。IAMベースライン、Bedrockモデルアクセス、オンデマンド対プロビジョンド対クロスリージョン推論の判断。
  • ercan.cloudのAWS Organizations向けマルチパーティ承認。「リスクのある操作を人間の定足数の背後にゲートする」という同じパターンを、エージェント側ではなく生のAWS Organizations側から扱う。

上記の2つの図、およびそれらが表すアカウントとIAMの構成は、コンパニオンリポジトリgithub.com/flightlesstux/agents-on-callにMarkdownとしても置かれており、このシリーズが少しずつ構築していくTerraformとPythonと並んでいる。この種のプラットフォームを大規模に運用する際のデータベースとインフラ側の話はercan.cloudのフィールドノートで、ハブはercanermis.comにある。