第13章 フルスタックエージェントを構築しよう — 学習メモ¶
書籍「Amazon Bedrock AgentCore実践入門」第13章のサンプルコード(このフォルダ)を読み解いた個人学習メモ。 AgentCore 全体像は
../../lectures/agentcore_basics/STUDY_NOTES.md参照。 実行検証は伴わない。コードに現れた API 名だけ断定し、読めない挙動は「〜と推測」で明示する。
一言で¶
新刊チェッカー BookChecker = AgentCore の5機能(Runtime・Memory・Identity・Built-in Browser・Observability)を1つの Agent() に束ねて、Next.js/Amplify のフロントから叩く、ハンズオン全4章中もっとも機能を濃く積んだ章。
Gateway は使われない(agentcore.json の agentCoreGateways / httpGateways は空配列、credentials も空配列)。ツールは「組み込み Browser」と「自作の Google カレンダー登録ツール(内部で Identity を使う)」の2つだけで、外部ツール集約の出番がないため。
全体像¶
flowchart TB
U["ユーザー<br>ブラウザ"]
COG["Cognito Authenticator<br>(providers.tsx)"]
FE["Next.js 16 + Amplify<br>page.tsx"]
RT["AgentCore Runtime<br>main.py invoke()"]
AG["Strands Agent<br>Sonnet 4.6"]
MEM["Memory<br>好み検索/保存<br>(4戦略・USER_PREFERENCE使用)"]
BRW["Built-in Browser<br>新刊カレンダー巡回"]
IDN["Identity<br>requires_access_token<br>(3LO)"]
GCAL["Google Calendar API"]
OBS["Observability<br>OTel自動計装(ADOT)"]
U --> COG --> FE
FE -->|"JWT + prompt<br>SSE POST"| RT
RT --> AG
AG --> MEM
AG --> BRW
AG -->|"カレンダー登録時"| IDN
IDN -->|"未認可なら認可URLを<br>event_queue経由でSSE配信"| FE
FE -->|"認可URLをクリック"| GCAL
GCAL -.->|"3LOコールバック"| FE
FE -->|"CompleteResourceTokenAuthCommand"| RT
IDN -->|"認可完了後トークン取得"| GCAL
RT -.->|"全実行を計装"| OBS
3LO(three-legged OAuth)の認可URL配信は、テキスト応答・ツール実行状況と同じ asyncio.Queue を共有して1本のSSEストリームに乗る。これが本章でいちばん凝った設計なので、シーケンスで別出し:
sequenceDiagram
participant User as ユーザー
participant FE as Next.js (page.tsx)
participant RT as Runtime (main.py invoke)
participant Agent as Strands Agent
participant CalTool as calendar_tool
participant Google as Google Calendar API
User->>FE: 「登録して」
FE->>RT: POST /invocations (JWT, prompt, session_id)
RT->>Agent: agent.stream_async(prompt)
Agent->>CalTool: add_calendar_event(...) 呼び出し
CalTool->>CalTool: requires_access_token(...) デコレータ実行
CalTool-->>RT: 未認可 → on_auth_url(url) → event_queue.put({"type":"auth_url"})
RT-->>FE: SSEで auth_url イベント配信
FE-->>User: 「Google連携を開始」ボタン表示
User->>Google: ボタンクリック→OAuth同意
Google-->>FE: /api/oauth2/callback?session_id=... へリダイレクト
FE->>RT: CompleteResourceTokenAuthCommand(sessionUri, userToken)
Note over CalTool: 認可完了でaccess_tokenが注入され<br>call_api()が再開・完了
CalTool->>Google: POST /calendars/primary/events
Google-->>CalTool: 登録結果
CalTool-->>Agent: 成功/失敗メッセージ
Agent-->>FE: テキスト応答(SSE)
使用ライブラリ・原理¶
| ライブラリ / API | 役割 |
|---|---|
strands (strands-agents) |
Agent クラス。tools=[...]・system_prompt・session_manager を渡すだけでReActループとメモリー連携が組み上がる |
strands_tools.browser.AgentCoreBrowser |
AgentCore の組み込みBrowserサンドボックスをStrandsツール化。.browser 属性をそのまま tools=[] に渡す |
bedrock_agentcore.runtime.BedrockAgentCoreApp |
Runtime機能。@app.entrypoint でHTTPエンドポイント化、app.run() でASGIサーバ起動 |
bedrock_agentcore.memory.integrations.strands.* |
Memory機能のStrands統合。AgentCoreMemoryConfig(設定)+ RetrievalConfig(名前空間ごとの検索設定)+ AgentCoreMemorySessionManager(Strandsのsession_managerインターフェース実装) |
bedrock_agentcore.identity.requires_access_token |
Identity機能。デコレータがOAuthトークン取得・3LOフロー起動・トークン注入を肩代わり |
asyncio.Queue |
テキスト・ツール実行状況・認可URLという種類の異なる3つのイベントを1本のストリームに合流させるための素朴な仕組み。生産者(agent_stream()タスクとcalendar_tool内の_on_auth_url)と消費者(invoke本体のwhileループ)が非同期に協調する |
| Next.js 16 (App Router) + React 19 | フロントエンド。app/page.tsxがクライアントコンポーネントでSSEを手動パース |
AWS Amplify Gen2 (defineBackend/defineAuth) |
Cognitoユーザープール定義とデプロイをコード化 |
@aws-amplify/ui-react Authenticator |
ログインUI一式(サインアップ・サインイン・パスワードリセット)を丸ごと提供 |
aws-amplify/auth fetchAuthSession |
ログイン中ユーザーのCognito JWT(アクセストークン)を取得し、Runtime呼び出しのAuthorization: Bearerに使う |
@aws-sdk/client-bedrock-agentcore CompleteResourceTokenAuthCommand |
3LOコールバックでAgentCore側のセッションバインディングを完了させるAPI(TypeScript側からも叩ける) |
aws-opentelemetry-distro (ADOT) |
Observability機能。Dockerfileの起動コマンドをopentelemetry-instrument python -m mainにするだけでコード変更なしに自動計装 |
ファイル別の役割¶
| ファイル | 役割 |
|---|---|
bookchecker/agent/app/BookChecker/main.py |
エントリポイント。5機能を束ねる中心。SSE用イベントキューの生成・消費 |
bookchecker/agent/app/BookChecker/calendar_tool.py |
Identity(3LO)経由でGoogle Calendar APIにイベント登録するツール。make_calendar_tool(event_queue)でキューを注入 |
bookchecker/agent/app/BookChecker/memory/session.py |
未使用のCLI雛形。main.pyは同等のロジックを独自にインライン実装しており、こちらは呼ばれない(後述の落とし穴参照) |
bookchecker/agent/app/BookChecker/model/load.py |
未使用のCLI雛形。load_model()はglobal.anthropic.claude-sonnet-4-5-20250929-v1:0を返すが、実際のmain.pyはAgent(model="us.anthropic.claude-sonnet-4-6")と文字列で直接指定しており呼ばれない |
bookchecker/agent/app/BookChecker/mcp_client/client.py |
未使用のCLI雛形(14行)。Gatewayを使わない本章では出番なし |
bookchecker/agent/app/BookChecker/Dockerfile |
Container build。opentelemetry-instrumentでObservabilityを自動計装、非rootユーザーで起動 |
bookchecker/agent/app/BookChecker/pyproject.toml |
依存パッケージ定義(bedrock-agentcore・strands-agents・strands-agents-tools・playwright等) |
bookchecker/agent/agentcore/agentcore.json |
AgentCoreの宣言的スキーマ。Runtime定義(Container/PYTHON_3_14)とMemory定義(4戦略)。agentcore deployが読む正本 |
bookchecker/agent/agentcore/cdk/lib/cdk-stack.ts |
agentcore.jsonをAgentCoreApplication/AgentCoreMcpのL3コンストラクトに橋渡しする薄いラッパー |
bookchecker/agent/AGENTS.md |
agentcore createが生成するAIアシスタント向けコンテキスト(フラットリソースモデルの説明) |
bookchecker/amplify/auth/resource.ts |
defineAuth({loginWith: {email: true}})。Cognitoのメールログインのみ定義 |
bookchecker/amplify/backend.ts |
defineBackend({auth})。Amplifyバックエンドは認証のみ(データ層はrm -rf amplify/dataで削除済み) |
bookchecker/app/providers.tsx |
Amplify.configure(amplifyOutputs) + Authenticatorでアプリ全体をラップ、UIを日本語化 |
bookchecker/app/page.tsx |
チャットUI本体。JWT取得→Runtime呼び出し→SSEパース→text/tool_use/tool_result/auth_urlの4種イベントをUIに反映 |
bookchecker/app/api/set-token/route.ts |
CognitoトークンをHttpOnly Cookieに保存するRoute Handler(3LOコールバック時に読み出すため) |
bookchecker/app/api/oauth2/callback/route.ts |
Googleからの3LOリダイレクト先。CookieのトークンでCompleteResourceTokenAuthCommandを実行しセッションを完了 |
handson-memo.txt |
ハンズオン中にメモするAWSリソースID等のテンプレ(プレースホルダのみ、実値は書かない) |
中心コードの読み解き¶
main.py:49-69 — Memory設定からAgent生成までの、本章のハイライト(3機能が1呼び出しに集約される瞬間):
# メモリーの設定を定義
memory_config = AgentCoreMemoryConfig( # ①
memory_id=MEMORY_ID,
session_id=session_id,
actor_id="user",
retrieval_config={
"/users/{actorId}/preferences": RetrievalConfig(),
},
)
# メモリーのセッションマネージャーを作成
session_manager = AgentCoreMemorySessionManager( # ②
agentcore_memory_config=memory_config,
)
# Strands AgentsでAIエージェントを作成
agent = Agent( # ③
model="us.anthropic.claude-sonnet-4-6",
tools=[browser.browser, calendar_tool], # ④
system_prompt=SYSTEM_PROMPT,
session_manager=session_manager, # ⑤
)
| 行 | やってること | なぜ |
|---|---|---|
① AgentCoreMemoryConfig(...) |
/users/{actorId}/preferences 名前空間だけを検索対象に設定 |
agentcore.json は4戦略(SEMANTIC/USER_PREFERENCE/SUMMARIZATION/EPISODIC)を定義しているが、実際にAgentが読むのは好み(USER_PREFERENCE)だけ。設定と実装に差がある(後述の落とし穴) |
② AgentCoreMemorySessionManager(...) |
Strandsのsession_managerインターフェースを満たすメモリー統合オブジェクトを生成 |
③に渡すだけで会話の自動保存・関連記憶の自動取得が有効になる(呼び出し側は保存/取得APIを直接叩かない) |
③ Agent(...) |
Strands Agent本体を生成 | この1呼び出しにBrowser・Calendar(Identity内包)・Memoryの3機能が集約される、本章の核 |
④ tools=[browser.browser, calendar_tool] |
組み込みBrowserツールと、Identity連携済みカレンダー登録ツールを渡す | browserはAgentCore Built-in Browser、calendar_toolは内部でrequires_access_tokenを使うためIdentity機能を内包している。Agent側からは「ただのツール2つ」に見える |
⑤ session_manager=session_manager |
①②で組み立てたメモリー統合をAgentに接続 | Strands統合の設計思想(「渡すだけで機能が足される」)がここでも成立 |
学んだこと(要点)¶
- AgentCoreの複数機能は、Agentの引数(
tools/session_manager)に「渡すだけ」で合成できる。Runtime・Memory・Identity・Built-in Browserという別々の機能が、コード上はAgent()のキーワード引数2つに収束している。 - SSEの多重化は
asyncio.Queueという素朴な仕組みで実現されている。テキスト・ツール実行状況・OAuth認可URLという性質の異なる3種のイベントを、生産者(ストリーミングタスク/Identityコールバック)と消費者(invokeのwhileループ)で協調させるだけで1本のストリームに合流できる。フレームワーク側の特別なAPIは不要。 - Identity(3LO)は「トークンが無ければ認可URLを投げて中断、認可後に再開」というデコレータパターン。
@requires_access_tokenが付いた内側の関数はトークンが未取得なら実行が保留され、on_auth_urlコールバックで通知だけ行う。呼び出し側(calendar_tool)はこの中断・再開を意識せず、await call_api()を1回呼ぶだけで完結しているように書ける。 - フロントのCookie+Route Handlerが3LOの「橋渡し役」。AgentCore Runtime自体はブラウザとの対話手段を持たないため、認可URLへの遷移とコールバックの受け皿はNext.js側(
/api/set-tokenでJWTを事前にCookie保存 →/api/oauth2/callbackでそのCookieを使ってセッションバインディングを完了)が担う。AgentCoreとフロントの責務分担が明確。 - Observabilityは「起動コマンドを変えるだけ」で入る。
DockerfileのCMDをopentelemetry-instrument python -m mainにするだけでADOTの自動計装が有効になり、アプリコードに計装コードを書く必要がない(この点はmain.pyにOTel関連のimportが一切無いことからも確認できる)。
落とし穴・デプロイ前提¶
handson-memo.txt(ランタイムARN・Cognito ID・コールバックURL等)は絶対にGitHubへpushしない。本ハンズオンの13.4節向けメモ帳で、プレースホルダのまま配布されている。- env変数: フロントは
NEXT_PUBLIC_AGENT_ARN(Amplifyデプロイ時)、RuntimeはCALLBACK_URL/CREDENTIAL_PROVIDER_NAME/AWS_DEFAULT_REGION(AgentCoreランタイム側)が必須。 aws bedrock-agentcore-control update-workload-identity --allowed-resource-oauth2-return-urlsをコールバックURL登録のために実行する必要がある(コード上には現れない、README記載のインフラ操作)。- AmplifyのSSRコンピュートロールにカスタム信頼ポリシーが必要(
amplify.amazonaws.comをPrincipalとするsts:AssumeRole)。 - Google Cloud側でOAuthクライアントを作成し、AgentCore Identityにクレデンシャルプロバイダーとして事前登録しておくことが前提。
agentcore.jsonのcredentials配列は空のままで、クレデンシャルプロバイダーはこのJSONスキーマの管理外(マネージドコンソール/CLIで別途作成)。 agentcore createが生成するmcp_client/・model/load.py・memory/session.pyは雛形のまま未使用。特にmemory/session.pyはmain.pyより広い名前空間(facts/preferences/summaries)を検索する完成度の高いコードに見えるが、実際に呼ばれるのはmain.pyにベタ書きされた(preferencesのみの)ロジック。読者が「どっちが本物か」で迷いやすい箇所。model/load.pyのload_model()は古いモデルID(claude-sonnet-4-5-20250929)を返す未使用スタブ。実際に使われるのはmain.pyの"us.anthropic.claude-sonnet-4-6"。- CLI
@aws/agentcore@1.0.0-preview.8はプレビュー版。バージョンアップでコマンド互換性が変わる可能性がある。 - Gatewayは本章で不使用(
agentCoreGateways/httpGatewaysとも空配列)。ツールはBrowserとカレンダー登録の2つのみで完結しており、複数ツールの集約が要らない規模のため。
記事参照¶
- 書籍 第13章「【ハンズオン】フルスタックエージェントを構築しよう」。
- 関連:
../../lectures/agentcore_basics/STUDY_NOTES.md(AgentCore全体像・8機能カタログ・既存lectureとの対応地図)。 - 関連lecture: Identity/OAuthの基礎パターンは同メモ「3-3. Identity」節、Memoryの短期/長期の分離は「3-2. Memory」節を参照。
作成: 2026-07-17 / 最終更新: 2026-07-17