
ServiceNow AIインシデント分析をPythonのStreamlitでWebアプリ化した手順まとめ
前回、PythonでServiceNowのインシデントレコードを取得し、ChatGPTに分析させその結果をExcelにレポートでまとめるアプリを作成しました。
プロトタイプ的な機能としては完成したのですが、、振り返ると、
・専用UIもなく、PythonプログラムをPowerShellから実行
・インシデントレコードを抽出する定義はハードコード
・分析させるプロンプトもハードコードで固定
という、いわば ”エンジンむき出しのモデルカー”みたいな状況でした。
そこで、今回は前回の続きとして、
・専用UIをWeb画面で提供
・ServiceNowインシデントレコード抽出条件を画面で入力可能
・その他LLMの切り替えやプロンプト編集が可能な画面入力項目
などを作成して、実際に現場でも利用ができるようなアプリケーションの完成形まで漕ぎつけようと思います。
1.UI設計とアーキテクチャ構成
まずUI設計についてです。今回はGUIをWebにするか、クラサバのような画面のどちらかで悩みましたが、今風なのでWebアプリにしようと思います。
・WebのGUIが比較的に綺麗に作りやい”Streamlit
“で作成してゆきます。
そして、UI設計としては以下図のイメージです。

全体のアーキテクチャを図解すると以下のようなイメージです。
全体は「UI → データ取得 → AI分析 → 出力」の4層の構成とします。

今回のアプリケーション機能の物理構成は以下となる予定です。

・sn_ay_analyzer:物理フォルダ
・app.py:UI層ロジック
・servicenow.py:ServiceNowへの接続およびインシデント取得
・llm.py:LLMの切り替えと接続
・.env:APIキー、認証情報の格納
2.環境構築と準備
まずプロジェクト用フォルダを作成し、依存ライブラリをインストールします。当方の環境ではPowerShellを使っています。
mkdir sn_ai_analyzer; cd sn_ai_analyzer
python -m venv venv
.\venv\Scripts\Activate.ps1
pip install streamlit requests openai cohere google-generativeai openpyxl pandas python-dotenv
pip freeze > requirements.txt1)stremlit:WebアプリのUI全体を構築するフレームワーク
2)requests:ServiceNow へのREST APIリクエスト送信用ライブラリ
3)openai, cohere, google*:個社Model用SDK。
4)openpyxl:Excelアクセス用ライブラリ。
5)pandas:APIレスポンス(JSON)をDataFrameに変換ライブラリ。
6)python-dotenv:envファイルからAPIキーや認証情報を読み込み。
7)freeze > requirements.txt:インストール済ライブラリ情報の書き出し
インストールが完了すると以下のようなファイルやフォルダが生成されます。

3.APIキー&認証情報の保管環境ファイルの定義
続いて、ServiceNowインスタンスや各LLMへ接続するための認証情報やAPIキーを格納するファイルを定義します。
New-Item .env
```
中身をテキストエディタで開いて記述します。
```
SN_INSTANCE=https://your-instance.service-now.com
SN_USER=admin
SN_PASS=パスワード
OPENAI_API_KEY=sk-...
COHERE_API_KEY=...
GEMINI_API_KEY=...4.ServiceNowインスタンスへの接続&インシデントレコードの取得機能の実装
続いてServiceNowインスタンスへの接続からインシデントレコードを取得する機能を作成します。
プロジェクトフォルダ内に、servicenow.pyファイルを作成します。この作業はコマンドで実施せず、メモ帳などでの作成でも問題ありません。
New-Item servicenow.py続いて、pyファイルを開き、以下コードを定義します。
import requests
import pandas as pd
from requests.auth import HTTPBasicAuth
def fetch_incidents(instance, user, password, state=None, priority=None, limit=50):
query_parts = []
if state: query_parts.append(f"state={state}")
if priority: query_parts.append(f"priority={priority}")
sysparm_query = "^".join(query_parts) if query_parts else ""
url = f"{instance}/api/now/table/incident"
params = {
"sysparm_limit": limit,
"sysparm_fields": "number,short_description,description,state,priority,assigned_to",
"sysparm_query": sysparm_query,
}
try:
resp = requests.get(url, auth=HTTPBasicAuth(user, password), params=params)
resp.raise_for_status()
return pd.DataFrame(resp.json()["result"])
except requests.exceptions.HTTPError as e:
raise Exception(f"APIエラー: {e}")
except Exception as e:
raise Exception(f"接続エラー: {e}")1)以下コードステップに関して
ここでは、ServiceNowのテーブルAPIに渡すフィルタ条件を動的に組み立てています。
query_parts = []
if state: query_parts.append(f"state={state}")
if priority: query_parts.append(f"priority={priority}")
sysparm_query = "^".join(query_parts) if query_parts else ""ServiceNowでは複数条件を ^(キャレット)でつなぐルールがあるため、条件がある時だけリストに追加して最後に "^".join() で結合しています。
条件が未選択(None)の場合はリストに追加しないことで、不要な条件がクエリに混入するのを防いでいます。
ちなみにこのsysparam_queryで複数条件結合で"^"を使うルール定義は以下Table APIの公式ドキュメント(Docs)に記載されています。
2)Table API接続やエラーハンドリング
その他コードステップに関しては前回、プロトタイプを作成した際のブログ記事(こちら)と同じ内容です。
5.各社LLMへ切り替え接続を行う機能の実装
続いて、各社のLLMへ接続する機能を作成します。
プロジェクトフォルダ内に、llm.pyファイルを作成します。上記と同様にこの作業はコマンドで実施せず、メモ帳などでの作成でも問題ありません。
New-Item llm.py続いて、このllm.pyファイルを開いて、コードを定義します。
import openai
import cohere
import google.generativeai as genai
def analyze(provider, prompt, incident_text, api_key):
full_prompt = f"{prompt}\n\n---\n{incident_text}"
if provider == "OpenAI":
client = openai.OpenAI(api_key=api_key)
r = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": full_prompt}],
max_completion_tokens=300,
)
return r.choices[0].message.content
elif provider == "Cohere":
client = cohere.ClientV2(api_key=api_key)
r = client.chat(
model="command-a-03-2025",
messages=[{"role": "user", "content": full_prompt}],
)
return r.message.content[0].text
elif provider == "Gemini":
genai.configure(api_key=api_key)
model = genai.GenerativeModel("gemini-3-flash-preview")
return model.generate_content(full_prompt).text1)各LLMへの切り替え接続を分岐ステートメントで画面から入力されてきたパラメータ値でスイッチさせています。
2)接続ヘッダなどの異なる箇所は個々のPythonの接続用ライブラリで吸収されていますので、非常にシンプルなステップで簡単に組めるのが良いですね。
3)max_completion_tokens:こちらのブログ参考ください。
6.Web画面(GUI)をStreamlitで作成
さて、ここからはGUIとしてのWeb画面をStremlitで作成してゆきます。
少しここで、Streamlitフレームワークについてコメントしておきます。このフレームワークはGUIを簡単に作れるメリットが非常に高いです。
通常のWebフレームワークはHTML/CSS/JavaScriptの知識が必要ですが、StreamlitはPythonコードだけでWebアプリのUIを構築できるように設計されています。データサイエンティストやエンジニアがフロントエンドの知識なしに素早くアプリを作ることを目的としたフレームワークとなっています。
今回のアプリでいえば、st.button()・st.text_area()・st.dataframe() などを呼び出すだけでUI部品が自動生成されます。HTMLを一行も書かずに済むのがStreamlitの特徴です。
以下ファイルをプロジェクトフォルダ下に定義します。
New-Item app.py続いてこのapp.pyファイルを開いて、コードを定義します。
import streamlit as st
import pandas as pd
from io import BytesIO
from dotenv import load_dotenv
import os
import openpyxl
from servicenow import fetch_incidents
from llm import analyze
load_dotenv()
st.set_page_config(page_title="SN AI Incident Analyzer", layout="wide")
with st.sidebar:
st.header("接続設定")
instance = st.text_input("Instance URL", os.getenv("SN_INSTANCE", ""))
user = st.text_input("Username", os.getenv("SN_USER", ""))
password = st.text_input("Password", os.getenv("SN_PASS", ""), type="password")
st.header("LLM選択")
provider = st.selectbox("LLM", ["OpenAI", "Cohere", "Gemini"])
api_key = st.text_input("API Key", type="password")
st.header("抽出条件")
state = st.selectbox("State", ["", "1", "2", "3"],
format_func=lambda x: {"": "All", "1": "Open", "2": "In Progress", "3": "On Hold"}.get(x, x))
priority = st.selectbox("Priority", ["", "1", "2", "3", "4"])
limit = st.slider("取得件数", 5, 100, 20)
run = st.button("分析実行", use_container_width=True)
prompt = st.text_area("プロンプト", "以下のインシデントを分析し、要約・推奨アクション・優先度を出力してください。", height=100)
if run:
with st.spinner("ServiceNowからデータ取得中..."):
df = fetch_incidents(instance, user, password, state or None, priority or None, limit)
results = []
for _, row in df.iterrows():
text = f"番号: {row['number']}\n件名: {row['short_description']}\n詳細: {row.get('description', '')}"
with st.spinner(f"{row['number']} を分析中..."):
res = analyze(provider, prompt, text, api_key)
results.append({"番号": row["number"], "件名": row["short_description"], "AI分析結果": res})
result_df = pd.DataFrame(results)
st.dataframe(result_df, use_container_width=True)
buf = BytesIO()
wb = openpyxl.Workbook()
ws = wb.active
ws.append(list(result_df.columns))
for r in result_df.itertuples(index=False):
ws.append(list(r))
wb.save(buf)
st.download_button("Excelダウンロード", buf.getvalue(), "incidents_ai.xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")1)st.set_page_config:ページタイトルなどの設定
2)st.sidebar:サイドバー設定
3)st.text_input:テキストの入力フォーム
4)st.selectbox:選択リストボックス
5)st.dataframe:データフレームを対話型テーブルで表示
6)st_dowload_button:
今回利用したStreamlitのAPIレファレンスは↓です。
こんな便利なリファレンス一覧も用意されていますね。
全ウィジェット・レイアウト・データ表示・ユーティリティ関数がコード例付きで一覧になっており、素早く検索したい時には ↑ が便利ですね。
これだけのシンプルで可読性の高いWeb画面のコードステップ作成は初めてです。通常はHTMLやCSSなどが入り込むと可読性の低い(読みにくい)ステップが作られるのがほとんどでしたので。
最後に、このアプリケーションがバッチファイルをダブルクリックすると起動して利用できるようにしておきたいと思います。
以下のバッチファイルを"start_Analyze.bat"という名前のファイル名で作成しておきます。
@echo off
cd /d C:\work\sn_ai_analyzer
call venv\Scripts\activate
streamlit run app.py
ここまでの作業で、アプリケーションは完成しました。
7.動作確認
さて、ここから作成したアプリケーションの動作確認を行います。
以下のコマンドをPowerShell上で実行するか、
streamlit run app.py上記の作業で作成した、バッチコマンドファイル"start_Analyze.bat"をダブルクリックします。
以下のようなステータスが応答され、ブラウザが8501ポート接続で自動起動します。

ブラウザ上で画面がロードされるのを待つと、以下のような画面が起動します。

まずは左画面で
・ServiceNowインスタンスの接続先の指定
・LLMの接続先の設定
・インシデントレコードの抽出条件の設定
を行います。
設定後に、[分析実行]を押下します。

インシデントレコードの取得から分析までが実行されます。
良い感じですね。

処理が完了すると、一覧画面が表示され、一緒に[Excelダウンロード]ボタンも表示されます。

Excelをダウンロードして、開いてみます。
分析結果レポートとしてレコードデータが書き込まれています。

プロンプトの入力もデフォルト値を変更してみます。
[入力したプロンプト内容]
以下のServiceNowインシデント情報を分析し、3点を簡潔に日本語で回答してください。
1. 要約(2文以内)
2. 推奨アクション(具体的に1〜2つ)
3. 対応優先度評価(High / Medium / Low)と理由
実行後、得られたレポートを確認してみます。
3つの要約要件を含めてレポートが正しく作成されているようです。

停止させる場合には、以下のいずれかで停止できます。
・PowerShellからコマンド実行した場合には、"Ctrl+C"を押下
・バッチファイル起動であれば、以下の図のように”Y”を指定してEnterキーを押下

8.このアプリを配布して他者環境でも利用させる場合の考慮点
まず、以下が考慮すべきポイントです。
・ServiceNowインスタンス接続やLLMなどのAPIキーを共通利用は避ける
・環境依存系するライブラリファイルは新規インストールさせる
①他端末環境でのインストール作業
`venv/` フォルダは環境依存のため配布に含めず、`requirements.txt` から再構築してもらう形が正しいです。
したがって以下コマンドをPowerShellで叩くかバッチファイルを作ってバッチファイルを一回実行してもらう形が良いかと。
python -m venv venv
.\venv\Scripts\Activate.ps1
pip install -r requirements.txt②配布すべきファイル群
以下を"sn_ai_analyzer"に含む形で配布すると良いかと。
app.py
servicenow.py
llm.py
requirements.txt
start.bat
.env.example ← .envのサンプルとして用意しておくと親切
③.envファイル
以下は配布先のメンバーが実際に自分で利用する接続設定を入れて貰う形で配布するのが良いかと。APIキーの共通利用は不可とする。
SN_INSTANCE=https://your-instance.service-now.com
SN_USER=
SN_PASS=
OPENAI_API_KEY=
COHERE_API_KEY=
GEMINI_API_KEY=
如何でしたでしょうか?
今回はServiceNowのインシデント分析アプリに
・WebのGUIをStreamlitで簡単で高速に作成
・分析エンジンとしての各LLMに接続先を変えられる機能も追加
・分析プロンプトの入力も行える
・インシデントレコードの抽出条件もフィルター定義できる
機能を実装して、運用でも利用しやすいアプリに仕立て上げてみました。
Pythonによるアプリ開発がかなり効率化されている点で、また驚きました。
そして、各LLM個社のAPIも頻繁にアップデートされ機能拡張されていることから、作ったものがすぐに陳腐化するのも、アプリ保守するうえではなかなか鋭敏な対応を求められそうだなという印象です。
バイブコーディングが盛んになっているとはいえ、、アップデートに対してどのように機能更新をすすめてゆくべきなのかは、生成AIをAPI経由で使いこなしてゆくためにはデザイン含めた考慮すべきポイントではないかと。
※このAPIのアップデートとそれに関わる保守観点については、個人的には別途調査しておいた方が良いなと思いました。
また次回のブログでも面白いアプリの作成を試みようと思います!では。