🔁

プロンプトの再現性をAI に自動チューニングさせる方法 ~ 暗黙知を排除する

に公開

AI の技術記事は食傷気味なんですが、さすがにこれは効くと思ったパターンを見つけたので紹介します。

tl;dr

  • プロンプト (skill / slash command) を書いた直後は「これで伝わるはず!」と思うのに、別のセッションで使うと暗黙知が不足していて、再現性がなくなる
  • 思い込みは当人に修正できないバイアスなので、別の AI に実際にやらせて詰まった箇所をレポートさせる
  • これを繰り返す。プロンプトが段階的に洗練される (TDD のテストと同じ位置づけ)

実際に手元 8 個の skill で試して、初稿 50 点が (AI 主観で) 80〜90 点まで上がった。ただし、モデルを変えての評価してないので、過剰に適応している可能性はある。

自分が書いたプロンプトを評価していますか?

自分は大学時代に暗黙知の研究をしていたのだが、世の人々は主観バイアスを過小評価している。また、AIは人間よりもバイアスの塊である。

プロンプトを書いた直後は「これでだいたい伝わるはず」と思うのだが、書いた直後の自分が一番ダメな読者 で、頭の中の前提を勝手に補って読んでしまう。別の AI セッションで使うと「判断基準が曖昧」「用語が定義されてない」みたいなのが普通に出てくる。これは書き手側で潰せない。(一晩寝かせて読み直すと直せる時もあるが...)

プロンプトの可読性は、それを使う AI に検証させて、修正ループを回すのが良い。

自己再読でも他人に読んでもらうのでもなく、実際に使う側に動かしてもらう。TDD で production code を最終的にテストで判定するのと同じ構造で、プロンプトの判定基準を持てるのは使う AI 自身だけ。

アプローチ: 別 AI にやらせて両面評価する

前提: Claude Code (2025 年以降の版、Claude Opus 4.7 で動作確認)、Task tool が利用可 (デフォルトで使えるはず)。Task tool は Claude Code の組み込み機能で、Task(description, prompt, subagent_type) の形で別 subagent を起動して結果を受け取れる。

実装は Claude Code の Task tool で別 subagent を立てる形だが、別セッションを別ターミナルで起動するでも、別 AI に投げるでも構造は同じ。書いた本人と判定者を完全に分離するのがポイント。

評価は 2 面取る:

  • 自己申告: 実行 AI 自身に「不明瞭点」「裁量で補完した箇所」「再試行回数」を箇条書きでレポートさせる
  • 指示側計測: 使ったツール数 / 所要時間 / 要件チェックリストの達成率を機械的に拾う

要件チェックリストには [critical] タグを最低 1 つ付ける。critical 全部 ○ で初めて成功扱い。これがないと「全部 50% 達成」みたいなぼやけた成功判定になって、次にどこを直せばいいかわからない。

実行 AI に渡すプロンプトのテンプレ

あなたは <対象プロンプト名> を白紙で読む実行者です。

## 対象プロンプト
<プロンプト本文 or ファイルパス>

## シナリオ
<状況設定 1 段落>

## 要件チェックリスト
1. [critical] <最低ライン項目>
2. <通常項目>
...

## タスク
1. 対象プロンプトに従ってシナリオを実行し、成果物を生成
2. 終了時に下記レポート構造で返答

## レポート構造
- 成果物: <生成物 or 実行結果サマリ>
- 要件達成: 各項目について ○ / × / 部分的(理由付き)
- 不明瞭点: 詰まった箇所、解釈に迷った文言(箇条書き)
- 裁量補完: 指示で決まっておらず自分の判断で埋めた箇所(箇条書き)
- 再試行: 同じ判断をやり直した回数とその理由

シナリオは「典型 (median) 1 個 + 端 (edge) 1〜2 個」で計 2〜3 個。並列で投げるとシュッと 1〜2 分で全部返ってくる。

実際のレポートが返ってくる

抽象的に書いても伝わりにくいので、実際のループを 1 回ぶん見せる。conventional-changelog skill (Conventional Commits + CHANGELOG 自動生成) を書いて、シナリオ A「TS ライブラリの初回 release-please 導入」を投げた時の subagent レポート抜粋:

成果物: commit 例 3 本 + release-please-config.json + manifest + workflow.yml

要件達成:
1. [critical] commit 構文の例示: ○
2. [critical] config + manifest + workflow の 3 点セット: ○
3. [critical] 初回 v0.1.0 を切る manifest 初期値: ○ (0.0.0 + bump-minor-pre-major で成立)
4. fix→patch / feat→minor / BREAKING→major: ○
5. CHANGELOG 自動生成: ○
6. 既存 ad-hoc commit の扱い: ○

不明瞭点:
- publish workflow を release-please と同一にするか別 workflow にするか skill 内で一意に決まらない
- bump-patch-for-minor-pre-major を入れるべきか記述なし
- npm provenance (id-token: write) まで含めるか不明

裁量補完:
- Node.js を 24 で固定、workflow 名を release.yml に
- --provenance --access public を採用 (OSS 前提)
- 運用手順を 5 行で構成

要件は全部通ってるが、不明瞭点 3 件が「自分で勝手に判断した」と申告されている。

このうち「publish workflow を同一/別どちらにするか」を skill 本文に「同一/別の比較表 + 選択指針」として追記して再評価したら、次の反復で subagent が「比較表に基づき同一 workflow を採用」と明記してくれて、この不明瞭点は消えた。これを各シナリオの不明瞭点に対して順次やる。

プロンプト再現のワークフロー

skill を ~/.claude/skills/<name>/SKILL.md に配置 (frontmatter の name / description が必須)、Claude Code セッションで評価を依頼する:

# 配置
mkdir -p ~/.claude/skills/foo/
cat > ~/.claude/skills/foo/SKILL.md <<'EOF'
---
name: foo
description: いつ使うかの説明
---
# Foo
本文...
EOF

# Claude Code を起動して依頼
$ claude
> ~/.claude/skills/foo/SKILL.md をシナリオ A/B/C で subagent 3 並列評価。
> 不明瞭点・裁量補完・要件達成 ○×・再試行回数をレポートさせて

Claude が skill を invoke + Task tool で dispatch、戻り値の <usage> から tool_uses / duration_ms を拾う。あとはこの繰り返し:

  1. シナリオと要件チェックリストを固定して、別 AI を並列 dispatch
  2. レポートから不明瞭点を 1 つ拾って最小修正 (1 反復 1 テーマ)
  3. 必ず新しい AI で再実行。連続 2 回で「新規不明瞭点ゼロ + 精度の伸びが頭打ち」になったら停止

事前チェックとして、frontmatter の description が謳う範囲と本文がカバーする範囲がずれてないかは静的に揃える。これを飛ばすと subagent が description に合わせて本文を「再解釈」して、欠けてる skill が偽通過する。

よくある失敗と対処:

  • Task tool が dispatch されない → 依頼プロンプトに「Task tool を使って subagent を起動して」と明示する。Claude が本文だけ読んで自分で答えるパターン
  • subagent のレポートに <usage> が出ない → dispatch 時のプロンプトに「終了時に成果物・要件達成・不明瞭点・裁量補完・再試行を含めて返答してください」と構造を強制
  • 並列でレートリミット (529 / overloaded) → 並列度を 3 → 1 に落として直列化、または 30 秒待って再 dispatch
  • 親 context の token が枯渇 → 別セッションを新規起動して評価専用にする (skill 評価は会話履歴に依存しないので分離可能)

一番大事なのは再現性

このワークフロー全体は「プロンプトの品質評価で一番大事なのは再現性」という前提から設計してる。

  • シナリオは事前に固定 — 後から動かすと、不明瞭点が潰れたように見せかけられる
  • 毎回新規 AI dispatch — 使い回すと前回の指摘を学習してて当然次は通る、指標が腐る
  • ツール数 / 所要時間は usage メタから機械的に取る — Claude Code の場合、Task tool の戻り値に <usage>total_tokens: N, tool_uses: M, duration_ms: D</usage> が付いてくるのでそれを拾う。「速くなった気がする」では再評価できない
  • hold-out シナリオ — 調整に使ってない新シナリオで過適合を弾く

これを徹底しないと、反復してるのが本当に改善なのか自分の願望なのかわからなくなる。

具体例: conventional-changelog を 4 反復で底上げ

Conventional Commits + CHANGELOG 自動生成の skill を書いて 4 回反復した。シナリオは TS ライブラリ初回導入 (median)、pnpm monorepo + workspace:* (edge)、Rust crate + git-cliff + cargo-release (hold-out) の 3 つ。

A 精度 B 精度 C 精度 主な修正
1 90% 70% 初稿
2 100% 85% pre-release / monorepo / git-cliff 詳細
3 100% 100% 100% なし (hold-out 投入)
4 100% 100% 100% publish workflow 比較 / cargo-release hook

3 回目で hold-out C を投入して 100% だったので過適合なし。4 回目で出た新規不明瞭点は全部「より細かい usage tip 不在」レベルだったので 80 点超えで止めた。

参考までに、シナリオ A で生成された成果物のうち release-please-config.json 最小例:

{
  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
  "release-type": "node",
  "packages": {
    ".": { "package-name": "foo-utils", "changelog-path": "CHANGELOG.md" }
  },
  "include-v-in-tag": true,
  "bump-minor-pre-major": true
}

.release-please-manifest.json{ ".": "0.0.0" } で初期化、最初の feat: commit で v0.1.0 が切れる。完全な 3 点セット (config + manifest + workflow.yml) は conventional-changelog skill 本体 を参照。

tool_uses は全反復で 1〜3 で安定。これは skill が自己完結してて、実行 AI が references/ を漁る必要がなかったということ。

学び: tool_uses で構造的欠陥がわかる

補足: skill は ~/.claude/skills/<name>/SKILL.md 本体に加えて、任意で references/*.md を同じディレクトリに置ける。本体には index 的な記述だけ書いて、詳細を references/foo.md に分けると、Claude が必要な時だけ Read で参照する。本体の肥大化を避けるための仕組み。

精度だけ見てると、プロンプトの構造的な問題が隠れる。シナリオ間で tool_uses を比べて、4 つは 1〜3 なのに 1 つだけ 15+ なら、そのプロンプトは decision-tree index 寄りで自己完結性が低いサイン。実行 AI がそのシナリオ用の recipe を references/ から探し回ってる。

精度が 100% でも、本文に「最小完成例 inline」や「いつ references を読むかの指針」を追加すると tool_uses は 15 → 3 みたいに落ちる。精度だけ追ってるとわからない構造的な穴で、tool_uses を見ると早めに気付く。

誤差逆伝搬で考える: 収束 / 発散 / 打ち切り

収束 (停止): 連続 2 回で「新規不明瞭点 0 / 精度 ≤+3pt / steps ±10% / duration ±15%」、加えて hold-out シナリオで直近平均から 15pt 以上落ちなければ過適合なしと判定。

発散: 3 回以上反復しても新規不明瞭点が減らないなら、プロンプトの設計方針自体が間違ってる。修正パッチで直すのをやめて構造を書き直す。

打ち切り: 重要度と改善コストが釣り合わなくなったら止める。conventional-changelog の 4 回目がまさにこれ。

落とし穴

何回かハマった話。

序盤、シナリオが甘い反復で「全部 100%」と出て歓喜したが、別セッションで使ったら普通に詰まった。シナリオが本文の説明範囲をなぞってるだけでエッジケースを含んでなかった。それ以来 median 1 + edge 1〜2 を最低条件にしてる。

「同じ AI を使い回す」もやらかした。SendMessage で続行した方が文脈効率いいだろと思ったら、前回の指摘を全部学習してるのでそりゃ通る。改善した気分だけが残る。毎回新規 dispatch が正解。

「メトリクスだけ見て反復を進める」も罠で、実行時間が短くなった嬉しいと思ってたら本文がどんどん削れて、別 AI で測ったら精度が下がってた。プロンプトが痩せすぎ。質的フィードバック (不明瞭点 / 裁量補完) が主、量的は補助。

あと 1 反復で複数修正を一気に入れると何が効いたか追えなくなるのと、シナリオを後から修正に合わせてチューニングするやつ (不明瞭点が潰れたように見せたくなる) は本末転倒なので絶対やらない。

有効性のレンジ

8 個の skill (gh-fix-ci, nix-setup, playwright-test, chezmoi-management, cloudflare-deploy, apm-usage, gleam-practice, conventional-changelog) で試して、全部 2〜4 回反復で 50 点 → 80〜90 点に底上げできた。各 skill の本文を読めば追試可能。

体感、50 → 80 が一番効く。1〜2 回で目に見えて改善する。80 → 90 もまだ効くが 2〜3 回かかる。90 → 100 は効果が頭打ちで明確にやめどき。逆に設計方針自体が間違ってるプロンプトはパッチでは直らないので書き直し。一回限りの使い捨てや、書き手の主観的好みを反映したいだけのケースは適用しない。

実装上の注意

別 AI dispatch ができない環境では適用できない。代替は「別セッションを起動してもらう」か「評価そのものをスキップして明示報告」のどちらか。自己再読で代替するのはダメ (バイアスが入る)。あと並列 dispatch は親の文脈をちゃんと食う (3 並列で各 30k token くらい)。重いプロンプトの評価は別セッションでやった方がいい。

おわり

このループで書いてると、初稿で「だいたい伝わる気がする」と思ったプロンプトが実際は普通に詰まることを毎回確認する。経験で直感が育てばループが要らなくなるかと思ったが、書く量が増えるほど逆に自己評価のバイアスが強くなってる気がする。

skill 化したものは empirical-prompt-tuning/SKILL.md にある。Claude Code 前提だが、両面評価のテンプレ自体は他にも持っていけそう。

反復数をもう少し減らしたいのと、評価シナリオの初期設計をもうちょい体系化できないかは課題。誰かが似たことやってたら教えてほしい。


おまけ: この記事自体をループに通している

書いた後で、ここで紹介した手法を記事自体に適用してみる。tech-article-reproducibility という別の skill を作って、「Claude Code は名前を聞いた程度の読者」をロールプレイする subagent に「手元で再現できますか」を判定させる。

以下は実行例

反復 1: ベースライン

主因
環境前提 0 Claude Code version / Task tool 前提なし
コード完全性 1 プロンプトテンプレは完成形だが Task 呼び出し例なし
コマンド正確性 0 実行コマンドが一切書かれてない
バージョン依存 0 CC / SDK のバージョン記載なし
設定ファイル 0 .claude/settings.json / skill frontmatter 例なし
期待出力 1 レポート抜粋はあるが usage メタの取得方法なし
エラー対処 0 失敗パスへの言及なし
プロジェクト前提 1 skill ディレクトリ構造が暗黙
リンク健全性 2 chezmoi-dotfiles 生存確認
著者依存知識 1 8 個の skill 名は読者は持ってない
合計 6/20 再現困難ゾーン

これは想定内でもある。この記事は思想紹介として書いたので、ハンズオン軸では足りない情報が多い。思想 80 点 / 再現性 30 点 で出てきた。

ここから、subagent の指摘に答える形で記事を実際に改善していく (この節自体が修正ループの可視化になる)。

反復 2: 環境前提とリンク強化

修正:

  • アプローチ節の冒頭に「前提: Claude Code (2025 年以降の版)、Task tool が利用可」+ Task tool シグネチャを 2 行追加
  • 末尾の chezmoi-dotfiles リンクを empirical-prompt-tuning/SKILL.md への直リンクに変更

再評価結果: 6 → 9/20 (+3pt)。軸 1「環境前提」と軸 4「バージョン依存」が 0 → 1。副作用なし (他軸の劣化ゼロ)。

subagent が次に潰すべきと指摘した最優先の穴:

  • L111 / L133 で tool_uses を「比べて」と書いてるが、どこから取得するか書いてない。Claude Code transcript? Task レスポンス? OpenTelemetry? メトリクスが手元で取れない限り「打ち切り判定」も「構造的欠陥検出」も実行不能。再現性の核。修正は 1 行で +2pt 見込み。

反復 3: メトリクス取得経路の明示

修正:

  • L111 「ツール数 / 所要時間は usage メタから機械的に取る」に「Claude Code の場合、Task tool の戻り値に <usage>total_tokens: N, tool_uses: M, duration_ms: D</usage> が付いてくるのでそれを拾う」を追記

再評価結果: 9 → 10/20 (+1pt)。軸 6「期待出力」が 1 → 2。

ただし反復 2 末尾の「+2pt 見込み」予測は外れて実測 +1pt。subagent からの構造的指摘がいい:

メトリクスのフォーマットを示しても、メトリクスを取得する shell コマンドが書かれてなければ軸 3 (コマンド正確性) には波及しない。軸 6 と軸 3 はペアで埋めないと再現性が立ち上がらない

「修正 1 件で複数軸に効く」期待は構造を見誤りやすい。pt 見込みは保守的に立てるべき という、反復ループ自身が学習した知見。これは反復しないと出てこない発見だった。

反復 4: 最小起動例の追加

修正:

  • ワークフロー節の頭に「skill 配置 (mkdir + frontmatter 例) + Claude Code 起動 + 依頼プロンプト例」のハンズオンブロックを 12 行ほど追加
  • 軸 3「コマンド正確性」と軸 8「プロジェクト前提」の同時解消を狙う

再評価結果: 10 → 12/20 (+2pt)。これで 12 を超えて再現可能ラインには乗った。軸 2 / 3 / 5 / 8 が同時に上昇 = 1 ハンズオンブロックが 4 軸に同時波及した。

反復 3 で学習した「pt 見込みは保守的に」と逆方向に振れた。1 つの構造的な情報 (mkdir + frontmatter + 起動 + 依頼) が複数の評価軸を同時に塞ぐケースがあって、これは事前予測しにくい。修正の波及範囲は構造による ので、保守見積もりも上振れも両方ある。これも反復しないと出てこない知見。

ここまでの推移:

反復 スコア 主な変動
1 (ベースライン) 6/20
2 (環境前提 + リンク) 9/20 (+3) 軸 1, 4
3 (メトリクス経路) 10/20 (+1) 軸 6
4 (最小起動例) 12/20 (+2) 軸 2, 3, 5, 8

12/20 で再現可能ゾーン下限には乗ったが、せっかくなので 16/20 (= 多少のググりで再現可能、公開可ライン) を目指して続行する。残る低得点軸は 7 (エラー対処、0)、3 (cmd 正確性、1)、5 (設定全文、1)、1 (環境前提、1)、4 (バージョン、1)、10 (著者依存、1)。

反復 5: 環境前提の具体化 + 失敗時対処

修正:

  • ワークフロー節の頭に「macOS / Linux + Claude Code CLI v1.x 以降、npm i -g @anthropic-ai/claude-code (Node.js 24+)、claude --version で確認」の環境前提を追記
  • ワークフロー末尾に「よくある失敗と対処」節を追加 (dispatch されない / <usage> が出ない / レートリミット / context 枯渇 の 4 件)

再評価結果: 12 → 14/20 (+2pt)。14 まで入った。軸 1 が 1→2、軸 4 が 1→2、軸 7 が 0→2 (1 段見込みだったのに一気に 2 段ジャンプした)。

事前見積もり +3pt に対して実測 +2pt。軸 7 はエラー対処 4 件列挙が判定表 2 段階分の効果を持って、1 段ではなく 2 段一気に上がった。反復 4 で得た「修正の波及範囲は構造による」と同パターン。

反復 6: references/ 規約の説明追加 (狙い外し)

修正:

  • 「tool_uses で構造的欠陥がわかる」節の頭に「skill は SKILL.md + 任意の references/*.md で構成される」の補足 2 行を追加
  • 軸 8 (1→2) と軸 10 (1→2) の同時解消を狙う

再評価結果: 14 → 14/20 (±0pt)。めっちゃ外した。

subagent から「references 規約の追記は『skill 機構の説明』であって、『著者環境のプロジェクト構造明示 (軸 8)』でも『読者が持ってないヘルパーの開示 (軸 10)』でもない」と返された。要は軸名だけ見て修正してたのが雑だった。

新規知見: 判定表の閾値文言を読まずに修正すると +0 もある。反復 3 (保守的に) / 反復 4 (上振れる) に加えて、ゼロ振れもありうる。評価軸を新設したら、各点の閾値文言を必ず subagent に参照させて、修正前に「この修正が閾値のどの文言を満たすか」を言語化させるべき。

16/20 到達への残作業候補 (subagent 提示):

  1. 軸 5 (1→2): conventional-changelog 例の release-please-config.json 等を最小実物として 1 つ inline 掲載 (+1pt)
  2. 軸 10 (1→2): 8 個の skill のうち 2〜3 個に public link を併記、<usage> フォーマットの CC バージョン依存性を明記 (+1pt)

両方やれば 16/20。ただ「思想紹介」の趣旨からはみ出る寄りになるので、ここで打ち切るのも妥当。

反復 7: 設定全文 + 全 skill 直リンク

修正:

  • 「具体例」節に release-please-config.json の最小例を inline + manifest 記述 + conventional-changelog skill への直リンクを追加 (軸 5 狙い)
  • 「有効性のレンジ」節の 8 skill 列挙を全て public 直リンク化 (軸 10 狙い)

再評価結果: 14 → 16/20 (+2pt)。16 まで来た。軸 5 と軸 10 が同時に 1→2、事前見積もり通りに振れた。

これで反復 3 (保守的)・反復 4 (上振れ)・反復 6 (ゼロ振れ)・反復 7 (見積もり通り) の 4 パターンが揃った。反復 7 だけ見積もり通りに当たった違いは、軸名から逆算で雑にやってたのを、判定表の文言を一字一句読んで「この修正が閾値のどの文言を満たすか」を先に subagent に言わせる形に変えたこと。これに変えたら一気に当たるようになった。

これは empirical-prompt-tuning 本体にフィードバックすべき学び: 評価軸を新設したら、各点の判定基準は閾値文言まで具体化して、subagent が必ず参照する形にする。

最終推移:

反復 スコア 主な変動
1 (ベースライン) 6/20
2 (環境前提 + リンク) 9/20 (+3) 軸 1, 4
3 (メトリクス経路) 10/20 (+1) 軸 6
4 (最小起動例) 12/20 (+2) 軸 2, 3, 5, 8
5 (環境前提具体化 + 失敗対処) 14/20 (+2) 軸 1, 4, 7
6 (references 説明、狙い外し) 14/20 (±0)
7 (設定全文 + 全 skill 直リンク) 16/20 (+2) 軸 5, 10

16/20 で打ち切り。再現性・公開可ゾーン上限近傍。残る低得点は軸 8 (プロジェクト前提、1) のみで、~/.claude/ 全体の構成 (settings.json / hooks / references の位置関係) を tree 出力で示せば 18 まで届くが、思想紹介の趣旨からは離れるのでここまで。

Discussion