10 月に Lambda Web Functions が出て、6 月の MicroVMs と合わせて、気づいたら Lambda が 3 種類になっていました。これは 3 つとも触ってみたい。
せっかくなら 3 つ全部に出番があるお題がいいなと思って探してみたら、なぜか手元に大阪のとあるホールの台データがありました。毎朝こつこつ集めていたやつです。
ということで、このデータにチャットで話しかけたら、AI が分析して答えてくれるものを作ってみました。
前提
- 東京リージョン(ap-northeast-1)
- AWS CLI 2.38.1。最初 2.33 系が入っていて、
lambda-webもlambda-microvmsもありませんでした。古い人は上げてから - Bedrock のモデルは Claude Haiku 4.5(
jp.の推論プロファイル) - データは SQLite に入っている 1 ホール分を CSV にしたもの(日付・台番号・機種・差枚・回転数など)
こう作ることにした
Lambda の 3 つは、ざっくりこういう分け方だと理解しています。
| Event Functions | Web Functions | MicroVMs | |
|---|---|---|---|
| 中身 | いつもの Lambda(名前が変わっただけ) | Web アプリをそのまま置ける | 人に貸せる隔離された VM |
| 向いてるもの | S3 にファイルが来たら何かする | 自分の画面と API | 他人や AI が書いたコードを動かす |
| 状態 | 持たない | 持たない | メモリもディスクも残る |
これを 1 つずつ役割に当てはめると、こうなりました。
- CSV を S3 に置くと、Event Functions が列の情報と日ごとの集計を JSON にして隣に置く
- Web Functions がチャット画面と API。質問が来たら Bedrock に渡す
- Bedrock は答えを直接は出さず、pandas のコードを書いてくる。それを MicroVM で動かして、結果を見てから答えを書く
この構成でいちばん大事なのは最後のところで、AI に数字を直接言わせるとそれっぽい数字を作ってしまうことがあるので、計算は必ずコードにさせています。AI が書いたコードは何をするか分からないので、隔離された MicroVM で動かす。ここで MicroVMs の出番、という流れです。
Web Functions で返事させてみた
画面と API は Hono で 1 つのアプリにしました。GET / で HTML を返して、POST /api/chat で答えを SSE で流します。普通の Node.js のサーバーとして書いて、そのままデプロイできます。
aws lambda-web deploy --name slot-chat --code web --create \
--env BEDROCK_MODEL_ID=jp.anthropic.claude-haiku-4-5-20251001-v1:0 \
--env SANDBOX_URL=https://<MicroVM のエンドポイント> ...
URL が出てきて、開くとチャット画面が出ました。SSE もそのまま流れて、Bedrock の返事が少しずつ表示されます。
API Gateway も CloudFront もなしで、画面から API まで Lambda 1 つだけでほぼすべて構築できました。
MicroVM に pandas を入れてみた
MicroVM は、Dockerfile とアプリを zip にして S3 に置き、イメージを作ってから起動します。中身は Python の小さな HTTP サーバーで、コードを受け取って実行し、標準出力と matplotlib のグラフを返すだけです。
aws lambda-microvms create-microvm-image --name slot-chat-sandbox \
--code-artifact uri=s3://<バケット>/microvm/sandbox.zip \
--base-image-arn arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 \
--build-role-arn <ビルド用ロール> \
--resources '[{"minimumMemoryInMiB":1024}]'
aws lambda-microvms run-microvm --image-identifier <イメージの ARN> \
--idle-policy '{"autoResumeEnabled":true,"maxIdleDurationSeconds":600,"suspendedDurationSeconds":7200}' \
--maximum-duration-in-seconds 14400 ...
イメージのビルドは数分、起動は数秒でした。idle policy と寿命の上限は最初から付けています。10 分話しかけなければ一時停止、一時停止が 2 時間続いたら終了、どちらにしても 4 時間で終了。消し忘れても勝手に消えます。
MicroVM には IAM の権限を渡さないようにしています。MicroVM で動くのは AI が書いたコードで、中身は実行するまで分かりません。実行ロールに S3 などの権限を付けると、そのコードからも同じ権限が使えてしまいます。
今回は MicroVM に権限を一切付けず、CSV は Web Functions が作った期限付きの署名付き URL で読ませています。AI が書いたコードを動かす場所には、必要なものを URL やトークンで都度渡して、権限そのものは持たせない、というのが安全です。
つないで聞いてみた
「8 月に平均差枚が高い機種トップ 5 を棒グラフにして」と聞くと、グラフ付きで返ってきました。
裏で何が起きているかというと、Bedrock との往復が 2 回です。1 回目で Bedrock が「このコードを実行して」とツール呼び出しを返してきて、Web Functions がそれを MicroVM に投げます。2 回目で実行結果を渡すと、それを読んで日本語の答えを書きます。画面の「実行したコード」を開くと、Bedrock が書いた pandas のコードがそのまま見られます。
1 回目の質問のときだけ MicroVM が S3 から CSV を読み込み、2 回目からはメモリに残った DataFrame をそのまま使います。毎回読み直さないので、2 問目からは速いです。
ちなみにこのスクショの答えは間違っていて、「8 月」を去年と今年の 2 年分まとめて集計していました。年を書いて聞き直したら直りました。
手動で計算して答え合わせしてみた
普段の手作業の分析メモと同じことを聞いて、答え合わせをしてみました。
| 質問 | チャット | 手作業のメモ |
|---|---|---|
| ある日のマイジャグラーVの平均差枚 | 25 | 25 |
| 同じ日のホール全体の平均差枚 | 288 | 490 |
ホール全体だけズレましたが、原因は手作業側の集計スクリプトが「回転数 2000 以上の台だけ」に絞っていたことでした(そんな設定を入れていたことすら覚えていませんでした(笑))。同じ条件で聞き直すと一致して、ほかに聞いた数問も DB を直接集計した値と合っていました。
放っておいて戻ってきた
MicroVM のいちばん気になっていたところです。しばらく放っておいてから見に行くと、10 分の idle policy で MicroVM は一時停止していました。
そのまま話しかけてみると、最初の 1 回だけ一瞬待たされて、普通に返ってきました。DataFrame もメモリに残っていて、CSV の読み直しはありませんでした。一時停止中は計算料金が止まって、スナップショットの保存料だけになります。
Lambda のいいところはそのままに、状態を維持するという今までの Lambda ではできなかったことができるのは、普通に便利だと思いました😊
いくらかかったか
丸 1 日いじった日の料金を Cost Explorer で見てみました(Bedrock はまだ反映されていなかったので、使ったトークン数から計算)。合計で 20 セントくらいでした。
いちばん多かったのは MicroVM で、半分以上がこれです。その次が Bedrock。Web Functions と Event Functions と S3 は、全部足しても 1 セントにもなりませんでした。Web Functions は、リクエストを待っている間も環境がある限りメモリの料金がかかりますが、この規模なら誤差です。
MicroVM のイメージを残しておくと、スナップショットの保存料が少しずつかかり続けます。使い終わったらイメージごと消しておくのが安心です。
趣味で変なアプリができあがってしまいましたが、これを業務に生かすにはどうするか🤔
業務だと認証が必要になることがほとんどで、Web Functions 単体だと認証は自分のコードで守ることになります。そう考えると、今のところは API Gateway → Lambda のままでいいかな、という感覚です。
でも、Web アプリを書いてコマンド 1 つで画面まで動くのは本当に手軽なので、学習を始めたばかりの人がここから入るのはいいなと思いました😊
つまずいたところ(おまけ)
Web Functions のデプロイでバケットに怒られる
デプロイパッケージを自分のバケットに置こうとしたら、2 回怒られました。
You must enable S3 versioning for your S3 bucket when S3ObjectStorageMode is set to REFERENCE.
バージョニングを有効にしたら、今度はこれ。
Lambda service principal lambda.amazonaws.com does not have s3:GetObject and s3:GetObjectVersion permission on s3://...
バケットポリシーで lambda.amazonaws.com に読み取りを許可したら通りました。--bucket-name を付けなければ CLI が専用のバケットを作ってくれるので、こだわりがなければそっちが楽です。
MicroVM の認証トークンは 60 分まで
MicroVM のエンドポイントは、create-microvm-auth-token で作ったトークンが無いと受け付けません。最初は 4 時間のトークンを作って環境変数で渡すつもりでしたが、60 分を超えると弾かれました。
ExpirationMinutes 240 exceeded max allowed of 60.
Web Functions の中で SDK(@aws-sdk/client-lambda-microvms)を使ってトークンを発行し、切れる前に作り直すようにしました。
実行結果に pandas の警告が出てくる
FutureWarning が標準出力に出ると、Bedrock がそれも読んで警告の説明を始めます。実行環境のほうで警告を止めました。

