【後編】Zabbix × Claude(Amazon Bedrock)× LibreChat で、ネットワーク障害の一次切り分けを AI に任せてみた ─ モデル比較とハマったところ

AIOpsAIOps,Amazon Bedrock,Claude,LibreChat,MCP,zabbix,ローカルLLM

はじめに

前編では、Zabbix が障害を検知したら AI が機器に入って調べ、2 分で切り分けの結果を報告する仕組みの構成を紹介しました。

→ 【前編】構成と仕組み

後編は、作ってみて分かったことです。

  • 同じ手順書・同じ道具を渡しても、モデルによって正解率が 100% と 0% に分かれた
  • 詰まった原因のほとんどは、モデルの能力ではなく「手順書・設定・データの渡し方」だった

7 つのモデルで比べてみた

「安いモデルで一次切り分けをして、難しければ上位のモデルに回す」という段階化ができないかと考え、条件を完全に固定して比べてみました。プロンプト・ツール(33 個)・手順書はすべて同じで、モデルだけを変えています。

お題は前編と同じ「QFX-01 のポートを人が disable にした」障害です。正解は「人による管理操作(物理故障ではない)」です。

モデル実行環境試行正解平均所要平均トークン
Claude Opus 4.8Bedrock 東京33 / 3155 秒8,002
Claude Sonnet 4.6Bedrock 東京33 / 3125 秒8,504
Claude Haiku 4.5Bedrock 東京30 / 370 秒4,999
Amazon Nova 2 LiteBedrock 東京10 / 1600 秒で打ち切り─
gpt-oss:20bローカル(Mac)10 / 1150 秒285
deepseek-r1:14bローカル(Mac)10 / 1600 秒で打ち切り247
qwen3:8bローカル(Mac)10 / 1690 秒1,111

Opus と Sonnet は 3 回とも正解し、Haiku は 3 回とも外しました。

ちなみに Opus 4.8 は単価こそ高いものの、消費トークンは Sonnet とほぼ同じでした。迷いが少ないぶん出力が短くなるようで、BFD の連鎖や無関係な障害の切り離しまで含めて、いちばん深く追えていたのも Opus です。

Haiku はなぜ外したのか

能力というより「行動」の差でした。3 回とも同じ間違い方をしています。

Haiku は「落ちて見える対向機」だけを調べ、原因のある機器まで渡らない。

対向機(QFX-03)を見ると、Admin up / Link down に加えて光のレベルが下がっているので、物理障害に見えます。しかし、対向が disable すればレーザーが止まって受光レベルが下がるのは当然で、これは disable の「結果」であって劣化の証拠ではありません。相関が強いデータほど、因果の向きを読み違えると、そのまま誤診になります。

もう 1 つ、存在しないツール名を呼んでいた回もありました。要求したコマンド自体は完璧だったのですが、Ansible のツール名(junipernetworks_junos_junos_command_mcp_ansible と 42 文字もある)を junos_cli_mcp_ansible と勝手に略して呼び、2 回とも失敗しています。そのうえで「実機のログは未確認」と自分で書きながら、「物理障害で確定度が高い」と断定していました。

ツール名が長すぎるのはこちらの設計の問題でもあるので、モデルだけのせいとは言い切れません。

「安いモデルを一次に置く」構想は成り立たなかった

いちばんの学びはこれです。

一次のモデルが返してくるのは「わかりません」ではなく、根拠つきの、自信を持った誤答でした。これでは「怪しかったら上位のモデルへ回す」という判定そのものが働きません。

コストを下げる効き目が大きかったのは、モデルを安くすることではなく、後で書く「ツール定義を減らす」ほうでした。

ローカル LLM は、この構成では動かなかった

手元の Mac(M5・24GB)で動かしたローカル LLM は、3 つとも正解にたどり着けませんでした。

ただし、これは「ローカル LLM は使えない」ではなく「この構成では使えない」です。33 個のツール定義(約 24,000 トークン)を毎回読んだうえで、8〜10 回の呼び出しを自分で組み立てる、という負荷の高いタスクだったためです。ツールを 3〜5 個に絞った単機能のタスクなら、成り立つ余地はあると見ています。

ハマったところ

ここがこの記事でいちばん実用的な部分だと思います。

1. 手順書に書いていないことは、本当にやらない

RAG(文書検索)と Ansible(機器の操作)の MCP をつないだ直後、どちらも呼ばれた回数が 0 回でした。手順書に「いつ、何のために使うか」を書いていなかったからです。書き足したら、Ansible は 6 回呼ばれるようになりました。

道具を持たせただけでは使われない。 「何を、どういうときに使うか」を手順に書いて、初めて動く。

2. 「必須」と書いても、前置きが「省略可」だったら省略される

構成図の表示を手順 6 に置いて「必須」と書いたのに、図が出てきませんでした。原因は手順全体の前置きです。

## 手順(上から順に。判明した時点で残りは省略可)

AI は「テスト用のトリガーなので実障害ではない」と分かった時点で、手順 6 を省略していました。指示どおりに正しく振る舞っているわけです。前置きを直して解決しました。

指示は全体で 1 つの文書として読まれる。 一か所に「必須」と書いても、ほかの箇所と矛盾していれば、緩いほうが採用されることがある。

3. 人がやった操作を「物理障害」と誤診した

最初に disable の障害を起こしたときは、AI は物理障害と断定しました。報告の末尾に付けた実行サマリーを見ると、Ansible を 1 回も呼んでいない。config もログも見ずに結論を出していたことが、数字で分かりました。

そこで手順書に「機器の config とログを見る」を必須として加え、機種別の確認コマンドを表で示し、次の判定表を入れました。

Admin StatusLink Status判定
updown物理障害(ケーブル・SFP・対向機器・電源)
downdown管理操作。障害ではない

さらに、「NetBox で同じケーブルの両端だと分かっても、それだけで物理障害と決めつけない(片側を disable しても、両端がリンクダウンとして見える)」と明記しました。この一文が、のちに Haiku の誤診を説明することになります(Haiku はまさにこの一文に反する推論をしていました)。

4. 「何を調べなかったか」が見えないと、改善できない

報告の末尾に実行サマリーを付けるようにしました。

| 所要時間       | 2 分 00 秒 |
| ツール呼び出し | 9 回       |
| 消費トークン   | 7,769      |

### 叩いた基盤
| Zabbix MCP  | 3 |
| Ansible MCP | 2 |   ← ここが 0 回なら、実機を見ていない

これが誤診の発見につながりました。「Ansible 0 回」という数字がなければ、なぜ間違えたのかは分からないままでした。

5. 呼び出した回数を数えるだけでは足りない

前述の Haiku が存在しないツール名を呼んで失敗したとき、サマリーには「Ansible MCP 2 回」と出ていて、必須の手順をやったように読めてしまいました。失敗を区別して数えるように直しています。

| ツール呼び出し | 3 回(うち失敗 2 回) |
| junos_cli_mcp_ansible | 2 ⚠ 失敗 2 |
> ⚠ 失敗したツール呼び出しが 2 回ある。取得できていない情報にもとづく結論が含まれていないか確認すること。

6. ツール定義は、何もしなくても毎回トークンを食う

ツールの定義は、毎回のリクエストに必ず載ります。 1 つあたり約 700 トークンなので、最初に登録していた 95 個では、まだ何も調べていない時点で約 66,000 トークンを使っていました。実際の調査の応答は 6,000〜18,000 トークンなので、固定費が本業の約 9 倍です。

削る基準は 2 つだけにしました。

  1. 書き込み系はすべて外す。 読み取り専用で調べるエージェントに、create / update / delete の権限があること自体が設計と矛盾していた
  2. 手順書が指していないツールは外す。 書いていないツールはどうせ呼ばれない
MCP削減前削減後
Zabbix6215
Ansible168
RAG62
LabUI53
NetBox54
内蔵(Web 検索)11
合計9533

これで1 回あたり約 43,000 トークン減りました。

ただし、やりすぎて失敗もしています。自由に図を描けるツール(render_html)を「構成図のツールと重複している」と考えて外したところ、「構成図を横向きにして」という指示に応えられなくなりました。代わりの手段まで取り上げていたのです。

削るときの基準は「重複しているか」ではなく「何ができなくなるか」。

7. 1 回目で動くことと、会話が続くことは別の問題

いちばん重要な発見でした。

自動の報告は問題なく出ていたのに、その会話で追加の質問をすると、返答が空になる(考えている形跡だけで本文がゼロ、エラーも出ない)という現象が起きました。

原因はツールの出力が大きすぎたことです。

1 回のコマンド実行結果 : 391 KB
会話全体               : 693 KB(≒ 17〜20 万トークン)
                         → 追加質問の時点で、文脈がほぼ埋まっている

中を見ると、Ansible の結果が stdout と stdout_lines に同じ内容を二重に持っていました(Ansible の仕様です)。*_lines を落とし、1 つの文字列を 32KB で打ち切るようにして、391KB → 84KB(78% 減)になりました。

MCP サーバの戻り値は「API のレスポンス」ではなく「プロンプトの一部」。 人間向けのコマンド出力をそのまま返すと、1 回で文脈を使い切る。

前編に載せた LibreChat の画面でも、右下の文脈の使用量は 1 回の調査の途中で 96% まで埋まっていました。

それまでの検証は、すべて「障害を起こす → 報告が出る」で終わっていて、2 往復目を一度も試していなかったのが盲点でした。

コストの考え方

LLM を使うか
60 秒ごとの Zabbix のポーリング使わない(コストゼロ)
障害の一次切り分け使う(約 8,000 トークン・2 分)
復旧の通知使わない
一瞬で戻った障害(瞬断)の通知使わない
繰り返す瞬断(フラッピング)の調査使う

歯止めとして、AI を起動する回数に1 日 10 回の上限を付け、設定 1 行で「検知だけして AI は起動しない」モードに切り替えられるようにしています。

限界

一次切り分けの「下書き」としては実用になると感じていますが、人の判断を置き換えるものではありません。

限界内容
判断は人がするAI は復旧の操作を提案するだけで、実行はしない
自信を持って間違える「わかりません」ではなく、根拠つきで誤ることがある。必ず人が確認する前提
監視していないものは見えないZabbix にトリガーが無ければ、検知どころか記録も残らない
BFD の 1 秒未満の断は捕まえられないSNMP のポーリングが 1 分間隔のため。拾うにはトラップの受信基盤が要る
知識が貯まらない会話で分かったことはどこにも残らない。残したい知見は、人が手順書か文書に書く

最後の点は意外と大事でした。今回の知見が残っているのは、手順書に書いたからであって、AI が学習したからではありません。会話の中だけに置いていたら消えていました。

まとめ

  • モデルの選択は「賢さ」より「行動」で決まる。 原因のある機器まで渡って調べられるか。安いモデルは、自信のある誤答を返す
  • 詰まる原因の多くは、手順書・ツールの数・ツールの出力の大きさ。モデルを替える前に、渡し方を見直す価値がある
  • 手順書は全体で 1 つの文書として読まれる。 一文の追加や前置きの書き方で、行動が大きく変わる
  • 「何を調べたか/調べられなかったか」を数字で出すと、AI の誤りに気づける

今後は、装置の種類や事象ごとに手順書を分けることや、トポロジ情報を使って 20 件の波及障害を「根本原因 1 つ+波及」に畳んでから AI に渡すこと、SNMP トラップで秒未満の断を拾うことを試してみたいと思っています。