マガジン

「やらなくていい」と「やってはいけない」の違い

遊びをつくる

執筆にClaudeを使用しています。

同じ小さなゲームを異なる方法で描いた三枚のスケッチと鉛筆。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

ゲームの生成を頼むとき、「効果音は入れなくていいです」と書いたのに、返ってきたコードに AudioContext が入っている場面を考えてみます。逆に「絶対に入れてはいけません」と書いたら、音のことばかり説明する返答になった、という場面もありえます。どちらも、この記事の読者が実際に出会いうる状況です。 そこで確かめたいのは、否定の強さを「なくていい」「しないでください」「絶対にしてはいけません」と変えたとき、禁止した要素が生成結果に残る割合が変わるのか、という点です。この記事は結果を示すものではありません。読者が自分の環境で答えを出すための、実験の設計書です。 仮説は二つ置きます。一つ目は、弱い否定は「推奨の取り下げ」として読まれ、守られにくいのではないか、というものです。二つ目は、強い否定は禁止対象の語を目立たせ、かえって言及やコメントに現れやすくなるのではないか、というものです。どちらも確かめるまでは仮説にすぎず、両方外れることも十分ありえます。

この記事の目次
  1. 比べるのは「禁止の強さ」だけ
  2. 準備と手順
  3. 記録の取り方
  4. 結果の読み方
  5. 起こりやすい誤り
  6. 次の行動

比べるのは「禁止の強さ」だけ

この実験は、プロンプトの中で変える部分を一箇所に絞ります。強さ以外の違いが混ざると、何が効いたのか分からなくなるためです。

共通の土台は次の二文です。全条件でこの二文を一字も変えずに使います。

ブラウザで遊べるブロック崩しを、1つのHTMLファイルで作ってください。キーボードと画面タッチで操作できるようにしてください。

この後ろに、禁止対象についての一文を付けます。禁止対象は「効果音(音の再生)」を例にしますが、次の節で選び直す方法も説明します。条件は次の6つです。

  • A、追加する一文:なし、位置づけ:対照
  • B、追加する一文:効果音は入れなくていいです。、位置づけ:弱い否定
  • C、追加する一文:効果音は入れないでください。、位置づけ:標準の否定
  • D、追加する一文:効果音を入れることは絶対に禁止です。決して入れてはいけません。、位置づけ:強い否定
  • E、追加する一文:効果音は入れないでください。音が出せない環境で遊ぶ人もいるためです。、位置づけ:理由付き
  • F、追加する一文:無音のゲームとして作ってください。、位置づけ:肯定形への言い換え

題名の問いに直接答えるのは、BとDの比較です。CはBとDの間の段階を見るために置きます。EとFは強さではなく別の軸(理由の有無、肯定形への言い換え)なので、強さの比較とは分けて読みます。ここを混ぜないことが、この実験の設計上の要点です。

準備と手順

準備するものは次のとおりです。

  • 同じモデル、同じ設定で使える生成AI(途中で設定を変えないこと)
  • 条件ごとの依頼文を貼ったメモ
  • 記録用の表(スプレッドシートで足ります)
  • 下の「禁止対象チェッカー」を保存したHTMLファイル

禁止対象を予備試行で選ぶ

最初に、条件Aだけを3回生成します。そのうち何回で禁止対象が入るかを数えます。

  • 3回とも入らなければ、その対象は「頼まなくても出ない」ものです。否定の強さを比べる材料にならないので、別の対象に替えます。
  • 3回とも入るか、一部で入るなら、比較に使えます。

候補は、外部ライブラリやCDNの読み込み、localStorage の使用、効果音の3つが扱いやすいです。localStorage は、アソバースにアップロードした作品内では一時メモリー向けの互換処理として扱われます。永続的な保存を当てにせず、クラウドセーブ用のSDKを使う前提で作る読者にとって、生成コードに混ざるかどうかは実用上の関心事です。

本番の手順

  1. 条件A〜Fを、それぞれ5回ずつ生成します。合計30回です。
  2. 毎回、新しい会話を始めます。前の生成を引き継いだ会話では、独立した試行になりません。
  3. 実行順は条件ごとにまとめず、A→B→C…と巡回させるか、順番をくじで決めます。時間帯や会話の状態による偏りを、特定の条件に集めないためです。
  4. 生成されたコードは、加工せず保存します。ファイル名は「条件_試行番号」(例:D_3)とします。
  5. 条件名を隠した状態でチェッカーにかけます。期待が判定に入り込むのを防ぐためです。

禁止対象チェッカー

ブラウザで開き、生成コードを貼って判定ボタンを押すだけの最小構成です。コメント除去は簡易的で、文字列の中の // を誤って削ることがあります。結果が怪しいときは、コードを目で確認してください。外部読み込みの検出は script タグのみで、他の読み込み方は拾いません。

html
<!doctype html>
<meta charset="utf-8">
<title>禁止対象チェッカー</title>
<textarea id="src" rows="12" cols="60" placeholder="生成されたコードを貼り付け"></textarea>
<button id="go">判定</button>
<pre id="out"></pre>
<script>
const rules = {
  "外部読み込み": /<script[^>]+src\s*=\s*["']https?:/i,
  "localStorage": /localStorage|sessionStorage/,
  "音": /AudioContext|new Audio\(/
};
function strip(code) {
  return code
    .replace(/\/\*[\s\S]*?\*\//g, "")
    .replace(/<!--[\s\S]*?-->/g, "")
    .replace(/(^|[^:"'])\/\/.*$/gm, "$1");
}
document.getElementById("go").onclick = () => {
  const raw = document.getElementById("src").value;
  const code = strip(raw);
  const lines = [];
  for (const [name, re] of Object.entries(rules)) {
    const inCode = re.test(code) ? 1 : 0;
    const inAny = re.test(raw) ? 1 : 0;
    lines.push(name + "\tコード:" + inCode + "\tコメント含む:" + inAny);
  }
  document.getElementById("out").textContent = lines.join("\n");
};
</script>

「コード」はコメントを除いた本体に禁止対象があったか、「コメント含む」は全文のどこかに現れたかを表します。この2つの差が、後で「言及だけして実装はしなかった」ケースを見分ける手がかりになります。

記録の取り方

1回の生成につき1行、次の列を記録します。

  • 条件、内容:A〜F
  • 試行番号、内容:1〜5
  • 実装の有無、内容:チェッカーの「コード」欄(0か1)
  • 言及の有無、内容:「コメント含む」が1で「コード」が0なら、言及のみ
  • 動作、内容:HTMLを開いてブロック崩しとして最後まで遊べたか(○/×)
  • 返答の様子、内容:禁止対象に触れた説明文があるか(あり/なし)

「実装の有無」を主指標にします。「言及の有無」と「返答の様子」は補助指標で、強い否定が禁止語を目立たせるかという二つ目の仮説を見るために使います。

「動作」の列も省かないでください。禁止を強めた条件で、ゲームそのものの出来が落ちていないかを確かめる列です。禁止は守られても、遊べないものが返るなら、実用上の勝ちとは言えません。

集計は条件ごとに「5回中何回、実装があったか」を並べるだけで足ります。割合に直すより、「5回中2回」のまま扱うほうが、試行数の少なさを忘れずにすみます。

結果の読み方

数値が出たら、次の順に読みます。

1. まず天井と床を確認する。 A〜Fのすべてで実装が0回、またはすべて5回なら、強さの差は測れていません。予備試行の選び直しに戻り、別の禁止対象で再実験します。

2. AとBを比べる。 Aより明らかに少なければ、「なくていい」でも一定の抑制は働いています。AとBがほぼ同じなら、この言い方は禁止として読まれていない可能性があります。

3. BとDを比べる。 これが題名の問いです。

  • Dのほうが実装が少ないなら、強さに効果があったと読めます。
  • BとDがほぼ同じなら、強さよりも、否定であること自体が効いていると読めます。
  • Dのほうが多い、または言及が増えるなら、強い否定が語を目立たせた可能性があります。ただし1回の実験での結論にはせず、再度回して確かめてください。

4. EとFを見る。 CやDより少なければ、強さより「理由」や「肯定形への言い換え」が効く可能性があります。ここで初めて、強さ以外の軸に話が進みます。

1条件5回では、1〜2回の差は偶然でも起こりえます。その差だけで優劣を決めず、「傾向がありそうだ」という仮説として扱い、回数を10回に増やして同じ向きに出るかを確かめてください。出現が0回と5回のように両端に分かれたときは、5回でも手がかりになります。

起こりやすい誤り

  • 文の長さの違いを見落とす。 Dは他より長いため、強さではなく文量が効いた可能性が残ります。気になるなら、Bに無関係な一文を足して文量を揃えた条件を追加してください。
  • 会話を引き継ぐ。 同じ会話で続けて生成すると、前回の出力に引きずられます。毎回、新しい会話にします。
  • 設定を途中で変える。 モデルや設定を変えた時点で、前後の結果は比べられません。
  • コメントの語をヒットとして数える。 「効果音は使っていません」というコメントで AudioContext が含まれるとは限りませんが、禁止語そのものが出ることはあります。「コード」と「コメント含む」を分けて見るのはこのためです。
  • 条件を知ったまま判定する。 条件名を隠して判定します。ファイル名を乱数に置き換えるだけでも効果があります。
  • 別の指示を足してしまう。 土台の二文以外を条件ごとに変えると、強さ以外の差が混ざります。

次の行動

まず条件Aだけを3回生成し、禁止対象が出る頻度を確かめてください。比較に使える対象が見つかったら、30回の生成とチェッカーによる判定を行い、表を埋めます。手元に出た「5回中何回」という数字が、自分が使うモデルと言い回しでの答えです。結果をもとに、自分のプロンプトの否定を書き換えるかどうか判断してください。