広告

ファイルシステム設定でセッション状態を保持し、シェルコマンドを実行する

Amazon AWS AI Blog / 2026/4/2

💬 オピニオンDeveloper Stack & InfrastructureSignals & Early TrendsTools & Practical Usage

要点

  • Amazon Bedrock AgentCore Runtime は(パブリックプレビューとして)マネージド・セッション・ストレージを導入し、マイクロVM ストレージの儚さ(エフェメラリティ)に対処しながら、セッション再起動をまたいでエージェントのファイルシステム状態を保持できるようにしました。
  • さらに、InvokeAgentRuntimeCommand によりシェルコマンドを実行する機能を追加し、各アクティブなエージェント・セッション内のマイクロVMで、決定論的な操作(例:npm test、git push)を実行できます。
  • 永続的なファイルシステムの「作業メモリ」と、実行環境内でのコマンド実行を組み合わせることで、従来は困難だった、または壊れやすいLLM駆動のワークアラウンドや独自ツールに依存していたエージェントのワークフローが実現しやすくなります。
  • 本記事では、セッションごとにマイクロVMを用意する AgentCore のモデルを説明します。具体的には、セッションがクリーンなファイルシステムで起動する方法、そしてセッションの終了(停止またはアイドルタイムアウト)によって通常は作成された成果物がすべて消えてしまう仕組みです。
  • マネージド・セッション・ストレージの利用と、エージェント環境内でのコマンド実行について、ウォークスルー形式で手順を示します。

AIエージェントはチャットの域を大きく超えて進化しています。コードの作成、ファイルシステム状態の永続化、シェルコマンドの実行、そしてファイルシステム全体にわたる状態の管理といったことができる例です。エージェント型のコーディング支援者や開発ワークフローが成熟するにつれて、ファイルシステムはエージェントの主要な作業用メモリとなり、コンテキストウィンドウを超えてその能力を拡張するようになりました。この変化により、生産環境向けエージェントを構築するあらゆるチームが直面する2つの課題が生まれます:

  • ファイルシステムはエフェメラルです。エージェントのセッションが停止すると、インストールされた依存関係、生成されたコード、ローカルのgit履歴のように、エージェントが作成したものはすべて消えます。
  • npm testgit push のような決定論的な操作がワークフローで必要な場合、大規模言語モデル(LLM)を経由させるか、実行時(ランタイム)の外でビルド用の独自ツールを構築することを強いられます。どちらの選択肢も良くありません。

Amazon Bedrock AgentCore Runtime は、2つの機能によってこれら2つの課題にいま対応しています。永続的なエージェントのファイルシステム状態のためのマネージドセッションストレージ(パブリックプレビュー)と、各アクティブなエージェントセッションに関連付けられた microVM 内でシェルコマンドを直接実行するためのコマンド実行(InvokeAgentRuntimeCommand)です。どちらもそれぞれ単独で有用です。これらを組み合わせることで、従来は不可能だったワークフローが可能になります。

この投稿では、マネージドセッションストレージを使ってエージェントのファイルシステム状態を永続化する方法と、エージェントの環境内でシェルコマンドを直接実行する方法を説明します。

AgentCore Runtimeセッションの内部

AgentCore Runtime は、各セッションを専用のmicroVM で実行し、独立したリソース(独自のカーネル、メモリ、ファイルシステムを含む)を提供します。このアーキテクチャは強固なセキュリティ境界を提供しますが、その一方で、すべてのセッションがクリーンなファイルシステムに起動することも意味します。microVM が終了すると、明示的なstop によってであれ、idle timeout によってであれ、エージェントが作成したものはすべて消えます。

それが実運用で何を意味するのかを考えてみましょう。コーディングエージェントが20分間かけてプロジェクトをひな形化します。ディレクトリ構造の設定、依存関係のインストール、雛形コードの生成、ビルドツールの設定です。ランチに離れて戻り、同じセッションを呼び出すと、エージェントは最初からやり直します。インストールし直されるすべてのパッケージ、再生成されるすべてのファイル。エージェントが有用な作業を再び始めるまでに、20分間の計算が無駄に消費されます。この制限は、セッション停止の前にファイルを Amazon Simple Storage Service(Amazon S3)へアップロードするチェックポイントのロジックを書いて、再開時にダウンロードすることで、または状態を失わないようにセッションを維持することで対処できます。この回避策は機能しますが、ファイルシステムレベルの制限を解消するものではなく、複雑さがエージェントのコードに追加されてしまいます。

同じ摩擦は決定論的な操作にも存在します。エージェントが修正を完了し、テストを実行する必要があるとき、コマンドをツール呼び出しとしてLLMにルーティングすると、決定論的で予測可能な操作に対してトークンコスト、レイテンシ、そして非決定性が加わります。別の選択肢は、ランタイムの外でそれとは別のオーケストレーションロジックを構築することです。ただしそれには、エージェントのファイルシステムへ接続する必要があり、複雑さが増します。

マネージドセッションストレージ(パブリックプレビュー):生き残る状態

最初の課題であるエフェメラルなファイルシステムは、マネージドセッションストレージによって解決されます。これは、停止/再開サイクルを生き延びる永続的なディレクトリをエージェントに提供します。永続化はランタイムに組み込まれており、エージェント作成時に設定されます。そのディレクトリに書き込まれたすべての内容は、計算環境が置き換えられても保持されます。

永続ストレージの設定

永続ストレージを設定するには、次の手順を実行します:

エージェントランタイムの filesystemConfigurationsessionStorage を追加します:

aws bedrock-agentcore create-agent-runtime \
  --agent-runtime-name "coding-agent" \
  --role-arn "arn:aws:iam::111122223333:role/AgentExecutionRole" \
  --agent-runtime-artifact '{"containerConfiguration": {
    "containerUri": "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-agent:latest"
  }}' \
  --filesystem-configurations '[{
    "sessionStorage": {
      "mountPath": "/mnt/workspace"
    }
  }]'

または、Python 向けの AWS SDK(Boto3)を使用します:

import boto3

# Use the control plane client for creating and managing runtimes
control_client = boto3.client('bedrock-agentcore-control', region_name='us-west-2')

response = control_client.create_agent_runtime(
    agentRuntimeName='coding-agent',
    agentRuntimeArtifact={
        'containerConfiguration': {
            'containerUri': '123456789012.dkr.ecr.us-west-2.amazonaws.com/my-agent:latest'
        }
    },
    roleArn='arn:aws:iam::111122223333:role/AgentExecutionRole',
    protocolConfiguration={
        'serverProtocol': 'HTTP'
    },
    networkConfiguration={
          'networkMode': 'PUBLIC'
    },
    filesystemConfigurations=[{
        'sessionStorage': {
            'mountPath': '/mnt/workspace'
        }
    }]
)

注:AgentCore は2つの Boto3 サービスクライアントを使用します。コントロールプレーンのクライアント(bedrock-agentcore-control)は、CreateAgentRuntimeGetAgentRuntimeDeleteAgentRuntime のようなランタイムのライフサイクル操作を処理します。データプレーンのクライアント(bedrock-agentcore)は、InvokeAgentRuntimeInvokeAgentRuntimeCommand のようなセッション操作を処理します。マウントパスは /mnt で始まり、その後にフォルダ名を続ける必要があります(たとえば /mnt/workspace/mnt/data)。設定後は、エージェントがこのパスに書き込む任意のファイルが、自動的にマネージドストレージへ永続化されます。

停止/再開の体験

エージェントを呼び出して、プロジェクトのセットアップを依頼します:

aws bedrock-agentcore invoke-agent-runtime \
  --agent-runtime-arn "arn:...:agent-runtime/coding-agent" \
  --runtime-session-id "session-001" \
  --payload '{"prompt": "Set up the project and install dependencies in /mnt/workspace"}'

エージェントはコードをダウンロードし、依存関係をインストールし、そのセッション専用の microVM 内で設定を生成します。次に、セッションを停止するか、idle timeout が発動すると、microVM は終了します。

そして、同じ runtime-session-id で再度呼び出します:

aws bedrock-agentcore invoke-agent-runtime \
  --agent-runtime-arn "arn:...:agent-runtime/coding-agent" \
  --runtime-session-id "session-001" \
  --payload '{"prompt": "Run the tests and fix any failures"}'

新しいコンピュート環境(microVM)が起動し、同じストレージをマウントします。エージェントは、/mnt/workspace を、ソースファイル、node_modules、ビルド成果物、.git の履歴を含めて、まさにそのままの状態で見ます。エージェントは再インストールや再生成を行う必要なしに、思考の途中から引き継ぎます。

エージェントの観点では、特別なことは何も起きていません。いつも通り、ディレクトリ内のファイルを読み書きするだけです。エージェントのコードを変更する必要はありません—特別なAPIも、保存/復元のロジックも、シリアライズもありません。/mnt/workspace にファイルを書き込み、セッションを停止し、再開すれば、そのファイルはそこにあります。

昨日のセッションのコンピュート環境(microVM)は消えていますが、ファイルシステムは生き残っています。

データが生き続ける期間を制御する

デフォルトでは、セッションストレージのデータはアイドル状態の14日間保持されます。このウィンドウ内にセッションが再開されない場合、データはクリーンアップされます。エージェントのエンドポイントが別バージョンに更新され、同じ runtime-session-id が呼び出された場合、セッションデータは更新されます。これにより、マウントされたディレクトリに、新しいバージョン用のクリーンなコンテキストが提供されます。

複数日間にまたがる開発ワークフロー

それが実際にどのような見え方をするか、具体的に見ていきましょう。Day 1—あなたはコーディングエージェントを呼び出し、コードベースをダウンロードし、ファイルを調査し、開発環境をセットアップするよう依頼します:

aws bedrock-agentcore invoke-agent-runtime \
  --agent-runtime-arn "arn:...:agent-runtime/coding-agent" \
  --runtime-session-id "fefc1779-e5e7-49cf-a2c4-abaf478680c4" \
  --payload '{"prompt": "Download the code from s3://amzn-s3-demo-bucket/fastapi-demo-main.zip and list all files"}'

エージェントはリポジトリを /mnt/workspace にダウンロードし、展開して、結果を報告します:

Files in the fastapi-demo-main project:
- Dockerfile
- README.md
- main.py
- requirements.txt

あなたはノートPCを閉じて帰宅します。Day 2—同じセッションIDで呼び出します:

aws bedrock-agentcore invoke-agent-runtime \
  --agent-runtime-arn "arn:...:agent-runtime/coding-agent" \
  --runtime-session-id "fefc1779-e5e7-49cf-a2c4-abaf478680c4" \
  --payload '{"prompt": "Add a new function called hello_world to main.py"}'

エージェントは、プロジェクトをまさにそのままの状態で見ます。main.py を直接変更します。再ダウンロードも、再展開もありません。エージェントにファイル一覧を尋ねると、新しく追加した hello_world 関数を含む修正済みの main.py を含め、すべてそこにあります。昨日のコンピュート環境(microVM)はすでに終了していますが、作業は維持されています。

これで最初の課題は解決されますが、次はあなたのエージェントが新しいコードを書いたので、それが正しく動くことを確認する必要があります。ここで2つ目の機能が登場します。

シェルコマンドを実行:決定的な操作をエージェントの環境内で直接行う

2つ目の課題である、決定的な操作をLLM経由で回さずに実行することは、InvokeAgentRuntimeCommand によって解決されます。稼働中の AgentCore Runtime セッション内でシェルコマンドを直接実行し、HTTP/2 経由で出力をストリーミングできます。

重要な着眼点は、エージェントとシェルコマンドは得意なことが異なるという点です:

execute コマンドを使う エージェントを使う
操作は既知のコマンド(npm test, git push 操作には推論が必要(「このコードを分析してバグを直して」)
決定的に実行したい—同じコマンド、同じ結果 LLMに何をするかを判断させたい
長時間プロセスからのストリーミング出力が必要 エージェントにツールをループで使わせたい
操作はワークフロー内のバリデーションゲート 操作は創造的または分析的な作業
エージェントが開始する前に環境をブートストラップする エージェントにタスクに取り組ませたい

エージェントがコードを書き終えて、テストを実行する必要がある場合、そこにLLMを使う必要はありません。npm testnpm test です。コマンドは既知で、挙動は決定的であるべきであり、LLMによる解釈ではなく、生の出力が必要です。

コマンドの実行

AWS SDK for Python(Boto3)を使ってコマンドを実行します:

import boto3
import sys

client = boto3.client('bedrock-agentcore', region_name='us-west-2')

response = client.invoke_agent_runtime_command(
    agentRuntimeArn='arn:aws:bedrock-agentcore:us-west-2:111122223333:runtime/my-agent',
    runtimeSessionId='session-id-at-least-33-characters-long',
    body={
        'command': '/bin/bash -c "npm test"',
        'timeout': 60
        }
)

for event in response['stream']:
    if 'chunk' in event:
        chunk = event['chunk']

        if 'contentStart' in chunk:
            print("Command execution started")

        if 'contentDelta' in chunk:
            delta = chunk['contentDelta']
            if delta.get('stdout'):
                print(delta['stdout'], end='')
            if delta.get('stderr'):
                print(delta['stderr'], end='', file=sys.stderr)

        if 'contentStop' in chunk:
            stop = chunk['contentStop']
            print(f"
Exit code: {stop.get('exitCode')}, Status: {stop.get('status')}")

レスポンスは、リアルタイムに3種類のイベントをストリーミングします:

返却形式: {"translated": "翻訳されたHTML"}
イベント いつ 含まれるもの
contentStart 最初のチャンク コマンドの開始を確認します
contentDelta 実行中 stdout および/または stderr の出力
contentStop 最後のチャンク exitCodestatusCOMPLETED または TIMED_OUT

出力は生成されるのに合わせてストリーミングされるため、実行が完了するのを待つのではなく、最初の数秒で失敗を検知してすぐに対応できます。

コンテナは同じ(ファイルシステムも同じ)

重要なポイントはこれです。コマンドは、エージェントと同じコンテナ、ファイルシステム、および環境で実行されます。サイドカーではなく、ソケット越しに通信する別プロセスでもありません。エージェントが /mnt/workspace/fix.py に書き込んだファイルは、cat /mnt/workspace/fix.py を実行するコマンドから即座に見えます。同期ステップはなく、ファイル転送もなく、設定する共有ボリュームもありません。

AgentCore Runtime の microVM には、デフォルトで開発者ツールが含まれていません。つまり、コマンドが依存するツール(gitnpm、または言語ランタイムなど)は、コンテナイメージに追加するか、実行時に動的にインストールする必要があります。

利用方法を形作る設計上の選択

  • ワンショット実行。各コマンドは新しい bash プロセスを生成し、完了するまで(またはタイムアウトするまで)実行して返します。コマンド間で永続的なシェルセッションはありません。これは、エージェントフレームワークがコマンド実行をどのように使うかに一致しています。コマンドを作成し、実行し、出力を読み取り、次に何をするかを判断します。
  • ノンブロッキング。コマンド実行は、エージェントの呼び出しをブロックしません。同じセッション上でエージェントを呼び出し、コマンドを並行に実行できます。
  • コマンド間でステートレス。各コマンドは新しく開始され、シェルの履歴はなく、前のコマンドで設定した環境変数も引き継がれません。状態が必要な場合は、コマンドにエンコードしてください:cd /workspace && export NODE_ENV=test && npm test

人々がそれを使って作っているもの

  • テスト自動化 — エージェントがコードを書いた後、コマンドとして npm test または pytest を実行します。出力をストリームし、反復のために特定の失敗をエージェントへフィードバックします。
  • Git のワークフロー — ブランチ作成、コミット、プッシュは決定論的です。コマンドとして実行し、バージョン管理のロジックは LLM の外に置きます。
  • 環境ブートストラップ — レポジトリのクローン、パッケージのインストール、エージェント開始前のビルドツールのセットアップを行います。直接コマンドとして実行することで、より高速で信頼性が高くなります。
  • ビルドパイプライン — 指定どおりに正確に実行されるべき既知のコマンドを含むもの。たとえば:cargo build --releasemvn packagego build.
  • バリデーションゲート — エージェントがコードを書いた後、しかしコミットする前に、リンター、型チェッカー、セキュリティスキャナをゲートとして実行します。
  • デバッグ — 実行時の環境を調べます。インストール済みパッケージ、ディスク使用量、実行中のプロセスを確認してください。これらはエージェントの失敗を理解するのに役立ちます。

より良く組み合わせて:ファイルシステムは共有コンテキスト

管理されたセッションストレージ(パブリックプレビュー)により、エポックなファイルシステムという課題に対処します。コマンドアドレスによる、決定論的な操作という課題を実行します。それぞれ単独でも価値がありますが、ワークフロー全体を結び付ける同じファイルシステムを共有するため、組み合わせるとさらに強力になります。

エージェントランタイムで /mnt/workspace に管理されたセッションストレージが設定されている場合、すべてが同じ永続ディレクトリ上で動作します:

  • InvokeAgentRuntime はコードを書き込み、成果物を生成し、/mnt/workspace 内でファイルを管理します。
  • InvokeAgentRuntimeCommand は、同じ /mnt/workspace から読み取り、そこへ書き込むことで、テスト、Git 操作、ビルドを実行します。
  • セッションを停止します。Compute(microVM)はスピンダウンします。/mnt/workspace は永続化されます。
  • 翌日再開します。新しい Compute が同じストレージをマウントします。エージェントと実行コマンドの両方が同じファイルを参照します。

ファイルシステムは、エージェントの推論、決定論的な操作、そして時間をつなぐ共有コンテキストになります。コード上では次のようになります:

import boto3
import json

client = boto3.client('bedrock-agentcore', region_name='us-west-2')

AGENT_ARN = 'arn:aws:bedrock-agentcore:us-west-2:111122223333:runtime/my-coding-agent'
SESSION_ID = 'fefc1779-e5e7-49cf-a2c4-abaf478680c4'

def run_command(command, timeout=60):
    """シェルコマンドを実行し、終了コードを返します。"""
    response = client.invoke_agent_runtime_command(
        agentRuntimeArn=AGENT_ARN,
        runtimeSessionId=SESSION_ID,
        contentType='application/json',
        accept='application/vnd.amazon.eventstream',
        body={'command': command, 'timeout': timeout}
        )
    for event in response.get('stream', []):
        if 'chunk' in event and 'contentStop' in event['chunk']:
            return event['chunk']['contentStop'].get('exitCode')
    return None

# 手順 1: エージェントが問題を分析し、修正を作成します
# (推論タスク → InvokeAgentRuntime を使用)
response = client.invoke_agent_runtime(
    agentRuntimeArn=AGENT_ARN,
    runtimeSessionId=SESSION_ID,
    payload=json.dumps({
        "prompt": "JIRA-1234 を読み取り、/mnt/workspace に修正を実装してください"
    }).encode()
)
# エージェントの応答を処理します...

# 手順 2: テストスイートを実行します
# (決定論的な操作 → InvokeAgentRuntimeCommand を使用)
exit_code = run_command('/bin/bash -c "cd /mnt/workspace && npm test"', timeout=300)

# 手順 3: テストが通ったら、コミットしてプッシュします
# (決定論的な操作 → InvokeAgentRuntimeCommand を使用)
if exit_code == 0:
    run_command('/bin/bash -c "cd /mnt/workspace && git checkout -b fix/JIRA-1234"')
    run_command('/bin/bash -c "cd /mnt/workspace && git add -A && git commit -m \'Fix JIRA-1234\'"')
    run_command('/bin/bash -c "cd /mnt/workspace && git push origin fix/JIRA-1234"')

エージェントは、プラットフォームがコマンドを実行している間にコードを書きます。各要素は、それぞれ意図された用途に対応します。/mnt/workspace はマネージド・セッション・ストレージでバックアップされているため、このセッションを停止して翌日戻っても、エージェントが引き続き反復できるように、ワークスペース全体がそのまま残っています。

これがパターンです。エージェントが推論し、コマンド実行アクションが行われ、永続的なファイルシステムがそれを覚えています。これらの3つの機能は、ラップトップを閉じても途切れないループを形成します。

はじめに

両方の機能が現在利用可能です。使い始める方法は次のとおりです。

マネージド・セッション・ストレージ(パブリックプレビュー)— CreateAgentRuntime を呼び出す際に、sessionStorage を指定して filesystemConfigurations を追加します。/mnt で始まるマウントパスを指定してください。エージェントがそのパスに書き込んだ内容はすべて、停止/再開のサイクルをまたいで保持されます。許可される最大データ量は、セッションあたり 1 GB です。

コマンド実行 — 有効な任意のセッションで、コマンド文字列とタイムアウトを指定して InvokeAgentRuntimeCommand を呼び出します。このコマンドはエージェントと同じコンテナで実行され、同じファイルシステムにアクセスできます。

チュートリアルとサンプルコードを始めるには:

課題は2つから始まりました。1つ目は、セッションが停止すると仕事を失ってしまうエージェント。2つ目は、決定論的な操作で、LLM 経由でルーティングするか、ランタイムの外側で構築する必要があったことです。マネージド・セッション・ストレージとコマンド実行は、どちらの課題にも対応します。両者で共有されるファイルシステムにより、エージェントが推論し、コマンドが実行され、その作業がセッション間をまたいで保持される開発ループが作られます。新しい Amazon Bedrock AgentCore の機能をぜひ試して、あなたが作るものを教えてください。


執筆者について

広告