GA4 の数字を文章にした月次レポートを作っていて、AI に誤りを直させたいけれど、数字まで勝手に変えられるのが怖い方向けの記事です。AI に本文を書き換えさせず、「変更前・変更後・理由」の対応表で修正案を出させ、1 件ずつ SQL で検算する手順を、実際に試した結果つきで紹介します。読み終わると、AI の修正のうちどれを信じてよいかを、自分で確かめられるようになります。
この記事で分かること
- AI の修正案を「対応表」で受け取ると、何が良いのか
- 誤りを 8 か所混ぜたレポートを AI に直させたら、何件が正しく、何件が誤りだったか
- 対応表を機械で検査する手順と、それだけでは足りない理由
- 検算でつまずきやすい点(曖昧な指定、定義の取り違え、図の中の数値)
ざっくり言うと:対応表で受け取ると、1 件ずつ SQL で検算できる
AI に修正案を頼むとき、本文を丸ごと返してもらう代わりに、直した箇所だけを表で返してもらいます。表の 1 行が 1 件の修正なので、その行の「変更後」を SQL の正解と比べれば、修正が合っているかを 1 件ずつ判定できます。
今回、AI が返した 9 件の修正は、「変更前の文が本文に 1 回だけあるか」という機械の検査をすべて通りました。ところが、SQL の正解と、筆者が決めた購入率の定義(購入イベント ÷ セッション)に照らすと、2 件は誤った修正でした。
図 1 のとおり、修正を当てる(本文に反映する)前の検査は、「場所」と「正しさ」の 2 段階に分かれます。機械で確かめられるのは場所までで、正しさは正解表と比べないと分かりません。
なぜ本文を丸ごと書き換えさせないか:何が変わったか分からなくなる
AI に「この文章を直して」と頼むと、直した本文が丸ごと返ってきます。20 行のレポートなら、どの行のどの数字が変わったかを、元の文と見比べて探す必要があります。探し漏れがあると、AI が勝手に変えた数字がそのまま上司に届きます。
対応表で返してもらえば、変わった箇所は表の行数と一致します。筆者がこのサイトの運用で試した記録でも、公開記事の定期点検で、修正担当の AI にファイルを直接書かせず、変更前と変更後の一覧を JSON(プログラムで読みやすい文字のデータ形式)で返させ、AI を使わないスクリプトで当てる方式にしています。ある回の点検では、AI の修正 20 件がすべて当たり、当たらなかった修正は 0 件でした。
ただし、その 20 件は日付の表記の統一など文体の修正が中心で、数字の中身を直す修正はありませんでした。そこで今回は、数字の誤りを混ぜたレポートで同じ方式を試しました。
図 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,401 | 79,421 | 2,054 | 144,260 |
| 2020年12月 | 133,368 | 104,315 | 2,434 | 160,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,368 | 133,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 分類の結果
| 種類 | 混ぜた数 | 正しく直した | 誤って直した | 見逃した | 余計に直した |
|---|---|---|---|---|---|
| 数値 | 2 | 2 | 0 | 0 | 0 |
| 増減率 | 2 | 2 | 0 | 0 | 0 |
| 順位 | 2 | 2 | 0 | 0 | 0 |
| 用語 | 2 | 1 | 1 | 0 | 0 |
| 誤りなしの文 | 0 | 0 | 0 | 0 | 1 |
| 合計 | 8 | 7 | 1 | 0 | 1 |
図 2 のとおり、数値・増減率・順位の 6 か所は全部正しく直り、見逃しは 0 件でした。崩れたのは用語の 1 か所で、そこから誤りのない文への修正が 1 件連鎖しました。筆者の計算では、混ぜた 8 か所のうち正しく直ったのは 87.5%(7 ÷ 8)、AI の修正 9 件のうち正しかったのは 77.8%(7 ÷ 9)です。
丸めた正しい記述(約 2.5 万、約 66 ドル)と、カナダとフランスの僅差の比較(+25.671% と +25.617%)は、AI は変えませんでした。
分析レシピ:対応表を機械で当てる手順
今回の手順を、自分のレポートで使える形にまとめます。
- SQL で正解表を作り、レポートと一緒に AI に渡す。
- プロンプトで、本文を書き換えず、変更前・変更後・理由の対応表を JSON で返すよう指示する。
- 変更前の文字列が本文にちょうど 1 回だけ現れるかを、機械で数える。
- 0 回や 2 回以上の行は当てずに、理由と一緒に記録する。
- 変更後の数値を、正解表または計算し直した値と 1 件ずつ比べる。
- 合った行だけを当て、合わない行は人が判断する。
図 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 レビューパックも用意しています。