【登壇レポート】 AI Builders Day Online (プレイベント)で「Amazon Bedrock AgentCore 本番導入への道 アーキテクチャ設計の実践」というタイトルで登壇しました!

【登壇レポート】 AI Builders Day Online (プレイベント)で「Amazon Bedrock AgentCore 本番導入への道 アーキテクチャ設計の実践」というタイトルで登壇しました!

2025.11.29

はじめに

こんにちは、スーパーマーケット(ラ・ムー)が大好きなコンサルティング部の神野です。

2025年11月27日(木)に開催されたAI Builders Day Online (プレイベント)で登壇させていただきました!

https://jawsug.connpass.com/event/375739

何気にこういった社外の大きなコミュニティイベントでお話しするのは、初めてだったので緊張しましたね・・・! 他の登壇者の方も実践的なテーマばかりで実際にAIエージェント作成している方の話を聞けるのは面白くて、とても良いイベントでした!運営の皆様、改めてありがとうございました!

登壇資料

本登壇はAgentCoreの実践を見据えた話をしたく、少しでもAgentCoreを触ったことがある方を前提としています・・・!

CleanShot 2025-11-29 at 19.25.28@2x

申し訳ないですがAgentCoreの触り部分などを知りたい方は下記ブログを参考にしてください!

https://dev.classmethod.jp/articles/amazon-bedrock-agentcore-developersio-2025-osaka

資料の解説

Runtime Endpointの活用方法

Runtimeにはエンドポイントが存在し、デプロイするたびにバージョンを保持していてインクリメントされて、常にDEFAULTエンドポイントと最新バージョンは紐付きます。なのでエンドポイントを呼び出すと最新のバージョンが実行される形となります。

CleanShot 2025-11-29 at 19.27.20@2x

DEFAULT以外でも名前付きのエンドポイントを指定することが可能です。
例えば、本番用のエンドポイントをprodみたいな形で名前を付けることが可能で、名前付きのエンドポイントは下記のようにqualifierパラメータをエンドポイントの名前を指定すれば呼び出せます。
逆にqualifierを何も指定しなければDEFAULTのエンドポイントが実行されます。

https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{EncodedAgentARN}/invocations?qualifier=prod

CleanShot 2025-11-29 at 19.29.43@2x

本番向けにRuntimeでホストするアプリケーションを考えた際に、最新バージョンを入念にテストして、問題なければ本番エンドポイントに紐づくバージョンをアップデートする形になると思います。

CleanShot 2025-11-29 at 19.31.38@2x

CloudFront / Lambda Proxyパターン

Runtimeをデプロイして使用できるエンドポイントのURLは下記のような形式で使用できます。

https://bedrock-agentcore.ap-northeast-1.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aap-northeast-1%3A123456789012%3Aagent-runtime%2Fabcd1234/invocations

うーーん・・・、アカウントIDが含まれたり、ARNをエンコードする必要があるのは少し抵抗がありますよね。また、カスタムドメインなどを使いたいケースもあると思います。

CleanShot 2025-11-29 at 19.36.09@2x

ここで上記問題に対応するためにCloudFrontをAgentCore Runtimeの前段で使用するケースを考えてみます。 カスタムドメインや場合によってはWAFも使用できるのは嬉しいポイントですよね。 これでARNをエンコードしたり、アカウントIDの露出を気にする必要はなくなります。

CleanShot 2025-11-29 at 19.37.44@2x

次はLambda + CloudFrontを前段に配置するケースを考えてみます。
こちらだと先ほどの構成に加えてLambdaで処理をインターセプトしたいユースケースや、Cognitoと連携して独自トークンの検証をしたいなども可能になるかと思います。

次にアクセス制御ですが、AgentCoreをIAM認証にすることで、基本的にLambda経由でしかアクセスできない構成が作れます。CloudFront単体だとトークンさえあれば元のURLでも実行可能でしたが、この構成なら元のURLはIAM権限がない限り叩けません。

とはいえ、現状AgentCoreにはリソースベースのポリシーが存在しないので、別途アクセス権限を持つIAMがあれば直接呼び出せてしまいます。「Lambda経由限定」を厳密に担保したい場合は、IAM権限の付与範囲を慎重に設計する必要がありますね。

CleanShot 2025-11-29 at 19.38.42@2x

直近のAPI Gatewayのアップデートでストリーム応答も可能になりました。このアップデートによって、API Gateway + Lambdaを前段に配置することも実現できます。 基本は先ほどと変わりはないですが、API Gatewayを前段に配置することで、API Keyの利用や認証の設定が容易になるのは嬉しいですよね。

CleanShot 2025-11-29 at 19.45.41@2x

いくつか案をご紹介してきましたが、特に何かが正解と言ったわけではなく、要件に応じて最適なアーキテクチャを考えていく必要があるかと思います。その考える際に、上記構成を思い出して少しでも参考になったら嬉しく思います。

フロントエンドとの連携

AgentCoreはAIエージェントをホストする上で便利なマネージドサービスなので、フロントエンドと連携する際もできるだけ便利なマネージドサービスを組み合わせていきたいですよね。ざっと下記のような選択肢があると思います。

  • Lambda

  • Amplify

  • App Runner

  • ECS

CleanShot 2025-11-29 at 19.48.32@2x

AmplifyやApp Runnerはサクッとアプリを作るときに便利でよく使っているのですが、AIアプリケーションとは相性が悪い制約があるので注意したいです。悲しい。

  • Amplify

    • Next.js API routesのストリーミングが動作しない(バッファリングされる) AI SDKなどをNext.js バックエンドで使用しようとすると使えなくて絶望します
  • AppRunner

    • 120秒のリクエストタイムアウト

      • エージェントとのやり取りが長時間に及ぶとタイムアウトになる可能性
    • WebSocketサポートなし(roadmapで最多要望)

      • StreamlitはWebSocketを使用するためApp Runnerでホストするのは難しい

CleanShot 2025-11-29 at 19.54.25@2x

Amplifyでホストする場合は、クライアントから直接リクエストを送る形になります。

CleanShot 2025-11-29 at 20.08.50@2x

Lambda関数にLambda Web Adapterを使ってNext.jsをホストするのが、コスト的に安くかつ手軽で良いかと思います
CleanShot 2025-11-29 at 20.10.34@2x

本番環境で手堅く実装したいならECS + ALB の組み合わせを選ぶことになると思います。直近のアップデートでECS Express Modeが誕生したことにより導入の敷居は下がった印象はあります。ただ、ECSでの最小コストはApp Runnerなどのマネージドサービスの最小コストよりは高くなる点に注意ですね。

CleanShot 2025-11-29 at 20.12.55@2x

GenU(Generative AI Use Cases JP)を使って手軽にAgentCoreを組みこむことも可能です。フロントエンドを作成するモチベーションがない場合はいい選択肢になるかと思います。ただ現時点では実験的な機能になるので注意が必要です。
CleanShot 2025-11-29 at 23.02.36@2x

GenUとの連携は試してみたブログもあるので、こちらも必要に応じてご参照ください。

https://dev.classmethod.jp/articles/generative-ai-use-cases-jp-genu-amazon-bedrock-agentcore

Tips:Runtime lifecycle settings

Runtime には idleRuntimeSessionTimeout(アイドル時のタイムアウト)と maxLifetime(最大稼働時間)パラメータが存在し、セッションの自動終了タイミングを制御できます。

CleanShot 2025-11-29 at 20.18.40@2x

え、そんな値何を設定するの・・・?と思いますが公式ドキュメントに設定値のベストプラクティスが記載されているので、ベストプラクティスと同じく、まずはデフォルト値からユースケースに応じて調整して形になると思います。

まずはデフォルト値(idle: 15分、max: 8時間)で運用を開始し、実際の利用パターンを見ながら調整するのがベストプラクティスです。開発・デモ環境では短め(idle: 2-5分)に設定してコストを抑え、本番環境ではユーザー体験を優先して長め(idle: 10-15分)に設定することを推奨します。

https://docs.aws.amazon.com/ja_jp/bedrock-agentcore/latest/devguide/runtime-lifecycle-settings.html

CleanShot 2025-11-29 at 20.27.53@2x

Gatewayの利用イメージ / Semantic Searchを活用する

本登壇で一番熱く語りたかったポイントです。

Gatewayは既存のAPI、Lambda関数、各種サービスをMCP(Model Context Protocol)互換のツールに変換して、AIエージェントから簡単に呼び出せるようにしてくれるサービスです。また既存のMCP Serverとのハブにもなって中央集約的に管理もできます。

CleanShot 2025-11-29 at 20.29.31@2x

よく誤解されがちなのですが、GatewayはMCP Server自体をホストするものではないです。あくまで既存のLambda関数をツール化したり他のMCP Serverを中央集約的に管理するのが役目となります。MCP Server自体をホストしたいならRuntimeを使うことになるかと思います。

CleanShot 2025-11-29 at 20.30.02@2x

Gatewayはハブとわかりましたがメリットがわかりづらいですよね。Gatewayを使用しなくても、RuntimeからLambdaやMCP Serverを直接呼び出せるのに、Gatewayを挟むと一見複雑になるように見えます。

CleanShot 2025-11-29 at 20.32.43@2x

例えば、100個以上のツールがある場合を考えてみます。毎回MCPツールの定義を書くコードを書いたり、100個のツールをAIエージェントが適切に見つけられるのでしょうか。

CleanShot 2025-11-29 at 20.33.45@2x

この疑問に対してGatewayが役立ちます。Gateway側にツールを登録し集約することで、AIエージェント自体の処理は追加や変更するごとに変えずに、Gatewayを介してツールの情報を同期することが可能かつ、求められている適切なツールを探すのにはSemantic Search機能が活用できます。

CleanShot 2025-11-29 at 20.35.53@2x

Strands Agentsを使っている場合ならtool_call_syncメソッドが存在し、Gateway紐づいているツール情報を取得することが可能です。

from strands import Agent  
from strands.tools.mcp import MCPClient  
from mcp.client.streamable_http import streamablehttp_client  

# MCP Server への接続  

def create_transport():  
    return streamablehttp_client(  
        "https://xxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",  
        headers={"Authorization": f"Bearer {access_token}"}  
    )  

# MCPClient でツールを同期  

client = MCPClient(create_transport)  

with client:  
    # ツール一覧を取得(同期)  
    tools = client.list_tools_sync()  

    print(f"Found {len(tools)} tools:")  
    for tool in tools:  
        print(f"  - {tool.tool_name}")  

    # Agent にツールを渡す  
    agent = Agent(  
        model="anthropic.claude-3-5-haiku-20241022-v1:0",  
        tools=tools,  # MCP Server のツールを直接渡す  
        system_prompt="You are a helpful assistant."  
    )  

    # Agent が自動的に適切なツールを選択・実行  
    response = agent("List all orders")  
    print(response.message['content'][0]['text'])

CleanShot 2025-11-29 at 20.37.11@2x

ツール同期する際にSemantic Search機能も活用できます。MCP Serverがツールとして大量に使える状態にあるとコンテキストを圧迫および不適切なツールを使用する可能性があります。そういった時にSemantic Search機能を使って適切なツールを見つけてAIエージェントに使わせましょう。

CleanShot 2025-11-29 at 20.38.26@2x

GatewayでSemantic Searchを有効にすると、ツール名x_amz_bedrock_agentcore_searchで検索を呼び出せます。 使用したところレスポンスは関連度順にツールが返却されるようにみえます。

リクエスト例

{  
  "jsonrpc": "2.0",  
  "id": "search-request",  
  "method": "tools/call",  
  "params": {  
    "name": "x_amz_bedrock_agentcore_search",  
    "arguments": {  
      "query": "注文の状態を変更する"  
    }  
  }  
}

レスポンス例

{  
  "jsonrpc": "2.0",  
  "id": "search-request",  
  "result": {  
    "structuredContent": {  
      "tools": [  
        {  
          "name": "order-tools___update_order_status",  
          "description": "Update the status of an existing order. Use this to move orders through the fulfillment process (pending -> processing -> shipped -> delivered).",  
          "inputSchema": {  
            "type": "object",  
            "properties": {  
              "orderId": {  
                "type": "string",  
                "description": "The order ID to update (e.g., ORD-001)"  
              },  
              "status": {  
                "type": "string",  
                "description": "New status for the order. Valid values: pending, processing, shipped, delivered, cancelled"  
              }  
            },  
            "required": ["orderId", "status"]  
          }  
        },  
        {  
          ・・・  
        }  
      ]  
    }  
  }  
}

CleanShot 2025-11-29 at 20.39.07@2x

Strands Agentsで実装する場合はcall_tool_syncで検索しつつ、適切なツールをAIエージェントと同期することが可能です。

@app.entrypoint  
async def agent_handler(payload, context):  
    user_query = payload.get('prompt', '')  

    client = MCPClient(create_transport)  

    with client:  
        # ユーザーの質問から関連ツールを検索  
        search_result = client.call_tool_sync(  
            "x_amz_bedrock_agentcore_search",  
            {"query": user_query}  
        )  

        relevant_tools = search_result['structuredContent']['tools']  

        # 関連ツールだけで Agent を実行  
        agent = Agent(  
            model=model,  
            tools=relevant_tools,  
            system_prompt="..."  
        )  

        return agent(user_query)

CleanShot 2025-11-29 at 20.40.40@2x

Semantic Searchを使用することでコンテキスト汚染を回避することにつながります。ANTHROPICの記事もMCP Serverをツールとして登録しすぎると、ツールの定義や結果に過剰なトークンが消費され、エージェントの効率が低下する可能性があるといっています。

https://www.anthropic.com/engineering/code-execution-with-mcp

CleanShot 2025-11-29 at 20.42.05@2x

これは人間でも同じようなことが言えると思います。いきなり、新しい職場に行って全ての情報を詰め込まれても適切な行動はできず自分がやりたいことに対してアドバイスしてくれる人が欲しいですよね。 AIエージェントも同じで、最適に実行できるようSemantic Searchで適切なツールを教えてあげるイメージを持つとわかりやすいです。

CleanShot 2025-11-29 at 20.42.43@2x

まとめるとGatewayの使い方としては、組織に既存のLambda関数やMCP Serverがたくさんあって、組み合わせる場合はGatewayに軍配が上がる気がします。あくまでオプションの選択肢で上記以外の用途なら無理に使う必要はない気もします。シンプルにLambda関数やRuntimeにMCP Serverをホストして使う方が早いと思います。

CleanShot 2025-11-29 at 20.43.32@2x

補足ですが、直近Gatewayでしれっと認証なしモードの設定が可能になりました。 現状、RuntimeでMCP ServerをホストするとIAMかJWT認証が必須なので、パブリックな環境にMCP Serverをホストしたい際にGatewayをハブとする選択肢も考えられますね。

CleanShot 2025-11-29 at 20.45.53@2x

関連して、認証を設定してRuntime、Gatewayを介してMCP ServerをホストするにしてもVSCodeやCursorなどのエディターだとDCRのような動的なトークン認証が難しく、Bearer Tokenを取得せざるを得ません。MCPの拡張で認証できるようになることを期待したいですね。

CleanShot 2025-11-29 at 21.15.20@2x

ただIAM認証でRuntimeの認証を設定して、mcp-proxy-for-awsを活用すればIAMの権限を使って、MCPクライアントから独自のMCP Serverにアクセスする方法も考えられます。Claude CodeやCursorなどで実現できないか検証してみたいです。

https://github.com/aws/mcp-proxy-for-aws

Memoryの制御

前提としてMemoryのデータ構造をおさえます。ユーザー毎にactor_id、セッション毎にsession_idがビルトインの属性で存在するので簡単にユーザー毎の会話履歴を保持可能となります。

CleanShot 2025-11-29 at 21.22.54@2x
短期記憶の単位はChatGPTやClaudeなどの会話履歴タブがイメージしやすいです。

CleanShot 2025-11-29 at 22.52.44@2x

ユーザーの質問はactor_idでどのユーザーか識別されるので、リクエストでユーザーを識別する値を入れて、AIエージェント側でactor_idとみなす形になると思います。

CleanShot 2025-11-29 at 21.24.07@2x

AgentCoreの認証をJWT認証としている場合、JWTをデコードしてactor_idに、デコードしたユーザー識別子を入れてactor_idに設定することも可能です。ユーザー毎の質問はIdentityと連携して簡単にMemoryと分離することが可能です。

CleanShot 2025-11-29 at 21.26.33@2x

Memoryの権限制御ですがアプリケーションだけではなく、インフラ側でも制御可能です。アプリケーションの設定ミスなどによる他者の記憶アクセスを回避することが可能です。JWTのIDTokenを活用して、Strands Agentsの処理で動的にIAMの権限を取得して権限分離を実現できます。

例えば下記のように記載して設定可能です。

{  
  "Version": "2012-10-17",  
  "Statement": [  
    {  
      "Effect": "Allow",  
      "Action": [  
        "bedrock-agentcore:CreateEvent",  
        "bedrock-agentcore:GetMemory",  
        "bedrock-agentcore:ListMemoryRecords",  
        "bedrock-agentcore:UpdateMemory",  
        "bedrock-agentcore:DeleteMemory"  
      ],  
      "Resource": "arn:aws:bedrock-agentcore:us-west-2:123456789012:memory/*",  
      "Condition": {  
        "StringEquals": {  
          "bedrock-agentcore:actorId": "${cognito-identity.amazonaws.com:sub}"  
        }  
      }  
    }  
  ]  
}

CleanShot 2025-11-29 at 21.26.52@2x

上記の設定を行うことで、ユーザーAさんが保持している権限ではユーザーBさんの記憶にアクセスできません。アプリケーション側で誤ってユーザーBの記憶にアクセスしようとしてもIAMの権限で拒否されます。

CleanShot 2025-11-29 at 21.28.07@2x

デプロイ手法について

直接アップロードかコンテナイメージをアップロードするか選択可能です。Zipアップロードは250MB以下のパッケージをZIP形式で素早くデプロイでき、更新も高速です。 一方、コンテナベースは1GBまでの大規模パッケージや特殊な依存関係に対応し、既存のCI/CDパイプラインも活用できます。開発フェーズでは直接コードで素早くプロトタイピングし、本番環境ではコンテナへ移行するハイブリッドアプローチも有効です。

CleanShot 2025-11-29 at 21.29.16@2x
公式ドキュメントに直接アップロードかコンテナイメージのどちらを採用するかの比較情報も記載があるので、選択する際は参考になると思います。

https://docs.aws.amazon.com/ja_jp/bedrock-agentcore/latest/devguide/runtime-get-started-code-deploy.html#runtime-code-deploy-concepts

CleanShot 2025-11-29 at 21.29.54@2x

おわりに

本登壇ではAgentCoreを本番利用する際に注意するポイントをいくつかご紹介させていただきました。何か1つでも皆様にとって新しい発見であったり、「AgentCoreをもっと使いこなしてみよう!」、「もっとAgentCoreを知りたい!」と思うきっかけになれば幸いです。次はIdentityをじっくり解説したいですね!

本記事が少しでも参考になりましたら幸いです!最後までご覧いただきありがとうございましたー!

この記事をシェアする

FacebookHatena blogX

関連記事