AI にレポートの修正案を「変更前・変更後の対応表」で出させて SQL で検算する:誤りを 8 か所混ぜた月次レポートで試した結果

GA4 公開サンプル 2 か月分の正解表で書いた月次レポートに誤りを 8 か所混ぜ、AI に対応表で直させました。機械の検査は 9 件すべて通り、SQL の正解と筆者が決めた購入率の定義に照らすと 2 件が誤りだった結果と、手順をまとめます。

17分で読めます Data
左に文章の行を表す灰色のバーが並び、中央の 2 列の表で灰色の変更前から青の変更後へ矢印が伸び、右の棒グラフへ点線で照合しているイラスト
この記事は AI が下書きを補助し、運営者が内容を確認して公開しています。

GA4 の数字を文章にした月次レポートを作っていて、AI に誤りを直させたいけれど、数字まで勝手に変えられるのが怖い方向けの記事です。AI に本文を書き換えさせず、「変更前・変更後・理由」の対応表で修正案を出させ、1 件ずつ SQL で検算する手順を、実際に試した結果つきで紹介します。読み終わると、AI の修正のうちどれを信じてよいかを、自分で確かめられるようになります。

この記事で分かること

  • AI の修正案を「対応表」で受け取ると、何が良いのか
  • 誤りを 8 か所混ぜたレポートを AI に直させたら、何件が正しく、何件が誤りだったか
  • 対応表を機械で検査する手順と、それだけでは足りない理由
  • 検算でつまずきやすい点(曖昧な指定、定義の取り違え、図の中の数値)

ざっくり言うと:対応表で受け取ると、1 件ずつ SQL で検算できる

AI に修正案を頼むとき、本文を丸ごと返してもらう代わりに、直した箇所だけを表で返してもらいます。表の 1 行が 1 件の修正なので、その行の「変更後」を SQL の正解と比べれば、修正が合っているかを 1 件ずつ判定できます。

今回、AI が返した 9 件の修正は、「変更前の文が本文に 1 回だけあるか」という機械の検査をすべて通りました。ところが、SQL の正解と、筆者が決めた購入率の定義(購入イベント ÷ セッション)に照らすと、2 件は誤った修正でした。

AI の修正案を受け取ってから当てるまでの流れ。レポート文と正解表を AI に渡し、返ってきた対応表を、変更前が本文に 1 回だけあるかの検査と、変更後を SQL の正解と比べる検査の 2 段階に通し、合うものだけを当てる(本文に反映する)

図 1 のとおり、修正を当てる(本文に反映する)前の検査は、「場所」と「正しさ」の 2 段階に分かれます。機械で確かめられるのは場所までで、正しさは正解表と比べないと分かりません。

なぜ本文を丸ごと書き換えさせないか:何が変わったか分からなくなる

AI に「この文章を直して」と頼むと、直した本文が丸ごと返ってきます。20 行のレポートなら、どの行のどの数字が変わったかを、元の文と見比べて探す必要があります。探し漏れがあると、AI が勝手に変えた数字がそのまま上司に届きます。

対応表で返してもらえば、変わった箇所は表の行数と一致します。筆者がこのサイトの運用で試した記録でも、公開記事の定期点検で、修正担当の AI にファイルを直接書かせず、変更前と変更後の一覧を JSON(プログラムで読みやすい文字のデータ形式)で返させ、AI を使わないスクリプトで当てる方式にしています。ある回の点検では、AI の修正 20 件がすべて当たり、当たらなかった修正は 0 件でした。

ただし、その 20 件は日付の表記の統一など文体の修正が中心で、数字の中身を直す修正はありませんでした。そこで今回は、数字の誤りを混ぜたレポートで同じ方式を試しました。

本文を丸ごと書き換えさせる方式と対応表で返させる方式の比較。何が変わったか分かるか、1 件ずつ検算できるか、曖昧な修正を弾けるかの 3 点で対応表方式が有利で、図の中の数値はどちらの方式でも直せない

図 4 の内容を表にすると次のとおりです。

比べる点本文を書き換えさせる対応表で返させる
何が変わったか分かるか差分を自分で取る必要がある1 行ずつ残る
1 件ずつ検算できるか変更箇所を探してから行ごとに SQL と比べられる
曖昧な修正を弾けるか弾けない変更前が 1 回だけかで機械が弾く
図の中の数値を直せるか直せない直せない(別に直す)

正解表を作る:GA4 公開サンプルの 2 か月分の集計

データは、Google が BigQuery(Google のデータ分析用データベース)で公開している GA4 のサンプルデータセット です。Google Merchandise Store の GA4 イベントを難読化したもので、期間は 2020 年 11 月 1 日から 2021 年 1 月 31 日です。今回はそのうち 2020 年 11 月と 12 月を使いました。

列名は GA4 の BigQuery Export スキーマ に沿っています。セッション(サイトへの 1 回の訪問)は、user_pseudo_id(GA4 がブラウザーや端末ごとに付ける匿名の ID)と、event_params の中の ga_session_id の組で数えました。ユーザーは user_pseudo_id の数です。月別合計の SQL は次のとおりです。

-- GA4 公開サンプル 2020年11月・12月の月別合計
WITH events AS (
  SELECT
    SUBSTR(event_date, 1, 6) AS month,
    user_pseudo_id,
    event_name,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS ga_session_id,
    ecommerce.purchase_revenue_in_usd AS revenue_usd
  FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20201101' AND '20201231'
)
SELECT
  month,
  COUNT(DISTINCT CONCAT(user_pseudo_id, CAST(ga_session_id AS STRING))) AS sessions,
  COUNT(DISTINCT user_pseudo_id) AS users,
  COUNTIF(event_name = 'purchase') AS purchase_events,
  ROUND(SUM(IF(event_name = 'purchase', revenue_usd, 0)), 2) AS revenue_usd
FROM events
GROUP BY month
ORDER BY month

デバイス別と国別は、同じ形で device.category と geo.country を GROUP BY に足しました。国別は、各月のセッション数で順位を付け、上位 5 か国に絞っています。

-- GA4 公開サンプル 2020年11月・12月のデバイス別セッション数
WITH events AS (
  SELECT
    SUBSTR(event_date, 1, 6) AS month,
    device.category AS device_category,
    user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS ga_session_id
  FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20201101' AND '20201231'
)
SELECT
  month,
  device_category,
  COUNT(DISTINCT CONCAT(user_pseudo_id, CAST(ga_session_id AS STRING))) AS sessions
FROM events
GROUP BY month, device_category
ORDER BY month, sessions DESC
-- GA4 公開サンプル 2020年11月・12月の国別セッション数(上位 5 か国)
WITH events AS (
  SELECT
    SUBSTR(event_date, 1, 6) AS month,
    geo.country AS country,
    user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS ga_session_id
  FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20201101' AND '20201231'
),
ranked AS (
  SELECT
    month,
    country,
    COUNT(DISTINCT CONCAT(user_pseudo_id, CAST(ga_session_id AS STRING))) AS sessions
  FROM events
  GROUP BY month, country
)
SELECT
  month,
  country,
  sessions,
  RANK() OVER (PARTITION BY month ORDER BY sessions DESC) AS rnk
FROM ranked
QUALIFY rnk <= 5
ORDER BY month, rnk

traffic_source は「ユーザーを最初に獲得した流入元」の情報(スキーマの説明)なので、月ごとの順位には使っていません。

3 本の SQL の処理量は、dry run(実行前の見積もり)で合計約 2.26 GB でした。BigQuery は 処理するクエリデータが毎月 1 TiB まで無料 なので、この範囲に収まります。結果(正解表)は次のとおりです。

月セッションユーザー購入イベント売上(USD)
2020年11月108,40179,4212,054144,260
2020年12月133,368104,3152,434160,555

12 月はデスクトップ 77,488、モバイル 52,900、タブレット 2,980 セッションでした。国別の 12 月の上位は、米国 58,398、インド 12,512、カナダ 10,070、英国 4,162、フランス 2,697 の順です。

誤りを 8 か所混ぜたレポート文

正解表の数字を使って、筆者が 20 行の月次レポートを書きました。そこに、数値・増減率・順位・用語の誤りを 2 か所ずつ、合計 8 か所混ぜました。AI に渡した本文は次の 20 行です。上から数えた行番号が、下の表の「行」です。

2020 年 12 月の Google Merchandise Store の月次レポートです。比較対象は 2020 年 11 月です。
12 月のセッション数は 138,368 で、11 月の 108,401 から増えました。
増えた数は約 2.5 万セッションです。
セッション数の前月比は +23.0% でした。
ユーザー数は 104,315 で、前月比は +13.1% でした。
ここでいうユーザー数は、訪問の回数を数えたものです。
購入イベントは 2,434 件で、前月比 +15.8% でした。
売上は 165,055 ドルで、前月比 +11.3% でした。
1 件あたりの売上は約 66 ドルで、11 月の約 70 ドルから下がりました。
12 月の購入率(購入イベント数をユーザー数で割った値)は 1.83% でした。
11 月の購入率は 1.89% だったので、わずかに下がっています。
デバイス別のセッション数は、モバイルが 1 位でした。
デスクトップは 77,488、モバイルは 52,900、タブレットは 2,980 セッションでした。
デスクトップの割合は 58.1% です。
タブレットの前月比は +25.2% で、3 種類の中で最も伸びました。
国別のセッション数は、1 位が米国で 58,398 でした。
2 位はカナダ、3 位はインドでした。
4 位は英国、5 位はフランスで、上位 5 か国の顔ぶれは 11 月と同じです。
5 か国の中で前月比が最も大きかったのはカナダの +25.7% です。
来月は 2021 年 1 月の結果を同じ形式で報告します。
行種類混ぜた誤り正しい内容
2数値12 月のセッション 138,368133,368
5増減率ユーザーの前月比 +13.1%+31.3%
6用語ユーザー数は訪問の回数user_pseudo_id の数(重複を除いた数。訪問の回数はセッション)
7増減率購入イベントの前月比 +15.8%+18.5%
8数値売上 165,055 ドル160,555 ドル
10用語購入率を「購入イベント ÷ ユーザー数」と説明(値 1.83% は正しい)「購入イベント ÷ セッション数」
12順位デバイスの 1 位はモバイルデスクトップ
17順位2 位カナダ、3 位インド2 位インド、3 位カナダ

誤りを混ぜていない 12 行には、わざと丸めた正しい記述も入れました。「増えた数は約 2.5 万セッション」(正確には 24,967)や、「1 件あたりの売上は約 66 ドル」(正確には 65.96 ドル)です。AI が丸めを誤りと見なして直すかを確かめるためです。

プロンプト:AI に渡した入力と指示

AI には、正解表 3 つと列の定義、レポート本文を渡し、最後に対応表で返させる指示を付けました。次がプロンプトの全文です。長くなるので、レポート本文の部分だけを省略しています。

次の集計表(正しい値)と、それをもとに書いた月次レポートの文章があります。文章には誤りが含まれています。

表 1 月別の合計(GA4 公開サンプル ga4_obfuscated_sample_ecommerce)

| 月 | セッション | ユーザー | 購入イベント | 売上(USD) |
|---|---|---|---|---|
| 2020年11月 | 108401 | 79421 | 2054 | 144260 |
| 2020年12月 | 133368 | 104315 | 2434 | 160555 |

表 2 デバイス別のセッション数

| 月 | desktop | mobile | tablet |
|---|---|---|---|
| 2020年11月 | 62820 | 43201 | 2380 |
| 2020年12月 | 77488 | 52900 | 2980 |

表 3 国別のセッション数(各月の上位 5 か国)

| 月 | 1位 | 2位 | 3位 | 4位 | 5位 |
|---|---|---|---|---|---|
| 2020年11月 | United States 47649 | India 10246 | Canada 8013 | United Kingdom 3445 | France 2147 |
| 2020年12月 | United States 58398 | India 12512 | Canada 10070 | United Kingdom 4162 | France 2697 |

定義: セッション = user_pseudo_id と ga_session_id の組の数。ユーザー = user_pseudo_id の数。購入イベント = event_name が purchase の行数。

--- レポート本文ここから ---
(ここに、上のレポート本文 20 行をそのまま貼りました)
--- レポート本文ここまで ---

指示:
- レポート本文を書き直さないでください。直すべき箇所だけを、変更前・変更後・理由の対応表として返してください。
- 出力は JSON の配列だけにしてください。各要素は {"old": "...", "new": "...", "reason": "..."} です。
- old は本文の文字列をそのまま写してください。本文の中にちょうど 1 回だけ現れ、改行を含まず、400 文字以内にしてください。
- new は old を置き換える文字列です。
- reason は「数値:」「増減率:」「順位:」「用語:」「その他:」のどれかで始め、表のどの値と比べたかを書いてください。
- 表と食い違っていない箇所は変えないでください。

モデルは claude-sonnet-5-5 で、2026 年 11 月 6 日に Claude Code の CLI(文字で操作する画面)から 1 回だけ実行しました。

Anthropic の プロンプト改善のガイド は、先に成功の基準と測り方を用意することを前提にしています。今回の基準は「SQL の正解と一致するか」です。

AI の答え:変更前・変更後・理由の対応表

AI は 9 件の修正を JSON で返しました。そのうち、誤りがあった 2 件をそのまま載せます。

[
  {
    "old": "12 月の購入率(購入イベント数をユーザー数で割った値)は 1.83% でした。",
    "new": "12 月の購入率(購入イベント数をユーザー数で割った値)は 2.33% でした。",
    "reason": "数値: 表1の 2434/104315 = 2.33%。"
  },
  {
    "old": "11 月の購入率は 1.89% だったので",
    "new": "11 月の購入率は 2.59% だったので",
    "reason": "数値: 表1の 2054/79421 = 2.59%。12月の 2.33% より高いので「わずかに下がった」は変えない。"
  }
]

残りの 7 件は、セッション数、売上、2 つの増減率、ユーザー数の説明、デバイスの順位、国の順位の修正でした。

検算:対応表の各行を SQL の正解と突き合わせる

検算は 2 段階で行いました。まず機械で場所を確かめ、次に変更後の値を正解表と比べます。

1 段階目:変更前が本文に 1 回だけあるか

筆者が node(JavaScript を動かす実行環境)で、変更前の文字列が本文に何回現れるかを数えました。条件は、このサイトの運用と同じく「ちょうど 1 回・改行なし・400 文字以内」です。結果は 9 件すべてが 1 回だけ一致し、9 件とも当てられました。

2 段階目:変更後を正解と比べる

増減率は「(12 月 − 11 月) ÷ 11 月 × 100」で筆者が計算し直しました。ユーザーは +31.344%、購入イベントは +18.500% で、AI の +31.3% と +18.5% は一致しました。順位も正解表の並びと一致しました。

合わなかったのは購入率の 2 件です。2434 ÷ 104315 = 2.333% という計算自体は、SQL の値と矛盾しません。正解表には購入率の列も定義も無いので、SQL の値と比べるだけでは、この 2 件は誤りと判定できません。

誤りと判定した根拠は、筆者がレポートを書くときに決めた購入率の定義(購入イベント ÷ セッション)です。この定義では、直すべきは定義の言葉の方で、1.83%(2434 ÷ 133368 = 1.825%)は正しい値でした。AI は数字の方を直したため、12 月は「誤って直した」、もともと正しかった 11 月の 1.89% は「余計に直した」と判定しました。

4 分類の結果

種類混ぜた数正しく直した誤って直した見逃した余計に直した
数値22000
増減率22000
順位22000
用語21100
誤りなしの文00001
合計87101

AI の修正 9 件を誤りの種類別に分類した棒グラフ。数値・増減率・順位は 2 件ずつすべて正しく直し、用語は正しく直した 1 件と誤って直した 1 件、誤りを混ぜていない文に余計に直した 1 件があり、見逃しは 0 件

図 2 のとおり、数値・増減率・順位の 6 か所は全部正しく直り、見逃しは 0 件でした。崩れたのは用語の 1 か所で、そこから誤りのない文への修正が 1 件連鎖しました。筆者の計算では、混ぜた 8 か所のうち正しく直ったのは 87.5%(7 ÷ 8)、AI の修正 9 件のうち正しかったのは 77.8%(7 ÷ 9)です。

丸めた正しい記述(約 2.5 万、約 66 ドル)と、カナダとフランスの僅差の比較(+25.671% と +25.617%)は、AI は変えませんでした。

分析レシピ:対応表を機械で当てる手順

今回の手順を、自分のレポートで使える形にまとめます。

対応表の 3 列と検算での使い道。変更前の列は本文に 1 回だけ現れるかの一意性の検査に、変更後の列は SQL の正解との比較に、理由の列は誤りの種類の分類の手がかりに使う

  1. SQL で正解表を作り、レポートと一緒に AI に渡す。
  2. プロンプトで、本文を書き換えず、変更前・変更後・理由の対応表を JSON で返すよう指示する。
  3. 変更前の文字列が本文にちょうど 1 回だけ現れるかを、機械で数える。
  4. 0 回や 2 回以上の行は当てずに、理由と一緒に記録する。
  5. 変更後の数値を、正解表または計算し直した値と 1 件ずつ比べる。
  6. 合った行だけを当て、合わない行は人が判断する。

図 3 のとおり、3 つの列はそれぞれ別の検査に使います。ただし理由の列は、手がかりにとどめるのが安全です。今回、用語の誤りを直した 1 件で、AI の理由は「数値:」で始まっていました。

つまずきやすい点

変更前の指定が曖昧で、複数箇所に当たる

変更前を「前月比」のように短く書くと、本文の何か所にも当たります。試しに「前月比」で数えると、今回のレポートでは 6 回現れ、機械の検査で当てずに止まりました。このサイトの運用でも、記事に 26 回現れる「です」を指定した修正は当てていません。

計算は正しいのに、直す側を取り違える

購入率の 2 件は、割り算としては正しい修正でした。定義の言葉と数字が食い違ったとき、どちらを直すべきかは、表を見ただけでは決まりません。

渡した正解表に購入率の列と定義が無かったことも、原因の一つと考えられます。正解表に「購入率 = 購入イベント ÷ セッション」と定義も書いて渡し、定義を変える修正は人が判断するのが安全です。

「新しい数値」を止める見張りでは足りない

このサイトの運用には、変更後に「変更前にも正解にも無い数値」が出たら当てない仕組みがあります。今回の 9 件に同じ規則を適用すると、誤っていた購入率の 2 件は止まりました。

一方で、正しい増減率の 2 件(+31.3% と +18.5%)も止まりました。増減率は正解表に無い計算値なので、手計算か SQL での検算が必要です。

AI が数字の丸めを「誤り」と言うことがある

今回の 1 回では、AI は丸めた記述を直しませんでした。ただし 1 回の試行なので、丸めを直す修正が出る前提で、正解表に「何桁で丸めるか」を書いておくと判定が速くなります。

図の中の数値は直せない

この方式は本文の文字列だけを置き換えます。グラフの画像に書かれた数値は直せないため、本文を直したら、図の数値とずれていないかを別に確かめる必要があります。

1 回の結果を一般化しない

今回の数字は、モデル 1 種・1 回・レポート 1 本で、誤りの位置を筆者が決めた結果です。また、サンプルデータは難読化されており、内部整合性が若干制限されることがある と説明されています。自社で使う場合は、自分のレポートで数回試してから判断してください。

まとめ

  • AI の修正は、本文ではなく「変更前・変更後・理由」の対応表で受け取ると、1 件ずつ SQL で検算できます。
  • 今回、変更前が 1 回だけあるかの機械の検査は 9 件すべて通りましたが、SQL の正解と筆者が決めた購入率の定義に照らすと 2 件が誤りでした。場所の検査と正しさの検査は別物です。
  • 誤りは定義の言葉と数字が食い違う箇所で起きました。正解表に定義も書き、定義を変える修正は人が判断するのが安全です。

次にやること

月次レポートの数字をどう見せるかを整えたい方は、ダッシュボードのページで、GA4 や BigQuery のデータを見える形にする方法を確認できます。正解表を作る SQL や集計の正しさに不安がある場合は、BigQuery SQL レビューパックも用意しています。

参考にした一次情報