0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tsurugi 上に Ops Incident Ledger(OIL) という運用インシデント管理 Web アプリケーションを構築し、oil-oss として公開しました。インシデントといってもセキュリティ・インシデントに限定した対応ツールではなく、広く一般の運用障害・作業ミス・顧客影響などを記録し、過去事例や手順書へつなげることで、障害対応までの時間と手間を軽減するための AI 支援ツールです。

運用監視ネットワークはインターネットに直接接続できないことがほとんどであり、障害内容や顧客名を外部 API に送れない現場を主な想定としています。LLM 推論・埋め込み・RAG 索引(FAISS)まで Ollama 上のローカル LLM で完結するオンプレ構成を標準としています。もちろん API キーを指定することでクラウド LLM(OpenAI)への切り替えも可能です。本稿では全体構成と、AI チャットにおける RDB 検索と RAG(ベクトル検索)の二系統設計を中心に紹介します。

Ops Incident Ledger の位置づけ

IT サービス管理(ITSMS)では、ヘルプデスクを起点にインシデント管理・問題管理・変更管理・リリース管理などのプロセスが連なります。OIL はそのうち、ヘルプデスク周辺のインシデント記録と復旧対応、および対応手順書(KEDB)によるナレッジ再利用を担います。根本原因の恒久対策を扱う問題管理以降のプロセスは対象外です。

プロセス OIL での扱い
インシデント管理(記録・初動・復旧) 台帳・AI トリアージ・対応履歴・チャット検索
対応手順書(KEDB) 手順の蓄積・推奨・下書き生成
問題管理 対象外(根本原因分析・恒久対策の管理は行わない)
変更管理・リリース管理 対象外

背景

運用インシデント管理の現場では、次のような課題がよく起きます。

課題 具体例
情報が散在する チケット、チャット、個人メモに履歴が分かれる
過去事例の検索が遅い 「似た障害、前にどう対応した?」に時間がかかる
初動の品質にばらつきがある 重要度・分類の付け忘れ、記載漏れ
ナレッジが残らない 解決後に手順書化されず、同種障害で再調査になる
件数把握が手作業になる 「先週の顧客 NW 障害は何件?」を都度 SQL や集計で調べる

Ops Incident Ledger は、これらに対して 記録 → 再利用 → 改善 のループを 1 画面で回すプロダクトです。

価値 機能
一元記録 インシデント・調査・対応履歴を 1 画面で管理
ナレッジ循環 対応手順書(KEDB)の蓄積、類似事例・推奨手順の提示
AI 支援 自然文検索、初動トリアージ、手順書下書き

AI は最終判断の代替ではなく、検索・下書き・入力補助に特化しています。データの正は RDB(Tsurugi)に置き、ベクトル索引は検索と推奨を強化する層として併用します。

閉域網の運用監視向けに

運用系の台帳は、インシデント内容・顧客名・内部ホスト名を外部 SaaS に送信できないことが前提に近いです。NOC や監視セグメントがインターネット非接続であるケースも珍しくありません。OIL は次をすべてオンプレで回せるよう設計しています。

オンプレの実装
台帳・検索 Tsurugi(RDB)
意味検索 FAISS(同梱索引は nomic-embed-text / 768 次元)
埋め込み Ollama nomic-embed-text
チャット・トリアージ・下書き Ollama qwen3.6:27b クラス(26B パラメータ級)

開発・評価では RTX 5090 クラス(VRAM 32GB)のワークステーション上で Ollama を用い、次の用途で実用に耐える応答を確認しています。

用途 オンプレ LLM での体感
チャット(RDB / RAG ツール呼び出し) 1 ターン十数秒〜数十秒
トリアージ・提案カード 重要度・種類の提案が成立
手順書下書き 解決済みインシデントから Markdown 下書きを生成可能

config.yamlai.provider / ai.llm_provideropenai に切り替えれば、インターネット経由のクラウド LLM でより短いレイテンシを狙えます。応答速度やツール選択の安定性はモデル・量子化・GPU に依存するため、本稿の体感は特定構成での参考値です。

システム概要

スタックとデータ規模

項目 内容
バックエンド FastAPI(Python 3.12)
フロントエンド Vue.js + Quasar(SPA)
RDB Tsurugi
ベクトル検索 FAISS
AI エージェント LangGraph(既定: Ollama。OpenAI 切替可)
オンプレ LLM Ollama + qwen3.6:27b、埋め込み nomic-embed-text
RAG 索引(同梱) FAISS / 2,896 文書 / nomic-embed-text(768 次元)
配布 Docker Compose

同梱のサンプルデータは、架空の SaaS 事業者「株式会社ストッククラウド」が運用する Mercury / Venus サービスの障害対応記録です。

データ 件数
インシデント 304
対応履歴 449
対応手順書 51
RAG 文書(障害報告・調査・対応) 2,896

モジュール構成

利用者が触るのはブラウザのみです。バックエンドが Tsurugi・FAISS・オンプレ LLM(Ollama)を束ねます。クラウド LLM を使う場合は設定変更のみで、構成図の LLM ノードが外部 API に置き換わります。

コンポーネント 効果
Tsurugi 一覧・詳細・保存の即時反映
FAISS 類似インシデント・手順書・自然文検索(オンプレ埋め込みで構築)
Ollama チャット応答、トリアージ提案、手順書下書き、ベクトル化

画面と業務フロー

5 領域の一体型ワークスペース

画面は次の 5 領域で構成されています。

領域 役割
ヘッダ タイトル、ログインユーザ、基準日、表示切替、ログアウト
左サイドバー クイックフィルタ(今月・先月・未解決)と手順書使用回数 Top5
中央 インシデント / 手順書の一覧・詳細・編集
AI チャット(幅リサイズ可)
下部 LLM 処理ログパネル(任意表示)

Ops Incident Ledger の画面構成

インシデント対応中に一覧・詳細・チャット・ログを行き来せず同時に見られる設計です。詳細を開くと、そのインシデントが AI チャットのコンテキストとして渡されます。

検知からナレッジ化まで

フェーズ 人手 AI / 自動
1. 検知・登録 新規インシデント入力 保存後トリアージ自動開始
2. トリアージ 提案の受入・却下 重要度・分類の提案、追加質問
3. 対応 手順適用、対応履歴記録 推奨手順・類似事例、チャット検索
4. ナレッジ化 手順書確認・保存 対応履歴から下書き生成

RDB 検索と RAG の二系統

AI チャットの中心は LangGraph エージェントです。ユーザーの自然文に対し、事前定義の RDB ツールと FAISS ベクトル検索を使い分けます。ローカル LLM でも安全・確実に実行するために、任意の Text-to-SQL は採用していません。

質問に応じて経路を分ける理由

質問の種類 経路 理由
条件付き一覧・件数集計 LangGraph ツール → Tsurugi(事前定義 SQL / 集計 API) 再現性と安全性を確保。LLM が SQL を自由生成しない
自然文・類似事例・手順探索 FAISS ベクトル検索 タイトル・説明・対応文の意味的類似を拾う
週次件数など定型サマリ 事前生成の集計サマリ文書(RAG) 毎回 SQL を組まず、自然文クエリでヒットさせる

エージェントが利用する主なツールは次のとおりです。

ツール 役割
search_incidents 状態・重要度・日付・キーワードで RDB から明細一覧
aggregate_incidents GROUP BY による件数集計(発生個所別・状態別など)
search_documents_rag FAISS で障害報告・調査・対応・集計サマリ・手順書を検索
get_incident_detail 特定インシデントの詳細取得
get_context_incident 画面表示中インシデントの詳細(コンテキスト付き質問用)
get_current_datetime アプリの現在日時・タイムゾーン・基準日の取得
get_system_context 企業・サービス・顧客・インシデント種類など運用背景マスタの取得

システムプロンプトでツールの使い分けを明示しています。例えば status には DB 値(OPEN / IN_PROGRESS / RESOLVED)を指定するよう指示し、画面表示の日本語ラベル(未着手・対応中・解決済み)との対応表も LLM に渡します。

質問例

種別 質問例 主に使われるツール
RDB のみで足りる 「未完了のうち、顧客ネットワークに関わるインシデントを教えて」 search_incidentskeyword でタイトル・説明を検索)
RDB 集計 「発生個所別の件数を教えて」 aggregate_incidents
RAG 「棚卸の突合エラーで過去にどう対応した?」 search_documents_rag → 必要なら get_incident_detail
RDB + RAG 併用 「未完了のインシデントを一覧して、顧客ネットワーク障害の過去の対応内容も参考に教えて」 search_incidentssearch_documents_rag

ツールの選択は LLM が行います。「未完了 × 顧客ネットワーク」のようにタイトル・説明のキーワード検索だけで足りる質問では search_incidents のみが呼ばれ、ai_rag ログは出ません。対応内容・調査記録・手順書など RDB の一覧では取れない情報を求めると、RAG ツールが追加で呼ばれやすくなります。

RDB と RAG の併用実行例

Docker Compose 上のサンプルデータで、オンプレ LLM(Ollama qwen3.6:27b)に次の質問を投げたときの実測例です。

質問

未完了のインシデントを一覧して、顧客ネットワーク障害の過去の対応内容も参考に教えて

ツール実行の流れ

順序 イベント 内容
1 chat_request 上記メッセージを受信(llm_provider: ollama, model: qwen3.6:27b
2 mcp_toolsearch_incidents status: ["OPEN", "IN_PROGRESS"] で未完了一覧(total: 22、先頭 20 件を返却)
3 ai_sql status IN ('OPEN','IN_PROGRESS') 等の事前定義 SQL
4 ai_rag クエリ "顧客ネットワーク障害 対応内容 事例" で FAISS 検索(10 件、約 3.07 秒)
5 mcp_toolsearch_documents_rag 同一クエリのツール返却(対応履歴・調査記録が中心)
6 chat_timing 全体約 34.9 秒(うち、ツール約 13.0 秒)

RAG でヒットした文書の例(doc_ids より):

doc_id 種別 回答での参照例
DOC-INV-00576 調査記録 監視ダッシュボード不表示の初期調査
DOC-RSP-00746 対応履歴 拠点 API 失敗時の情報収集・連絡体制
DOC-RSP-00831 対応履歴 DNS 設定点検・キャッシュクリア
DOC-RSP-00960 対応履歴 類似のネットワーク系障害パターン

LLM の回答

現在未完了(OPEN / IN_PROGRESS)のインシデントは計 22 件。そのうち顧客ネットワーク障害に関連する進行中事象と、RAG から得た過去の対応パターンを次のように整理しました。

1. 未完了インシデント一覧

【顧客ネットワーク障害】関連(4 件)

incident_id タイトル 状態 重要度 発生日
INC-2026-00327 【障害報告】【顧客ネットワーク障害】拠点限定API失敗 対応中 LOW 2026-06-18
INC-2026-00148 【障害報告】【顧客ネットワーク障害】拠点限定API失敗 対応中 LOW 2026-03-27
INC-2024-00026 【障害報告】【顧客ネットワーク障害】代理サーバー502 対応中 LOW 2024-08-19
INC-2022-00303 【障害報告】【顧客ネットワーク障害】TLS握手切断 対応中 LOW 2022-06-05

【他カテゴリ】代表的な未完了(抜粋): INC-2026-00039 合成監視失敗 (HIGH・未着手)、INC-2026-00283 ブルートフォース誤検知 (CRITICAL)、INC-2026-00504 WALアーカイブ滞留 (HIGH) など。

2. 過去の「顧客ネットワーク障害」関連の対応内容事例(RAG 由来)

  • パターン A(拠点 API 失敗) — 障害発生 30 分以内の情報収集と影響拠点への連絡、社内エラーログの確認・原因特定会議の設定(DOC-RSP-00746
  • パターン B(DNS・接続切断) — DNS 設定の点検・更新、キャッシュクリア、影響店舗への復旧状況の逐次報告(DOC-RSP-00831
  • パターン C(再発防止) — テスト環境での連携テスト、定例リリース前検証の強化

一覧の件数・ID は Tsurugi の search_incidents が担保し、対応パターンの文脈は FAISS 上の DOC-RSP-* / DOC-INV-* から補われています。1 ターン約 35 秒で外部 API に本文を送らずに統合回答が得られる例です。

実際のサーバログ

2026-07-03T22:16:10.599+09:00chat_request{"seq":3,"event":"chat_request","ts":"2026-07-03T22:16:10.599+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","user_message":"未完了のインシデントを一覧して、顧客ネットワーク障害の過去の対応内容も参考に教えて","turn":2,"history_messages":3,"context_incident_id":null,"llm_provider":"ollama","model":"qwen3.6:27b"}
2026-07-03T22:16:20.379+09:00ai_sql{"seq":4,"event":"ai_sql","ts":"2026-07-03T22:16:20.379+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","sql":"SELECT COUNT(*) FROM oil_incidents i WHERE i.company_id = ? AND i.status IN (?,?)","params":["COMP-001","OPEN","IN_PROGRESS"],"duration_ms":9.02,"row_count":1}
2026-07-03T22:16:20.388+09:00ai_sql{"seq":5,"event":"ai_sql","ts":"2026-07-03T22:16:20.388+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","sql":"SELECT i.incident_id, i.occurred_at, i.title, i.status, i.severity FROM oil_incidents i WHERE i.company_id = ? AND i.status IN (?,?) ORDER BY i.occurred_at DESC LIMIT 20","params":["COMP-001","OPEN","IN_PROGRESS"],"duration_ms":8.49,"row_count":20}
2026-07-03T22:16:20.411+09:00ai_sql{"seq":6,"event":"ai_sql","ts":"2026-07-03T22:16:20.411+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","sql":"SELECT incident_id, COUNT(*) FROM oil_incident_responses GROUP BY incident_id","params":[],"duration_ms":22.27,"row_count":818}
2026-07-03T22:16:20.412+09:00mcp_tooltool=search_incidents params={"status":["OPEN","IN_PROGRESS"]} response={"total": 22, "items": [{"incident_id": "INC-2026-00039", "occurred_at": "2026-06-24 12:48:38+00:00"… (4147文字)
2026-07-03T22:16:24.865+09:00ai_rag{"seq":8,"event":"ai_rag","ts":"2026-07-03T22:16:24.865+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","query":"顧客ネットワーク障害 対応内容 事例","top_k":10,"duration_ms":3067.28,"result_count":10,"doc_ids":["DOC-INV-00576","DOC-RSP-00960","DOC-RSP-00256","DOC-RSP-00628","DOC-RSP-00607","DOC-RSP-00831","DOC-RSP-00746","DOC-RSP-00705","DOC-RSP-00123","DOC-RSP-00656"],"scores":[0.728,0.709,0.702,0.6962,0.6932,0.6921,0.6907,0.6898,0.6895,0.6875]}
2026-07-03T22:16:24.866+09:00mcp_tooltool=search_documents_rag params={"query":"顧客ネットワーク障害 対応内容 事例"} response=[{"doc_id": "DOC-INV-00576", "score": 0.7280425429344177, "text": "初期調査の結果、運用コンソール内の監視ダッシュボードが表示されない… (2929文字)
2026-07-03T22:16:46.777+09:00chat_timing{"seq":10,"event":"chat_timing","ts":"2026-07-03T22:16:46.777+09:00","service":"oil","env":"docker","version":"0.1.0","request_id":"82caa2da-68ae-4db8-9507-ebdc6958866e","duration_ms":34884.14,"llm_ms":34882.84,"tool_ms":12972.97,"turn":2,"response_chars":1366,"llm_provider":"ollama","model":"qwen3.6:27b","status":"ok"}

対比:RDB のみで終わる質問

同じ「未完了 × 顧客ネットワーク」でも、

未完了のうち、顧客ネットワークに関わるインシデントを教えて

のように一覧だけを求めると、search_incidentskeyword: "顧客ネットワーク" が渡され 4 件に絞り込まれ、search_documents_rag は呼ばれません(ai_rag ログなし)。

画面表示との連携

インシデント詳細を開くと、チャットを使わなくても 推奨手順書と類似インシデントが FAISS 類似検索で自動提示されます。一覧画面ではキーワード検索に加え、意味検索(RAG)オプションでベクトル検索結果を一覧表示できます。

データの正と RAG の鮮度

トリガー 動作
インシデント保存 タイトル+説明の差分 upsert、集計サマリ再生成
対応保存 関連文書・集計サマリ更新
手順書保存 手順書ベクトルの upsert(無効時は削除)

いずれも HTTP 応答は RDB 確定後に即返却し、RAG 更新は BackgroundTasks で非同期実行します。公開リポジトリ同梱の data/faiss/ は Ollama nomic-embed-text でビルド済みであり、Docker 起動後すぐオンプレ RAG 検索が利用できます(manifest.jsonembedding_model を参照)。

AI と DB 更新の境界

エージェントは原則として RDB を直接更新しません。トリアージで重要度や種類を提案しても、ユーザーがチャット内の提案カードで「受け入れる」ボタンを押したときに初めて REST API 経由で保存されます。保存操作の権限はロール(VIEWER / OPERATOR / ADMIN)で制御します。

Dockerで試す

本記事の手順は oil-oss リポジトリの Docker Compose を想定しています。

項目 内容
実行環境 Docker / Docker Compose v2
GPU ワークステーション(推奨) RTX 5090 クラス、Ollama で qwen3.6:27b
AI(標準) ホスト上の Ollama(LLM + 埋め込み)
AI(オプション) OPENAI_API_KEY を設定し config.yamlprovider / llm_provideropenai に変更 → より高速な応答
データベース Tsurugi(compose に同梱)
RAG 索引 同梱 data/faiss/nomic-embed-text、2,896 文書)
サンプルデータ 架空SaaS「Mercury」「Venus」障害対応(2020年4月~2026年6月)

1. Ollama の準備

必要なモデルをPULLします。

ollama pull qwen3.6:27b
ollama pull nomic-embed-text

2. oil コンテナの起動

git clone https://github.com/septigram/oil-oss.git
cd oil-oss
cp .env.example .env
docker compose up --build

既定の docker/config/config.yaml は Ollama オンプレ向けです。

ai:
  provider: ollama
  llm_provider: ollama
  ollama_base_url: http://host.docker.internal:11434
  ollama_llm_model: qwen3.6:27b
  ollama_embedding_model: nomic-embed-text

oil コンテナからホスト上の Ollama に接続します(Windows / macOS の Docker Desktop では host.docker.internal)。Linux では extra_hosts 等でホストゲートウェイを設定してください。バックエンドをホスト上で直接起動する場合は http://localhost:11434 で構いません(BUILD.md 参照)。

3. ブラウザで開く

ブラウザで http://localhost:8000/oil/ にアクセスしてください。

項目
ログイン ID admin
パスワード .envOIL_BOOTSTRAP_PASSWORD(未設定時は admin

クラウド LLM を使う場合

.envOPENAI_API_KEY を設定し、ai.provider / ai.llm_provideropenai に変更します。

FAISS 索引を OpenAI 埋め込みで作り直す場合は python tools/build_faiss_index.py を実行してください(次元が変わるため必須)。

4. チャットの動作確認

  1. 左サイドバー「未解決」→ 一覧を確認(RDB 系の画面操作)
  2. 「発生個所別の件数を教えて」→ aggregate_incidents の応答を確認
  3. 「棚卸の突合エラーで過去にどう対応した?」→ RAG のみの応答を確認
  4. 「未完了のインシデントを一覧して、顧客ネットワーク障害の過去の対応内容も参考に教えて」→ search_incidentssearch_documents_rag の併用
  5. 下部ログパネルで mcp_tool(ツール名)と ai_rag の有無を確認

成果物

参考リンク

リンク 説明
Tsurugi トランザクション処理向け OSS データベース
Ollama オンプレ LLM・埋め込み
user-manual.md OILの利用者向け操作ガイド
BUILD.md OILのビルドと設定
SECURITY.md OILの脆弱性報告

まとめ

Ops Incident Ledger プロダクトは、次の 4 点を実現します。

  1. 閉域の運用監視網でも、台帳・RAG・AI チャットをオンプレで回せること
  2. データの正は Tsurugi、FAISS はオンプレ埋め込みで構築した検索・推奨層であること
  3. RDB ツールと RAG の役割分担が、エージェント型運用ツールの実装パターンとして参考になること
  4. クラウド LLM はより高速な応答のためのオプションであり、標準は Ollama 上の qwen3.6:27b クラスで実用可能であること

応答時間ログや Prometheus メトリクスなど、本番運用を想定した計測・可観測性も備えています。外部 Webhook によるインシデント受信や Slack Bot 連携、一覧画面の意味検索オプションなどは、公開リポジトリの release-notes に記載されています。

本稿の構成や数値は特定環境・サンプルデータに基づく参考情報です。ご利用にはご注意ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?