4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bedrock AgentCoreにStrandsで作成したAIエージェントをデプロイして、Lambdaから呼び出すアプリを作ってみた

Last updated at Posted at 2025-09-04

はじめに

AWSの新サービス「Amazon Bedrock AgentCore」とAWSの開発したオープンソースAIエージェントSDK「Strands Agents」を使って、週刊AWSの記事を自動で要約・解説して、読者のレベル(初級者・中級者)ごとにコンテンツをWebサイトで公開するシステムを構築してみました。MCPサーバーとの連携も行っています。
この記事では、AgentCoreとStrandsの概要から実際の開発で遭遇した課題、そして最終的な実装まで詳しく解説します。

LangChainのLLMを使った同じようなアプリ開発に興味がある方は、こちらを参照ください。LangChainを使った経緯も書いています。
Bedrock AgentCoreにLangChainで作成したBedrockエージェントをデプロイして、Lambdaから呼び出すアプリを作ってみた

完成したWebサイト

生成されたトップページと実際の記事は以下です。
気が向いたら公開しようと思います・・・
コードは整理したらGitHubを載せます。

トップページ:

image1.png

実際の記事:

image2.png

Amazon Bedrock AgentCoreとは

Amazon Bedrock AgentCoreは、エンタープライズレベルのAIエージェントを構築・デプロイするためのフルマネージドサービスです。従来のエージェント開発では、スケーリング、セキュリティ、メモリ管理、オブザーバビリティなどの運用面を個別に実装する必要がありましたが、AgentCoreはこれらの機能を統合的に提供します。

なかでも、注目すべき機能として、短期・長期メモリの管理、ID・アクセス制御の統合、MCP(Model Context Protocol)を通じたツール連携、オブザーバビリティが挙げられます。

参考:Amazon Bedrock AgentCore の紹介 – あらゆる規模で AI エージェントを安全にデプロイし、運用する

Strandsエージェントとは

Strandsは、AWSが開発したオープンソースのAIエージェントSDKです。わずか数行のコードでAIエージェントを構築・実行するモデル駆動型アプローチを採用しています。Amazon Q Developer、AWS Glue、VPC Reachability Analyzerなど、AWSの複数チームが既に本番環境で使用している実績があります。

参考:Strands Agents – オープンソース AI エージェント SDK の紹介

AWS Knowledge MCP Serverとは

本システムでは、AWS Knowledge MCP Serverとの連携もしています。
AWS Knowledge MCP Serverは、AWSが提供するMCPサーバーです。最新のAWSドキュメント、APIリファレンス、アーキテクチャガイダンス、ベストプラクティスなどの公式情報にリアルタイムでアクセスできます。今回のプロジェクトでは、Strandsエージェントがこのサーバーを通じて最新のAWS情報を参照し、正確で信頼性の高い要約を生成します。

システム構成

構築したシステムは以下の構成になっています。
Lambda関数が週刊AWSのRSSフィードを取得し、AgentCoreにデプロイしたStrandsエージェントを呼び出して記事を要約します。生成された要約は初心者・中級者向けに分けられ、HTMLページとしてS3に保存されます。EventBridgeによる定期実行とDynamoDBでの既読管理により、新しい記事のみを自動処理します。最終的にCloudFrontを通じて静的サイトとして配信されます。

AgentCore Memoryについては、Short-term Memory と Long-term Memoryの二つがあり、その特徴は以下のようです。

今回のユースケースとして、Short-term が利用できるかと思いましたが、Short term memoryでは、実際、同一セッション/アクターの会話履歴が保存されるため、合わないと思い、DynamoDBを利用しました。

  • Short:Short-term Memoryは、セッション中の会話履歴を保持する機能
  • Long:Long-term Memoryは、Short-term Memoryから自動的に重要な情報を抽出・統合する機能

参考:[Amazon Bedrock AgentCore]Memory機能で会話履歴を記憶するエージェントを実装してみた

アーキテクチャ図

  • Lambda: RSS取得・要約・HTML生成・S3アップロード
  • EventBridge: 毎週月曜・火曜12時に実行
  • DynamoDB: 既読記事管理
  • S3: 静的サイトホスティング
  • CloudFront: CDN配信
  • AgentCore + Strands Agent: 記事要約生成

開発でハマった課題

CPUアーキテクチャの違いによる問題

当初、開発はCloudShellで進めていましたが、CPUアーキテクチャの違いが問題になりました。CloudShellはx86_64アーキテクチャで実行されていますが、AgentCoreはコンテナをARM64アーキテクチャで実行することを要求します。

⚠️ [WARNING] Platform mismatch: Current system is 'linux/amd64' but Bedrock AgentCore requires 'linux/arm64'.

CodeBuildでのエラー確認

AgentCoreのデプロイはCodeBuildで実行されるため、エラーが発生した際はCodeBuildコンソールでログを確認することができます。

要約が途中で切れる問題の調査と解決

テスト中、生成された記事が途中で切れてしまう問題が発生しました。原因を特定するため、Bedrockが何をインプット・アウトプットしているのか、エージェントの処理内容を詳しく確認するため、Bedrockコンソールの設定からモデル呼び出しログを有効化しました。

※AgentCoreのObservavlity機能では、上記も確認できます。とても助けられました。
※そのため、Bedrockをモデルに利用していなくても、確認できるので便利です。

ログを確認した結果、問題の原因は出力トークンの上限設定であることが判明しました。モデルの設定を調整して十分なトークン数を確保することで、この問題を解決しました。

タイムアウト問題

長い記事の要約処理で、boto3のデフォルトタイムアウト(60秒)により処理が中断される問題が発生しました。

Read timeout on endpoint URL: "https://bedrock-agentcore.us-west-2.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aus-west-2%3A622632352793%3Aruntime%2Fweekly_aws_summary_agent-aeU9lkEVOl/invocations"

この問題は、以下の二箇所でタイムアウト設定を延長することで解決しました:

1. Lambda側(AgentCore呼び出し)

config = Config(read_timeout=1800)  # 30分に延長
bedrock_agentcore = boto3.client('bedrock-agentcore', config=config)

2. AgentCore側(Bedrock呼び出し)

model = BedrockModel(
    boto_client_config=Config(
        read_timeout=1800  # 30分に延長
    ),
    model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
    max_tokens=6144
)

StrandsのBedrockModelクラスを使用することで、AgentCore内でのBedrock呼び出しタイムアウトも適切に設定できました。

再ローンチの必要性

開発中、エージェントの設定変更後に期待通りの動作をしない場合がありました。このような場合は、agentcore launchコマンドで再デプロイすることで問題が解決することが多くありました。

Strandsエージェントのレスポンス処理問題

最も困難だった課題の一つが、Strandsエージェントからのレスポンス形式の解析でした。当初、AgentCoreからのレスポンスがJSON形式で返されると想定していましたが、実際には文字列化されたPythonオブジェクトとして返されていました。

"{'result': AgentResult(stop_reason='end_turn', message={'role': 'assistant', 'content': [{'text': '実際のテキスト内容'}]})}"

この問題に対しては、以下で対応しました:

  1. レスポンス形式の特定: デバッグログを追加してAgentCoreからの実際のレスポンス内容を確認
  2. 正規表現による抽出: 文字列化されたオブジェクトから正規表現で実際のテキスト内容を抽出
  3. エスケープ文字の処理: \n\'などのエスケープされた文字を適切に変換

Strandsエージェントの戻り値がドキュメントの例とは異なる形式で返される場合があるのですが、これはエージェントだからなのか、そういう仕様なのかどちらかわからないですが、とにかく苦労しました・・・

AgentCoreにデプロイするStrandsエージェントの実装

AgentCoreにデプロイするStrandsエージェントは、BedrockAgentCoreAppを使用してエントリポイントを定義し、AWS Knowledge MCP Serverと連携してAWS公式情報を参照します。

from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
from botocore.config import Config

app = BedrockAgentCoreApp()

@app.entrypoint
def invoke(payload):
    content = payload.get("prompt", "Hello")
    audience = payload.get("audience", "初心者")
    
    # AWS Knowledge MCP Serverを初期化
    mcp = MCPClient(lambda: stdio_client(
        StdioServerParameters(
            command="uvx",
            args=["mcp-proxy", "--transport", "streamablehttp", "https://knowledge-mcp.global.api.aws"]
        )
    ))
    
    # 対象読者別のシステムプロンプト
    system_prompts = {
        "初心者": "あなたは初心者向けのAWS記事要約アシスタントです。既知のAWSサービスには外部ツールを使用せず、新しい・不明なサービスのみツールを使用してください。一度の回答で完結させてください。",
        "中級者": "あなたは中級者向けのAWS記事要約アシスタントです。既知のAWSサービスには外部ツールを使用せず、新しい・不明なサービスのみツールを使用してください。一度の回答で完結させてください。"
    }
    
    # タイムアウトを1800秒(30分)に延長したBedrockModelを作成
    model = BedrockModel(
        boto_client_config=Config(
            read_timeout=1800,
            retries=dict(max_attempts=3, mode="adaptive")
        ),
        model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        max_tokens=6144,
        temperature=0.1
    )
    
    # MCPクライアントを起動してエージェントを作成・実行
    with mcp:
        agent = Agent(
            model=model,
            system_prompt=system_prompts.get(audience, system_prompts["初心者"]),
            tools=mcp.list_tools_sync()
        )
        
        prompts = {
            "初心者": f"元のタイトルをそのまま使用し、「はじめに」セクションは作らず、直接「### トピック名」から始めてください。専門用語を避けて初心者向けに説明してください。\n\n記事内容: {content}",
            "中級者": f"元のタイトルをそのまま使用し、「はじめに」セクションは作らず、直接「### トピック名」から始めてください。アップデート内容、メリット、導入方法、注意点を中級者向けに説明してください。\n\n記事内容: {content}"
        }
        
        prompt = prompts.get(audience, prompts["初心者"])
        
        result = agent(prompt)
        
    return {"result": result}

if __name__ == "__main__":
    app.run()

LambdaからAgentCoreを呼び出す実装

LambdaからAgentCoreのエージェントを呼び出す実装では、boto3クライアントを使用してエージェントランタイムAPIを呼び出します。

def call_agentcore_agent(content, audience):
    config = Config(read_timeout=1800)
    bedrock_agentcore = boto3.client('bedrock-agentcore', config=config)
    session_id = f'session_{hashlib.md5(f"{content}_{audience}".encode()).hexdigest()}'
    
    payload = json.dumps({
        "prompt": content,
        "audience": audience
    })
    
    try:
        response = bedrock_agentcore.invoke_agent_runtime(
            agentRuntimeArn=os.environ['AGENTCORE_ARN'],
            runtimeSessionId=session_id,
            payload=payload
        )
        
        response_body = response['response'].read()
        response_str = response_body.decode('utf-8')
        
        # 文字列からAgentResultのテキストを抽出
        match = re.search(r"'text': '([^']*(?:\\'[^']*)*)'\}\]", response_str)
        if match:
            # エスケープされた文字を元に戻す
            result = match.group(1).replace('\\n', '\n').replace('\\\'', "'").replace('\\', '')
        else:
            result = response_str
        
        return result
    except Exception as e:
        return f'AgentCore呼び出しエラー: {str(e)}'

デプロイ手順

システムのデプロイは3つのステップで実行します。まずAgentCoreにエージェントをデプロイし、次にCloudFormationでAWSリソースを作成し、最後にLambda関数を更新します。

AgentCoreエージェントのデプロイ

CloudShellで以下のコマンドを実行し、StrandsエージェントをAgentCoreにデプロイします。

# Python 3.10以上が必要なため、CloudShellでPython 3.12をインストール
sudo yum install python3.12 -y
sudo ln -sf /usr/bin/python3.12 /usr/bin/python3
python3 --version

# 仮想環境の作成とツールキットのインストール
python3 -m venv agentcore-env
source agentcore-env/bin/activate
pip install --upgrade pip
pip install bedrock-agentcore-starter-toolkit

# エージェントの設定とデプロイ(大文字は自動作成されるECRで引っかかる、-はagentcoreのエージェーンと名で引っかかる)
agentcore configure --entrypoint agentcore.py --name weekly_aws_summary_strands_agent

agentcore launch

AWSリソースのデプロイ

AWSコンソールからCloudFormationテンプレート(infrastructure.yaml)をデプロイし、Lambda、S3、DynamoDBなどのリソースを作成します。

Lambda関数の更新

依存ライブラリを含めたLambdaパッケージを作成し、関数を更新します。

# パッケージの作成とデプロイ
mkdir lambda-package
cp lambda_function.py lambda-package/
cp lambda-requirements.txt lambda-package/requirements.txt
cd lambda-package
pip install -r requirements.txt -t .
zip -r ../lambda-package.zip .
cd ..

aws lambda update-function-code \
  --function-name weekly-aws-summery-agent \
  --zip-file fileb://lambda-package.zip

動作確認

デプロイ完了後、以下のコマンドでシステムの動作を確認できます。EventBridgeスケジュールは毎週月曜・火曜12時に自動実行されますが、手動でもテスト可能です。

# エージェントの処理が長いため非同期実行(バックグラウンドで実行)
aws lambda invoke \
  --function-name weekly-aws-summery-agent \
  --invocation-type Event \
  --payload '{}' \
  response.json

# ログのリアルタイム監視
aws logs tail /aws/lambda/weekly-aws-summery-agent --follow

まとめ

Amazon Bedrock AgentCoreを使用したエージェントアプリケーションの開発は、今後AIエージェントを開発するにあたって、多くの学びがありました。特にCPUアーキテクチャの違いやタイムアウト時間、トークン数など、実際の開発でしか遭遇しない課題を通じて、AgentCore、Bedrcokの特性をより深く理解できました。

今回のエージェントは、Strandsのモデル駆動型アプローチとAWS Knowledge MCP Serverを活用した本格的なAIエージェントです。今後はAgentCoreのメモリ機能やゲートウェイ機能の活用、より複雑なマルチエージェント構成の実装など、AgentCoreの高度な機能を実装していきたいと思います。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?