キャラチャット、会話の最小単位は1対1で行われるものだ、という前提で作ってて、複数話者が参加する会話を実装する際には、1対1の会話の集合として定義するつもりだった。

しかし、例えば3人の話者ABC(Aは人間ユーザーでも良い)が参加するだけでも、A-B、B-C、C-Aの3つの組み合わせを要することになってめんどいな。

つまり、設計が良くなかったかもしれない。

フォロー

そもそも、chatはspeaker1(ユーザーとか主人公とかのrole)とspeaker2(speaker1の会話相手としてのrole)の会話で構成されていて、両者は等価な扱いをしてないんよね。
なので、A-B、A-Cは良いとして、B-Cの組み合わせってのがそもそもできない。BとCを等価に扱う仕組みになってないので。

でも、会話は「自分」と「相手」の2人で行うものである、というモデル化は悪くないと思ってる。

LLMで実装する場合、会話参加人数分、個別の「主人公が相手と話す、という1人称小説を書いて下さい」というプロンプトを推論することで、登場キャラたちの人格が混ざりにくくなる効果があるので。

だからまあ、うまいこと、このモデルを多人数会話に拡張したいなあ。精度と効率を保ちつつ。

A-B、A-Cの会話を交互に(あるいはLLMによる選択に従って)実行し、チャットログを共有する、というのが良さそう。

A→B→Cという順で発話をさせたい場合、A-B→A-Cの順で会話を実行するが、2つ目の会話ではAの発言をスキップする、という風にすれば良いだろう。(発言スキップはできるようになってる)

また、BからCに話すときは、A-Bの会話中で、「BがA以外の相手に話しかける」イベントとして組み込めば良いな。あくまでチャットの中心はAなので、A以外に話すのはどちらかというと従の行為だから、こういう扱いで良さそう。

この仕組みだと、会話参加人数を何人でも増やせるはず。

speaker1はA固定で、speaker2にB,C,D…がターン毎に差し替わる。

まあ、そういう作りになってないのは確かなので、大改造は必要だけど、根本的な会話モデルに手を入れなくて済む。

A-B、A-C、A-D…な会話プロンプトをローテーションさせることのメリットは他にもある。KVキャッシュのsave & loadが効く。ここにB-Cなどのプロンプトまで含めると、保持しておくべきKVキャッシュの数が増えて非効率だからね。

「次の話者を選択する仕組み」も既に実装してある。
実装は単純で、

A「おはよう」
B「

というプロンプトが、

おはようございます」
A「そ

と補完された場合、【おはようございます】部分を推論結果として出力し、【A】部分を次の話者として記憶する。それだけ。

複数人チャットの場合、A-B会話中に【A】が返ってきたら次の話者はユーザーになるし、【B】なら次ターンもA-Bの会話、【C】なら次ターンはA-Cの会話でA(ユーザー)発言を省略、となる。

AがB、Cのどちらに話しかけるか、つまりA-B会話にするかA-C会話にするかの選択は、LLMに敢えて選択させるまでもないかな。
@ Bみたいなコマンドや、「おはようCさん」みたいな台詞からの文字列検索で自動決定で十分だろう。

A-BをA-Cに切り替えるコストは、KV cacheのsave & loadを駆使しても、そんなに安い処理では無いのも事実なので、なるべく数ターンに渡って会話相手を固定できるようにしといた方がいいかもしれない。

この辺の実装、だいたいできた。ただ、やはり複数人同士の会話になると、ボットが自分のキャラを見失いがちだ。色々と工夫を試してはいるが著効せず、7Bモデルの限界かもしれん。

一番の問題は、コンテキストに自分以外のキャラの発言が含まれること。他のキャラがうつってしまう。

対策として、他キャラ発言を地の文に変換してみたんだけど、そうすると、そのキャラ自身も地の文でしゃべってしまう。これはあくまでチャットだから、そうされるとまずい。地の文出力をやめるという手もあるにはあるが…。

ログインして会話に参加
Fedibird

様々な目的に使える、日本の汎用マストドンサーバーです。安定した利用環境と、多数の独自機能を提供しています。