AWS Hong Kong Summit 2026 · Developer Lounge 振り返り

Bedrock AgentCore で Serverless AR ゲームを構築する

Dev Lounge 振り返りシリーズ

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 AgentCoreAWS 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 FPS21 個の 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 Gatewaybedrockagentcore.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 の力を一つの屋根の下に集めることだ。