VPoTの岩本 (iwamot) です。
本ブログの新着記事をレビューしてくれるAIエージェント「ブログほめ太郎」について、実行環境をAWS LambdaからAmazon Bedrock AgentCore Runtimeに移行しました。
今回の記事では、なぜ移行したのか、どのように移行したのかをお伝えします。
なぜ移行したのか
ブログほめ太郎をAgentCore Runtimeに移行した理由は大きく2つあります。
- 汎用的なLambdaより、AIエージェントに特化したAgentCore Runtimeのほうが実行環境として好ましい(餅は餅屋)と以前から考えていた
- Amazon EventBridgeスケジューラからAgentCore Runtimeが呼び出せるようになった(図1)

つまり、AWSの機能改善によって、理想的な運用が可能になったからというわけです。
どのように移行したのか
移行は以下の手順で進めました。
agentcore createで初期コードを生成- コードを調整
terraform applyでデプロイ
1. agentcore create で初期コードを生成
まず、Bedrock AgentCore Starter Toolkitを使って、初期コードを生成しました。
agentcore create --project-name bloghometaro \ --template production \ --iac Terraform \ --non-interactive
IaCをCDKでなくTerraformにしたのは、ENECHANGEでは全社的にTerraformを活用しているためです。
2. コードを調整
続いて、コードを調整しました。調整のポイントは以下の通りです。
- ブログほめ太郎では不要なファイルやTerraformリソースを削除(おもにMCPやAgentCore Memory関連)
- 足りないTerraformリソースを追加(EventBridgeスケジューラなど)
- Dockerビルドコマンドを調整 (
terraform/bedrock_agentcore.tf) src/main.pyを差し替え
terraform/bedrock_agentcore.tf で定義されているDockerビルドコマンドについては、AgentCore RuntimeがARM64のみサポートしているため、以下のように調整しました。
docker build -t ... ↓ docker build --platform linux/arm64 -t ...
また、src/main.py は以下の内容で差し替えました。Lambda向けのハンドラ関数を定義しなくて済むので楽です。
# src/main.py import gc import os from typing import List from bedrock_agentcore.runtime import BedrockAgentCoreApp from pydantic import BaseModel, Field from strands import Agent from strands.models import BedrockModel from strands.session.s3_session_manager import S3SessionManager # /var/task のままだと、slackツールのimport時にディレクトリ作成エラーになる # https://github.com/strands-agents/tools/issues/199 os.chdir("/tmp") from strands_tools import http_request, rss, slack app = BedrockAgentCoreApp() # 環境変数から設定を取得 RSS_URL = os.environ.get("BHT_RSS_URL", "https://tech.enechange.co.jp/feed") SLACK_CHANNEL_ID = os.environ.get("BHT_SLACK_CHANNEL_ID", "") SESSION_BUCKET = os.environ.get("BHT_SESSION_BUCKET", "") NEW_ARTICLE_FINDER_PROMPT = f""" あなたは新着記事のURLリストを取得する専門エージェントです。 1. RSSフィード {RSS_URL} を参照する 2. 最後にレビューした記事のURL(システムメッセージで提供)より後に公開された記事を取得する - 最後にレビューした記事のURLが提供されていない場合は、最新記事1件を取得する 3. 取得した記事のURLのみをシンプルなリストとして返す(古い順) - 例:["https://example.com/article1", "https://example.com/article2"] - 新着記事がない場合は空のリスト [] を返す - 説明は不要、URLリストのみを出力すること """ # convert_to_markdown=True を指定しないとHTMLで全文参照され、 # トークン量が増えることがある ARTICLE_REVIEWER_PROMPT = """ あなたは技術ブログ記事をレビューする専門エージェントです。 1. http_requestツールで当該記事の全文を参照する - convert_to_markdown=Trueを必ず指定すること 2. 日本語400字程度で、技術的に価値のあるレビューメッセージを生成する - 「<!channel> 新着記事レビューです!」から始める - 記事タイトルとURLを紹介する - 投稿に感謝する。筆者名が分かれば名前で呼びかける(会社名やチーム名は不要) - 絵文字や *アスタリスク1つ* を使って適度に強調する - 太字にしたい場合は、 *アスタリスク1つだけ* で囲むこと - いかなる場合も、アスタリスクの前後には必ずスペースを入れること - アスタリスク2つ(`**`)は絶対に使わないこと - レビューメッセージ以外の出力は不要 技術的レビューの観点例: - 読者が得られる学び - 技術的な新規性や独自性 - さらに深掘りできる内容の提案 """ SLACK_PUBLISHER_PROMPT = f""" あなたはレビューをSlackに投稿する専門エージェントです。 1. slackツールで投稿する - Slackチャンネル:{SLACK_CHANNEL_ID} """ class NewArticleFinderOutput(BaseModel): urls: List[str] = Field( default_factory=list, description="新着記事のURLリスト(古い順)" ) @app.entrypoint def invoke(payload): """ブログほめ太郎のメインエントリポイント""" # セッションマネージャーを初期化(状態を永続化) session_manager = S3SessionManager( session_id="blog-home-taro", bucket=SESSION_BUCKET, prefix="sessions", ) # 状態管理用のエージェント(セッションマネージャー付き) state_agent = Agent( model=BedrockModel(cache_tools="default"), session_manager=session_manager, ) # 最後にレビューした記事URLを取得 last_reviewed_url = state_agent.state.get("last_reviewed_url") print(f"Last reviewed URL: {last_reviewed_url}") # 新着記事を検索 last_url_info = ( f"最後にレビューした記事のURL: {last_reviewed_url}" if last_reviewed_url else "最後にレビューした記事のURLはありません" ) new_article_finder = Agent( model=BedrockModel(cache_tools="default"), tools=[rss], system_prompt=NEW_ARTICLE_FINDER_PROMPT, ) new_article_finder(f"{last_url_info}\n\n新着記事のURLリストを取得してください") finder_output = new_article_finder.structured_output(NewArticleFinderOutput) del new_article_finder gc.collect() urls = finder_output.urls print(f"New articles: {urls}") if not urls: return {"result": "新着記事はありません"} for url in urls: article_reviewer = Agent( model=BedrockModel(cache_tools="default"), tools=[http_request], system_prompt=ARTICLE_REVIEWER_PROMPT, ) reviewer_output = article_reviewer(f"この記事をレビューしてください:{url}") del article_reviewer gc.collect() slack_publisher = Agent( model=BedrockModel(cache_tools="default"), tools=[slack], system_prompt=SLACK_PUBLISHER_PROMPT, ) slack_publisher(f"以下のレビューを投稿してください:\n\n{reviewer_output}") del slack_publisher gc.collect() # 最後にレビューした記事URLを保存 state_agent.state.set("last_reviewed_url", urls[-1]) session_manager.sync_agent(state_agent) return {"result": f"レビュー完了: {len(urls)}件の記事を処理しました"} if __name__ == "__main__": app.run()
3. terraform apply でデプロイ
あとは、Terraformでデプロイするだけです。Dockerイメージのビルドも実行してくれるので、簡単に済みました。
cd terraform terraform init terraform apply
まとめ
以上、ブログほめ太郎の実行環境をAgentCore Runtimeに移行した理由と方法についてご紹介しました。
今回はLambdaからの移行でしたが、新規でAIエージェントを開発する場合も、同じ手順(agentcore create → コード調整 → terraform apply)で進められます。
AgentCore Runtimeは、まだEventBridgeルールのターゲットとしては指定できませんが、EventBridgeスケジューラで定期実行するだけなら好ましい実行環境だと考えます。ぜひお試しください。