第3章で AgentCore Gateway を作りました。最終章では、エージェントコードを書いて AgentCore Runtime にデプロイし、iPhone の位置情報トリガーと LINE プッシュ通知まで繋げてアプリを完成させます。
※第3章へのリンク
https://qiita.com/toshi-arch/items/f5bfdb388c29a4a95334
Step 1. エージェントコードの作成
依存パッケージのインストール:
uv add bedrock-agentcore strands-agents mcp-proxy-for-aws python-dotenv
main.py:
import os
from dotenv import load_dotenv
from mcp_proxy_for_aws.client import aws_iam_streamablehttp_client
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from bedrock_agentcore.runtime import BedrockAgentCoreApp
load_dotenv()
GATEWAY_URL = os.environ['GATEWAY_URL'] # 第3章の setup_gateway.py の出力値
app = BedrockAgentCoreApp()
@app.entrypoint
def run_agent(payload: dict, context) -> dict:
store_name = payload.get('store_name', '')
mcp_client = MCPClient(
lambda: aws_iam_streamablehttp_client(
endpoint=GATEWAY_URL,
aws_service='bedrock-agentcore',
)
)
with mcp_client:
tools = mcp_client.list_tools_sync()
agent = Agent(
model=BedrockModel(model_id='jp.anthropic.claude-haiku-4-5-20251001-v1:0'),
tools=tools,
system_prompt=f"""
あなたは買い物アシスタントです。
ユーザーが「{store_name}」に近づいています。
以下の手順でツールを呼び出し、今日買うべきものを提案してください。
1. search_purchase_history で「{store_name}」の購買履歴を取得する
2. calculate_consumption で購入提案リストを生成する
3. 提案を自然な日本語でまとめる(箇条書き、100文字以内)
""",
)
result = agent(f'{store_name}で今日買うべきものを教えて')
return {'message': str(result)}
if __name__ == '__main__':
app.run()
ローカルで動作確認
# ターミナル1
GATEWAY_URL=https://xxx.gateway.bedrock-agentcore.ap-northeast-1.amazonaws.com/mcp \
uv run python main.py
# ターミナル2
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{"store_name": "イオン"}'
Step 2. AgentCore Runtime へのデプロイ
CLI のインストール
uv add bedrock-agentcore-starter-toolkit
⚠️ ハマりポイント: デプロイ CLI は pip の
bedrock-agentcore-starter-toolkitです。npm の@aws/agentcoreとは別物で仕様が異なります。
configure
uv run agentcore configure \
--entrypoint main.py \
--execution-role arn:aws:iam::[ACCOUNT_ID]:role/SmartShopperAgentCoreRuntimeRole \
--requirements-file requirements.txt \
--deployment-type container \
--name smartShopperAgent \
--region ap-northeast-1 \
--non-interactive
⚠️ ハマりポイント: エージェント名は英数字とアンダースコアのみ、48文字以内。ハイフンが含まれるとエラーになります。
configure を実行すると .bedrock_agentcore/smartShopperAgent/Dockerfile が自動生成されます。
Dockerfile に GATEWAY_URL を追記
ENV GATEWAY_URL=https://[gateway-id].gateway.bedrock-agentcore.ap-northeast-1.amazonaws.com/mcp
deploy
uv run agentcore deploy
デフォルトは CodeBuild モード(AWS 上でコンテナをビルドするため、ローカルの Docker は不要)。完了すると Agent Runtime ARN が表示されます。
⚠️ ハマりポイント:
--deployment-type CodeZipにすると pip install がコールドスタート時に走り「Runtime initialization time exceeded」でタイムアウトします。必ずcontainerを使いましょう。
動作確認
uv run agentcore invoke '{"store_name": "イオン"}'
.gitignore に追加
.bedrock_agentcore.yaml
.bedrock_agentcore/
これらにはアカウント ID が平文で含まれます。
Step 3. 位置情報トリガーと LINE プッシュ通知
既存の LINE Webhook Lambda(第1章で作ったもの)に、位置情報トリガーの受け口・AgentCore 呼び出し・LINE プッシュ通知を追加します。
import json, uuid, os, boto3
from linebot.v3.messaging import (
Configuration, ApiClient, MessagingApi,
PushMessageRequest, TextMessage
)
AGENT_RUNTIME_ARN = os.environ.get('AGENT_RUNTIME_ARN')
configuration = Configuration(access_token=LINE_ACCESS_TOKEN) # 第1章の設定を流用
def lambda_handler(event, context):
body = event.get('body', '')
parsed = json.loads(body) if isinstance(body, str) else (body or {})
# 位置情報トリガー
if parsed.get('trigger_type') == 'location_trigger':
store_name = parsed.get('store_name', '')
user_id = parsed.get('user_id', '')
if not store_name or not user_id:
return {'statusCode': 400, 'body': 'store_name and user_id are required'}
return handle_location_trigger(store_name, user_id)
# 既存の LINE Webhook 処理(第1章のコード)...
def handle_location_trigger(store_name: str, user_id: str) -> dict:
try:
message = invoke_agent(store_name)
except Exception as e:
print(f"AgentCore 呼び出しエラー: {e}")
return {'statusCode': 500, 'body': 'Agent invocation failed'}
try:
send_push_message(user_id, message)
except Exception as e:
print(f"LINE プッシュ通知エラー: {e}")
return {'statusCode': 500, 'body': 'LINE push notification failed'}
return {'statusCode': 200, 'body': 'OK'}
def invoke_agent(store_name: str) -> str:
"""AgentCore Runtime を呼び出してエージェントの回答を取得する"""
client = boto3.client('bedrock-agentcore', region_name='ap-northeast-1')
response = client.invoke_agent_runtime(
agentRuntimeArn=AGENT_RUNTIME_ARN,
qualifier='DEFAULT',
runtimeSessionId=str(uuid.uuid4()),
payload=json.dumps({'store_name': store_name}),
)
raw = response['response']
body = raw.read() if hasattr(raw, 'read') else raw
return json.loads(body).get('message', '提案が取得できませんでした。')
def send_push_message(user_id: str, message: str) -> None:
"""LINE Messaging API でプッシュ通知を送る"""
with ApiClient(configuration) as api_client:
MessagingApi(api_client).push_message(
PushMessageRequest(
to=user_id,
messages=[TextMessage(text=message)]
)
)
Lambda の環境変数に AGENT_RUNTIME_ARN(Step 2 で表示された ARN)を追加。
Step 4. iOS オートメーションの設定
iPhone の「ショートカット」アプリで位置情報トリガーを設定します。
- 「ショートカット」→「オートメーション」→「+」→「場所」
- 店舗を地図で指定 →「到着」を選択
- アクション:「URLの内容を取得」
- URL: API Gateway の Webhook エンドポイント
- 方法: POST
- 本文(JSON):
{ "trigger_type": "location_trigger", "store_name": "イオン", "user_id": "あなたのLINEユーザーID" }
- 「実行の前に確認」→ オフ
完成したフロー
iPhone が「イオン」の半径内に入る
→ ショートカットが API Gateway に POST
→ Lambda が trigger_type を検知
→ AgentCore Runtime を invoke
→ Strands Agent が推論開始
→ Gateway 経由で search_purchase_history を呼び出す
→ S3 から「イオン」の購買 JSONL を全件取得
→ Gateway 経由で calculate_consumption を呼び出す
→ 消費サイクルを計算して提案リストを生成
→ エージェントが自然な日本語でまとめる
→ Lambda が LINE プッシュ通知を送信
→ iPhone に「今日はシャンプーと牛乳を買うといいです」が届く
全4章 ハマりポイント総まとめ
| # | 症状 | 原因と対処 |
|---|---|---|
| ① | Lambda リソースポリシーで権限エラー |
setup_gateway.py より前に aws lambda add-permission を実行 |
| ② | Gateway が作れない / 後で認証エラー |
create_gateway に authorizerType='AWS_IAM' が必須 |
| ③ | ステータス待ちが終わらない | 待つべきは READY(ACTIVE では永久ループ) |
| ④ | ツールが呼び出されない |
targetConfiguration は {'mcp': {'lambda': {...}}} とネストが必要 |
| ⑤ | ツールが常に Unknown tool
|
Gateway は ターゲット名___ツール名 形式で渡す。___ でプレフィックスを除去 |
| ⑥ |
agentcore configure でエラー |
エージェント名にハイフン不可(英数字とアンダースコアのみ) |
| ⑦ | コールドスタートでタイムアウト |
--deployment-type container を使う。CodeZip は起動時に pip install が走る |
| ⑧ | npm の agentcore CLI で詰まる | デプロイは pip の bedrock-agentcore-starter-toolkit。npm 版は別物 |
おわりに
全4章を通じて、LINE でレシートを送ると購買履歴が記録され、店舗に近づいたら購入提案が届くアプリを作りました。
IPhoneのオートメーションでHTTP request送れるっていうのが意外でしたね。全く知らんかったです。LINE Messaging API使うことでほぼバックエンド側のサーバーレス構成組めてコストも抑えられたのもよかったです。
そしてAgentCore を使うことで、エージェントのコンテナビルド・ホスティング・IAM 認証を自前で実装せずに済みました。一方でドキュメントがまだ薄く、特に Gateway 周りは試行錯誤が必要でした。同じところで詰まっている方の助けになれば幸いです。