はじめに
前回:Dify+Xinference+OllamaでローカルAIチャットボットを作る!
続というからには前回のなんとなくの全容がわかるようなわからないような話ではなくて、どういう風な実装を行ったかとかについて話していければいいなって思いました。
そもそも、前回は大体ざっくりなもうそもそも作ってなくてもできそうなレベルの話をしていたのでw
チャットボットの実装
チャットボットは基本的にはDifyで組んでいます。
全体像
基本的な考え方としては、LLMにも得手・不得手があるので、得意分野のLLMに得意なものを食わせる形にするという方向性で実装していきます。
0番の説明
0番の本流では話題を推定しています。どの話題なのか?専門性はあるのか?をざっくりと確認する形にします。
Difyには質問分類器というノードがあるんですが、分類対象の質問が増えるとうまく判定してくれなかったりそもそも処理が遅いのでLLMに独自にプロンプトを流して軽くするなどの工夫をしているのでこうなっています。
次に1~3の分流があります。
1番はレビューの分流
2番は専門的な知識を要求する分流(今は電気工事の内容のみ、今後はIT関係の知識も並列に組み込むつもり)
3番は雑談の分流
1番
- 〇〇の文章を翻訳して だとか(1-2)
- このコードの意図を教えて だとか(1-1)
- このコードにある脆弱性を教えて だとか(1-1)
そういう自然言語やコードレビューを行わせる流れが1番です。
2番
専門的な話についての分流が2番です、辞書を引く必要があるものですね。ここでいう辞書を引く必要があるかどうかは、LLMの知識で対応できないものを指します。なのであらかじめ0番で質問内容が専門的であり特定の領域の話であるかどうかを判定しておきます。
この経路はRAGの経路です。LLMには知識がないことが往々にして有ります。推論は正しそうだけど明らかに違うこと言ってるから質問の回答を探すクエリを正しく作れないことがまぁ有ります。ここはLLMのモデルによって様々ですがユーザクエリを基に用語集を辞書から引っ張ってきて事前知識を与えることにしました。
書籍にはAdvanced-RAGのHyDEという手法であると記述されていますが、さらにこれを発展させてみました。
考え方
参考書籍によれば、HyDEは質問から仮の推論結果を出させることを指しています。ベクトルDBから検索したいデータは質問の回答と近似した内容であるためですね。
ここからは自由研究の範囲なので、論文とかがあるわけではないですが一応書いておきます。
ここでの知識がないというのは、LLMが用語自体は学習しているけど文脈があいまいで、用語を正しく使えない時を知識がない状態であると定義します。さらに知識というのは例えば、電圧や電流に関する定義、分類といった専門性のある分野の話です。(低圧や高圧、特別高圧の電圧区分のような話を指します)
なので、質問文から辞書ベースで仮の知識を与え、さらに引いた辞書の内容(コンテキスト)と質問から、質問に対する仮の推論結果を専門的な用語を用いて出させます。
こうすることで、推論結果の質がモデルによって極端に左右されることなく出せるかなと思った次第です。
書籍に載っているHyDE
- 回答をLLMに推論させる
- 推論した結果をVectorDBに引かせる
- LLMに要約させる
改良したHyDE
- 質問文をVectorDBに引かせる
- LLMにVectorDBの文脈を基に質問文について回答せよと指示を与える
- 推論した結果をVectorDBに引かせる
- LLMに要約させる
こんな感じ。
3番
雑談フローです!基本的に壁当てBotの心臓部分といっても良い気はします。
LLMは現在の気温や季節なんかの問い合わせには非常に弱いので現在時刻や現在が朝昼晩なのか日は沈んでいるのかだとかそういう情報をまず与えてから雑談させています。これがエモさです。
で、一応ここにはユーザからの質問に対する直接的な応答が入るのでシステムプロンプトの出力チェックを入れています。(一番高リスクなので)
セキュリティ
Difyで実装する場合においては、システムプロンプトもステートレスであることで、書き換えが発生したとしてもそのクエリ(ただしメモリ機能を使わない場合)のみの書き換えに収まることを一応は検証しました。
(若干本当か?感はありながら書いているのでまたあとで訂正するかも)
なのでとりあえずは、出力がされてるかどうかのチェックをすることにしています。
システムプロンプトの出力チェックはシンプルに発言内容であらかじめプロンプトの内容を保存したベクトルDBを引くことで実現しています。もし、プロンプトが引かれていたら定型文を返却することにしています。
ブラインド系の攻撃が有りそうだけどまぁ個人利用の範疇で外部公開やサービス化はしないつもりなので受容したい。とはいえセキュリティ的な事項なのでこの辺りの勉強したい感は強いね。
まとめ
- 基本はLLM単体の性能では比較的早期に頭打ちとなる(重み付き量子化4bit~5bitモデルの場合の検証結果です)
- 複数のLLMを用いるが、そのカバー対象となる話題の判定が結構難しかったりする
- バカつよマシンがあればクソデカ基盤モデルを載せて動かせるのでその限りではないかのうせいはあるが、PCなどのエッジノードレベルでやるならこの方法がよさそう