# AI生成小説における描写の反復と、その防止策が引き起こす逆説についての思索

## 何が起きているのかという現象の整理 🚶

AIを道具として用いて書かれた小説において、読者が覚える奇妙な足踏み感の正体は、出来事の停滞ではなく「描写の反復」という現象にある。

ここで起きていることを整理すると、物語の筋書きや劇中で起きる事件そのものは確実に前へと進んでいる。新しいキャラクターが登場し、舞台が変わり、新たな衝突が発生している。

それにもかかわらず、前の章ですでに丹念に描かれ、読者が十分に体験し終えたはずの場面や設定が、後続のエピソードにおいて再びまとまった分量の文章の束として詳しく書き直されてしまう。

- 第1話である決定的な事件が起き、その光景や登場人物の動揺が十分に描写される
- 第2話では新しい事件が進行しているはずなのに、冒頭や途中で前回の事件の情景や心理が改めて詳細に語られる
- 第3話以降でも、その出来事に触れるたびに、簡潔な言及にとどまらず情景描写や内省のブロックが立ち上がる

これは単語や言い回しの単純な重複ではない。また、似たような事件が作中で二度起きているわけでもない。

客観的な出来事としては一度しか起きていない事象に対して、それを読者に見せるための描写のかたまりが、後の文脈で何度も投入されている状態だ。しかもその際、表現形式や使われる語彙が変えられていることが多いため、単純なコピペ検出のような表面的な照合では引っかからない。

読者はすでに知っている過去の情報を、新しい解釈も加わらないまま何度も追体験させられることになり、ページをめくる速度に対して物語の情緒的な時間がまったく進まないという疲労感を味わうことになる。

## なぜ分割して生成し、個別にチェックせざるを得ないのか ⚙️

この現象を防ぐための試みについて考える前に、なぜそもそもAIによる執筆がエピソード単位の分割生成という形態をとらざるを得ないのか、その工学的な背景を整理しておく必要がある。

作者の視野の広さや狭さといった心理的な問題以前に、言語モデルという計算機の仕組みそのものが抱える制約が大きく関係している。

モデルに一度に長大な物語をすべて把握させ、一息に長編を出力させることはできない。コンテキスト長（一度に扱える文章の長さ）が長くなればなるほど、計算に必要なコストは跳ね上がっていく。

それに加えて、より深刻なのは品質の劣化だ。入力される文章が長大になればなるほど、モデルは過去の文脈を均一に保持できなくなり、中盤の情報を見落としたり、指示に従わなくなったり、後半に進むにつれて文章の密度や語彙の豊かさが目に見えて崩れていく。

```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 170" width="520" height="170" role="img" aria-label="一度に全部を生成すると後ろほど品質が薄れ、章ごとに分けると品質は保てるが毎回前提情報を渡すことになる">
  <defs>
    <linearGradient id="novel-fade">
      <stop offset="0" stop-color="currentColor" stop-opacity="0.65"/>
      <stop offset="1" stop-color="currentColor" stop-opacity="0.08"/>
    </linearGradient>
    <pattern id="novel-hatch-split" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
      <path d="M0 0V6" stroke="currentColor" stroke-width="1.5"/>
    </pattern>
  </defs>
  <g fill="currentColor" font-size="11">
    <text x="60" y="26">一度に全部を生成する</text>
    <text x="60" y="96">章ごとに分けて生成する</text>
  </g>
  <rect x="60" y="34" width="440" height="22" fill="url(#novel-fade)" stroke="currentColor"/>
  <g stroke="currentColor">
    <rect x="60" y="104" width="16" height="22" fill="url(#novel-hatch-split)"/><rect x="76" y="104" width="64" height="22" fill="currentColor" fill-opacity="0.65"/>
    <rect x="150" y="104" width="16" height="22" fill="url(#novel-hatch-split)"/><rect x="166" y="104" width="64" height="22" fill="currentColor" fill-opacity="0.65"/>
    <rect x="240" y="104" width="16" height="22" fill="url(#novel-hatch-split)"/><rect x="256" y="104" width="64" height="22" fill="currentColor" fill-opacity="0.65"/>
    <rect x="330" y="104" width="16" height="22" fill="url(#novel-hatch-split)"/><rect x="346" y="104" width="64" height="22" fill="currentColor" fill-opacity="0.65"/>
    <rect x="420" y="104" width="16" height="22" fill="url(#novel-hatch-split)"/><rect x="436" y="104" width="64" height="22" fill="currentColor" fill-opacity="0.65"/>
  </g>
  <g fill="currentColor" font-size="10">
    <text x="500" y="72" text-anchor="end">塗りの強さ：文章の質（後ろほど崩れる）</text>
    <rect x="300" y="140" width="12" height="10" fill="url(#novel-hatch-split)" stroke="currentColor"/>
    <text x="318" y="149">毎回渡す前提情報</text>
  </g>
</svg>
```

（この記事の図や表は、説明のために作った模式図や架空の例で、実測したものではない。）

長大な文脈を抱え込ませたまま走らせると全体が崩壊するからこそ、実用上の自衛策として、物語を章やシーンという短い単位に分割せざるを得ない。

そして各ステップにおいて、必要な前提情報だけをプロンプトとして切り取って渡し、出力された数千字をその都度人間が点検して確定させるという、段階的な制作工程が採用されることになる。

この分割生成と個別チェックは、モデルの性能限界を回避して一定水準の文章を保つための、極めて合理的で必然的なアプローチとして導入されているわけだ。

## 防止のための試みと、それが引き起こす裏目の連鎖 🔄

しかし皮肉なことに、長文劣化を防ぐためのこの合理的な試みこそが、描写の反復という病理を構造的に呼び寄せる引き金になってしまう。

### 試みとその裏目：前提情報の注入が過剰な描写を招く

各話を独立して生成する際、前の話との整合性を保つために、プロンプトには登場人物の性格、過去の事件、現在の心理状態がコンテキストとして注入される。前話で仲間を失ったのなら、「仲間を失った深い悲しみを抱えている」という情報を渡さなければ、急に明るく振る舞うような矛盾が生じるからだ。

しかし、AIにとって入力されたコンテキストは「行動を方向づけるための内部制約」であると同時に、「今から書くべきお題」としても機能してしまう。

モデルは渡された前提を忠実に反映しようとするあまり、行動の端々に影を落とすだけでなく、その過去の事件そのものを本文の中で律儀に情景描写や内省として書き下ろしてしまう。整合性を保つためにコンテキストを親切に与えれば与えるほど、過去の場面が本文へ露出する回数が増えていく。

### 試みとその裏目：局所的な推敲が再描写を巨大化させる

分割して出力された各話の文章を人間が点検するとき、元の出力に「前回の裏切りを思い出して悲しんでいた」というような要約的な記述を見つけることがある。

書き手は文章を良くしようとして、「もっと小説らしく、感情や情景を具体的に描写してほしい」とAIに修正を依頼する。説明的なあらすじを排除し、豊かな表現へと置き換えようとする、真っ当な推敲の試みだ。

しかし、これを受けたAIは、その一行の要約を、夕暮れの街並みや相手の冷淡な視線、胸を刺すような痛みといった、長大な描写ブロックへと展開して出力し直す。

結果として、局所的な文章の情緒や完成度は劇的に向上する。しかし作品全体を引いて見れば、すでに前話で描かれた内容が、より強固で巨大な文章の塊となって定着してしまう。推敲して文章を磨こうとする誠実な努力が、全体の冗長性を強化するという逆転が起きる。

### 試みとその裏目：削ろうとすると前後の依存関係が崩れる

全体を通読して「この第2話の再描写は余計だ」と気づいたとしても、単純にその段落を切り取ることはできない。

小説の文章は前後の文脈と強く結びついている。その再描写ブロックが醸し出していた空気感や時間の長さがあるからこそ、その直後にある登場人物の重々しい沈黙や決断の台詞が説得力を持っていたりする。

不要に見える描写を削ると、後ろの台詞が唐突に響いてシーン全体が軽薄になってしまう。台詞を直すと会話の流れが狂い、シーンの着地点がずれる。

ひとつの重複を取り除くために、その章全体、場合によっては前後の章まで巻き込んだ全面的な書き直しという膨大な手戻りが発生する。その修正コストの重さに耐えきれず、結局は「くどいけれど、破綻はしていないから」と再描写を残したまま公開することになる。

## チェックする機構を作ろうとしたときの難しさ 🔍

こうした構造的な罠に対して、後から機械的に検査する仕組み、いわば継続的な文書チェック機構を導入しようと考えた場合、そこにはどのような技術的・概念的な困難が横たわっているのか。

コードの自動テストや静的な構文チェックのような枠組みを小説に持ち込もうとすると、言語表現特有の曖昧さと文脈依存の深さに突き当たることになる。

### 1. 文字列の類似度では捉えられない意味的な追跡の困難さ

最も単純なアプローチは、文章同士の重複をテキストの類似度で検出することだ。しかし、この方法はほとんど機能しない。

再描写される場面は、前話とは異なる視点から描かれたり、会話中心だったものが心理描写に変わっていたり、使われる比喩や語彙が一新されていることが多い。

```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 230" width="520" height="230" role="img" aria-label="段落同士の文字列の類似度では対角線しか光らないが、描いている出来事で比べると離れた段落同士が同じ場面だとわかる">
  <g fill="none" stroke="currentColor" stroke-width="0.5" opacity="0.4">
    <path d="M40 40h160v160H40zM60 40v160M80 40v160M100 40v160M120 40v160M140 40v160M160 40v160M180 40v160M40 60h160M40 80h160M40 100h160M40 120h160M40 140h160M40 160h160M40 180h160"/>
    <path d="M300 40h160v160H300zM320 40v160M340 40v160M360 40v160M380 40v160M400 40v160M420 40v160M440 40v160M300 60h160M300 80h160M300 100h160M300 120h160M300 140h160M300 160h160M300 180h160"/>
  </g>
  <g fill="currentColor" fill-opacity="0.7">
    <rect x="40" y="40" width="20" height="20"/><rect x="60" y="60" width="20" height="20"/><rect x="80" y="80" width="20" height="20"/><rect x="100" y="100" width="20" height="20"/><rect x="120" y="120" width="20" height="20"/><rect x="140" y="140" width="20" height="20"/><rect x="160" y="160" width="20" height="20"/><rect x="180" y="180" width="20" height="20"/>
    <rect x="300" y="40" width="20" height="20"/><rect x="320" y="60" width="20" height="20"/><rect x="340" y="80" width="20" height="20"/><rect x="360" y="100" width="20" height="20"/><rect x="380" y="120" width="20" height="20"/><rect x="400" y="140" width="20" height="20"/><rect x="420" y="160" width="20" height="20"/><rect x="440" y="180" width="20" height="20"/>
  </g>
  <g fill="currentColor" fill-opacity="0.7">
    <rect x="360" y="40" width="20" height="20"/><rect x="420" y="40" width="20" height="20"/>
    <rect x="300" y="100" width="20" height="20"/><rect x="420" y="100" width="20" height="20"/>
    <rect x="300" y="160" width="20" height="20"/><rect x="360" y="160" width="20" height="20"/>
  </g>
  <g fill="currentColor" font-size="12" text-anchor="middle">
    <text x="120" y="24">文字列の似かた</text>
    <text x="380" y="24">描いている出来事</text>
    <text x="120" y="220" font-size="10">対角線（自分自身）しか光らない</text>
    <text x="380" y="220" font-size="10">第1・4・7段落が同じ裏切りの場面</text>
  </g>
  <g fill="currentColor" font-size="9" text-anchor="middle" opacity="0.7">
    <text x="50" y="36">1</text><text x="110" y="36">4</text><text x="170" y="36">7</text>
    <text x="310" y="36">1</text><text x="370" y="36">4</text><text x="430" y="36">7</text>
  </g>
</svg>
```

検査システムが比較しなければならないのは、表面的な文字列ではなく、「その文章が、物語内のどの出来事やどの状況を描写対象としているか」という指示対象のレベルである。

本文中のどの段落が、過去に起きたどの事件を指し示しているのかを意味的にマッピングし、追跡する仕組みが必要になる。これは形態素解析や単純な埋め込みベクトルのコサイン類似度だけで解ける問題ではなく、物語内の出来事と描写ブロックの対応関係を把握する高度なモデルを要求する。

### 2. 合否判定ではなくプロファイラにならざるを得ない曖昧さ

さらに難しいのは、同じ場面を再び描くこと自体が、常に悪であるとは限らない点にある。

過去の出来事を別の角度から再描写することで、それまで隠されていた新たな事実が判明したり、登場人物の欺瞞が暴かれたり、反復そのものがリズムや強調として機能する場合もある。再描写が価値を生むケースも確実に存在する。

したがって、再描写を検出したからといって、テストのように赤信号を出して機械的にリジェクトすることはできない。

システムにできるのは、どの出来事に対して、作品全体のどこで、どれだけの描写分量が費やされているかという分布を可視化すること、すなわちプロファイラのような情報提供にとどまる。その分量が提供している新しい情報や感動に対して過大であるかどうかという価値判断は、数値として一意に計算することが極めて難しい。

プロファイラとは、プログラムのどこにどれだけ時間がかかったかを集計して見せる道具のことだ。小説に当てはめれば、出来事ごと・話ごとに描写の分量を数えた次のような表になる（■ひとつがおよそ千字という程度の、架空の例）。

| 出来事 | 第1話 | 第2話 | 第3話 | 第4話 | 第5話 |
| --- | --- | --- | --- | --- | --- |
| 裏切り | ■■■■■ | ■■■ | ■■ |  | ■■ |
| 移動 |  | ■■■ |  |  |  |
| 遭遇 |  |  | ■■■ |  |  |
| 決断 |  |  |  | ■■■■ | ■ |

この表から、裏切りの場面が第1話のあとも三度にわたって戻ってきていることは読み取れる。けれど、第3話と第5話の「裏切り」の欄はどちらも■■で、表の上では見分けがつかない。第3話のほうは仲間が裏切った本当の理由が初めて明かされる再描写で、第5話のほうはただの繰り返しだ、ということが十分にありうる。その違いは、本文を読んで初めてわかる。

### 3. 読者シミュレーターが直面する文脈のジレンマ

人間が気づけない冗長性を検知するために、モデルを使って「読者の体験をシミュレーションさせる」という発想がある。文章を順番に読ませて、退屈を感じた箇所や、既知の情報だと判定された箇所を警告させる手法だ。

しかしここには、入力文脈をどう扱うかという深刻なジレンマが存在する。

モデルの負荷を減らすために各章を独立して読ませると、読者モデルは前話までの文脈を持っていないため、過去の出来事への再描写を「親切で必要な背景説明」として高く評価してしまう。文脈を持たない読者モデルに頼ると、むしろ再描写を増やす方向へシステムが誘導されてしまう。

逆に、第1話からの全テキストを蓄積させて読ませようとすれば、冒頭で触れたコンテキスト長の増大による品質劣化の問題が、シミュレーター側でそのまま再現される。長い文脈を読んだモデル自身が過去の詳細を忘れ、中盤以降の評価の解像度が落ちてしまう。

```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 240" width="520" height="240" role="img" aria-label="人間の読者は第1話の場面をゆっくり忘れていくが、章ごとに読ませたモデルは章の境目で忘れ、全文を読ませたモデルは中盤で抜け落ちる">
  <g stroke="currentColor" fill="none">
    <path d="M60 30V190H500" stroke-width="1"/>
    <path d="M148 30V190M236 30V190M324 30V190M412 30V190" stroke-width="0.5" stroke-dasharray="2 4"/>
    <path d="M60 175C100 120 130 60 148 50C250 54 400 66 500 74" stroke-width="3"/>
    <path d="M60 175C100 120 130 60 148 50C200 70 260 120 330 140S450 150 500 152" stroke-width="2" stroke-dasharray="7 4"/>
    <path d="M60 175C100 120 130 60 148 50V180H500" stroke-width="1.5" stroke-dasharray="2 3"/>
  </g>
  <g fill="currentColor" font-size="11">
    <text x="496" y="66" text-anchor="end">人間の読者</text>
    <text x="496" y="144" text-anchor="end">全文を読ませたモデル</text>
    <text x="496" y="174" text-anchor="end">章ごとに読ませたモデル</text>
    <g text-anchor="middle">
      <text x="104" y="206">第1話</text><text x="192" y="206">第2話</text><text x="280" y="206">第3話</text><text x="368" y="206">第4話</text><text x="456" y="206">第5話</text>
      <text x="280" y="228">本文を読み進める位置 →</text>
    </g>
    <text x="64" y="22">第1話の場面をどれだけ覚えているか ↑</text>
  </g>
</svg>
```

人間の読者は第1話の場面をおおむね覚えたまま読み進め、記憶はゆっくりとしか薄れない。再描写が冗長だと感じられるのは、この記憶があるからだ。章ごとに読ませたモデルは章の境目でその記憶を丸ごと失い、全文を読ませたモデルは中盤で記憶を取りこぼす。どちらの読ませ方も、人間の読者とは別の形でずれている。

読者が頭の中に持っている記憶の定着や風化、感情の累積といった動的な読書プロセスを、計算機上で安定して再現することは容易ではない。

### 4. 修正案の一意性の欠如

仮にシステムが冗長な再描写を正確に特定し、作者に警告できたとしても、そこから先の「ではどう修正すべきか」という提案を一意に生成することができない。

重複を解消するための選択肢はひとつではない。

- 第2話の再描写を削り、短い言及に置き換える
- 第2話の再描写を残す代わりに、第1話側の描写をあらかじめ淡泊にしておく
- 描写の順序を組み替え、別のエピソードへ分散させる
- あえて冗長さを残し、その後の爆発的な感情吐露への助走として維持する

どの修正が最適であるかは、作者がその作品で何を最も伝えたいかという意図や、作品全体のテンポ配分に依存している。

自動リファクタリングのように「安全にこの形へ書き換える」という正解が存在しないため、システムが修正を代行しようとすると、前述したように別の余計な描写を付け足して文脈を壊す二次災害を引き起こしやすい。

## 構造的な課題の結節点として 🕳️

こうして全体を眺めてみると、AI生成小説における描写の反復は、単なるツールの使い方の拙さや、初心者の不注意という一言では片付けられない深さを持っている。

- 言語モデルの長文耐性の低さが、分割生成と個別チェックという分断された工程を強いる
- 分割された隙間を埋めるために注入されたコンテキストが、モデルの出力癖によって本文へと漏れ出す
- 局所的な文章の質を高めようとする人間の推敲が、過去の場面の再描写をさらに巨大化させる
- 文章の持つ非局所的な依存関係が、発見された重複の切除を極めて高コストなものにする
- それらを外部から機械的に検出しようとしても、意味追跡の困難さや読者モデルの文脈ジレンマが立ちはだかる

局所的な破綻を防ぎ、文章の品質を保とうとする合理的な試みのひとつひとつが、次の段階において別の冗長性を生み出す養分になっていく。

語るべきことを語ることよりも、すでに伝わったことを信じて沈黙を守ることのほうが、はるかに高度な文脈の制御を必要とする。計算機による創作をめぐるこの奇妙な足踏みは、文章を書くという行為において「引き算」を行うことがどれほど複雑で、どれほど多くの前提に支えられていたのかを、逆照射しているように思える。
