M.

claude -p を評価器にして、AI の生成結果を930件自動採点した

Chord Eureka は、キーワードからコード進行を作る Web アプリです。画面には「切ない」「ジャジー」「セカンダリードミナント」のようなキーワードのボタンが69個並んでいて、押すとそのキーワードで生成できます。

あるとき、ふと疑問に思いました。このボタン、本当に全部効いているのだろうか。「ノスタルジック」と「優しい」で、出てくる進行は本当に違うのか。押しても何も変わらないボタンがあるなら、消したほうが画面がすっきりします。

確かめるには、キーワードごとに何回も生成して比べるしかありません。そこで、Claude Code の claude -p を生成器にして930件を作り、プログラムで採点しました。その方法をまとめます。

※ Chord Eureka のリポジトリは非公開なので、ソースは載せず、手法として書きます。

なぜ API ではなく claude -p なのか

本番のアプリは Claude API を呼んでいます。同じことを930回やると、そのぶん API の料金がかかります。

claude -p(Claude Code の非対話モード)なら、Claude Code のサブスクリプションの枠の中で 生成できます。プロンプトを渡すと結果を出力して終わるので、スクリプトから何百回でも呼べます。

ただし、claude -p は API と同じではありません。Claude Code 自身のシステムプロンプトや設定が乗るからです。そこで、できるだけ本番の API 呼び出しに近づけるオプションを付けました。

本番に近づけるためのオプション

1回の生成は、次のような引数で claude を起動しています。

claude -p \
  --model claude-sonnet-5-5 --effort medium \
  --system-prompt "<本番と同じシステムプロンプト>" \
  --json-schema '<本番と同じ JSON スキーマ>' \
  --output-format json \
  --tools "" --strict-mcp-config --setting-sources "" \
  --disable-slash-commands --no-session-persistence

それぞれの役割は次のとおりです。

オプション目的
--model / --effort本番と同じモデル・思考量にする
--system-promptClaude Code の既定のシステムプロンプトを、本番のものに置き換える
--json-schema本番と同じ構造化出力にする。結果は JSON の structured_output に入る
--output-format json結果を JSON で受け取る。トークン数(usage)も取れる
--tools ""ファイル操作などのツールを使わせない。コード進行を答えるだけなので要らない
--strict-mcp-config自分の環境の MCP サーバーを読み込まない
--setting-sources ""~/.claude やプロジェクトの設定(CLAUDE.md・hooks など)を読み込まない
--disable-slash-commandsスキルやスラッシュコマンドを無効にする
--no-session-persistence930件分の会話ログを残さない

ポイントは、普段の開発用の設定を全部切る ことです。グローバルの CLAUDE.md には「日本語で答える」「キャラクターになりきる」のような指示が書いてあるので(設定ツアー参照)、そのまま読ませると生成結果に混ざりかねません。

それでも、本番と完全には一致しません。入力トークンには Claude Code の分が上乗せされますし、内部の呼び出し方も違います。なので、この測定は 「本番の傾向の近似」 として扱うことにしました。

Windows では .cmd を経由しない

Windows でひとつハマりました。npm で入れた claude は、実体が claude.cmd というラッパーです。Node.js から shell: true で呼ぶと、cmd.exe を経由するので システムプロンプトの改行や引用符が崩れます。

対策として、ラッパーの場所から本体の claude.exe を探し、シェルを通さずに直接起動しました。ユーザープロンプトは引数ではなく標準入力から渡しています。改行を含む長い文字列は、引数よりも標準入力のほうが安全です。

(今はネイティブ版の Claude Code に移行したので、ラッパーの問題自体がなくなっています。)

中断しても続きから再開できるようにする

930件となると、途中で止まることもあります。利用上限に当たる、PC がスリープする、などです。

そこで、結果は1件ごとに JSONL(1行1件の JSON)へ追記し、起動時にはファイルを読んで 成功済みの(キーワード, 回)を飛ばす ようにしました。止まっても同じコマンドを打ち直せば、続きから始まります。最初から失敗が5件続いたとき(たいてい利用上限です)は、自分で止まるようにもしています。

並列数は3にしました。結果として、930件は 約40分で、失敗0件 で終わりました。1件あたりの応答時間は中央値で約7秒です。

何を生成したか

  • 既存のキーワード69語 + 追加を検討していた候補23語
  • ベースライン(キーワード無し)
  • それぞれ10回ずつ、8小節で生成 → 計930件

一番大事なのはベースラインです。「キーワードが効いている」とは、キーワード無しのときと比べて出力が変わっている ということだからです。比べる基準がないと、「ジャジーで7thが多い」が、キーワードのおかげなのか、もともと7thが多いだけなのか分かりません。

採点は AI にさせない

生成した進行の採点は、AI ではなく プログラムで しました。

Chord Eureka には、もともと進行を分析する機能があります。キーの推定、各コードの機能(トニック・ドミナントなど)、進行名の判定、珍しさのスコアです。これらは AI ではなく決まったロジックで計算しているので、同じ進行なら何度やっても同じ結果になります。この分析をそのまま採点に使いました。

AI に「この進行は『切ない』らしいですか?」と聞く方法もありますが、採点自体がぶれますし、930件分の料金や時間もかかります。測る側は決定的にしておく ほうが、結果を信用できます。

指標1:ベースラインからの距離

1回の生成ごとに、13の特徴を数えます。

  • 7th コードの割合、テンション(9th 以上)の割合、分数コードの割合
  • sus・dim・aug の割合
  • キーから外れたコードの割合、セカンダリードミナントやサブドミナントマイナーの割合
  • 短調で始まるか、キーが C 以外か、有名な進行名が含まれるか
  • 珍しさのスコア

キーワードごとに10回の平均を取り、ベースラインとの距離を出します。特徴ごとに単位がばらばらなので、各特徴を「語どうしのばらつき(標準偏差)」で割ってから距離を測りました。距離が大きいほど、そのキーワードが出力を変えている ということです。

指標2:遵守率(理論用語のキーワード)

「ツーファイブ」「偽終止」「ペダルポイント」のような理論用語は、入っているかどうかを判定できます。そこで、語ごとに判定ルールを書きました。

  • ツーファイブ:マイナーのコードから、4度上のメジャーかセブンスのコードへ進む箇所がある
  • 偽終止:V(または V7)から VIm へ進む箇所がある
  • ペダルポイント:同じベース音が3つ以上続き、上のコードは変わっている

10回のうちルールを満たした割合が遵守率です。

分かったこと

システムプロンプトのくせが一番強かった

まず驚いたのはベースラインです。キーワード無しで生成すると、7th コードが99%、キーは100% C でした。

システムプロンプトに「テンションや7thも使って豊かに」という趣旨の指示があり、それが強く効いていたのです。7th を外せたのは「明るい」「ポップ」「シンプル」「ロック」のような語だけでした。キーワードの効き目を測るつもりが、先にプロンプト自体のくせが見えました。

効いていないボタンがあった

距離が小さく、ほぼベースラインと同じ出力になる語がありました。

語距離
神聖な1.24
ノスタルジック1.78
ロマンチック1.86
優しい1.98

一番効きが強い「オーギュメントコード」「無機質」は 9.5 前後なので、かなり小さい値です。

逆に、同じカテゴリでほぼ同じ出力になる語の組 も見つかりました。「希望に満ちた」と「壮大」(距離0.77)、「切ない」と「哀愁」(1.17)などです。

判断は人がする

数字が出たら、あとは自分で決めました。

  • 削除(6語):効きの弱い語と、ほぼ同じ出力の組の片方
  • 追加(5語):候補23語のうち、効いていて既存と被らないもの(サブドミナントマイナー・半音進行・偽終止・疾走感・フォーク)
  • 補強(1語):「神聖な」はプロンプトに語の意味(sus・プラガル終止など)を補足した。再測定すると距離は 1.24 → 3.26 になり、7th の割合も84% → 30% に下がった

距離が小さくても、その言葉で押したい人がいる語は残す、という判断もありえます。「ジャンル名として検索される語は残す」なども、数字だけでは決められません。測定は判断材料を出すところまで で、決めるのは自分です。

注意したこと

  • 1語10件はノイズが大きい:距離1.5未満の差は誤差かもしれない、と割り切って読みました。差が小さいものの判断は保留寄りにしています
  • 判定ルールの厳しさで遵守率が変わる:「循環コード」の遵守率は40%でしたが、ルールを「前半4つと後半4つのルートが同じ」と厳しめにしたせいもあります。低い遵守率は、AI のせいかルールのせいかを確かめてから扱いました
  • あくまで近似:本番は API、測定は claude -p なので、細かい数字の差には意味を持たせすぎないようにしました

同じ仕組みで、モデルの比較もできた

この仕組みは一度作ると使い回せます。10月に新しいモデル(Sonnet 5.5)が出たときは、モデルと思考量を引数で切り替えられるようにして、旧モデルと比べました。応答の速さ、出力トークン、そして「同じキーワードで同じ進行が出ていないか」まで、同じ集計で並べられます。

その結果どうなったかは、AI コード進行アプリを2年運用して分かったこと に書きました。

生成 AI を使ったアプリは、プロンプトやモデルを変えたときに 良くなったのか悪くなったのか が分かりにくいものです。claude -p で数をこなし、採点はプログラムでする。この組み合わせで、手元のサブスクリプションの範囲で、数字を見ながら判断できるようになりました。

この記事をシェア

「Chord Eureka」の記事(4件)

  1. コード進行アプリの楽譜表示を自作した(大譜表・コード名どおりの綴り・転調で調号を変える)
  2. コード進行アプリにボイシングのプリセットを10種類足した(Drop 2・シェル・4度堆積など。既定の音は1バイトも変えない)
  3. AI コード進行アプリを2年運用して分かったこと(GPT-4o から Claude へ、2024→2026)
  4. ▶ claude -p を評価器にして、AI の生成結果を930件自動採点した

関連する記事

Claude Code に GCP の課金を棚卸しさせたら、月1万円が半分になった(失敗込みの記録)

個人開発で使っている GCP の全プロジェクトを、Claude Code と一緒に横断して見直しました。gcloud での調査、ストレージの掃除、通信料の削減、そして CUD の二重契約という失敗まで。AI に任せられたこと・人間がやる必要があったことを整理します。

Claude に「敵対的レビュー」をさせて、指摘がどれくらい当たっていたかを数えた

個人開発では、Claude Code に「壊れるところを探して」と頼む敵対的レビューを何度も使っています。4つのリポジトリに残っていた再検証の記録から、指摘がどれくらい当たり、どう外れていたかを数えました。外れ方には決まった型がありました。

Claude Code 向けのドキュメントは3つに分ける(CLAUDE.md はルール、README はセットアップ、PROGRESS.md は次にやること)

Claude Code に任せて開発していると、CLAUDE.md・README・PROGRESS.md が同じ説明で膨らんでいきます。個人開発のリポジトリで役割を分け直したら、CLAUDE.md は117行から50行、README は172行から35行になりました。分け方と、書かないことにしたものをまとめます。

GCP の予算アラートで Cloud Run の GPU だけを自動停止する(maxInstanceCount: 0 では止まらなかった)

画像生成アプリの GPU 費用が予算を超えないよう、予算アラート → Pub/Sub → Cloud Functions で GPU ワーカーだけを止める仕組みを作りました。Cloud Run の設定を書き換える方式は効かず、GCS のフラグファイル方式に変えた経緯と、段階導入・90%しきい値の理由をまとめます。

テーマから探す