AWS Lambda MicroVMs を使うと、自分の AWS アカウントでエージェントのツールを実行できます。エージェントのハーネスは OpenAI が実行します。各 MicroVM は codex exec-server を実行し、セッションのワークスペースにあるファイルを保持します。
デフォルトでは、サンプルは 1 ターンに 1 台の MicroVM を使用します。再利用可能なイメージを用意し、アプリケーションから、または OpenAI の Webhook を受けて、そのイメージから MicroVM を起動します。どちらの方法でも、使うイメージと認証情報は同じです。セッションごとに、どちらがプロビジョニングを担当するかを決めてください。
アプリケーションで管理するサンドボックスと Webhook で管理するサンドボックスを試すには、Cookbook の AWS サンプルを参照してください。
動作の仕組み
Webhook を使う場合、アプリケーションはセルフホスト型のセッションを作成し、入力を送信します。セッションでエグゼキューターが必要になると、OpenAI は agent.session.action_required を送信します。このイベントには environment_connection アクションが含まれます。API Gateway は、ランチャーとして動作する Lambda に Webhook を転送します。ランチャーは署名を検証し、セッションの現在の状態を確認して、MicroVM を起動または再開します。
MicroVM の /run フックは、Secrets Manager から環境キーを取得してエグゼキューターを起動します。エグゼキューターから OpenAI へのアウトバウンド接続が確立すると、待機中の入力の処理が始まります。アプリケーションはセッションのストリームを監視し、出力ファイルをダウンロードして、最終ターンの後に MicroVM を終了します。

事前準備
次のリソースを用意します。
- AWS へのアクセス: Lambda MicroVMs を利用できるアカウント、
lambda-microvmsを含む AWS CLI、イメージのビルドと MicroVM の実行に必要な権限を用意します。AWS のスタートガイドに従って、アーティファクトを格納する S3 バケットと、イメージのビルドに使う IAM ロールを作成します。 - アプリケーションキー:
OPENAI_API_KEYを使ってセッションを作成し、入力を送信します。 - 環境キー(
OPENAI_EXECUTOR_API_KEY): アプリケーションキーと同じ組織、プロジェクト、所有者(ユーザーまたはサービスアカウント)に属する環境キーを別途作成します。キーの値は Secrets Manager のシークレットに保存します。シークレット名には、たとえばcodex/agents-api/executorを使用できます。/runフックは、このキーをCODEX_API_KEYとして Codex に渡します。 - MicroVM の実行ロール: このロールが読み取れるシークレットを、環境キーを格納したものだけに限定します。カスタマーマネージド KMS キーを使う場合は、復号権限も追加します。ロールの設定については、AWS のセキュリティと権限を参照してください。
アプリケーションキーと Webhook の署名シークレットは MicroVM の外部で管理してください。Webhook ランチャーでは、この 2 つの認証情報を Secrets Manager のランチャー専用シークレットに保存します。VM に渡すのは、環境キーを格納したシークレットの ARN だけです。
再利用可能なイメージの準備
Codex CLI、ツールの依存関係、/workspace などの作業ディレクトリ、AWS のライフサイクルフックを処理する HTTP サーバーを含むイメージをビルドします。
サンプルでは、/aws/lambda-microvms/runtime/v1 配下に次のフックを実装しています。
| フック | 動作 |
|---|---|
/ready |
AWS がスナップショットを取得できる状態になったら、サーバーは HTTP 200 を返します。エグゼキューターは未接続のままにします。 |
/validate |
Codex が動作し、ワークスペースに書き込めることを確認します。 |
/run |
セッションの接続情報とシークレットの ARN を読み取り、環境キーを取得してエグゼキューターを起動します。 |
/suspend |
AWS が VM のスナップショットを取得する前に、エグゼキューターを停止します。 |
/resume |
環境キーを再取得し、保存済みの接続情報を使ってエグゼキューターを再起動します。 |
/terminate |
VM が終了する前にエグゼキューターを停止します。 |
Dockerfile とフックを処理するサーバーを S3 アーティファクトにまとめ、codex-executor などの名前でバージョン付きイメージをビルドします。イメージの設定で 6 つのフックをすべて有効にし、フックのポートをサーバーのポートに合わせます。イメージのスナップショットには、セッション ID、認証情報、エグゼキューターのアクティブな接続を含めないでください。ビルドとフックの設定については、AWS の「MicroVM イメージ」を参照してください。
起動時に、アプリケーションまたはランチャーは次の値を JSON 文字列に変換し、runHookPayload に格納します。
| 値 | 用途 |
|---|---|
session.environment.id |
エグゼキューターの接続先環境を識別します。 |
session.environment.remote_url |
エグゼキューターが OpenAI への接続に使う URL を指定します。 |
| 環境キーを格納したシークレットの ARN | フックはこの ARN と MicroVM の実行ロールを使ってキーを取得します。 |
/run フックは、AWS からのリクエスト本文に含まれるこの文字列を解析し、キーを取得します。その値を子プロセスの環境変数 CODEX_API_KEY に設定し、エグゼキューターを起動します。プロセスが起動した時点でフックの応答を返してください。エージェントのターンが完了するまで待つと、フックがタイムアウトすることがあります。
エグゼキューターに必要なアウトバウンド接続と、Secrets Manager へのアクセスを許可します。プライベートリソースにアクセスする場合やネットワークに制限がある場合は、AWS のエグレスコネクタを設定します。ファイルをダウンロードするには、サーバーにルートを追加します。サーバーのポートにスコープを限定した AWS 認証トークンを使い、MicroVM の HTTP エンドポイント経由でそのルートを呼び出します。
MicroVM の起動
プロビジョニングは、アプリケーションまたは Webhook のどちらかで管理します。どちらの場合も、接続から入力の処理、ターンの完了まで、セッションのイベントストリームを開いたままにします。
アプリケーションによるプロビジョニング
- イメージと同じ作業ディレクトリを指定してセルフホスト型のセッションを作成し、セッションのイベントストリームを開きます。
- AWS の RunMicrovm を呼び出し、イメージの ARN とバージョン、実行ロール、ネットワークコネクタ、
runHookPayloadを渡します。返されたmicrovmIdをセッション ID とともに保存します。 agent.session.environment.connectedを待ってから入力を送信し、ストリームでターンの結果を確認します。- 出力ファイルを取得し、MicroVM を終了します。
Webhook によるプロビジョニング
API Gateway の HTTP API と、ランチャーとして動作する Lambda を使います。アプリケーションはセッションを作成し、ストリームを開いて入力を送信します。セッションで接続が必要になると、Webhook を受けたランチャーがコンピューティングリソースを起動または再開します。
- ランチャーを呼び出す
POST /webhookルートをデプロイします。選択したイメージに対するlambda:RunMicrovm、lambda:GetMicrovm、lambda:ResumeMicrovm、lambda:TerminateMicrovmの権限をランチャーに付与します。ランチャーには、自身の認証情報を読み取り、MicroVM の実行ロールを渡し、設定済みのネットワークコネクタを使用する権限も必要です。 - エンドポイントを登録し、
agent.session.action_requiredとagent.session.failedを購読します。エンドポイントの署名シークレットは、ランチャーのアプリケーションキーと一緒に保存します。 - セッションにアクセスしたり、コンピューティングリソースを起動したりする前に、未加工のリクエスト本文を使って Webhook の署名を検証します。セッションの最新情報を取得し、そのセッションがハンドラーの管理対象であることを確認します。たとえば、セッションのエージェントが、このハンドラー専用に保存したエージェントと一致するかを確認します。
environment_connectionがまだ保留中であれば、GetMicrovmで記録済みの VM の状態を確認します。SUSPENDEDの VM はResumeMicrovmで再開し、PENDINGまたはRUNNINGの VM は接続されるまで待ちます。VM が記録されていない場合に限り、RunMicrovmを呼び出します。起動した VM の ID をセッションのメタデータに保存します。保存に失敗した場合は、その VM を終了します。- セッションが引き続き
failed状態であれば、そのセッションに記録された MicroVM を終了します。削除済みのセッション、解決済みのアクション、別のハンドラーが管理するイベントは無視します。
接続がタイムアウトする前にエグゼキューターが接続すれば、入力を再送信しなくても、待機中の入力の処理が始まります。
プロトタイプでは、MicroVM を同期的に起動し、その ID をセッションのメタデータに保存できます。本番運用に移る前に、どのハンドラーが起動を担当するかを永続的に記録し、起動処理の冪等性を確保したうえで、プロビジョニング処理をキューに追加してください。メタデータだけでは重複起動を防げません。また、起動に時間がかかると、Webhook の応答期限を超えることがあります。
MicroVM の終了
セッションのストリームで、agent.session.turn.completed、agent.session.turn.failed、agent.session.turn.cancelled のいずれかを待ちます。対象はメインエージェントのイベント(event.turn.subagent_id が null)です。サブエージェントも同じ MicroVM を使うため、サブエージェントのターン終了イベントを受けてクリーンアップを開始しないでください。最終ターンの後に必要なファイルを取得し、TerminateMicrovm を呼び出して、VM が TERMINATED 状態になったことを確認します。アプリケーションでエラーが発生した場合も、クリーンアップを実行します。
ターンの結果はストリームのイベントとして届きます。Webhook では購読できません。agent.session.failed の Webhook はセッションの失敗を通知しますが、ターンが失敗するたびに届くわけではありません。agent.session.idle だけを根拠に VM を終了しないでください。このイベントは、待機中の入力の処理が始まる前に届くことがあります。
クリーンアップを実行できなかった場合に備えて、AWS で次の制限を設定します。
| 設定 | 設定の目安 |
|---|---|
maximumDurationInSeconds |
ワークロードに合わせて時間の上限を設定します。たとえば 900 は 15 分間のテスト用の値です。上限に達すると、実行中の処理が中断されることがあります。 |
maxIdleDurationSeconds |
想定するワークロードに十分な時間を設定します。AWS が計測するのはインバウンドトラフィックです。エグゼキューターからのアウトバウンド接続では、このタイマーはリセットされません。 |
suspendedDurationSeconds / autoResumeEnabled |
サンプルでは、デフォルトで 0 / false を使用し、300 / false は --suspend-resume を指定した場合に使用します。 |
稼働時間とアイドル時間の設定については、AWS の「MicroVM の実行と使用」を参照してください。
セッションの削除は別途行います。セッションを削除しても、AWS のコンピューティングリソースは終了せず、削除を通知する Webhook も送信されません。イメージと環境キーを格納したシークレットは、再利用できるように保持します。後続のターンでコンピューティングリソースを再利用または置き換え、ファイルを永続化する方法については、サンドボックスのライフサイクルを参照してください。
ターン間の一時停止と再開
AWS の一時停止と再開を使うと、ターン間でメモリとディスクの内容を保持できます。suspendedDurationSeconds にはゼロ以外の値を設定してください。一時停止中はスナップショットのストレージ料金が発生します。maximumDurationInSeconds による上限は、実行時間と一時停止時間を合わせて 8 時間です。
どちらのサンプルでも、--suspend-resume を指定して実行すると、/workspace/hello.txt に書き込んでから VM を一時停止し、2 回目のターンでそのファイルを読み取ります。アプリケーションで管理するサンプルでは、アプリケーションが VM を直接再開します。Webhook で管理するサンプルでは、アプリケーションが再度入力を送信し、それをきっかけにランチャーが記録済みの VM を再開します。どちらもファイルの内容を確認し、最終ターンの後にクリーンアップを実行します。
/suspend フックはエグゼキューターを停止し、/resume フックはキーを再取得してエグゼキューターを再接続します。一時停止するのは、ツールとサブエージェントの処理がすべて完了してからにしてください。AWS で自動再開するには VM へのインバウンドトラフィックが必要です。Agents API に入力を送信するだけでは、VM は再開しません。
検証と監視
/workspace に小さなファイルを作成するよう指示するプロンプトでテストします。エグゼキューターが接続すること、ターンが完了すること、ダウンロードしたファイルに期待どおりの結果が含まれること、クリーンアップ後に MicroVM が TERMINATED 状態になることを確認してください。起動に成功しただけでは、連携全体が機能するかどうかは確認できません。
AWS サンプルのディレクトリで jq を使い、保存済みのビルド状態からイメージの ARN とリージョンを読み取ります。--state で別のパスを指定した場合はパスを変更し、ランチャー名を変更した場合はロググループ名を置き換えてください。
image_state=application_managed/.local/image.json
region=$(jq -r '.region' "$image_state")
image_arn=$(jq -r '.image_arn' "$image_state")
aws logs tail /aws/lambda/codex-agents-api-webhook --since 10m --region "$region"
aws lambda-microvms list-microvms \
--image-identifier "$image_arn" --region "$region" \
--query 'items[].{id:microvmId,state:state}' --output table
実行を追跡できるように、セッション ID と MicroVM ID を一緒にログに記録します。認証情報や未加工の Webhook リクエスト本文はログに記録しないでください。
トラブルシューティング
| 症状 | 確認事項 |
|---|---|
| Webhook の署名が拒否される | エンドポイントの署名シークレットを使い、リクエスト本文を変更せずに署名を検証してください。 |
| MicroVM が起動しない | Webhook の購読設定、セッションの所有者を判定するフィルター、保留中の environment_connection アクション、ランチャーの IAM 権限を確認してください。 |
| イメージのビルドに失敗する | S3 アーティファクト、イメージのビルド用ロール、/ready フックの応答を確認してください。 |
/run が失敗するかタイムアウトする |
シークレットへのアクセスとエグゼキューターの起動を確認してください。ターンの終了を待たず、プロセスが起動した時点で応答を返してください。 |
| エグゼキューターが接続できない | 環境 ID、リモート URL、キーの所有者、ネットワークのアウトバウンドアクセスを確認してください。 |
| ターンの途中で VM が停止する | 稼働時間の上限とアイドル時のポリシーを確認してください。エグゼキューターからのアウトバウンドトラフィックは、インバウンドのアクティビティとしてはカウントされません。 |
接続に失敗した場合は、agent.session.environment.failed とエグゼキューターのログを確認します。エグゼキューターに共通する動作仕様については、セルフホスト型サンドボックスを参照してください。
参考資料
- ライフサイクル:「MicroVM の実行と使用」では、起動、一時停止、再開、終了について説明しています。
- セキュリティ:「セキュリティと権限」では、IAM ロール、認証トークン、アクセス制御について説明しています。