障害調査は、システムの開発者以外には地味にハードルが高い
障害が起きたときの最初の一歩は大体決まっています。
ログを開き、エラーが出ている箇所を探し、当該バージョンのソースコードと照らし合わせて原因を絞り込みます。この一連の作業は、ログの読み方とコードの読み方の両方を知っている人にしかできません。これは初動対応ができる人が限られ、その人の稼働状況がそのまま問題解決のスピードに直結することを意味します。
この一連の流れを誰でもできるようにするのが今回の目的です。
こんな感じでつくってみた
今回はSlackからボット経由で使えるようにしてみました。
過去の障害をもとにテストデータを作成して、実際に検証してみます。
以下のようにシステムのバージョンと症状を簡単に記入して、さらにログファイルを添付します。

すると、おおよそ10分後に以下のように即時回避策と根本的な対応策を提示してくれます。
1回あたりのコストは0.5〜1ドルぐらいです。
これはLLM APIの使用料のみのため、AWSの利用料が別途かかります。
システムの全体像
Slackにログを添付して投稿するとAWS上で調査が自動で走り、結果が同じスレッドに返ってくる仕組みにしました。受付と重い調査処理は分離しています。エージェント本体にはClaude Agent SDKを使っています。
Slackへの投稿はLambdaが受け取り、SQSにジョブとして入れるだけに徹しています。Slackの応答3秒制限に合わせるにはLambdaの処理は軽くしておく必要があり、実際の調査(git worktree展開・Claude Agent SDK実行)は実行に10分前後かかりLambdaの制約(メモリ・実行時間)には収まらないため、ECS Fargateに切り出しました。
LLM APIで低コストかつ高精度を実現するには
ローカルでClaudeやCursor等のエージェントを使う場合、ログファイルやソースコードはエージェントが見られるフォルダに置いておけば済みます。プロンプトでやり取りする際にも、コストをそれほど気にする必要はありません。
しかし、LLM API(今回はAmazon Bedrock経由のClaude)を使う場合は、単純に考えると、ログファイルやソースコードをリクエストに含めて渡す必要があります。データサイズが大きくなるとそのままコストに跳ね返ってきます。
| 前提 | ローカルでAIエージェントを使う場合 | LLM APIを使って調べる場合 |
|---|---|---|
| リポジトリ | 既にクローン済み | リクエストごとに用意する必要がある |
| プロンプトサイズ | その都度判断できるので気にしない | コストとレイテンシに直結するため、渡す量を制御する必要がある |
| 大きなログ | フォルダにそのまま置いておけばよい | そのまま渡すとコストと遅延が膨らむ |
低コストかつ高精度を実現するための5つの工夫
1. ソースコードは必要な箇所だけ読ませる
ソースコードを丸ごとLLM APIに渡すと、それだけでコストが膨らみます。そこでソースコードはプロンプトに含めず、調査対象バージョンの作業ツリー(git worktree)をジョブごとに用意して、エージェントがRead/Grepで必要な箇所だけを読む形にしました。LLMに送られるのは実際に読んだ部分だけなので、リポジトリ全体の大きさに関係なくコストを抑えられます。
2. 巨大なログを必要最小限に絞り込む
実際の障害ログは数万行に達することがあり、そのまま渡すとプロンプトサイズの制約に収まりません。そこで、LLMへ渡す前に、次のルールでログを絞り込んでいます。この処理はAIを使わず、Pythonで機械的に行っているので、絞り込みそのものにはトークンのコストがかかりません。
- ログをHTTPリクエスト単位(開始〜終了マーカー)でセッションに分割する
- ERROR/WARN/Exceptionを含むセッションだけを残す
- セッション内に3秒以上のギャップ(処理が止まっている箇所)があるセッションも残す
- 残したセッションは、該当箇所の前後15行を文脈として付ける
- 同じSQLが4回以上出てきたら、2回目以降は省略して回数だけ記録する
- SQLの長い部分を削る(SELECTの列一覧を「[...]」に置き換えたり、バインド値を省略したりする)
これにより、数万行のログを数百行まで圧縮することができます。
3. 症状情報を渡す
当初はログだけを渡してエージェントに調べさせていましたが、手がかりが少ないぶん探索が発散し、最大ターン数に達して結論が出ないまま終わることもありました。調べたい症状をプロンプトに含めるようにしたところ、探索範囲が絞られ、少ないターン数で根本原因にたどり着けるようになりました。
4. セッションを継続して追加質問に答えられるようにする
最初の調査で終わりではなく、結果に対して追加で質問したくなることがあります。そのたびに最初から調査をやり直すのは、コストや時間が無駄になります。そこでセッションIDと作業ツリーを紐づけて保持しておき、同じセッションを継続できるようにしました。エージェントはそれまでに調べた内容を踏まえて追加質問に答えられます。なお、これは現時点ではスクリプトでのPoCまでで、本番のSlack連携には組み込めていません。
5. 調査コストを可視化する
投入・出力トークン数から実際の金額を算出し、調査結果のレポートに表示するようにしました。1件あたりのコストが見えることで、ログフィルタリングなどの工夫がコスト削減にどれだけ効いているかを数字で確認しながら改善を進められるようになりました。
ローカル検証で得た結果
過去の障害パターンを基に4つのテストケースを用意して検証しました。結果は全て期待通りでした。
| ケース | 内容 | 検証ポイント |
|---|---|---|
| 1 | 実績をエクスポートしようとしてNullPointerException | 例外が起きた箇所を特定したうえで、その不具合が次期バージョンで修正済みであることを突き止め、「アップデートで解消する」と案内できるか |
| 2 | ケース1と同じNullPointerExceptionが、どんなデータ条件で起きるかの深掘り | 追加質問で、さらに詳細(どんなデータ条件で起きるか)まで調査できるか |
| 3 | 中間テーブルのフルスキャンによる遅延 | SQL実行計画レベルの指摘ができるか |
| 4 | Excelエクスポートの遅延・OOM | 入力された症状とログの実測値が食い違うとき、決めつけずに保留できるか |
まとめ
Slackにログを添付して投稿するだけで、開発者でなくても障害調査の初動ができる仕組みを構築できました。用意した4つのテストケースでも、すべて期待通りの結果が出ています。
障害調査をAIで自動化する際のポイントは以下の3つです。
- ソースコードは丸ごと渡さず、エージェントに必要な箇所だけ読ませる
- 巨大なログは、AIを使わずにスクリプトで必要最小限まで絞ってから渡す
- 使っていない時間にはコストがかからない構成にする(受付と調査を分け、ジョブがなければワーカーは0台)
今回は仕組みを構築するところまでですが、将来的には製品に組み込み、ユーザー自身がトラブルシューティングとして使えるようにしたいと考えています。

