kaedeasset記事 · Notes霧走町 流氷に眠る

通じ率 23% が、一晩で 100% になった。測っていたのは自分の写経だった

Comprehension went from 23% to 100% overnight: we were measuring our own copying

 D25-4-T50-goodhart-23-to-100・技術・日本語入力でプレイする仕組み

失敗の名前Goodhart's lawtest-set contaminationCampbell's law(触れるだけ)claude自然言語処理

本筋の外の問いに、町の人がまともに答えた割合。
8 月 4 日に測ると 23% でした。
翌朝には 100% になっていました。
照合は何も賢くなっていません。
落ちた問いの文を、そのまま言い換えの辞書に写しただけです。

この回の位置と、前後の回#

区切り: T50〜T57 失敗の名前(8 回のうち 1 回目)
先に読むとよい回: T42(holdout を見た回数で数える)
次に読む回: T51(代わりの指標を目的と取り違える)

名前 — Goodhart's law#

正式名
Goodhart's law
日本語
グッドハートの法則
初出
C. A. E. Goodhart, "Problems of Monetary Management: The U.K. Experience", 1975(Reserve Bank of Australia の会議で発表。Papers in Monetary Economics vol. 1)
よく引かれる言い回し
Marilyn Strathern, "'Improving ratings': audit in the British University system", European Review 5(3), 1997
組で起きたもの
test-set contamination(評価データの汚染。語の初出は確かめられませんでした)

Goodhart's law とは#

もとは金融政策の話です。
Goodhart の 1975 年の言い方は、おおよそこうです。
「観測された統計的な規則性は、統制の目的で圧力をかけると崩れる」。
マネーサプライと景気のあいだに安定した関係が見えていても、
中央銀行がその量を目標にした途端、その関係は消える、という観察でした。

いま広く知られている形は、Strathern が 1997 年に大学の評価制度を論じた論文の一文です。
"When a measure becomes a target, it ceases to be a good measure."
指標が目標になると、良い指標ではなくなる。
Strathern 自身は、これを Hoskin の言い方として引いています。
名前は Goodhart、言い回しは Strathern、という分担で覚えておくと検索で迷いません。
社会政策の側には、ほぼ同じ観察に Campbell's law という別の名前があります。

仕組みは単純です。
指標は、目的の一部を切り取ったものです。
指標そのものを上げにいくと、切り取られなかった部分を犠牲にして、指標だけが上がります。

機械学習の評価では、これが評価データの汚染として現れます。
評価に使う文が、学習や調整の側に入り込む。
すると評価は「未知の入力でどれだけできるか」ではなく、
「見たことのある入力をどれだけ覚えているか」を測るようになります。
大きな言語モデルの評価でも、ベンチマークの問題が学習データに混ざっていないかを、
n-gram の重なりで調べるのが定番になっています(この検出の仕組みは T43 で書きます)。

既にある対処は、大きく 3 つです。

  • 評価に使う文を、調整に使う側から機械で隔てる(重なりの検出)
  • 評価の組を、見たら使い切りにする(T42 の holdout の運用)
  • 指標を 1 つにしない(ほかの指標と組にして、片方だけ上がる動きを見つける)

うちで起きたこと — Goodhart's law#

指標は「応答率」です。
本筋から外れた問い(宿のこと、天気のこと、町のこと)に、意味のある返事が返る割合。
推理アドベンチャーで日本語入力を使う以上、寄り道しても町が黙らないことは大事です。

2026-08-04、設計書(Docs/Reports/2026/08/04/17)がこの指標を置きました。
本筋外の入力 30 手で測って、7 手。23% です。
目標は 80% 以上。
そして設計書の §3.2 には、こう書いてありました。
「30 手のプローブで落ちた 13 件が、そのまま最初の追加リストになる」。

開発の AI(Claude Code)は、その指示どおりに作業しました。
落ちた手を言い換えの辞書に足しました。
足した言い換えの中に、プローブの文そのものが入っていました。
写した文は照合で当然ほぼ満点になるので、固定プローブの応答率は 28 手のうち 28 手。100% です。
そのあと雑談と調べる意図をさらに増やし、意図は 72 本から 100 本になりました。

翌 2026-08-05 の報告(08/05/01 §3)が、これを自分で崩しました。
同じ話題を別の言い回しで書いたプローブ、まったく新しい話題で書いたプローブを足して測ったのです。

  • 固定プローブ(落ちた文を辞書に写した) 28/28 = 100%
  • 同じ話題を別の言い回しで新しく書いたもの 22/28 = 79%(直したあと 28/28。直すのに使ったので、これも使い切り)
  • 未知の話題で新しく書き、1 回だけ測ったもの(sealed) 6/28 = 21%
  • 意図を 100 本に増やした後に新しく書いたもの(sealed2) 5/28 = 18%

意図を 39% 増やして、未知の入力への応答率は 21% から 18%。
上がったのは、そのつど「測った文を書き足したプローブ」の数字だけでした。
報告の言葉では「測っているのは自分の写経である」。

sealed2 で落ちた手は、こういう問いでした。
「布団は自分で敷くんですか」「バスは一日に何本来るんです」「この辺りに熊は出るのか」「救急車は呼べるんですか」。
どれも自然で、どれも辞書に書いていない。
話題を 1 つ書き足すとプローブの 1 手は通るが、隣の未知の 1 手には効かない。
この尾は、書き足しでは尽きません。

その日の commit(5a87c715)の本文の最後に、作業した AI の一言が残っています。
「指標が全部緑なのに、新しく書いたプローブを流したら 21% だったときは血の気が引いた」。

ここで言っておきたいのは、誰かがずるをしたわけではない、ということです。
設計書は「落ちた手を追加リストにする」と書きました。
それ自体はふつうの改善の進め方です。
ただ、落ちた手の「話題」を足すのか、「文」を足すのかが書いていなかった。
そして測る側の文と、直す側の辞書のあいだに、仕切りがありませんでした。
指標が目標になった瞬間に、指標を上げるいちばん近い道が、写すことだったのです。

直したこと#

同じ日の深夜、2026-08-05 01:09 の commit(bdea96eb)で、lint に L18 を足しました。
プローブの各行と、言い換えの辞書の全文を、文字 3-gram の集合にして Jaccard 係数を取り、0.8 以上なら error にします。
正規化は照合の核と同じ関数を使います(別に書くと、核の正規化を変えたときに検出だけが静かにずれるため)。

ソースの注記は、いまもこう書いてあります(Tools/adv-sim/main.cpp)。

// L4 と同じ検査をプレイ評価のプローブにも掛ける。これが無いと、落ちた手の文を
// 言い換え辞書へ写すだけで応答率が上がってしまう。
2026-08-05 に実際にそれをやって
// 23%→100% を作ってしまった(08/05/01)。golden だけ守っても、測る側が別にあれば
// 抜け道はそちらに移るだけなので、サンプルは全部同じ規則で守る。

導入した時点で、その日の書き写し 42 件をすべて検出しました(bdea96eb の本文)。
golden(凍結した問いと正解の組)には L4 という同じ検査が前からありました。
抜け道は、守っていない側のプローブに移っていただけでした。

使い切ったプローブは probes-archive/ へ退避します。
L18 はサブフォルダを見ないので、退避したものは、もう辞書と比べられません。
「見たものは捨てる」が、置き場所で強制される形です。

もう 1 つは、改善の手の向きを変えたことです。
2026-08-05 の残りの作業は、文ではなく話題で直しました。
世界に無かった話題(布団・医者・バス・器・熊・救急車)を、話題ごとに雑談の意図として足す。
そして裏取りに、まだ誰も見ていない sealed3・sealed4 を新しく書き起こして、触る前の値を取りました(08/05/04)。
sealed3 は 23.1% から、そのプローブに触る前の時点で 69.2%。
見ていない文への改善なので、こちらは汎化の証拠として読めます。

ループのスクリプト(Scripts/adv-loop.ps1)は、FAIL のたびに直し方の規約を出します。

直し方の規約(これを外すとループが計測を騙しにいく):

  • プローブの文を言い換え辞書に写さない。写すと L18 が落とす
  • 直すのは一般化された側(辞書・材料条件・段の設計・専用応答)。個別の1文に合わせない

8 月 17 日には、別の道具でも同じ判断をしています。
動詞と言い方の展開表から 194 通りの問いを作ると、194 全部が狙った意図に着地した。
ここで生成した文を辞書へ書き写すと、検査が「同じ文があるか」を測るだけの同語反復になる。
だから展開表は辞書を増やす道具ではなく、測る道具のままにする(08/17/03)。

今日の値(10/29) — Goodhart's law#

lint は 0 error。L18 の行は出ていません。
封印プローブ 3 本は、それぞれ 84.0%・88.5%・92.3%。連続で通じなかった手は最大 2、誤って推理が進んだ手(LEAK)は 0。
合格線(応答率 60% 以上・連続 2 以下・LEAK 0)は 3 本とも越えています。

名前どおりでない所・まだ残っている弱さ — Goodhart's law#

Goodhart's law は、名前どおりに踏みました。
指標(応答率)を目標にして、指標だけが上がった。
test-set contamination も名前どおりです。評価の文が、調整の側のデータに入りました。

ただ、残っている弱さが 3 つあります。

一つ目、L18 は文字の重なりしか見ません。
プローブを読んで「この話題が無いな」と思って、その話題の意図を足すのは、L18 から見えません。
2026-08-05 に、まさにそれを正しい直し方として採りました。
話題を足すのは汎化、文を写すのは汚染、という線は人の判断です。
話題を足したあとに同じプローブで測った数字は、もう未知の入力の数字ではありません。

二つ目、封印プローブが封印ではなくなっています。
3 本とも、毎周のループ(adv-loop.ps1)で回る回帰テストに入っています。
sealed2 は 2026-08-05 に「直しながら見た」と記録されていて、その時点で封印としては使い切りです。
今日の 3 本の値は「雑談の下限が崩れていないか」の回帰の見張りとしては有効ですが、
汎化の証拠としては読めません。
名前を付け直していないので、名前だけが当時の意味を残しています。

三つ目、23% と 100% は、母数の違う 2 つの数字です。
23% は 8 月 4 日の 30 手、100% は 8 月 5 日の 28 手のプローブ。
うちの文書は「23%→100%」と一続きに書いてきました。
失敗の形を覚えておく言い方としては便利ですが、比べてよい 2 つの数字ではありません。

検索語#

Goodhart's law
"When a measure becomes a target"
test set contamination n-gram overlap
benchmark data contamination detection

町の人は、事件と関係ない問いにも答えます。布団のことでも、バスのことでも。辞書に無い言い方で、『霧走町 流氷に眠る』の第一章をブラウザで試してみてください。プロフィールのリンクから。

#claude #自然言語処理