月次コストを収集し、Claude 3 Haikuに最適化提案させてみた

Y
2025-05-23
2025-05-23

AWSを利用していると、気になるのが毎月のコストですね。
本記事では、AWS Cost Explorer API + Claude 3 Haiku (Amazon Bedrock) を用いて、
AIによるコストアドバイスがもらえないかと思い、試してみました。

やりたいことは以下の通りです。
・AWS CLI/Pythonで月次コストを自動取得
・Claude 3 Haiku にデータを渡し、コスト削減や構成改善のアドバイスを受け取る
・エンジニア目線で改善ポイントの参考にする

今回Claude 3 Haiku を使いますが、モデルアクセスを有効化やAWS CLI のコンフィグファイル設定などは割愛します。



スクリプト全体(Python)

以下のコードで、コストの取得からAIによる提案までが完結します。

import boto3
import datetime
import json

# === 1. AWSコストデータ取得 ===
def get_monthly_costs(start_date, end_date):
    ce = boto3.client('ce')

    response = ce.get_cost_and_usage(
        TimePeriod={
            'Start': start_date,
            'End': end_date
        },
        Granularity='MONTHLY',
        Metrics=['UnblendedCost'],
        GroupBy=[
            {'Type': 'DIMENSION', 'Key': 'SERVICE'}
        ]
    )

    results = {}
    for group in response['ResultsByTime'][0]['Groups']:
        service = group['Keys'][0]
        cost = float(group['Metrics']['UnblendedCost']['Amount'])
        results[service] = cost
    return results

# === 2. Claude向けプロンプト生成 ===
def build_prompt(cost_data):
    prompt = "以下は、あるAWSアカウントの今月のサービス別コストです。\n\n"
    for service, cost in cost_data.items():
        prompt += f"- {service}: ${cost:.2f}\n"
    prompt += (
        "\nこのコストデータをもとに、以下を含む改善提案をください:\n"
        "- 無駄なコストが発生している可能性があるサービス\n"
        "- リザーブドインスタンスやSavings Plansの適用検討\n"
        "- サービス統合・構成変更によるコスト削減案\n"
        "- 可能であればアーキテクチャ改善も含めたアドバイス\n"
    )
    return prompt

# === 3. Claude 3 Haikuへ送信(Messages API) ===
def call_bedrock_claude(prompt):
    bedrock = boto3.client(
        service_name="bedrock-runtime",
        region_name="ap-northeast-1"  # 対応リージョン(例: us-east-1)
    )

    body = {
        "messages": [
            {
                "role": "user",
                "content": prompt
            }
        ],
        "anthropic_version": "bedrock-2023-05-31", # anthropic バージョン
        "max_tokens": 800, # 生成されるテキストの最大長を指定
        "temperature": 0.5 # レスポンスに注入されるランダム性の量
    }

    response = bedrock.invoke_model(
        modelId="anthropic.claude-3-haiku-20240307-v1:0",
        body=json.dumps(body),
        contentType="application/json",
        accept="application/json"
    )

    response_body = json.loads(response['body'].read())
    return response_body["content"][0]["text"]

# === 実行 ===
if __name__ == "__main__":
    today = datetime.date.today()
    start = today.replace(day=1).isoformat()
    end = today.isoformat()

    print(f"[+] Fetching cost data from {start} to {end}...")
    cost_data = get_monthly_costs(start, end)

    prompt = build_prompt(cost_data)

    print("\n[+] Prompt for Bedrock:\n")
    print(prompt)

    print("\n[+] Asking Bedrock (Claude 3 Haiku)...\n")
    result = call_bedrock_claude(prompt)
    print(result)

上記スクリプトを実行してみると。

 
[+] Fetching cost data from 2025-05-01 to 2025-05-19...

[+] Prompt for Bedrock:
以下は、あるAWSアカウントの今月のサービス別コストです。

- AmazonEC2: $132.45
- AmazonS3: $23.67
- AWSLambda: $0.00
...

このコストデータをもとに、以下を含む改善提案をください:
...

[+] Asking Bedrock (Claude 3 Haiku)...

→ Claudeからの自然言語による提案が返ってきます

終わりに

Bedrock経由でClaudeにコストデータを渡し、
回答が返ってくることは実現できました。
想定はしていましたが、今月のコスト感だけでより良い改善提案内容は返ってこないので、
過去の月別コストデータや、Cloudwatchで取得している各インスタンスのリソース状況等の情報も渡してみて
より良い改善案が返ってくるか検証してみようと思います。

【参考記事】
https://aws.amazon.com/jp/builders-flash/202405/awsgeek-amazon-bedrock/
https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/getting-started.html
https://blog.denet.co.jp/cloudwatch-cpu-graph-bedrock-analysis/