SaaS 企業のサポートがチケットの記録・リリースの予定・契約数から Python で翌週の分類ごとの問い合わせの件数を予測し、初回の返信の目標を守る担当の割り振りの案を出す
SaaS 企業のサポートのチケットの記録、リリースの予定、契約の数から、Python で翌週の日ごと・分類ごとの問い合わせの件数を幅付きで予測します。担当の予定と並べて未返信の残りを見込み、初回の返信の目標を外しそうな分類と、割り振りの変更の案を出します。
- 連携・自動化
- Python
- 対象業界
- EC/IT・SaaS
- 対象部門
- カスタマーサポート
- 対象業務
- 集計・分析
- 主な課題
- 人手が足りない/判断に時間がかかる/期限・対応漏れが起きる
- AIで行う処理
- 予測
- 主な効果
- 判断支援/対応スピード向上/属人化解消
- 導入難易度
- ★★★★☆
- 実装レベル
- 本格構成
- 費用感
- 個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- 金曜に、リーダーが Zendesk で先週と前月の同じ週の分類ごとの件数を書き出す
- 開発のリリースの予定表で、翌週のリリースの日と中身(画面が変わるか、どの機能か)を確かめる
- 請求の締めの日と、新しい契約の数の伸びを確かめる
- 分類ごとに「来週は何件くらい来るか」を見立てる
- 担当の予定の表の出勤と見比べて、分類ごとの担当の数を決める
- 足りない分類は、ほかの分類の担当を寄せるか、開発に技術の応援を頼む
- 週の途中で未返信が積み上がったら、リーダーがその場で担当を寄せ直す
- 人開発が、リリースの予定表に翌週のリリースの日、規模、画面が変わるか、対象の機能を入れる(いまの予定表に列を足す)
- 自動毎日の深夜に、Python が Zendesk から前日までに変わったチケットを取り込み、分類ごとの件数を更新する
- 自動木曜の朝に、契約の数、リリースの予定、請求の締めの日を読み込み、翌週の日ごと・分類ごとの件数を、中央と上振れで予測する
- 自動分類ごとの処理の時間と担当の予定から、日ごとの未返信の残りを足し引きし、初回の返信の目標を外しそうな日と分類に印を付ける
- 自動担当を寄せる案と、技術の応援を頼む時間の案を出す
- 人サポートの運用の責任者とリーダーが印の付いた分類を中心に見て、割り振りと応援の依頼を決める
- 【自動/人】 月曜の朝に、週末の件数を足して予測し直し、リーダーが直すかを決める
各工程の詳しい説明を読む
- 金曜に、リーダーが Zendesk で先週と前月の同じ週の分類ごとの件数を書き出す
- 開発のリリースの予定表で、翌週のリリースの日と中身(画面が変わるか、どの機能か)を確かめる
- 請求の締めの日と、新しい契約の数の伸びを確かめる
- 分類ごとに「来週は何件くらい来るか」を見立てる
- 担当の予定の表の出勤と見比べて、分類ごとの担当の数を決める
- 足りない分類は、ほかの分類の担当を寄せるか、開発に技術の応援を頼む
- 週の途中で未返信が積み上がったら、リーダーがその場で担当を寄せ直す
(a)リリースの週に目標を外す。 4番の見立てで、リリースの効き方を少なく見ると、木曜と金曜に使い方の未返信が積み上がり、初回の返信の目標を外します。 目標を外したチケットの利用者は、返事を待つあいだに同じ問い合わせをもう一度送ってきます。件数がさらに増え、残りがまた積み上がります。
(b)未返信の残りに気づくのが週の半ば。 7番で寄せ直すのは、残りが目に見えて増えてからです。ほかの分類から担当を寄せると、今度はそちらの残りが増えます。 技術の応援は、開発の予定に入っていないと当日には来ません。
(c)見立てがリーダーの頭の中にある。 画面の変わるリリースはどれだけ効くか、請求の締めの何日後に山が来るかは、リーダーが経験で知っています。リーダーが休みの週は、前の週と同じ割り振りのまま進み、リリースの週に外れます。
(d)契約の伸びを見ていない。 前月の同じ週の件数は、前月の契約の数で起きた件数です。新しい契約が伸びた月は、使い方の問い合わせが前月の数では足りません。 契約の数とチケットの数は、別の画面にあります。
- 【人】 開発が、リリースの予定表に翌週のリリースの日、規模、画面が変わるか、対象の機能を入れる(いまの予定表に列を足す)
- 【自動】 毎日の深夜に、Python が Zendesk から前日までに変わったチケットを取り込み、分類ごとの件数を更新する
- 【自動】 木曜の朝に、契約の数、リリースの予定、請求の締めの日を読み込み、翌週の日ごと・分類ごとの件数を、中央と上振れで予測する
- 【自動】 分類ごとの処理の時間と担当の予定から、日ごとの未返信の残りを足し引きし、初回の返信の目標を外しそうな日と分類に印を付ける
- 【自動】 担当を寄せる案と、技術の応援を頼む時間の案を出す
- 【人】 サポートの運用の責任者とリーダーが印の付いた分類を中心に見て、割り振りと応援の依頼を決める
- 【自動/人】 月曜の朝に、週末の件数を足して予測し直し、リーダーが直すかを決める
6番目で決めるのは人です。 モデルが出すのは件数と残りの案で、担当ごとの得意な分類、新人の育成の予定、開発の繁忙を知っている責任者とリーダーが決めます。
技術の応援は、木曜のうちに開発に頼みます。 第3章の(b)で応援が当日に来なかったのは、開発の予定に入っていなかったからです。上振れで残りが積み上がる見込みの日は、木曜の時点で開発のリーダーに時間を空けてもらいます。
02今回想定するシステム構成
Zendesk のチケット(Incremental Exports API で毎日取り込む) + 契約の数(契約の管理の仕組みの書き出し) + リリースの予定表(日・規模・画面の変更・対象の機能) + 請求の締めの日 + 祝日(内閣府の CSV) + 担当の予定の表(日ごとの出勤と分類) │ ▼【トリガー】毎日深夜(取り込み)、木曜の朝と月曜の朝(予測) Python(pandas) ├──▶ チケットの重複を除き、作成日ごと・分類ごとの件数にそろえる ▼ scikit-learn(HistGradientBoostingRegressor) │ 翌週の日ごと・分類ごとの「契約1,000社あたりの件数」:中央(ポアソン)・上振れ(分位点) ▼ Python ── 件数に戻し、処理の時間と担当の予定から未返信の残りを足し引き ▼ Python ── 目標を外しそうな日と分類、担当を寄せる案、応援の時間の案 ▼ 【人】責任者とリーダーが割り振りと応援の依頼を決める
| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 実行環境 | Python(pandas・scikit-learn) | R |
| 処理エンジン | scikit-learn の HistGradientBoostingRegressor(ポアソン損失と分位点損失) | LightGBM、statsmodels |
| 集計 | Python(件数への戻し、未返信の残りの足し引き、担当の数への換算) | スプレッドシートの計算式 |
| 連携 | Zendesk(Incremental Exports API でチケットを取り込む) | Freshdesk、HubSpot |
| 保管 | Google スプレッドシート(リリースの予定、処理の時間の表、決めた割り振りの記録) | - |
新しく足すのは、Python の処理と取り込みのスクリプト、処理の時間の表です。 Zendesk と担当の予定の表はこれまでどおりで、この構成はチケットの割り当ても予定の表も書き換えません。 出すのは分類ごとの案です。
チケットの取り込みに Zendesk の Incremental Exports API を使うのは、前回から変わったチケットだけを取れるからです。 公式のページでは、カーソルを使う書き出しが「性能と応答の大きさが安定する」として強く勧められ、1回に最大1,000件、1分あたり10回まで呼べるとされています。
予測のエンジンに HistGradientBoostingRegressor を選んだのは、率を予測するのに重みを使えるからです。 件数を契約の数で割った率を目的にし、fit の sample_weight に契約の数を渡して loss="poisson" で学習すると、契約の多い日の件数ほど重く見る、率のポアソン回帰と同じ形になります。上振れには loss="quantile" を使います。
生成AIは使いません。 予測は数の問題で、責任者とリーダーに渡すのは分類ごとの表です。
03どうやって実装するのか
処理の起点を決める
取り込みは毎日の深夜、予測は木曜の朝と月曜の朝に動かします。 取り込みを毎日にしておくのは、Zendesk から1週間分をまとめて取ると、取り込みが失敗した日に気づくのが木曜になるからです。社内のサーバーか、クラウドの小さな仮想マシンの定時実行(cron)で Python のスクリプトを起動します。
木曜の朝は、翌週の割り振りを決めるための回です。 金曜に担当の予定の表を確定させるので、木曜のうちに案を見て、開発に応援を頼める時刻にします。月曜の朝は、週末に入ったチケットを足して、その週の残りの日を予測し直す回です。 週末に大きな障害があった週は、月曜の残りが平常の週と違います。
月に1回、モデルを作り直します。 毎月の第1木曜に先月までの記録で学習し直し、作り直す前と後で、先月の当たり方を比べた結果を残します。悪くなっていれば、前のモデルのまま使います。
結果の表には、作った日時と、最後に取り込みが成功した日時を必ず印字します。 取り込みが止まっていると、直近の件数が少なく見え、翌週を少なく見込みます。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| チケット | チケットの番号、作成日時、経路(メール・フォーム)、分類の項目、状態、統合(マージ)の有無、迷惑メールかどうか | Zendesk(Incremental Exports API) |
| 契約の数 | 日ごとの契約中の利用者の数、そのうち契約から30日以内の数 | 契約の管理の仕組みの書き出し |
| リリースの予定 | リリースの日、規模(小・中・大)、画面が変わるか、対象の機能、利用者へのお知らせのメールの有無 | リリースの予定表 |
| 請求の締め | 請求書の発行の日、口座振替の日 | 経理の日程 |
| 祝日 | 国民の祝日の日付 | 内閣府の祝日の CSV |
| 担当の予定 | 日ごとの担当の出勤と、受け持つ分類 | 担当の予定の表 |
| 処理の時間の表 | 分類ごとの1件あたりの処理の時間、1人の1日の処理の時間 | 処理の時間の表(リーダーと決める) |
質を決めるのは、リリースの予定表の「画面が変わるか」の列です。 同じリリースでも、内部の改善だけのリリースと、画面の並びが変わるリリースでは、使い方の問い合わせの増え方がまるで違います。 開発に1列足してもらうだけで、モデルが両者を見分けられるようになります。
障害の日を記録しておきます。 大きな障害の日は、不具合とログインの問い合わせが一気に増えます。障害は前もって分からないので、予測の対象にしません。 学習のときに外すため、障害の日と時間帯を記録します。
祝日は内閣府の CSV を使います。 祝日の CSV は、翌年の分が前の年の2月に載るとされているので、年に1回、2月に入れ替えます。
データの取得方法を決める
| 取るもの | どこから | 何に使うか |
|---|---|---|
| チケット | Zendesk の /api/v2/incremental/tickets/cursor を毎日、前回のカーソルから呼ぶ | 作成日ごと・分類ごとの件数 |
| 契約の数 | 契約の管理の仕組みから日ごとの数を書き出す | 率の分母と、新しい利用者の割合 |
| リリースの予定 | スプレッドシートを CSV で書き出して読む | リリースの項目 |
| 担当の予定 | スプレッドシートを CSV で書き出して読む | 日ごとの処理できる件数 |
最初の1回だけ start_time を渡し、2回目からはカーソルで続きを取ります。 公式のページでは、start_time は Unix の秒で指定し、少なくとも1分前でなければならないとされています。前回の応答の after_cursor を保存し、次の日はそこから呼びます。end_of_stream が true になるまで呼び、その日の取り込みを終えます。
同じチケットが何度も届くことを前提にします。 この書き出しは、作られたチケットだけでなく、前回から変わったチケットを返します。 公式のページでは、比べるのはチケットの updated_at ではなく generated_timestamp で、システムによる更新でも値が変わるとされています。担当が返信しただけでも、同じチケットがまた届きます。チケットの番号で重複を除き、件数は作成日時で数えます。
削除したチケットは、既定で書き出しに含まれます。 迷惑メールとして削除したものが件数に入らないよう、exclude_deleted=true を付けるか、削除の印のあるものを外します。 1分あたり10回までの制限があるので、ページを続けて取るときは間を空けます。
AIへ渡す前に整形する
- 重複を除く … チケットの番号ごとに最後に届いたものだけを残します
- 数えないものを外す … 迷惑メール、削除したもの、ほかのチケットに統合されたもの、自動の返信(不在の通知など)を外します
- 作成日・分類ごとに数える … 作成日時で営業日ごとに、5つの分類ごとの件数にします。土日に作られたものは月曜の分に足します
- 障害の日を外す … 記録した障害の日と翌営業日は、学習の行から外します
- 率にする … 件数をその日の契約の数で割り、1,000を掛けて「契約1,000社あたりの件数」にします
- 項目を作る … 分類、曜日、祝日の翌日か、月、月末からの日数、請求書の発行の日からの日数、直近のリリースからの日数、その規模、画面が変わったか、対象の機能が分類に関係するか、お知らせのメールの有無、契約から30日以内の利用者の割合、直近4週の同じ曜日の率の平均
- 分類・曜日・リリースの規模を Categorical にする … pandas の Categorical の型にしておけば、既定の設定でカテゴリとして扱われます
1番目と3番目が、この構成の肝です。 重複を除かずに数えると、返信のやり取りが多い不具合のチケットほど何度も数えられ、件数が膨らみます。 更新の日時で数えると、リリースの週の件数が、翌週の返信の日に移ってしまいます。件数は必ず、チケットの番号ごとに1回、作成日時で数えます。
4番目で障害の日を外すのは、障害の山を学習すると、ふだんの週を多めに見込むからです。 障害の日が過去のリリースの日と重なっていると、モデルはリリースの効き方を大きく覚えます。
AIに処理させる
させるのは、翌週の日ごと・分類ごとの「契約1,000社あたりの件数」を予測することだけです。 機械学習のモデルを2本作ります。
| 出すもの | 損失 | 使いみち |
|---|---|---|
| 中央の見込み | loss="poisson"、sample_weight に契約の数 | 担当の数の目安 |
| 上振れの見込み(0.9) | loss="quantile"、quantile=0.9 | 初回の返信の目標を外しそうな日の印、応援の時間 |
上振れに0.9を使うのは、目標を外したときの戻りが大きいからです。 返事を待つ利用者が同じ問い合わせを送り直し、残りがさらに増えます。どの分位を使うかは、目標を外す重さと、応援を頼む開発の負担のどちらを重く見るかで、責任者が決めます。
未返信の残りは、日ごとに足し引きします。 その日の件数の見込みと前日の残りを足し、その分類の担当の処理できる件数を引いたものが、その日の終わりの残りです。 処理できる件数は、担当の出勤の時間を、分類ごとの1件あたりの処理の時間で割って出します。
| 日の終わりの残り(上振れ)と、翌日の午前に返信できる件数 | 案 | 表の印 |
|---|---|---|
| 残りが翌日の午前に返信できる件数以下 | 通常 | - |
| 残りが午前の件数を超え、1日の件数以下 | ほかの分類から担当を寄せる案 | 黄 |
| 残りが1日の件数を超える | 技術の応援を頼む時間の案、寄せる案 | 赤 |
初回の返信の目標が営業日の4時間以内なので、「翌日の午前に返せるか」で見ます。 残りが翌日の午前に返せる数を超えると、前日の夕方に来た分が目標を外します。
| させないこと | 理由 |
|---|---|
| 担当の勤務と割り振りの決定 | 担当ごとの得意な分類と育成の予定を知る人が決める |
| 障害の判断と、利用者への告知 | 障害の対応の決まりで行う |
| リリースの日程の変更 | 開発と製品の責任者が決める |
| 利用者への返信の中身 | 担当が書く |
| 初めての規模のリリースの効き方 | 記録が無い。責任者が上乗せする |
3行目は、とくに気を付けてください。 上振れの赤の日が出ても、それを理由にリリースを延ばす判断に予測を使わないでください。 予測はサポートの割り振りを決めるための見込みです。
指示内容を固定する
生成AIを使わないので、プロンプトはありません。 かわりに、率の予測と未返信の残りの足し引きの中身を示します。
from sklearn.ensemble import HistGradientBoostingRegressor
FEATURES = ["queue", "weekday", "after_holiday", "month", "days_to_month_end",
"days_since_invoice", "days_since_release", "release_size",
"ui_changed", "release_hits_queue", "notice_mail",
"new_contract_share", "recent4w_same_rate"]
# queue・weekday・month・release_size は pandas の Categorical にしておく
train["rate"] = train["tickets"] / train["contracts"] * 1000
w = train["contracts"] / 1000
# 直近の8週を検証に取り分け、時間の順を守って早期の打ち切りに使う
cut = train["date"].max() - pd.Timedelta(weeks=8)
tr, va = train[train["date"] <= cut], train[train["date"] > cut]
def hgb(**kw):
return HistGradientBoostingRegressor(max_iter=600, learning_rate=0.05,
random_state=0, **kw)
center = hgb(loss="poisson")
upper = hgb(loss="quantile", quantile=0.9)
for m in (center, upper):
m.fit(tr[FEATURES], tr["rate"], sample_weight=w[tr.index],
X_val=va[FEATURES], y_val=va["rate"], sample_weight_val=w[va.index])
def backlog(arrivals, capacity, start=0):
"""日ごとの終わりの未返信の残り"""
out, b = [], start
for a, c in zip(arrivals, capacity):
b = max(0, b + a - c)
out.append(b)
return out
検証を X_val と y_val で渡しているのは、時間の順を守るためです。 公式のページでは、early_stopping の既定の 'auto' は、行が10,000を超えるときか、X_val と y_val を渡したときに有効になるとされています。validation_fraction は学習の行から一定の割合を取り分ける指定で、直近の週を選ぶ指定ではありません。 未来の週で学習して過去の週で確かめることになりかねません。直近の8週を検証に取り分ければ、早期の打ち切りが働き、時間の順も守れます。
当たり方の確認は、TimeSeriesSplit で週の順に行います。 公式のページでは、時間の順に並んだデータで、k 回目は最初の k の区切りで学習し、次の区切りで確かめる分け方とされ、学習と確かめの間を空ける gap も指定できます。分類ごとの行を日付の順に並べ、区切りを週の単位にそろえます。 公式のページは区切りの間隔がそろっていることを求めています。
件数に戻すときは、翌週の契約の数を掛けます。 翌週の契約の数は、直近の伸びをそのまま延ばして置きます。大きな販促の予定がある週は、営業の見込みの数を入れます。
出力形式を固定する
責任者とリーダーに渡すのは、次の表です。 木曜の朝の打合せで画面に映して見ることを前提にします。
【翌週の分類ごとの問い合わせの見込み(11月第3週・木曜 8:05 作成/取り込み 3:12)】
| 日 | 分類 | 件数(中央/上振れ) | 処理できる件数 | 日の終わりの残り(上振れ) | 印 | 案 |
|---|---|---|---|---|---|---|
| 水 | 使い方 | 118/146 | 130 | 22 | - | 通常(リリース日・画面の変更あり) |
| 木 | 使い方 | 164/203 | 130 | 95 | 赤 | 請求から1名寄せる、技術の応援4時間 |
| 木 | 不具合 | 41/55 | 48 | 9 | - | 通常 |
| 月 | 請求 | 72/88 | 64 | 24 | 黄 | ログインから半日寄せる |
「印」と「案」で、責任者が見る先を決めます。 赤の日は、技術の応援を頼むかと、どの分類から担当を寄せるかを決めます。黄の日は、寄せるかどうかを決めます。 寄せる元の分類の残りが増えないかも、同じ表で確かめます。
表の一番下には、注意の印を並べます。 初めての規模のリリースには「リリースの上乗せ未定」、リリースの予定表の「画面が変わるか」が空の日には「リリースの項目が未入力」、取り込みが前日より古ければ「取り込みが止まっている」を出します。
機械で読む用には、同じ内容を CSV でも残します。 列は、日、分類、契約の数、率と件数の中央と上振れ、処理できる件数、残り、印、案、モデルを作った日付です。翌週に実績と並べて当たり方を見るのは、この CSV です。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| Zendesk | Incremental Exports API(カーソル)で毎日取り込む。API のトークンは読み取りに使う専用の利用者で発行 | チケットの番号、作成日時、分類、状態 |
| 契約の管理の仕組み | 日ごとの契約の数を書き出す | 率の分母 |
| リリースの予定表・担当の予定の表 | スプレッドシートを CSV で書き出して読む | リリースの項目、出勤と分類 |
| Zendesk のチケットの割り当てと担当の予定の表 | 書き込まない(決めてから人が直す) | - |
Zendesk には読み取りしかしません。 取り込みに使う利用者の権限を読み取りに絞り、チケットの割り当てや状態を変える処理は作りません。 割り振りを変えるのは、リーダーが Zendesk の画面で行います。
人が確認する
- 作った日時と取り込みの日時を見る … 表の上の2つの日時が当日の朝であることを確かめます
- 赤と黄の分類を見る … 寄せる担当と、技術の応援を頼むかを決めます
- 寄せる元の分類を確かめる … 寄せたあとに、寄せる元の残りが増えないかを表で見ます
- 予測の外の事情を足し引きする … 大口の利用者の一斉の導入、法改正に伴う機能の変更、外部のサービスの仕様の変更などを足し引きします
目標は、20件をならして1件9分です。 印の無い分類は案を写すだけで、時間を使うのは赤と黄の分類と、リリースの週です。
例外に対処する
| 起きること | 対応 |
|---|---|
| 取り込みが失敗した・止まっている | 予測を止め、表の一番上に「取り込みが止まっている」と出す。カーソルは前回の成功のものから再開 |
| 1分あたりの呼び出しの上限に当たった | 間を空けて呼び直す |
| 分類が空のチケット | 「未分類」として数え、件数を表に出す。分類の付け忘れが多い週はリーダーに知らせる |
| 大きな障害が起きた週 | 障害の日を記録し、学習から外す。その週の予測は表に印を付ける |
| 初めての規模のリリース | 表に印を出し、責任者が上乗せ |
| 分類の区分を変えた | 変えた日より前の件数を新しい区分に読み替える表を作り、作れなければ変えた日から学習し直す |
| 作り直したモデルが前より外れる | 前のモデルのまま使い、作り直しの記録を残す |
6行目は、運用を続けると必ず起きます。 「連携」を「API」と「外部のサービス」に分けた、といった変更で、過去の件数と新しい区分がつながらなくなります。 分類を変える前に、サポートの運用の責任者に知らせる決まりにします。
記録を残す
- 実行の日時、使ったモデルの作成日、最後に取り込みが成功した日時とカーソル
- 日ごと・分類ごとの率と件数の中央と上振れ、処理できる件数、残り、印、案
- 責任者とリーダーが決めた割り振りと応援の依頼と、案から変えた理由
- 翌週の実績(分類ごとの件数、初回の返信の目標を外した件数、日の終わりの残り)
- 月ごとの当たり方(分類ごとの中央の外れの大きさ、上振れを上回った日の割合)と、モデルの作り直しの結果
3つ目と4つ目を並べると、割り振りの判断が合っていたかが分かります。 赤の日に応援を頼み、目標を外した件数が出なかったなら、判断は働いています。印の無い日に目標を外したなら、処理の時間の表を見直します。
04実装レベルの3段階
本記事の想定は本格構成です。 半自動化では件数の表までで、残りの足し引きと担当の数への置き換えはリーダーの手に残ります。 第4章の③の時間がそのまま残ります。 半自動化で1件36分が20分ほどに、本格構成で9分になります。 差が大きいのは、残りの足し引きと寄せる案が、処理の時間の表があれば機械で出せる作業だからです。 段階を飛ばさないでください。 半自動化の表を1か月見ると、どの分類とどのリリースの予測が当たり、どこが外れるかが分かります。外れる部分の記録を直してから、本格構成に進みます。
05工数削減シミュレーション
導入後 20件 × 9分 ÷ 60 = 3 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 契約の利用者が数千社以上で、問い合わせをメールとフォームのチケットで受け、分類ごとに担当を分けている SaaS 企業。2週間ごとなど決まった間隔でリリースがあり、リリースのあとに使い方と不具合の問い合わせが増える場合。初回の返信の目標の時間を決めていて、週によって目標を外す分類が出る場合。EC の出店者向けのサポートなど、契約の数で問い合わせが動く窓口にも使える。
- 電話とチャットが中心で、1時間ごとの席の数を決めたい窓口(時間帯ごとの受付の数を見込む別の構成が向く)。チケットに分類が付いておらず、件数を分類ごとに数えられない場合。契約の数が数百社で、週の件数が数十件しか無い場合。なお、担当の勤務の決定、障害の判断と告知、リリースの日程の変更、利用者への返信の中身は、この構成では代替できません。
07最小構成で試す方法
- Zendesk の画面か API で、過去1年分のチケットの番号、作成日時、分類を書き出す
- 同じ期間のリリースの日と、画面が変わったかを、開発のリリースの記録から拾う
- 契約の管理の仕組みから、月ごとの契約の数を書き出し、日ごとにならす
- Python で第7章の設定を動かし、最後の8週を「翌週」として、週ごとに予測させる
- 当時のリーダーの見立てと、実際の件数と並べる
1年・8週で十分です。 確かめたいのは、「リリースの効き方と契約の伸びを、リーダーの見立てと同じくらい拾えるか」です。
| 出てきた内容 | 判断 |
|---|---|
| リリースの週の使い方の件数が実績と合う | 処理の時間の表を作り、残りの足し引きまで出す段階に進む |
| リリースの週が低めに出る | 画面が変わったかの区別が無い。リリースの記録に列を足す |
| 件数が全体に多めに出る | 重複が除けていない。チケットの番号で数え直す |
3行目は、ほとんどの会社で一度は出ます。 更新されたチケットが何度も届くためで、失敗ではなく、件数の数え方を決める理由が数字で分かったということです。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
| 同じチケットを何度も数える | チケットの番号で重複を除き、作成日時で数える |
| 契約の伸びを見ずに件数で学習する | 契約1,000社あたりの率で学習し、件数に戻す |
| 障害の山を学習する | 障害の日を記録し、学習から外す |
| 画面の変わるリリースと内部の改善を区別しない | リリースの予定表に「画面が変わるか」の列を足す |
| 検証の行をでたらめに選ぶ | X_val と y_val で直近の週を渡す |
| 削除・迷惑メール・統合したチケットを数える | exclude_deleted=true と状態で外す |
start_time を今の時刻にして取りこぼす | 少なくとも1分前を指定する |
| 1分あたりの上限に当たる | 間を空けて呼び直す |
| 分類の区分を変えて過去とつながらない | 読み替えの表を作る |
| 取り込みの利用者に書き込みの権限がある | 読み取りに絞る |
上の2行が、この構成の失敗のほとんどです。 どちらも、画面で見ている件数と、本当に新しく来た問い合わせの数がずれることから起きます。ここを押さえれば、残りは他の件数の予測と同じ注意で足ります。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: チケットの番号、作成日時、分類、状態、契約の数、リリースの予定、担当の出勤です。チケットの本文と、利用者の名前とメールアドレスは、取り込みの応答に含まれます。
- チケットの本文と利用者の情報を残さない … 取り込みの応答から、番号・作成日時・分類・状態・経路以外の項目を捨ててから保存します。予測に要るのは件数だけです
- API のトークンを読み取りに絞る … 取り込みに使う利用者は読み取りの権限だけにし、トークンはスクリプトに書かず、サーバーの秘密の置き場に置きます
- データを外に出さない … 予測は社内のサーバーか自社のクラウドの中で動き、生成AIや外部のサービスに記録を送りません
- 割り振りは人が決める … 案はあくまで案で、担当の勤務と受け持ちは責任者とリーダーが決めます。 予測の数を担当の評価に使わないでください
- リリースの判断に使わない … 赤の日が出ても、リリースの日程は開発と製品の責任者が決めます
- 未リリースの機能の情報を広げない … リリースの予定表には、利用者にまだ知らせていない機能の名前が載ります。表の共有先を、サポートの責任者とリーダーに限ります
誤りが起きた場合のリスクは、初回の返信の目標を外すことと、応援を頼みすぎて開発の手を止めることの2つです。 前者は重複の除き方や障害の日の扱いを誤ると起き、後者は上振れの線が高すぎると起きます。分類ごとの当たり方と、上振れを上回った日の割合の確認で、両方を抑えます。
10まず何から始めるか
1週目:数え方を決める
Zendesk から過去1年分のチケットを書き出し、チケットの番号で重複を除いて作成日時で数えた件数と、画面で見ていた件数を比べます。 障害の日も、障害の記録から拾います。
2週目:1年分で試す
第8章のとおり、リリースの記録と契約の数を合わせ、最後の8週を週ごとに予測させます。リリースの週が低めに出ていないか、件数が多めに出ていないかを最優先で見ます。
3週目:処理の時間の表と、リリースの予定表の列を決める
リーダーと一緒に、分類ごとの1件あたりの処理の時間と、上振れの分位を表にします。開発と、リリースの予定表に「規模」「画面が変わるか」「対象の機能」の列を足す取り決めをします。
4週目:翌週の表を毎週出す
毎日の取り込みと、木曜の朝に分類ごとの件数の表を出す半自動化を始め、リーダーはこれまでどおり自分で決めながら、表と見比べます。 翌週の木曜に、リーダーの見立てと表の中央のどちらが実績に近かったかを書き残します。
2か月目以降: 未返信の残りの足し引きと寄せる案を足し、月曜のやり直しを始めます。案から変えた理由、目標を外した件数、上振れを上回った日の割合を毎月見ます。 リーダーが印の付いた分類だけを見て割り振りを決められるようになった時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
HistGradientBoostingRegressor の loss に 'poisson'(目的の値が0以上であることが要る)と 'quantile' があること。fit が sample_weight と X_val・y_val・sample_weight_val を受け取ること。early_stopping='auto' は行が10,000を超えるときか X_val と y_val を渡したときに有効になること。categorical_features の既定が 'from_dtype' であること(版 1.9.1) | scikit-learn: HistGradientBoostingRegressor | 2026-10-29 |
TimeSeriesSplit が時間の順のデータで k 回目に最初の k の区切りで学習し次の区切りで確かめること、区切りの間隔がそろっている必要があること、gap で学習と確かめの間を空けられること(版 1.9.1) | scikit-learn: TimeSeriesSplit | 2026-10-29 |
Incremental Exports API のカーソルによるチケットの書き出し(/api/v2/incremental/tickets/cursor)が強く勧められていること。1ページ最大1,000件、1分あたり10回までであること。start_time は Unix の秒で少なくとも1分前であること。前回から変わったチケットを返し、generated_timestamp で比べ、システムによる更新でも値が変わること。削除が既定で含まれ exclude_deleted=true で外せること。after_cursor と end_of_stream | Zendesk Developer Docs: Incremental Exports | 2026-10-29 |
| 国民の祝日の CSV が昭和30年から令和9年までを収録し、令和10年の分を前年の2月に掲載するとされていること | 内閣府: 国民の祝日について | 2026-10-29 |
担当の勤務と割り振り、障害の対応、リリースの判断は、会社の判断で行ってください。 本記事は公開されている仕様で確認できた範囲だけを扱っています。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-2304)についてのご相談はこちらから。
