Dev Lounge 振り返りシリーズ
- 記事 1:アーキテクチャを Steering として記述し、AI Agent を導く
- 記事 2:Agent Harness こそ真のエンジニアリングの堀
- 記事 3:平易な言葉で可観測性データを尋ねる
- 記事 4:Bedrock AgentCore で Serverless AR ゲームを構築する
- 記事 5:AgentCore 上のマルチ Agent クオンツ・バックテスト
- 記事 6:3 分でブログをスライドにする——Kiro で
AWS Hong Kong Summit 2026 · Developer Lounge 振り返り · 全 6 本中 第 4 本
AWS Magazine · ビクトリア・ハーバーからの現地レポート
現場:中環スワッガーが Serverless 呪術と出会う
六十年にわたり技術シフトを追ってきた私は、何百ものカンファレンスフロアに立ってきたが、AWS Hong Kong Summit 2026 Developer Lounge の電撃的な脈動に匹敵するものはほとんどない。
ビクトリア・ハーバーの壮大な背景を背負う Developer Lounge は、香港のラグジュアリーと AWS ハイテク工芸の鮮烈な衝突だった。想像してほしい:ベンチャーキャピタリストとスタートアップ創業者が職人ドリップコーヒー越しに七桁のディールを締め、国際スピーカーがアーキテクチャ図を交わし、プライベート開発者ミートアップが高リスクなベンチャートークでうなっている様子を。金は出入りし、協業は即興で形になり、ネオンのきらめきと中環のエネルギーのなかで、ビルダーたちは画面の周りに集まり、純粋な serverless 呪術を目撃していた。
Lounge の目玉アトラクションは?Cyrus Wong による、ラグジュアリーエンタメとクラウドエンジニアリングを融合したデモ:呪術廻戦 領域展開 AR ゲーム。
「唔錯喎!反應好似我去搶購減價化妝品噉快!當堂順眼好多!」 (Not bad! Your reaction is almost as fast as me grabbing a limited-edition bag in Shibuya!)
カメラの前で五条悟の Unlimited Void(無量空処)や両面宿儺の Malevolent Shrine(伏魔御廚子)の印を結ぶと、画面が 3D パーティクルエフェクトで爆発し、実物(またはシミュレート)のヒューマノイドロボットが功夫の構えを取る——すべて、おしゃれでファッション好きなローカル広東語で話す AI コメンテーターがライブ実況する。
以下は、このファンメイドアプリが AWS Bedrock AgentCore、AWS CDK、serverless オーケストレーションでどう構築されたかの深いハンズオンアーキテクチャ分解だ。
ショーの主役:AI コメンテーター釘崎野薔薇
体験の心臓部は Kugisaki Nobara(釘崎野薔薇) をモデルにした AI コメンテーターだ。マルチモーダル AI ビジョン駆動で、プレイヤーの手の印、服装、姿勢、散らかった部屋をリアルタイムでからかう。
多言語サポートとビジョン知能
-
言語:ローカル広東語、台湾華語、日本語、英語。
-
個性:中環ハイファッション × アニメ呪術。
-
モデルスタック:Bedrock 上のカスタム ECR コンテナ内で動く
moonshotai.kimi-k2.5、高忠実度ニューラル音声合成の AWS Polly と組み合わせ。
システムアーキテクチャ概要
| サーフェス / 機能 | モデルとインフラ実装 | 主要サービススタック |
|---|---|---|
| AI コメンテーター(Nobara) | moonshotai.kimi-k2.5 による視覚認識テキスト推論 |
AWS Bedrock AgentCore Runtime |
| 音声合成(TTS) | ニューラル広東語、華語、日本語、英語 | AWS Polly & Amazon S3 |
| ジェスチャー追跡 | 60 FPS で 21 個の 3D ランドマーク | Google MediaPipe Hands(Client JS) |
| ロボティクス制御 | ハードウェアと 3D シミュレータの MQTT スタンス | AWS IoT Core & AWS Lambda |
| インフラ | 100% Infrastructure as Code | AWS CDK(TypeScript) |
ステップバイステップ・ハンズオン実行フロー
+-----------------------------------------------------------------------------------+
エンドツーエンド・ジェスチャーから音声へのフロー
1. [ Browser Client ] -- MediaPipe 60FPS --> [ API Gateway ]
2. [ API Gateway ] -- Cognito JWT --> [ Monolithic Lambda ]
3. [ Monolithic Lambda ] -- XML multimodal payload --> [ AgentCore Runtime ]
4. [ AgentCore Runtime ] --> [ AWS Polly ] neural speech
5. [ AWS Polly ] --> [ S3 Audio Bucket ] --> browser playback
+-----------------------------------------------------------------------------------+
ステップ A:クライアント側ジェスチャー検出と API シグナリング
ブラウザは Google MediaPipe Hands を使う hand_tracker.js を実行し、60 FPS で 21 個の 3D ランドマークを分析する。ジェスチャー(例:Malevolent Shrine)が検証されると、battle.js が Cognito Bearer JWT 付きで Amazon API Gateway へ POST リクエストを送る:
// battle.js: Dispatching recognized gesture to API Gateway[cite: 1]
async function triggerCursedTechnique(techniqueName) {
const token = await getCognitoAccessToken(); // High-security Bearer Token[cite: 1]
try {
const response = await fetch("/api/trigger-technique", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify({
technique: techniqueName, // e.g. "malevolent_shrine"[cite: 1]
robotId: "all",
sessionId: "mcpserver"
})
});
const result = await response.json();
playCommentaryAudio(result.audioUrl); // Play resulting neural voice track[cite: 1]
} catch (err) {
console.error("Failed to execute server-side technique orchestration:", err); //[cite: 1]
}
}
ステップ B:Cognito 認可と XML Base64 バイパス
API Gateway がトークンを検証すると、リクエストをモノリシック Flask Lambda(lambda_function.py)へ転送する。
企業ネットワークプロキシが転送中にバイナリ multipart 画像データを剥ぎ取るのを防ぐため、commentary.py は Web カメラのスナップショットをテキストペイロード内のカスタム XML タグへ埋め込む:
# commentary.py: Packaging snapshots inside XML text tags[cite: 1]
def generate_ai_commentary(content_block, session_id="mcpserver", image_base64_p1=""):
if image_base64_p1:
content_block += f"\n<p1_webcam_base64_jpeg>{image_base64_p1}</p1_webcam_base64_jpeg>" #[cite: 1]
agent_client = boto3.client("bedrock-agentcore", region_name="us-east-1") #[cite: 1]
payload_dict = {
"prompt": content_block,
"session_id": session_id
}
response = agent_client.invoke_agent_runtime(
agentRuntimeArn=os.environ.get("AGENTCORE_RUNTIME_ARN"),
runtimeSessionId=session_id,
payload=json.dumps(payload_dict).encode("utf-8")
)
return response.get("response").read().decode("utf-8") #[cite: 1]
ステップ C:Serverless AgentCore Runtime 実行
AWS Bedrock AgentCore Runtime は IAM SigV4 経由で呼び出しをカスタムコンテナ(domain_commentator_agentcore)へルーティングする。コンテナの FastAPI サービス(commentator_agent.py)は regex で base64 XML ブロックを抽出し、Bedrock 向けバイナリマルチモーダルペイロードを再構築する:
# commentator_agent.py: Unwrapping XML image parts inside container[cite: 1]
@app.post("/invocations")
async def invoke_agent(request: Request):
body = await request.json()
prompt_text = body.get("prompt", "")
p1_pattern = re.compile(r"<p1_webcam_base64_jpeg>(.*?)</p1_webcam_base64_jpeg>", re.DOTALL) #[cite: 1]
p1_match = p1_pattern.search(prompt_text)
image_b64_p1 = ""
if p1_match:
image_b64_p1 = p1_match.group(1).strip()
prompt_text = p1_pattern.sub("", prompt_text).strip() # Clean text prompt[cite: 1]
img_bytes_p1 = base64.b64decode(image_b64_p1)
message_content = [
{"text": "Player 1 webcam snapshot:"},
{"image": {"format": "jpeg", "source": {"bytes": img_bytes_p1}}},
{"text": prompt_text}
]
response = await strands_agent.invoke_async(message_content) #[cite: 1]
return JSONResponse(content={"response": str(response)}, status_code=200) #[cite: 1]
ステップ D:AgentCore Tool Gateway 経由のハードウェアディスパッチ
モデルが物理アクションをトリガーすると、ランタイムは AgentCore Tool Gateway(bedrockagentcore.Gateway)を呼び出し、それが IAM SigV4 経由で robot_tool_lambda.py を呼び出して AWS IoT Core へ MQTT コマンドを publish する:
# robot_tool_lambda.py: Stripping tool prefix and invoking IoT Core[cite: 1]
def lambda_handler(event, context):
full_tool_name = event.get("tool_name", "") # e.g., "robot-only-mcp-lambda___robot_wave"[cite: 1]
local_tool_name = full_tool_name.split("___")[-1] if "___" in full_tool_name else full_tool_name #[cite: 1]
if local_tool_name == "robot_wave":
iot_client = boto3.client("iot-data")
iot_client.publish(
topic="arn:aws:iot:us-east-1:123456789012:topic/robot_1/topic",
qos=1,
payload=json.dumps({"action": "wave_hand", "timestamp": int(time.time())})
)
return {"status": "SUCCESS", "message": "Robot hand wave triggered."} #[cite: 1]
Infrastructure as Code:CDK コアパターン
インフラを繰り返し可能、モダン、クリーンに保つため、システム全体が AWS CDK でモデル化されている。
1. 集中型 Tool Gateway Construct(robot-tool-gateway.ts)
// Constructing the Tool Gateway with IAM SigV4 security[cite: 1]
export class RobotToolGatewayConstruct extends Construct {
public readonly robotToolFunction: PythonFunction;
public readonly gateway: bedrockagentcore.Gateway;
constructor(scope: Construct, id: string, props: RobotToolGatewayConstructProps) {
super(scope, id);
this.robotToolFunction = new PythonFunction(this, "RobotToolFunction", {
entry: path.join(__dirname, "../../../mcp_server"),
runtime: SHARED_PYTHON_RUNTIME,
index: "robot_tool_lambda.py",
handler: "lambda_handler",
timeout: Duration.seconds(30),
});
this.gateway = new bedrockagentcore.Gateway(this, "RobotToolGateway", {
description: "AgentCore gateway fronting the robot Lambda tools",
authorizerConfiguration: bedrockagentcore.GatewayAuthorizer.usingAwsIam(), // SigV4 Auth[cite: 1]
});
this.gateway.addLambdaTarget("RobotToolLambdaTarget", {
gatewayTargetName: "robot-only-mcp-lambda",
lambdaFunction: this.robotToolFunction,
toolSchema: bedrockagentcore.ToolSchema.fromLocalAsset(materializeRobotToolSchemaAsset()),
});
}
}
2. Serverless AgentCore コメンテーター Runtime(domain-expansion-serverless.ts)
// Deploying commentator runtime with cost-aware lifecycles[cite: 1]
const runtime = new agentcore.Runtime(this, "Runtime", {
runtimeName: "domain_commentator_agentcore",
agentRuntimeArtifact: agentcore.AgentRuntimeArtifact.fromAsset(
path.join(__dirname, "../../../domain-expansion-commentator-agentcore"),
{ platform: Platform.LINUX_ARM64 }
),
authorizerConfiguration: agentcore.RuntimeAuthorizerConfiguration.usingIAM(),
lifecycleConfiguration: {
idleRuntimeSessionTimeout: Duration.seconds(120), // 2 min idle timeout[cite: 1]
maxLifetime: Duration.seconds(900), // 15 min max session[cite: 1]
},
tracingEnabled: true,
environmentVariables: {
BEDROCK_MODEL_ID: "moonshotai.kimi-k2.5",
},
});
分割ルート API Gateway セキュリティモデル
チームは、古典的な Web 衝突を解くため分割ルート REST モデルを実装した:標準ブラウザ要素(<img src="...">)は Bearer ヘッダーを渡せないが、書き込み操作は LLM 費用がかかる。
// Public vs Protected Endpoint Configuration[cite: 1]
const restApi = new apigateway.RestApi(this, "DomainExpansionRestApi", {
restApiName: "Domain Expansion Serverless REST API",
});
const restAuthorizer = new apigateway.CognitoUserPoolsAuthorizer(this, "DomainExpansionRestApiAuthorizer", {
cognitoUserPools: [props.userPool],
});
// 🔓 PUBLIC READ-ONLY ENDPOINTS (No Cognito Token required)[cite: 1]
apiResource.addResource("get-snapshot").addMethod("GET", lambdaIntegration, {
authorizationType: apigateway.AuthorizationType.NONE, //[cite: 1]
});
// 🔒 PROTECTED WRITE ENDPOINTS (Strict Cognito Validation)[cite: 1]
apiResource.addResource("trigger-technique").addMethod("POST", lambdaIntegration, {
authorizationType: apigateway.AuthorizationType.COGNITO, // Edge validation[cite: 1]
authorizer: restAuthorizer,
});
可観測性とエンタープライズトレーシング
可観測性は CloudWatch Vended Logs 名前空間と AWS X-Ray で処理される:
// Configuring Vended Logs namespace for AgentCore[cite: 1]
const applicationLogGroup = new logs.LogGroup(scope, `${id}ApplicationLogGroup`, {
logGroupName: `/aws/vendedlogs/bedrock-agentcore/gateway/APPLICATION_LOGS/${gateway.gatewayId}`, //[cite: 1]
retention: logs.RetentionDays.THREE_DAYS,
});
これにより、単一の X-Ray マップ上でエンドツーエンド分散トレーシングが保証される:
Browser Gesture → API Gateway → Lambda Router → AgentCore Container → Strands LLM → AWS Polly TTS。
スマートクライアントガードとキャラクターエンジニアリング
1. コストガードセッションロジック(auth-check.js)
アイドルなブラウザタブが AgentCore ソケットを開き続けて請求漏れを起こすのを避けるため、クライアントはデバイス上で 30 秒ごとに Cognito JWT をチェックする:
Session Expired = currentTime >= jwt.exp
期限切れなら、アクティブな WebSocket を直ちに閉じる:
function checkSessionGuard() {
const token = getCognitoToken();
if (isTokenExpired(token)) {
if (webSocketConnection) webSocketConnection.close(); // Prevent billing leaks[cite: 1]
triggerLocalLogout();
}
}
setInterval(checkSessionGuard, 30000); // 0 cloud compute overhead[cite: 1]
2. 音声テキスト・サニタイズ(commentary_tts.py)
モデル出力を AWS Polly に渡す前に、BeautifulSoup で Markdown 記号(**bold**、#)をきれいなプレーンテキストへ変換し、Polly が構文を読み上げないようにする:
import markdown
from bs4 import BeautifulSoup
def sanitize_text_for_tts(raw_text):
html_formatted = markdown.markdown(raw_text)
return BeautifulSoup(html_formatted, "html.parser").get_text() # Clean plain text[cite: 1]
3. Soul as Code 設定
キャラクター同一性は、ランタイムで読み込まれる標準 Markdown ファイルへ完全に分離される:
-
IDENTITY.md:辛口広東語スタイルと態度の指示。 -
SOUL.md:戦闘 lore ルール(例:五条悟ユーザーをどうからかうか)。
アーキテクチャ経済学と従量課金
| アーキテクチャ選択 | コストと効率への影響 |
|---|---|
| ゼロアイドル課金 | マッチがアクティブでないときコスト $0.00;常時稼働の EC2/ECS サーバなし。 |
| S3 ライフサイクルルール | Web カメラスナップショットと Polly MP3 音声ストリームは 7 日後に自動削除。 |
| P2P ビデオ WebRTC | ビデオはピアツーピアで直接ストリーム;API Gateway WebSocket は軽量テレメトリのみ。 |
締めくくり:Developer Lounge の空気感
Cyrus Wong とチームが AWS Hong Kong Summit 2026 Developer Lounge で示したのは、楽しいファンゲーム以上のものだった。それは現代 serverless 設計のマスタークラスだ:ハイファッション、ハイテクノロジー、低レイテンシ、ゼロアイドルコスト。
夕陽が中環に沈みビクトリア・ハーバーを照らすなか、開発者たちはまだブースの周りに群がり、CDK リポジトリをスキャンし手の印を試していた。それこそが AWS Developer Lounge の本当の精神——世界級のエンジニアリング、活気あるローカル文化、serverless の力を一つの屋根の下に集めることだ。
