「AIの誤検知」を調べたら、間違っていたのは自分の正解データだった — スクショを見るAIで外観監視を試す

AI
B!

サイトの外観監視で「前回スクショとのピクセル差分」を撮っている運用は多いと思います。ただ差分は「どれだけ変わったか」しか教えてくれません。記事が1本増えても差分は動くし、逆に画像が1枚消えても差分上はわずかにしか動きません。「何がどうおかしいのか」は、結局スクショを人が見ないと分からない。

そこで、スクリーンショットを画像認識AI(claude-sonnet-5)に「見せて」、正常/崩れの疑い/改ざんの疑いを判定させ、画面のどこがどうなっているかを言葉で説明させる仕組みを試しました。自社2サイト(toha.jp / noimi.jp)で、正常20枚・異常20枚を実測しています。

先に結論を書くと、検知率90%・誤検知率30%でした。この30%を隠さず中身を調べたら、間違っていたのは AIではなく、こちらが用意した「正解」ラベルのほうでした。監視用スクショの撮影環境が、実サイトの見た目を正しく写していなかったのです。以下、作り方・計測・ハマりどころを技術者向けにまとめます。決済者向けの要約版は 実績ページの事例(AIに画面を見せたら、監視の穴が見つかった) にあります。

最初に断っておくと、これは「疑い」を人に上げるトリアージであって、防御ではありません。自動でアラートを飛ばしたり、改ざんをブロックしたりする機能はありません。あくまで「人が確認すべき画面を絞る」ための仕組みです。

既存のピクセル差分と何が違うのか

自社の保守サービス(Sonagear)は、すでに毎日スクショを撮ってピクセル差分で変化を検知しています。今回の「画像を見るAI」は、それを置き換えるものではなく、役割が違います。

既存(ピクセル差分)今回(画像を見るAI)
分かることどれだけ変わったか(数値)何がどうおかしいか(言葉)
前回画像必須不要(1枚でも判定できる)
差分は「変化量」、AIは「意味」。後述するとおり、この2つはきれいに補い合います。

構成

  • Laravel 13 / PHP 8.3 / SQLite(docker 不要の小さな検証環境)
  • 判定モデル:claude-sonnet-5 の画像認識。スクショを1枚渡し、判定区分・確信度・根拠テキストをJSONで返させる
  • 撮影:Chrome headless。正常サンプルは Sonagear が実際に撮って S3 に上げているものを流用
  • コスト管理:全コールのトークンと円を記録。月次3,000円+1枚あたりの上限を設定

最初にハマったのが撮影側です。Chrome headless の既定 UA のままだと、公開ホストが Forbidden を返すことがありました。実ブラウザの UA を明示して撮る必要があります。監視スクショを自前で撮る場合の定番の落とし穴なので、先に書いておきます。

// Chrome headless の既定 UA は "HeadlessChrome/..." を含み、
// WAF や一部ホストで弾かれることがある。実ブラウザ相当の UA を明示する。
await page.setUserAgent(
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 '
  + '(KHTML, like Gecko) Chrome/xxx.0.0.0 Safari/537.36'
);

サンプルの作り方 ― ここで手を抜くと数字が嘘になる

内容枚数
正常Sonagear が実際に撮っているスクショ(S3)18枚 + 手元で撮影 2枚20枚
異常実際に CSS/JS を差し込んで壊し、レンダリングして撮影(10種類 × 2サイト)20枚

異常の10種類は、レイアウト崩壊 / 要素のはみ出し / 画像が出ない / 文字が極端に大きい / 配色が壊れる / ほぼ空白 / 途中までしか描画されない / サーバエラー画面(以上「崩れ」)、文言の改ざん / 改ざんバナーの挿入(以上「改ざん」)です。

ここで2つ、意識的に守ったことがあります。

  • 画像を後から加工して異常を作らない。加工画像だと「加工の痕跡」を見つけているだけになり、本物の表示崩れを見つけられるかの検証にならない。だから実ページに CSS/JS を差し込んでレンダリングし直して撮っています。
  • 正解は撮影時に確定して保存する。あとから「これは異常だった」と決めると、検知率も誤検知率も自分の都合で動かせてしまう。これが後で効いてきます。
正常・改ざんの疑い・崩れの疑いのサンプル
上から正常・改ざんの疑い・崩れの疑い。異常は実際にCSSを壊して表示させたものです。

結果 ― 検知率90% / 誤検知率30%

AI: 異常と判定AI: 正常と判定
実際に異常182
実際は正常614
正常20枚・異常20枚。異常サンプルは自作。検知率18/20(90%)、誤検知率6/20(30%)。

崩れと改ざんの区別は、異常と判定できた18枚すべてで正解でした(崩れ14/16・改ざん4/4・区分違い0)。コストは1枚あたり1.03円・平均5.7秒(40枚の実測)。見た目の判定にしては安いほうだと思います。

問題は誤検知率30%です。見た目の判定は誤検知しやすいので、これ自体は驚きではありません。ただ、この数字をそのまま運用に乗せると「毎日6件の誤報」になり、通知は確実に無視されます。ここで確信度が効きます。

確信度で足切りすると、人に上がる誤報が0になった

AIは判定ごとに確信度(0〜100)を返します。調べると、誤報6件はすべて確信度30〜40、正しい判定はすべて60以上に固まっていました。確信度60以上だけを人に上げる運用にすると、こうなります。

足切りなし確信度60以上だけ上げる
人に上がる異常18/20(90%)17/20(85%)
人に上がる誤報6/20(30%)0/20(0%)
確信度60でしきった場合。検知率を5ポイント落とす代わりに、人に上がる誤報を0にできました。
検知率・誤検知率と、確信度で足切りした場合の効果
検知率・誤検知率と、確信度で足切りした場合の効果。

ここは他の事例と比べると面白いところです。別に作った AI コードレビュー(E-1)や問い合わせ仕分け(B-2)では、確信度が当てになりませんでした。誤った判定に自信92や95が平気で付いていて、確信度でしきっても誤報が減らなかったのです。ところが画像判定では、確信度が正誤をきれいに分けました。

断定はできませんが、テキストの「もっともらしい嘘」は自信を持って生成されやすいのに対し、画像で「崩れているかどうか」の視覚判断は、迷いがそのまま確信度に出やすいのかもしれません。いずれにせよ、確信度が使えるかどうかはタスクごとに実測しないと分からない——これが持ち帰れる教訓でした。「確信度で足切りする」という設計は、確信度が正誤と相関していて初めて成立します。

誤検知の中身を見に行ったら、自分の正解が間違っていた

足切りで運用は成立しました。でも、せっかく誤報6件があるので中身を見てみました。ここがこの検証の本題です。

誤検知とされた6枚は、すべて noimi.jp の、Sonagear(サーバ)が撮影した分でした。同じサイトを手元の Mac で撮った分では誤検知0件です。

サイト撮影元誤検知
noimi.jpSonagear(サーバ)9枚中6枚
noimi.jp手元の Mac1枚中0枚
toha.jpSonagear(サーバ)9枚中0枚
toha.jp手元の Mac1枚中0枚

AIの説明はこうでした。

右側の「くわしい解説記事」欄で、本来絵文字が入るはずの見出し「「 」とは?アボカド絵文字の意味と使い方」の括弧内が空白になっており、絵文字画像またはテキストが表示されていない可能性があります。

同じ箇所を、サーバ撮影と手元の Mac 撮影で並べました。

  • サーバ撮影:「 」とは?アボカド絵文字の意味と使い方 ― 絵文字が空白
  • 手元撮影:「🥑」とは?アボカド絵文字の意味と使い方 ― 正しく表示
サーバ撮影では絵文字が空白、手元撮影では正しく表示されている比較
上がSonagearのサーバ撮影(絵文字が空白)、下が手元での撮影。AIの指摘どおりでした。

Sonagear の撮影環境に絵文字フォントが入っておらず、実際に絵文字が欠落していました。noimi.jp は絵文字を解説するサイトなので、これは無視できない欠落です。つまり誤検知とされた6件は、少なくとも6件ともAIの指摘が正しく、誤っていたのはこちらが付けた「正常」というラベルのほうでした。AIは自信30〜40(=確信が持てない)としながら、位置も内容も正確に指摘していました。

この検証で実際に見つかった一番大きな問題は、これです。監視スクショそのものが、実サイトの見た目を正しく写していなかった。ピクセル差分は「前回のサーバ撮影」と「今回のサーバ撮影」を比べるので、両方に同じ欠落があれば永遠に気づけません。撮影環境の再現性は、監視を自前で組むときに見落としやすい前提だと痛感しました。

そして、これに気づけたのは誤検知率を隠さず、中身を見に行ったからです。率だけ見て「30%か、まあこんなものか」で終わっていたら、絵文字の欠落には一生気づけませんでした。

見逃した2枚 ― 1枚だけ見る判定の限界

見逃した異常2枚は、両方とも「画像が表示されない」タイプでした。しかも「正常」と自信90・95で判定しています。画像が消えてもレイアウトは整うため、元の姿を知らないと「そういうデザイン」に見えてしまう。1枚だけを見る判定には、原理的にこの限界があります。

これは裏を返すと、前回世代との比較が要る種類の異常があるということです。まさにピクセル差分(既存のSonagear)が得意な領域で、「変化量を数値で見る」やり方と「1枚を見て意味を理解する」やり方は、得意な領域が違い、補い合う関係にありました。どちらか一方ではなく、両方を持つのが現実的です。

他の案件にも持っていける設計

  • 確信度で足切りするトリアージ。通知を乱発しないための設計。検知率と誤報のトレードオフを数字で決める。ただし前提として、そのタスクで確信度が正誤と相関しているかを先に測る。
  • 異常サンプルを「本物」として作る。加工画像ではなく、実際に壊してレンダリングして撮る。
  • 正解を先に確定する。あとから決めると、検知率も誤検知率も自分の都合で動く。
  • 誤検知の中身を必ず見る。率だけ見ていると、正解ラベルの誤り(=データ側の問題)に気づけない。

数値の母数と、書いていないこと

すべて実測値です。誇大にならないよう、母数と条件を添えます。検知率90%・誤検知率30%は「正常20枚・異常20枚(異常は自作)」での値、足切り後の17/20・0/20は「確信度60以上だけを上げた場合」、1.03円・5.7秒は「40枚の平均」、絵文字欠落は「noimi.jp のサーバ撮影9枚中6枚(toha.jp では0件)」です。

そして、測っていないので書けないこと。「改ざんを防げます」「不正アクセスを防止」とは書けません(防御機能はなく、疑いの提示だけ)。「見逃しゼロ」でもありません(20枚中2枚を見逃し)。異常サンプルは自作なので実運用の障害での検知率は測っていません。前回世代との比較は実装しておらず(1枚だけで判定)、検証はPC版のみ・自社2サイトのみです。Sonagear の監視に組み込んだわけでもありません(検証のみ)。

まとめ

「見た目がおかしい」は数値で拾いきれません。画像を見るAIは、確信度で足切りすれば「疑いを人に上げるトリアージ」として実用になりました。そして誤検知の中身を見に行ったことで、監視スクショが実サイトを正しく写していないという、仕組みそのものの穴が見つかりました。AIの「間違い」は、こちらの正解が間違っているサインかもしれない——率だけでなく中身を見ることを、次からも徹底しようと思います。

事例の要約(非エンジニア・決済者向け)は 実績ページ に、AI活用の他の事例は AI活用ページ にまとめています。既存サイトへのAI機能追加のご相談は お問い合わせ から。

B!
← 一覧へ戻る