AWSのアップデートをSlackに通知する"What’s New Summary Notifier"をAmazon Novaで動かす

# はじめに

以前の記事では、AWSブログの情報収集、日本語での要約、受信Webhookに対応したコラボレーションツールへの投稿を行うソリューション `What’s New Summary Notifier` をSlackフリープランのWebhookで受信する方法を紹介しました。

https://qiita.com/revsystem/items/c6a9cfae9f1047da602e

このソリューションは、AWS BedrockのInvoke APIで Anthropic Claude 3 Sonnetを呼び出す前提となっています。そのため、他のモデルを使うためにはそのモデルの出力に合わせた処理が必要です。そこで、この記事ではInvoke API呼び出しをConverse API呼び出しに置き換える修正を紹介します。これにより、以下の利点が得られます。

- 様々なモデルを試すことで、好みやコストに合わせたモデルが選択可能になる
- マーケットプレイスに依らないAWSのモデルが利用可能になる
- Amazon NovaなどAWSのモデルを選択することで、AWSクレジットの活用が可能になる

特にAWSクレジットを持っているユーザーには、3番目の利点が魅力ではないでしょうか。

# 参考情報

https://aws.amazon.com/jp/builders-flash/202406/catch-up-genai-update/

https://docs.aws.amazon.com/en_us/bedrock/latest/userguide/model-parameters-nova.html

https://docs.aws.amazon.com/nova/latest/userguide/using-converse-api.html

# 構築手順

`What’s New Summary Notifier` の構築手順は、AWSブログもしくは以前の記事を参考にしてください。どちらをもとに構築した場合でも変更箇所は同じです。

https://aws.amazon.com/jp/builders-flash/202406/catch-up-genai-update/

https://qiita.com/revsystem/items/c6a9cfae9f1047da602e

## コードの修正とデプロイ

### modelIdの変更とConverse API 呼び出し

モデルIDの指定は  `cdk.json` 内の値を変更します。今回は、Nova Microを使用します。

```diff:./cdk.json
     "context": {
         "modelRegion": "us-east-1",
-        "modelId": "anthropic.claude-3-5-sonnet-20240620-v1:0",
+        "modelId": "amazon.nova-micro-v1:0",
         "summarizers": {
             "AwsSolutionsArchitectEnglish": {
                 "outputLanguage": "English.",
```

Invoke API 呼び出しから Converse API 呼び出しへの変更は `./lambda/notify-to-app/index.py` で行います。Converse API の呼び出しに合わせて、システムプロンプトのテンプレートやAPIパラメータ、出力結果の受け取り部分を変更します。

```diff:./lambda/notify-to-app/index.py
         assumed_role=os.environ.get("BEDROCK_ASSUME_ROLE", None),
         region=MODEL_REGION,
     )
-    beginning_word = "<output>"
+
     prompt_data = f"""
-<input>{blog_body}</input>
 <persona>You are a professional {persona}. </persona>
 <instruction>
 Describe a new update in <input></input> tags in bullet points to describe "What is the new feature?", and "Who is this update good for". The description shall be output in <thinking></thinking> tags, and each thinking sentence must start with the bullet point "- " and end with "\n".
```

```diff:/lambda/notify-to-app/index.py

     max_tokens = 4096

-    user_message = {
-        "role": "user",
-        "content": [
-            {
-                "type": "text",
-                "text": prompt_data,
-            }
-        ],
-    }
-
-    assistant_message = {
-        "role": "assistant",
-        "content": [{"type": "text", "text": f"{beginning_word}"}],
-    }
-
-    messages = [user_message, assistant_message]
+    system_prompts = [
+        {
+            "text": prompt_data
+        }
+    ]

-    body = json.dumps(
+    messages = [
         {
-            "anthropic_version": "bedrock-2023-05-31",
-            "max_tokens": max_tokens,
-            "messages": messages,
-            "temperature": 0.5,
-            "top_p": 1,
-            "top_k": 250,
+            "role": "user",
+            "content": [
+                {
+                    "text": f"<input>{blog_body}</input>"
+                }
+            ]
         }
-    )
+    ]

-    accept = "application/json"
-    contentType = "application/json"
-    outputText = "\n"
+    inference_config = {
+        "maxTokens": max_tokens,
+        "temperature": 0.5,
+        "topP": 1,
+    }

+    additional_model_request_fields = {
+        "inferenceConfig": {
+            "topK": 125
+        }
+    }
     try:
-        response = boto3_bedrock.invoke_model(
-            body=body, modelId=MODEL_ID, accept=accept, contentType=contentType
+        response = boto3_bedrock.converse(
+            system=system_prompts,
+            messages=messages,
+            modelId=MODEL_ID,
+            inferenceConfig=inference_config,
+            additionalModelRequestFields=additional_model_request_fields
         )
-        response_body = json.loads(response.get("body").read().decode())
-        outputText = beginning_word + response_body.get("content")[0]["text"]
+
+        outputText = response["output"]["message"]["content"][0]["text"]
+
         print(outputText)
         # extract contant inside <summary> tag
         summary = re.findall(r"<summary>([\s\S]*?)</summary>", outputText)[0]
```

### デプロイ

上記のとおり変更後、デプロイを行います。

```console
cdk deploy
```

# Anthropic Claude 3 SonnetとAmazon Novaとの比較

モデルの変更前後で同じAWSブログをクロールし、内容の比較を行いました。サマリーとしては両者の内容に大きな差はないため、コストで比較するならばトークンあたりのコストが低い Amazon Nova が有利と言えそうです。

<table>
  <caption>モデルによるサマリーの比較</caption>
  <thead>
    <tr>
      <th>anthropic.claude-3-5-sonnet-20240620-v1:0</th> <th>amazon.nova-micro-v1:0</th>
    </tr>
  </thead>
  <tr>
      <td>
<p><a href="https://aws.amazon.com/blogs/machine-learning/achieve-2x-speed-up-in-llm-inference-with-medusa-1-on-amazon-sagemaker-ai/">Achieve ~2x speed-up in LLM inference with Medusa-1 on Amazon SageMaker AI</a><br />
AWSがAmazon SageMaker AIでLLMの推論を約2倍高速化するための新しいMedusa-1フレームワークを発表しました。モデルの品質を損なうことなく、低遅延のアプリケーションに適しています。</p>

<ul>
<li>AWSが新しいMedusa-1フレームワークをAmazon SageMaker AIで発表しました。</li>
<li>Medusa-1は、特定の用途のためにLLMを最適化するための2つのステップのアプローチを必要とします。</li>
<li>LLMを最初に微調整し、その後Medusaヘッドを追加して訓練します。</li>
<li>このフレームワークは、LLMの推論を約2倍高速化し、モデルの品質を損なうことなく低遅延のアプリケーションに適しています。</li>
<li>この更新は、リアルタイムのテキスト完成、同時翻訳、会話型音声アシスタントなど、応答時間が重要であるアプリケーションを開発するユーザーに適しています。</li>
     </td>
      <td>
<p><a href="https://aws.amazon.com/blogs/machine-learning/achieve-2x-speed-up-in-llm-inference-with-medusa-1-on-amazon-sagemaker-ai/">Achieve ~2x speed-up in LLM inference with Medusa-1 on Amazon SageMaker AI</a><br />
Amazon SageMaker AIを使用してMedusa-1フレームワークでLLMの推論速度を約2倍に向上させる方法が紹介されました。この手法は元のモデルの出力品質を維持しながら、低レイテンシーのテキスト生成が必要なアプリケーションに特に適しています。</p>

<ul>
<li>Medusa-1というフレームワークを使用してLLMの推論速度を約2倍に向上させる方法が紹介されています。</li>
<li>Amazon SageMaker AIを使ってLLMの微調整とMedusaヘッドの訓練を行う手順が示されています。</li>
<li>Medusa-1は元のモデルの出力品質を維持しながら推論速度を向上させることができます。</li>
<li>この手法は特に低レイテンシーのテキスト生成が必要なアプリケーションに適しています。</li>
</ul>
     </td>
  </tr>
  <tr>
     <td>
<p><a href="https://aws.amazon.com/about-aws/whats-new/2025/02/amazon-rds-for-postgresql-new-minor-versions/">Amazon RDS for PostgreSQL supports minor versions 17.3, 16.7, 15.11, 14.16, 13.19</a><br />
Amazon RDS for PostgreSQLが最新のマイナーバージョンをサポートし、セキュリティとパフォーマンスが向上しました。自動アップグレードやBlue/Greenデプロイメントなど、柔軟なアップグレードオプションも提供されています。これにより、データベース管理者はより安全で効率的な運用が可能になります。</p>

<ul>
<li>Amazon RDS for PostgreSQLが最新のマイナーバージョン17.3、16.7、15.11、14.16、13.19をサポートするようになりました。</li>
<li>セキュリティ脆弱性の修正やPostgreSQLコミュニティによるバグ修正の恩恵を受けられます。</li>
<li>PostgreSQL拡張機能（pg_active 2.1.4、pg_cron 1.6.5、pg_partman 5.2.4など）も更新されています。</li>
<li>自動マイナーバージョンアップグレード機能を使用して、スケジュールされたメンテナンス時間内に自動的にアップグレードできます。</li>
<li>Amazon RDS Blue/Greenデプロイメントを使用して、物理レプリケーションによるマイナーバージョンアップグレードも可能です。</ul>
    </td>
     <td>
<p><a href="https://aws.amazon.com/about-aws/whats-new/2025/02/amazon-rds-for-postgresql-new-minor-versions/">Amazon RDS for PostgreSQL supports minor versions 17.3, 16.7, 15.11, 14.16, 13.19</a><br />
Amazon RDS for PostgreSQLが最新のマイナーバージョンをサポートし、セキュリティの強化とバグ修正を提供します。自動アップグレードとブルー/グリーンデプロイメントが利用可能です。</p>

この機能はPostgreSQLデータベースを管理する開発者や運用者に有益です。
<ul>
<li>Amazon RDS for PostgreSQLが最新のマイナーバージョン17.3、16.7、15.11、14.16、13.19をサポートするようになりました。</li>
<li>最新のマイナーバージョンにアップグレードすることで、以前のバージョンのPostgreSQLにおける既知のセキュリティ脆弱性を修正し、PostgreSQLコミュニティによるバグ修正の恩恵を受けることができます。</li>
<li>更新には、pg_active 2.1.4、pg_cron 1.6.5、pg_partman 5.2.4などのPostgreSQL拡張機能の更新が含まれます。</li>
<li>自動マイナーバージョンアップグレードを使用して、スケジュールされたメンテナンスウィンドウ中にデータベースを自動的に最新のバージョンにアップグレードできます。</li>
<li>Amazon RDSブルー/グリーンデプロイメントを使用して、物理レプリケーションによってマイナーバージョンアップグレードを行うことができます。</li></ul>
    <td>
    </td>
  </tr>
  <tr>
     <td>
<p><a href="https://aws.amazon.com/about-aws/whats-new/2025/02/amazon-q-developer-upgrade-java-21/">Amazon Q Developer now supports upgrade to Java 21</a><br />
Amazon Q Developerが、JavaアプリケーションのJava 21へのアップグレードをサポートするようになりました。この新機能により、開発者はAIを活用してコードアップグレードを効率的に行えます。Java 8から21までの幅広いバージョンに対応し、IDEとCLIの両方で利用可能です。これにより、最新のJava機能を活用しつつ、アプリケーションの性能や安全性を向上させることができます。</p>

<ul>
<li>Amazon Q Developerが、Mavenを使用したJavaアプリケーションのJava 21へのアップグレードをサポートするようになりました。</li>
<li>開発者は、Amazon Q DeveloperのAI機能を活用してJava 21へのコードアップグレードを加速できます。</li>
<li>Java 8、11、17、21からJava 17または21へのアップグレードが可能です。</li>
<li>IDEとCLIの両方でこの機能が利用可能です。</li>
<li>ライブラリやフレームワークのアップグレードもJDKバージョンを上げずに行えます。</li>
     </td>
     <td>
<p><a href="https://aws.amazon.com/about-aws/whats-new/2025/02/amazon-q-developer-upgrade-java-21/">Amazon Q Developer now supports upgrade to Java 21</a><br />
Amazon Q DeveloperはJava 21へのアップグレードをサポートし、ジェネレーティブAI機能を活用してコードのアップグレードを加速します。Java 17および21と互換性のあるアプリケーションのライブラリやフレームワークをアップグレードできます。</p>
<ul>
<li>Amazon Q DeveloperがJava 21へのアップグレードをサポートするようになりました。</li>
<li>JavaアプリケーションをJava 21にアップグレードするためのAmazon Q Developerの変換機能が利用可能になりました。</li>
<li>パフォーマンス、セキュリティ、相互運用性、最新機能の強化を活用したい開発者は、Amazon Q DeveloperのジェネレーティブAI機能を使用してJava 21へのコードアップグレードを加速できます。</li>
<li>Javaバージョン8、11、17、または21のソースバージョンから、ターゲットバージョン17または21にJavaアプリケーションをアップグレードできます。</li>
<li>Java 17または21と互換性のあるアプリケーションで使用されるライブラリやフレームワークを、JDKバージョンをアップグレードせずにアップグレードできます。</li>
<li>Java変換機能は、IDE（Visual Studio CodeおよびJetBrains IntelliJ IDEA）とCLI（LinuxおよびMacOS）の両方で利用可能です。</li>
</ul>
     </td>
  </tr>
</table>

# まとめ

AWSが提供する `What’s New Summary Notifier` を Converse API 呼び出しに対応するよう変更し、モデルにAmazon Nova を使用してみました。Converse API 呼び出しに変更したことで、モデルの切替が容易になり、クロスリージョン推論なども試しやすくなりました。以前の記事では、AWSブログ以外のブログやニュースサイトから記事を取得する実装を紹介しました。取得する記事の分野に合わせて、その分野を得意とするモデルに切り替えるといったこともできそうです。