
はじめに
こんにちは、入社一年目の小崎です。普段はWeb基盤システムの運用保守・開発を行っています。 仕事ではAWSを触ることが多いのですが、まだまだサービスについて知らないことが多く、仕事の合間を見て勉強中です。
そんな私ですが、コンソールの使い方も少しずつ慣れてきたので、生成AIを用いた内部システム開発に挑戦してみることにしました。実際にリリースする訳ではありませんが、R&Dの一環として動くシステムを構築しました。
この記事では開発を通して学んだAWSの生成AIサービス「Bedrock」の魅力を紹介していこうと思います。
AWSは普段利用しているけど「Bedrock」はまだ触ったことない方や、「Bedrock」を利用したシステム運用担当者の負担軽減に興味がある方、ぜひ見てください!
Bedrockとは
Bedrock(ベドロック)とは、AWS(Amazon Web Services)が提供する完全マネージド型の生成AIサービスです。
このサービスの最大の特徴は、「モデル選び・インフラ管理・セキュリティ」をAWSが全部面倒見てくれるという点です。つまり、自分で生成AIを運用するための高性能GPUやモデルホスティングなど、生成AIを動かすための“重くて難しい裏側の作業”を、全部AWSが肩代わりしてくれます。
Bedrock利用者としてやることは、既にAWS側で用意されている基盤モデルを選ぶ→APIにリクエストを送る→生成AIの回答を受け取る
たったこれだけなので、とても便利です。そして、Bedrockは「単体AI」ではなく、AWSアーキテクチャの一部として使う前提で設計されています。AWS設計に、生成AIを1部品として手軽に組み込めるのがこのサービスの強みです。
では、実際にどうやって組み込むのかを、今回作成したシステムを例にして説明したいと思います。
作成したシステムの概要
今回作成するシステムは、「EC2の障害ログ検知&通知をしてくれるシステム」です!
サーバで障害が起きた時に、原因を特定するためにログを調べて影響度や対応内容を検討する作業って、とても骨が折れる... そんなシステム運用担当者の負担を軽減することを目的としています。 こちらがシステムの全体構成図です。

システムの流れとしては以下になります。
- EC2に障害が発生し、システムログに障害内容が出力される
- CloudWatch Logsがフィルターパターンに合致した障害ログを検知
- CloudWatchアラームのアクションでLambdaを呼び出して手順4,5を実行させる
- 障害ログをBedrockへ渡し、生成AIにログの要約・影響度の推定、対応内容を生成してもらう
- 生成してもらった内容をSlackに通知する
このシステムの肝は、Lambdaを利用した通知システムの中にBedrockを組み込んでいるという点です。システムエンジニアが手動で行おうとすると時間がかかってしまうログの要約・影響度の推定・対応内容を考える作業を生成AIに任せています。
とても楽をしようとしていますが、生成AIの回答は本当に役に立つのでしょうか?
LambdaでBedrockを利用する方法
LambdaでBedrockを利用する方法について紹介していきます。今回は、手順4のLambdaで障害ログをBedrockへ渡す部分のみ説明します。
Lambdaに必要な実行権限
LambdaでBedrockを呼び出すためには、Lambdaに以下の実行権限が必要です。
- 「bedrock:InvokeModel」:Converse API によるモデルの呼び出し・推論を実行させるため
- 「aws-marketplace:ViewSubscriptions」:すでに対象モデルにサブスク済みかを確認するため
- 「aws-marketplace:Subscribe」:対象モデルにサブスクライブするため
この三つをポリシーに含んだIAMロールをLambdaにアタッチする事を忘れないようにしましょう!
今回のシステムではLambda と CloudWatch Logs を連携させるための権限を追加したポリシーを含んだIAMロールをアタッチしています。

上手くアタッチできるとLambdaの実行ロールに「AWS Marketplace」「Amazon Bedrock」が表示されるようになります。
生成AIモデルの呼び出し方
Lambdaの環境変数にAmazon Bedrock 内で利用できる生成AIモデルの「推論プロファイルARN」を指定することで、Bedrockの生成AIモデルを呼び出すことができます。 「推論プロファイルARN」とは、「どのモデルを、どんな実行条件で呼び出すか」を指す識別子のことです。
そのためにはまず、「推論プロファイルARN」を取得する必要があります。
・「AWSマネジメントコンソール >Bedrock >モデルカタログ」へ移動して、利用したいモデルを選択します。

今回は、複雑な推論と分析に特化した生成AIモデルである「Claude 3.5 Sonnet v2」を選びました。
・次に、選択したモデルのモデルIDをコピーします。

・CLIを開いて、青の下線部分にコピーしたモデルIDを貼り付けて以下のコマンドを叩きます。

赤枠の結果出力が「推論プロファイルARN」です。
こちらが取得出来たら、コード内であらかじめ定義したLambdaの環境変数(今回はBEDROCK_MODEL_ARN)に値を入れていきます。

これで、LambdaがBedrockを呼び出すことができるようになりました!
プロンプトの渡し方
Bedrockの推論モデルへプロンプトを渡すためには、大きく分けて以下の4ステップをLambdaに処理してもらう必要があります。
- プロンプトを組み立てる
- 組み立てたプロンプトをBedrockが理解できるようにAPIリクエスト形式に変換する
- API を叩き、プロンプトをBedrockに渡す
- プロンプトに渡す材料(今回だとEC2の障害ログ)を集めて、1~3の一連の処理を実行する
実際に1~4までの流れをコードで書くと、抜粋部分だけでもこの量になります。全体で約 310 行に及びました。私はここでも生成AIを頼りまくりました。。。

とても大変な作業になりますが、Bedrockにはプロンプトを管理してコードを簡略化できるサービスが備わっています!
それが「Amazon Bedrock Prompt Management」です。
「Amazon Bedrock Prompt Management」の紹介
このサービスはシステムを構築した後に知ったので、今回の構築には利用していません。
ですが、調べるとこのサービスを利用するメリットがたくさんあったので、ここで紹介させていただこうと思います!
・「Amazon Bedrock Prompt Management」を利用すると、プロンプトを AWS コンソールに保存することができます。
→呼び出すときは「推論プロファイルARN」の代わりに「プロンプトの ARN」をLambdaの環境変数に指定するだけなので、Lambdaのコードでプロンプトを組み立てる工程を省くことができます。今回書いたコードだと最初の2ステップ(1. プロンプトを組み立てる、2. 組み立てたプロンプトをBedrockが理解できるようにAPIリクエスト形式に変換する)を省くことができますね。約 170 行分に及びます。
・プロンプトの保存だけではなく、このサービスにはバージョン管理機能があります。
→バージョン管理機能を利用すれば、プロンプト自体をDraft/Version1/Version2… のように管理できるため、プロンプトを間違えても簡単にロールバックでき、 ソースコードに「旧プロンプトがコメントアウトで残ってる問題」がなくなります。
・プロンプトのテストが GUI でできるのも特徴の一つです。
→今回作成したシステムだと、 Bedrock に実際にプロンプトを投げてみないと、このプロンプトで本当に動くのかを試せません。ですが、「Prompt Builder」という GUIを利用すると、「プロンプトを書く→変数に値を入れる→複数モデルに実行→結果を横並びで比較」の流れでテストができるようになり、 プロンプトの改善時間短縮が期待できます。
こんなサービスがあったなんて...完全に見落としていました。
生成AIの回答精度を上げるためには
いくら生成AIを利用して手動タスクの手間が省けても、回答精度が悪ければ意味がないです。今回のシステムで例えると、生成AIが回答してくれた推定影響や対処方法が的外れでは、「最初から生成AIに任せずに手動で原因調査を行えばよかった」と思いますよね。
ですが、プロンプトをうまく工夫することが出来れば、回答精度を高めることができます。
今回テストとして利用した障害ログは以下になります。
amazon-ssm-agent[]: Error occurred fetching the seelog config file path: open /etc/amazon/ssm/seelog.xml: no such file or directory
このエラーは、Amazon SSM Agent が /etc/amazon/ssm/seelog.xml ファイルを見つけられない場合に発生します。ですが、実際このエラーは “再起動直後に毎回出る軽微な障害ログ”として正しい挙動であり、実運用上の問題はないことが分かっています。
“This should probably just trigger a warning rather than an error, since the config file doesn't exist, I'm assuming amazon-ssm-agent is operating based on default values and that's not really an error in itself.” (訳:これは本来 warning 相当であり、設定ファイルが無い場合には SSM Agent は デフォルト値で動作しており、本質的なエラーではない。)
出典:SSM agent syslog errors | AWS re:Post
ですので、私が期待している回答は、簡単に言うと「特に影響はないから問題ないよ」という旨の内容です。
最初に生成AIモデルへ投げたプロンプトは以下になります。
"あなたは運用SREです。以下の障害ログとアラーム情報から、要約・推定影響・原因仮説・推奨対処(優先度付き)を日本語で作成してください。 出力は必ず JSON で返してください。余計な文章は不要です。"
- プロンプトに渡す材料:原因となるログ一件
では、実際にSlackに届いた通知内容を見ていきましょう。

推奨影響で「システム運用に支障をきたす恐れあり」と回答がありますが、これは私の期待していた回答とは異なります。 なぜ過大な影響評価をしてしまうのか調査したところ、これは私の投げているプロンプトの内容に問題がありました。
- プロンプトに渡す材料:原因となるログ一件
この部分です。
CloudWatch Logsで実際に障害ログを見てみると、該当する障害ログの後に以下の二つのログが出ていました。

「 設定ファイルが無い → ロガー初期化 → 作成出来たので通常稼働」が一連の挙動としてデフォルトで行われているのが分かります。
ですが、生成AIの推論モデルは原因となるログ一件のみを判断材料として推論を行っていたので、「ロガー初期化 → 作成出来たので通常稼働」の部分は知らなかったのです。期待通りに回答してくれなかったのはプロンプトに渡す材料不足が原因でした。
では、命令文はそのままで、渡す材料を以下のように変更したらどうなるでしょうか。
- プロンプトとして渡すログ:
原因となるログ一件→ 原因となるログから前後20行分
これで、原因となるログの前後で起きる挙動も推論モデルが把握してくれます。では、実際に届いた通知内容を見てみましょう。

推定影響に「実運用への影響は限定的」と回答しています。変化がありましたが、実際にはこのログは正常な挙動であり影響はありません。期待していた回答に近づきましたが、まだ正確な回答とは言えないですね。
では、渡す材料はそのままで、命令文の内容を詳細にして正確な回答を得られるように修正してみましょう。
修正したプロンプトの命令文は以下になります。
あなたはSREアナリストです。以下の障害ログとアラーム情報を分析し、 過大な影響評価や不要な対処提案を避けることを最優先に、日本語で要約・影響・原因仮説・推奨対処を返してください。
重要な抑制ルール(厳守)
(回復ログの扱い)原因行の直後や前後文脈に自己回復/正常化を示すシグナルがある場合 (例: "Initializing new seelog logger", "New Seelog Logger Creation Complete", "active (running)", "recovered", "succeeded" など)、 影響は「低」または「なし」とし、推奨対処の第一候補は「対応不要/監視ノイズ抑制/起動後グレース適用」とする。
また、検出した回復シグナルを evidence.recovery_signals に必ず列挙する。
(優先度ガイドの固定)Pレベルを次の通り用いること:
- P0: 直ちに顧客影響/全停止/データ損失(具体的な被害ログやメトリクスが必須)
- P1: 重大障害(緊急対応)
- P2: 限定的影響/回避策あり/業務時間内対応
- P3: 影響軽微/改善提案
- P4: 既知の情報/ノイズ/対応不要(Benignや自己回復確認時は原則ここ) ※ 具体的な被害の根拠が無い限り、P2以上を提案してはならない。"
最初の命令文よりも判断基準を正確にして、提案内容に制限をかけました。では、実際に届いた通知を見てみましょう。

成功です!
推定影響は「影響なし」、検出された回復シグナルを根拠に推奨対処も「P4(対応不要)」と回答してくれています。
プロンプトの変更によって全ての障害ログが「影響なし」寄りになってしまっていないか、以下のテスト用障害ログをloggerコマンドを使って送り、挙動を確かめてみましょう。
エラー内容:20秒間、毎秒1回 DB拒否を送る
for i in {1..20}; do logger -p daemon.crit "CRITICAL: database unavailable: Connection refused" sleep 1 done
このエラーで実際に届いた通知を見てみると、

推定影響は「データベースの接続エラー」だと回答していて、推奨対処は「P2以上」が出ているので、「影響あり」の場合も正しく判断してくれることが分かります。
- プロンプトに渡す材料:AIが判断するために必要な「証拠」を全部渡すこと
- 命令文の内容:判断基準を具体的に明記し、場合によっては禁止(制限)事項を具体的に書く
生成AIの回答精度は、プロンプトで上記二つを意識するだけで正確性がかなり高まることが分かりました。
まとめ
今回の検証で分かったのは、生成AIの回答精度は「プロンプトに渡す材料」と「命令文の内容」で大きく変わるという当たり前だけど超重要な事実でした。
特に運用現場では、一行の障害ログだけで判断させると過大評価になりやすく、前後文脈や回復シグナルを「証拠」として渡すだけで、“影響なし”という妥当な結論に近づくことが確認できました。AIが「現場で使える品質」に到達できたら仕事のやりやすさも変わりそうだなーと思いました。
また、シンプルに開発が楽しかったです。今回の学びをベースに、生成AIのプロンプトをより一層意識してタスクをこなしていこうと思います。
ここまで読んでいただき、ありがとうございました!