【AWS×Google Cloud Vertex AI】AWSアップデートを4コマ漫画にして解説するSlackボットを作ってみた

記事タイトルとURLをコピーする

垣見です。
毎日AWSアップデートの漫画を生成してくれるSlackボットを作りました。

はじめに

日々大量に発信されるAWSのアップデート情報。キャッチアップは重要ですが、業務の合間に全てを追いかけるのは容易ではありません。

以前こんなブログを書いたところ、社内外で多くの「わかりやすい」「いいね」というお声がけを頂きました。

blog.serverworks.co.jp

Google CloudのVertex AIでNano Banana Proの画像生成を行い、各種アップデートを4コマ漫画にしたものになります。

こちらとてもいいモデルだと感じたので、自動化しようと思いました。

実は弊社では、先輩エンジニアが作成した「RSSフィードからAWSアップデート情報を取得して要約・投稿するSlackボット」が既に稼働していました。 そこで、そのボットを改修する形で、AWSアップデートを自動で4コマ漫画化してSlackに投稿するシステムを開発しました。

朝Slackを開くと、AWSアップデートが漫画形式で届き、娯楽感覚でアップデートを視覚的に追えるような体験を目指しました。

できたもの

毎朝定時に、以下のように前日1日分のアップデートを漫画付きで投稿してくれます。

あまり日本に関係のないアップデートに関しては漫画がなく、文字だけの生成になっています。

漫画は例えばこんな感じです。

※あくまでAIが作成した文章・画像ですので、間違いが含まれていないかはご注意ください。

システム構成

本システムは、Amazon EventBridge Schedulerで毎朝トリガーされる4つのAWS LambdaとAWS Step Functionsで構成しています。

EventBridge Scheduler
    ↓
ProducerFunction
    ├─ RSS取得・フィルタリング
    └─ Step Functions起動
         ↓
ComicGeneratorStateMachine(Step Functions)
    └─ Map State(1件ずつ直列処理)
         ├─ WorkerFunction
         │    ├─ Amazon Bedrock(Claude Sonnet)で重要度判定・整形
         │    ├─ S3の参考画像をVertex AIに渡して漫画生成
         │    ├─ JPEG圧縮
         │    ├─ S3保存
         │    └─ Slack投稿
         ├─ ThrottleWait 30秒(Vertex AI RPM制限対策)
         └─ [失敗時] FallbackFunction(テキストのみSlack投稿)
    ↓ 全件完了後
NotifyFunction(完了通知)

使用モデル:

  • テキスト整形・重要度判定: Amazon Bedrock Claude Sonnet 4.5(jp.anthropic.claude-sonnet-4-5-20250929-v1:0)
  • 漫画生成: Google Vertex AI Gemini 3 Pro (gemini-3-pro-image-preview) ※まだプレビュー版の表記があります

わざわざGoogle Cloud のVertex AIを採用しているのは、「読める日本語を含めた画像を生成してくれるAI」が、まだBedrock上で見つけられていなかったからです。Geminiの通称Nano Banana Pro、大好きです。

参考:Stable Image Services(Ultra v1.1)

AWS側のデプロイはサーバレス開発に便利なAWS Serverless Application Model (AWS SAM)で行いました。(Google Cloud 側の操作や認証情報、Slack連携などは手作業が必要です)

blog.serverworks.co.jp

プロンプト設計

生成AIの品質は、プロンプト設計に大きく依存します。本システムでは、Amazon Bedrock(Claude Sonnet)とVertex AIそれぞれで以下のようなプロンプトを設計しました。

Claude整形プロンプト(重要度判定機能付き)

Claudeには、①漫画化が必要ないアップデートかどうか判断してフラグを立てる、②情報を構造化して翻訳・要約する、という2つの役割を担わせています。
特に、②の要約文は、「ユーザーがSlack上で見る文章」であり、かつ「後続のVertex AIが画像生成時のプロンプトとして参照する文の一部」であるので、必要な要素がわかりやすく入るようにこだわりました。

def format_with_claude(update):
    """Bedrock Claudeで整形・重要度判定"""
    prompt = f"""あなたはAWS専門のテクニカルライターです。
以下のAWSアップデート情報を分析し、JSON形式で返答してください。

# 重要度判定基準:
- **TRUE (重要)**: 新サービス、新機能、機能追加、価格改定、東京/大阪リージョンに関連する記述、グローバルに影響する重要な変更。
- **FALSE (低)**: 東京/大阪以外の特定のリージョン(例: 欧州、中東、南米など)への単なる展開・拡張で、新機能を含まないもの。

# 出力形式:
必ずJSON形式で返答してください。Markdownのコードブロックは不要です。

{{
  "is_important": true,
  "reason": "判定理由を簡潔に記述",
  "formatted_text": "Slackのmrkdwn形式の要約テキスト"
}}

# formatted_textの制約条件:
- 必ず日本語で解説。
- 結論から書く。
- 解説は500字以内。
- Slackのmrkdwn形式で記載し、以下のルールを守る:
  * 太字: *テキスト* (重要な用語やキーワード)
  * インラインコード: `コード` (サービス名、API名、技術用語)
  * リンク: <URL|タイトル>
- 以下のフォーマットを厳守。

*① 内容の要約*
1行で簡潔に。(東京・大阪リージョンの場合は :jp: を付ける)

*② 従来との比較*
• *従来*: 従来の仕様
• *今回*: 今回の変化

*③ 専門用語*
• `用語1`: 説明(初心者向け)
• `用語2`: 説明
• `用語3`: 説明

*④ 利用可能リージョン*
(東京・大阪以外のリージョン拡張の場合は絵文字不要、事務的に記載)

*⑤ 参考リンク*
(公式ドキュメントやブログがあれば <URL|タイトル> 形式で記載、なければこの項目は削除)

# アップデート情報:
タイトル: {update['title']}
リンク: {update['link']}
説明: {update['description']}
"""
    # ... Claude呼び出し処理 ...

設計のポイント:

  • 重要度判定によるコスト最適化: すべてのアップデートを漫画化するとコストが高くなるため、重要度が低いと判定されたアップデート(海外特定リージョンへの単純な展開など)は漫画生成をスキップし、テキストのみで投稿しています。ユースケースに合わせて特定サービスだけなどに変えると、より自身にあったアップデートが来ると思います。

これにより、Vertex AI APIの呼び出し回数を削減し、コストを最適化しつつ、ユーザーが注目すべきポイントが絞られます。

テスト中にいただいたフィードバックを反映させていただきました。オーナーシップに大感謝です!

Slack mrkdwnでのフォーマットの厳密な指定など、Slack上での読みやすさにもこだわりました。

本来の用途とは違うのですが、投稿時には>という引用マークやタイトルの強調、統一された絵文字をつけることで、連続投稿により前後の投稿同士がつながって見えることを回避しています。
(連続投稿すると上下の投稿がつながって見えてしまうことがあります。また、AIは毎回カラフルな絵文字を付けて目がちかちかしがちなので、構造化された部分は字の文側で統一します。)

Vertex AI漫画生成プロンプト

Vertex AIには、整形されたテキスト情報を視覚的な4コマ漫画に変換する役割を担わせています。

comic_prompt = f"""あなたはAWSの技術アップデートを伝える4コマ漫画家です。
与えられた要約をもとに、エンジニアあるあるを交えた4コマ漫画を生成してください。

# 制約条件:
- かならず、参考画像のキャラクターを登場させて、アートスタイル(色使い・雰囲気)も準拠すること。
  ただし構図は必要に応じて変更してよい。
- 左上、右上、左下、右下、の順で読む4コマの日本の漫画の形式で記す。
- コマには読む順番を付ける
- 「今までと何が変わったのか」「何が良いのか」の情報が入る
- 上部にはタイトルとしてアップデート名と要約を示す
- 文章は日本語
- 企業ロゴやサービスロゴなど著作権に問題があるものは使わない

# スタイル:
- ミニマルな2色使い(モノトーン、淡いオレンジ、淡いネイビー)
- 記号的でわかりやすいアイコンを活用
- 参考画像に従う。ただし、構図は必要に応じて変更してよい。

# アップデート情報:
{formatted_text}
"""

設計のポイント:

  • 参考画像の活用: あらかじめS3に保存した参考画像をLambdaがBase64エンコードして渡すことで、スタイルの一貫性を確保しています。参考画像(とプロンプト)を変えれば、オリジナルのスタイルに簡単に変更できます。
  • 4コマ形式の明示: 日本の漫画の読み順(左上→右上→左下→右下)を明確に指定
  • 著作権への配慮: ロゴ使用を禁止し、安全な運用を実現(ただしこれを指定しても、たまにロゴを生成してしまうことがあります……。プロンプトの工夫や、再チェックの仕組みを入れると厳密にできるかもしれません。)
  • 情報の明確化: 「何が変わったか」「何が良いか」を必ず含めることで、実用性を担保

ちなみに、この参考画像はこんな感じで雑に書いた「クラウド」モチーフのキャラクターを

頭が雲になっている

Geminiに綺麗にしてもらって、

すごい

そこからいくつか漫画を生成して、気に入ったものを採用しました。(渡し方は後述)

色はあえてシンプルに

4コマの構成もプロンプトと見本でがっちり固定して、著作権の侵害確率を減らし、かつ認知負荷がかからないようにしています。

(逆に自分専用だったら、それぞれを違うアートスタイルの漫画ができるようにすることで、インパクトや覚えやすさを上げるというのも面白いかもしれませんね。)

実装上の工夫

1. Vertex AIとの連携アーキテクチャ

本システムの特徴の一つは、AWS環境からGoogle CloudのVertex AIを呼び出す点です。
簡単に解説します。

認証情報の管理

Google Cloudのサービスアカウント認証情報(JSON)は、AWS Secrets Managerで安全に管理しています。

この認証情報はグローバル変数にキャッシュしており、ウォームスタート時にSecrets Manager APIの呼び出しをスキップします。

Vertex AI REST APIの直接呼び出し

Vertex AIへのリクエストは、REST APIを直接呼び出す形で実装しています。

サービスアカウントから短期のアクセストークンを動的取得してAuthorizationヘッダーに付与し、urllib3でPOSTします。
requestsなどの追加ライブラリを使わずにboto3に同梱のurllib3を活用しているため、依存関係が少ないです。

なお、globalリージョンと特定リージョンでエンドポイントのホスト名が異なるため、環境変数で切り替えられるようにしています。

参考画像のクロスクラウド共有

漫画のスタイルを統一するため、参考画像をVertex AIに渡しています。この参考画像はS3に保存し、Lambda実行時に取得してBase64エンコードする方式を採用しました。

S3の参考画像は手動でファイルアップロードするだけで入れ替えが可能なので、後から自分好みのテイストの参考画像に変えられるようにしています(再デプロイ不要です)

代替案として「Google Cloud StorageにアップロードしてURIで参照」も検討しましたが、参考画像は1枚のみでサイズも小さい(数百KB程度)ため、S3+Base64方式で問題ないと判断しました。

2. Slack直接画像投稿の実装

当初はS3署名付きURLをWebhookで投稿する方式でしたが、URLの有効期限問題Slack内での画像永続化のニーズから、Slack Web APIによる直接アップロード機能を追加しました。

ここは結構苦戦しました。

files_upload_v2 APIの活用

Slackのfiles_upload_v2 APIを使用することで、画像をSlackに直接アップロードできます。

なお、SlackのファイルアップロードAPIは、files_upload(旧API)が2025年5月に廃止されており、files_upload_v2を選択する必要があります。initial_commentで画像と同時にテキストも投稿可能です。

必要な権限設定

Slack直接アップロードを使用するには、以下の権限が必要です:

  1. Bot Token Scopes:

    • files:write: ファイルアップロード権限
    • chat:write: メッセージ投稿権限
  2. 環境変数:

    • SLACK_BOT_TOKEN: Bot User OAuth Token(xoxb-...
    • SLACK_CHANNEL_ID: 投稿先チャンネルID(C0123456789
  3. アプリのチャンネルへの招待
    (私はこれに引っ掛かりました。投稿自体はできてしまうので、なぜ失敗したかわからず首をひねっていました。)

これらが設定されていない場合、画像の直接アップロードは失敗します。

ちなみに最初は「S3署名付きURL」で実装していました。設定期間を超えると見えなくなってしまいますが、より簡単に実装できるかと思います。

3. Step Functionsによる処理設計

最初はLambda 1つで全件を並列処理する構成を試みましたが、Vertex AIのレート制限対応や、失敗時のリトライをコードで制御するのが複雑になっていました。Step Functionsに移行することで、以下のメリットが得られました。

  • レート制限対応の簡素化: Vertex AIのレート制限は、ASL(Step Functionsの定義ファイル)にWait stateを宣言するだけで対応できます。Pythonコード内でtime計測やsemaphoreを書く必要がありません。
  • 耐障害性の向上: 個別の処理失敗はRetry(最大3回、指数バックオフ)と、失敗時のCatch → FallbackFunctionへのルーティングでハンドリングします。1件の失敗が他の処理を止めません。
  • 実行状況の可視化: Step Functionsコンソールで、どの件が成功・失敗したかをビジュアルに確認できます。

各アップデートはMap stateで1件ずつ直列処理し、WorkerFunction完了後に30秒待機してから次の件へ進みます。
最初は並列処理も考えましたが、Vertex AIのレート制限に苦しみ、MaxConcurrency: 1(直列)にしました。これにより、Slack投稿の順序をRSSフィードの順番通りに保てるようになりました。

4. JPEG圧縮による画像サイズの最適化

もともとVertex AIが生成する画像はPNG形式で、サイズが1MB~2MBでした。 PillowでJPEGに変換することでサイズを1/10程度に削減でき、アップロード高速化やコスト削減につなげました。

そのほか工夫

このシステム固有というわけではないですが、過去の経験をもとに以下のようなことも実施しています。

  • Lambda用のCloudWatch LogGroupの保存期限を7日間に設定(CloudWatch LogGroup作成と保持期間設定を明示的に書かないと、Lambdaが動いた後にできるCloudWatch LogGroupでデフォルトで無期限に保管され、コストに影響します。)
  • S3ライフサイクルポリシーで30日経過した画像を自動削除し、ストレージコストを削減
  • コスト配分タグをつけて、料金をアプリ単位で追えるようにしています(なお、BedrockのInvokeModelなどの推論コストはリソースタグでは追跡できません。Application Inference Profilesでコスト追跡ができます)
  • AWS Service Catalog AppRegistryでアプリケーションとして登録し、アプリとしてまとめてAWS側で追えるようにしています
  • ログを出して、エラーが起きたときにCloudWatch Logsで確認できるようにしています(何度も助けられました)

運用コスト

実際3月に毎日動かしたときはGoogle Cloud側が3800円/月、AWS側が$2/月くらいでした。(約26ドル) Vertex AIは通常6件生成した日で90円程度です。

やはり画像生成でお金がかかります。

アップデートがない日もそれなりにあり、また重要度の低いアップデートは画像生成していないため、このようなグラフになっています。(※3/30は検証で多く動かしています)

re:Invent期間などでアップデートが多い場合はもっと増えるでしょう。

Gemini 3 Pro ImageのAPI料金はこちらに記載があります。

なお、AWS側の内訳として、Bedrockが一日に大体$0.1以下でした。開発・検証で約60回呼び出したときには一日に$1.25かかりました。 その他は、Secrets Managerが固定で$0.40/月かかっている以外は、無料利用枠に収まっているようです。

まとめ

もともとの既存のアップデート取得システムがとても良かったので、それをアップデートさせていただく形で開発できました。ありがたいことです。

もし詳細にご興味ありましたらお気軽にお声がけください。

本ブログが皆様のお役に立てば幸いです。

あたたかい反応をいろいろもらいました

垣見(かきみ)(執筆記事の一覧)

2023年新卒入社 エンタープライズクラウド部所属 2025 Japan AWS Jr.Champions

図解するのが好き。「サバワク」のアイキャッチ作成も担当しています