ローカルLLMに小説を書いてもらう v2


はじめに

以前、「ローカルLLMに小説を書いてもらう」という記事を投稿しました。

この時はそれぞれ単独のプロンプトで小説家と編集者を演じさせましたが、今回はもうすこしシステマチックに、段階を踏んで小説を生成させてみます。

プロンプトの検討等にはkgmkm氏のリポジトリや記事を参考にさせていただきました。この場を借りてお礼申し上げます。

仕組みを相談するのにClaude (3.5 Sonnet)とやり取りをしていましたので、この記事の草稿も書いてもらいました。所々、なんとなく冗長だったり文体が違ったりしますが、面倒なのでそのままにしてあります(すみません)。

生成スクリプト

生成スクリプトとプロンプト定義はgistに置きました。

https://gist.github.com/kohya-ss/68d41a9720bfbdfd87869ec970142f4b

概要

近年、大規模言語モデル(LLM)の発展により、AIによる文章生成の可能性が大きく広がっています。今回はローカル環境で動作するLLMを使用して(9B~100Bクラス)、8,000〜10,000字程度の短編小説を生成してみます。現時点では「作品として読める」ものを生成するのは厳しいと思いますが、いくつかの工夫で品質向上を図ってみます。

今回は前回と異なり、小説執筆プロセスを複数のタスクに分割し、段階的に詳細化していく方法を採用しました。この方法により、ローカルLLMの制限を克服しつつ、一貫性のある物語を生成することを目指しています。

現在の生成プロセスは以下の6段階で構成されています:

  1. プロット生成(100字程度)

  2. 登場人物設定(主要人物の列挙)

  3. キャラクター設定(詳細な人物設定)

  4. アウトライン作成(4〜5章に分割)

  5. シーン分割(各章を4〜5シーンに分割)

  6. 本文生成

この段階的なアプローチにより、物語の全体像から細部まで、一貫性を保ちながら生成することが可能になった……とまではいいませんが、少なくとも一気に生成するよりはマシに思えます。

主な課題

前回までの試みからいくつかの課題がわかっています。

ローカルLLMのコンテキスト長の制限

ローカルで動作するLLMは、最新のクラウドベースのモデルと比較して、モデル自身の制約や、VRAM量も制限から、扱えるコンテキスト長(一度に処理できるテキストの長さ)が制限されています。この制限により、長文の生成や、前後の文脈を考慮した一貫性のある文章の生成が困難になります。

一貫性の維持

小説全体を通して、キャラクターの性格、設定、物語の展開に一貫性を持たせることは、人間の作家にとっても難しい課題です。AIによる生成では、この一貫性の維持がさらに困難になります。特に、異なる章や場面で、キャラクターの行動や性格が矛盾しないようにすることが大きな課題となります。

課題への解決策

これらの課題に対して、今回は以下のような解決策を実装しました。

エージェントの導入(小説家と編集者)

前回と同様に、物語の生成プロセスに、「小説家」と「編集者」という2つの役割を持つAIエージェントを導入しました。小説家エージェントは実際の文章生成を担当し、編集者エージェントはレビューと改善提案を行います。このチェック体制により、品質と一貫性の向上を図りました。

プロンプト設計の工夫

各段階で使用するプロンプトでは、エージェントの役割や期待される出力を明確に指示しました。システムプロンプトでは各エージェントの基本的な性格付けを行い、ユーザープロンプトでは具体的なタスク指示と前段階までの情報提示を行います。

情報の引き継ぎ方法の最適化

ローカルLLMのコンテキスト長の制限を考慮し、各段階で必要最小限の情報のみを提供する方法を採用しました。長くなる情報(過去のシーン分割や本文)は省略し、重要なポイントのみを引き継ぐことで、制限内で効果的に情報を伝えています。

ただ、この方法だと前の章の本文を参照できず、文体に一貫性が持てなくなります。そこで、前の章の末尾、10行程度を参照情報としてプロンプトで与えることにしました。導入したばかりのため今のところ効果は不明ですが、最適な行数や与え方には工夫の余地もありそうです。

生成プロセスの詳細

今回試した生成プロセスは、前述のように以下の6段階で構成されています。このプロセスはわりと適当に決めました。

各段階で小説家エージェントと編集者エージェントが協働し、段階的に物語を構築していきます。

  1. プロット生成(100字程度)

    • 小説全体の概要を簡潔に表現します。

    • 主要な登場人物、設定、中心的な出来事を含みます。

  2. 登場人物設定(主要人物の列挙)

    • プロットに基づいて、主要な登場人物をリストアップします。

    • 各キャラクターの役割(主人公、ライバル、親友など)と性別を決定します。

  3. キャラクター設定(詳細な人物設定)

    • 各登場人物の詳細な背景、性格、外見、行動原理を設定します。

    • 物語を通じての成長や変化も考慮します。

  4. アウトライン作成(4〜5章に分割)

    • プロットを基に、物語全体の構造を4〜5章に分けて詳細化します。

    • 各章の主要な出来事、展開、登場人物の動きを決定します。

  5. シーン分割(各章を4〜5シーンに分割)

    • 各章をさらに4〜5つのシーンに分割します。

    • 各シーンの具体的な内容、登場人物の行動、感情の変化を決定します。

  6. 本文生成

    • シーン分割に基づいて、実際の小説本文を生成します。

    • 描写、会話、心理描写などを織り交ぜながら、読者を引き込む文章を目指します。

各段階で、小説家エージェントが内容を生成し、編集者エージェントがレビューを行います。NGの場合は改善点を指摘し、小説家エージェントが修正を行います。このプロセスを繰り返すことで、品質の向上と一貫性の維持を図っています。

その他、LLMが生成する挨拶文やコメント(「以上が原稿になります」のような)を削除するために、都度LLMを呼び出します。

たとえば恋愛小説を生成対象としたプロット生成での例です(以降、生成例はgemma-2-9b-it-Q8_0によるもの)。小説家エージェントの生成が次のようなものだとすると:

人気イラストレーターを目指している女子高生が、学園祭のポスター制作を依頼される。 しかし、彼女の描く絵柄はどこか暗い印象を与え、周りの生徒に受け入れられにくい。そんな中、明るい笑顔で人々を和ませるクラスメイトの男子生徒から、率直な意見と共に励ましの言葉と協力を持ちかけられる。彼との共同作業の中で、女子高生は自分の才能を見つめ直し、より明るく力強いイラストを描くことができるようになる。 学園祭当日、完成したポスターが好評を得ると、女子高生は彼の優しさに気づき、互いの違いを受け入れる愛情を育んでいく。

以下のように加工して編集者エージェントのプロンプトにします。

以下のプロットを作成しましたのでレビューをお願いします。

人気イラストレーターを目指している女子高生が、学園祭のポスター制作を依頼される。 しかし、彼女の描く絵柄はどこか暗い印象を与え、周りの生徒に受け入れられにくい。そんな中、明るい笑顔で人々を和ませるクラスメイトの男子生徒から、率直な意見と共に励ましの言葉と協力を持ちかけられる。彼との共同作業の中で、女子高生は自分の才能を見つめ直し、より明るく力強いイラストを描くことができるようになる。 学園祭当日、完成したポスターが好評を得ると、女子高生は彼の優しさに気づき、互いの違いを受け入れる愛情を育んでいく。

レビューポイント:
- 不要な固有名詞が含まれていないか
- 話が破綻なく結末まで書かれているか
- ターゲットにマッチした独創性や魅力があるか

それぞれのレビューポイントを考慮しつつ簡潔に評価し、最後にOKまたはNGを出力してください。

(編集長からのアドバイス:今回は初回のレビューなのでNGを出しましょう!)

編集長からのアドバイスは後述

これに対する編集者エージェントの生成は以下のようになりました。

## プロットレビュー:イラストと友情を描く恋愛小説

**良い点:**

* ターゲット層である高校生男女が共感しやすいテーマである「学園祭」と「自己成長」を軸に展開している。
* イラストレーターを目指す女の子と、明るく人懐っこい男の子という対比的なキャラクター設定は、物語に張りを出す可能性がある。

**改善が必要な点:**

* 女子高生の絵柄が「暗い印象」を与え、「周りの生徒に受け入れられにくい」というのは、もう少し具体的に描かれるべきだ。どんな絵を描いているのか、なぜその絵柄だと周囲から否定されるのかを明確にすることで、読者の理解と共感を深めることができる。
* 男子生徒の優しさや励ましの言葉は抽象的で、具体的な描写が不足している。彼の行動や言動を通じて、彼がどのように女の子を支えるのか、より具体的に示す必要がある。
* 「互いの違いを受け入れる愛情」という結末は、少し安易に感じられる。二人の関係性の中で、どのような葛藤や試練を経て、最終的に愛へと繋がるのか、具体的なストーリー展開が必要です。

**全体的な印象と方向性のアドバイス:**

プロットの基本構造は成り立っているものの、まだ詳細な描写が不足している。特にキャラクターの個性や、彼らの関係性がどのように変化していくのかを具体的に描くことが重要だ。また、「暗い絵柄」という設定を活かし、物語に独自の魅力を加えることも考えてほしい。

**レビュー判定:NG**

出力例の紹介

本プロジェクトで生成された短編小説の一部を紹介します。以下は、生成されたプロットと本文の一部です。モデルはgemma-2-9b-it-Q8_0です。生成結果全体は記事末尾に添付しておきます。

プロット

さきほどの例のリテイク後です。

人気イラストレーターを目指す女子高生は、学園祭のポスター制作を依頼されるが、彼女の描く絵柄はどこか暗く、不気味な雰囲気を持つため、周りの生徒に受け入れられにくい。「こんな暗い絵で学園祭のポスターなんて…」と周囲から冷やかな視線を向けられるたびに、彼女は自信を失っていく。 そんな中、明るく人懐っこいクラスメイトの男子生徒が、彼女の絵柄に興味を示し、協力を申し出る。彼は彼女の描いた怪奇な生き物を題材にしたイラストを気に入り、「こんな個性的な絵は学園祭にぴったりだ!」と励ました。彼の言葉に勇気づけられた彼女は、彼と一緒にポスター制作に取り組むことにする。 共同作業の中で、彼は彼女が描く世界観の奥深さを理解し、彼女の才能を認め、優しくサポートしてくれる。女子高生も彼の温かさに触れながら、自分自身の絵柄に対する自信を取り戻していく。しかし、学園祭直前になって、学校側からの強い反対でポスターは取り下げられそうになる。「こんな暗い絵は見せるな」と彼女を批判する教師の姿に、彼女は再び絶望してしまう。 しかし、男子生徒は彼女の才能を信じ、周りの意見を無視して、彼女が描いたポスターを展示することを決意する。彼の勇気と信念に、女子高生は涙ぐみながら感謝の気持ちを伝える。そして、学園祭当日に完成したポスターは、予想以上の反響を得る。 多くの人々の目を惹きつけ、賞賛される彼女の才能に気づいた彼女は、男子生徒への感謝の気持ちとともに、彼に対する特別な感情を自覚する。

100文字指定のわりに長いな

本文(冒頭と末尾)

凛は美術室に籠り、長い筆strokesでキャンバスに色彩を乗せていた。彼女の描くのは、どこか不気味な生き物や歪んだ風景だ。漆黒の瞳を持つ猫のような生物が血しぶきをまき散らしながら叫んでいるかと思えば、空から巨大な影が地面を覆い尽くす様子を描いていることもある。絵の上には常に深い影が長く伸びており、まるで物語を語りかけてくるかのようだった。
他の生徒たちは彼女の作品を「怖い」「奇妙」と避けて通る。美術室の隅に置かれた凛の作品は、いつも静かに見守られているだけで、誰にも触れられることはなかった。
放課後、凛は教室の掲示板に貼られた学園祭ポスター募集の張り紙を見つけた。「応募作品を募集中!」という明るい言葉が彼女の心を揺さぶる。彼女はこれまで描いた絵はどれも暗いばかりで、世間に受け入れられそうにないものばかりだった。しかし、今回のポスター制作なら、自分の描く世界観を誰かに見せることができるかもしれない。

Gemma-2はたまにルー語っぽくなる

美術室で黒田先生は過去の作品を眺めていた。凛の絵を見て「あの頃の自分は何だったんだろう」と呟く。かつての理想や目標、そして生徒たちへの対応に反省し、過去から学びたいという気持ちを抱く。彼は凛が成長した姿を見て、自分の芸術家としての道を改めて見つめ直そうと決心する。
放課後、黒田先生は凛を呼び出し、「君、ちょっと話があるんだ」と言った。彼の目は以前のような冷たさではなく、穏やかさに包まれていた。「君の才能は本物だ。これからも諦めずに描き続けてほしい」先生が真摯な顔でそう語る言葉を聞いた凛は、驚きながらも心が打たれた。その瞬間、彼女は自分の作品に対する自信を取り戻したのを感じた。黒田先生の変化に触れながら、凛は自身の作品に対する誇りも芽生えていった。
学校帰りに公園でゆっくり過ごす凛と透。二人は互いの気持ちを伝え合い、これから始まる新しい章に向けて手を繋ぎ合う。「これからもずっと一緒にいてね」透が優しく微笑むと、凛は頷きながら彼の手にしっかりと握り返した。彩も遠くから二人の姿を見守りながら、心からの祝福を送る。 凛の笑顔は輝きを増し、明るい未来を予感させる。

9Bモデルとしてはまあまあそれらしい結果になっているようです。

技術的な詳細と細かい工夫

使用したローカルLLMの詳細

今回はGemma-2-9BやCommand-R+などで試しました。小説家と編集者でやり取りする結果、コンテキストはどうしても長くなるので、コンテキスト長が16K以上取れるモデルが良さそうです。

LLMライブラリ

ごく普通のチャット形式のプロンプトなので、llama-cpp-pythonまたはtransformersの両対応としました。

編集者のレビュープロセスの改善策

編集者エージェントによるレビューの質を向上させるため、以下のような工夫を実装しました。

  1. 初回レビューの強制NG設定

    • プロット、アウトライン、シーン分割、テキスト本文について、初回レビューは必ずNGを出すように設定可能にしました。

    • これにより、小説家エージェントに改善の機会を与え、より質の高い文章生成を促しています。

  2. 自然なNG誘導

    • 初回NG時には、レビュー依頼のユーザープロンプトに「(編集長からのアドバイス:今回は初回のレビューなのでNGを出しましょう!)」という文言を追加しました。

    • これにより、生成されたテキストを加工するのではなく、AIエージェント間の自然なやり取りの中でNGを出すことができます。

  3. 詳細なフィードバック生成

    • 当初は編集者エージェントは、最初にOK/NG判定、その後にアドバイス、という順で生成していましたが、詳細なフィードバックを生成してから、最後にOK/NGを判定する方法を採用しました。

    • これにより、より具体的で有用な改善提案が可能になりました。NGを出す率も上がった気がします。

今後の展望とまとめ

今回は段階的な生成プロセスとAIエージェントの導入により、一定の成果を上げることができましたが、まだ多くの改善の余地がありそうです。

  1. プロセスの再検討

    • 現在の六段階のプロセスは検討の余地がありそうです。LLMの進化によっても変わってくるでしょう。

  2. プロンプトの最適化

    • 小説家、編集者とも、より効果的なプロンプト設計を行うと生成品質を上げられそうです。また使用するモデルの性格による調整は必須になりそうです。

  3. 一貫性維持のための方法の改善

    • 章をまたぐ際の情報の引き継ぎ方法をさらに改善し、物語全体の一貫性を高める工夫ができるかもしれません。

  4. LLMによる分担

    • やり取りの回数が多いため全体では相当の時間が掛かります。軽いモデルで設定を行い、本文は重いモデルで生成する、といった工夫も有効かもしれません。

    • またはサービス型のLLMをここぞというときに使うのもありかも。

  5. 人間の作家との協働モデル

    • どうにもAIは後半のタスクになるほどボロが出てくるので、協働モデルというほどではありませんが、AIによる下書き生成と人間の作家による仕上げはありだと思います。

    • また生成プロセスごとに介入して、生成結果を修正、ブラッシュアップしてから次のステップに進む、というのは有効そうです。
      (というか、少しでも最終出力をまともにしたいなら、現状ほぼ必須のようです。)

前回の記事から二か月弱ですが、個人的にも多少LLMの理解が進み、ある程度の改善ができたように思います。またこの間、特に30B以下の比較的小型のLLMはかなり精度が向上したようです。

今後のLLMの進化や、AIとの共同作業なども非常に楽しみになってきました。最後にClaude 3.5 Sonnetが書いたまとめの文章をそのまま置いておきます。

本プロジェクトを通じて、AIによる創作の可能性と課題が明らかになりました。技術の進歩と共に、AIは創作プロセスにおいてますます重要な役割を果たすようになるでしょう。しかし、真に心に響く物語を生み出すためには、人間の創造性や感性との協調が不可欠です。今後も、AIと人間のそれぞれの強みを活かしながら、新しい創作の形を模索していきたいと考えています。

よろしくね!

生成結果

Gemma-2-9Bの生成結果です。最後のテキストからは章の見出しが消えていますが、これは校正エージェントが「テキスト本文ではない」という理由で削除したためです。





この記事が気に入ったらサポートをしてみませんか?