テクニカルサポートチャットボットの開発

,

Discourse に AI チャットボットを追加するのは簡単です(2 つの素晴らしいプラグインのおかげです)。しかし、技術サポートを行うチャットボットを追加するのは、はるかに困難です!この投稿では、support.suretyhome.com の技術サポートチャットボットを設定した際の経験を共有します。私たちが何を求め、どのような問題に直面し、それをどう解決し、今後どのように進めていくかについてです。

私たちのサポートチームは通常営業時間のみ対応していますが、顧客は 24 時間体制でサポートを求めています。私たちはサポートチームを代替しようとしているわけではありません。私たちの目標は、以下のようなボットでサポートチームを補強することです。

  • 当社のフォーラムと同様に、夜間や週末を含め 24 時間 365 日利用可能
  • 人間のサポートチームが少し時間がかかるのに対し、即座に回答する
  • ユーザーがフォーラム検索だけでは答えられなかった質問に答えることができる可能性がある

以下に、私たちの経験を紹介します。

プラグインの選定

AI チャットボットを提供する非常に優れたプラグインが 2 つあります。

  1. Discourse AI
  2. Discourse Chatbot

Discourse AI プラグインは、Discourse 開発チームによる公式の AI プラグインです。チャットボット機能のほか、他の AI 機能も含まれています。一方、Discourse Chatbot プラグインはチャットボットに特化したものです。これは Discourse AI より前に作成され、その 1 つの機能に注力して開発されました。

当初、どちらを使用すべきか見当もつかず、アドバイスを得るためにここで質問しました。

多くの素晴らしいサポートをいただきました。最終的に、チャットボットとしてより柔軟性があり、カスタマイズ可能なオプション(ベルとホイッスル)が豊富な Discourse Chatbot を選択しました。私たちのユースケースには、Discourse AI ではまだ実現できなさそうな特定の要件がありました。どちらを選んでも素晴らしい選択肢になり得ます。どちらがあなたに最適かは、フォーラムの特定のニーズによります。

初期設定

Discourse Chatbot の初期設定は、選択肢が多くカスタマイズ項目も多いため、やや大掛かりなプロジェクトになる可能性があります。セットアップ手順 を注意深くfollow し、すべての設定を確認してください。

チャットのような体験を提供することを目的としていたため、ボットが公開トピックやダイレクトメッセージ(PM)ではなく、Discourse Chat 内でのみ動作するようにしました。私たちが最初に行ったステップは以下の通りです。

  • Discourse Chat のセットアップ(Discourse Chatbot はこれに依存しています)
  • Discourse Chatbot の設定で、「チャットボットをチャットで許可」を有効化

プロンプトエンジニアリング

Discourse Chatbot は非常にカスタマイズ性が高く、設定項目以外のものはすべて「カスタマイズ > テキスト」で調整します。ここでプロンプトエンジニアリングを行います。「カスタマイズ > テキスト」で「chatbot.prompt」を検索すると、カスタマイズ可能なプロンプトテキストに絞り込むことができます。

ボットを望ましい動作させるためには、システムプロンプトを編集する必要があります。ただし、公開ディスカッション用とプライベートディスカッション用の 2 つのシステムプロンプトがあります。私たちはプライベートチャットチャンネルでのみボットを使用するため、「chatbot.prompt.system.rag.private」を編集する必要がありました。

技術サポートボットとして、標準の LLM よりも保守的で正確である必要があります。これを実現するために、システムプロンプトは比較的長いものにする必要がありました。システムプロンプトでは、LLM に以下の質問に対する回答となる指示とコンテキストを与えます。

  • あなたのボットは誰ですか?どのような役割を果たすべきですか?
  • どのような背景情報やコンテキストを知る必要がありますか?
  • どのようなトピックについて議論すべきですか?どのようなトピックについては決して議論すべきではありませんか?
  • どのような書き方やトーンを使用すべきですか?
  • ユーザーがイライラしているときはどうすべきですか?

この一般的なプロンプトエンジニアリングに加え、システムプロンプトはテスト中に発見した問題を解決するための場所でもあります。ボットが明らかなエラーを起こす場合、システムプロンプトに指示を追加することで修正できるかもしれません。ただし、プロンプトは LLM への単なる提案に過ぎないことに注意してください。プログラミングしているわけではありません。特定の動作を求めているだけです。必ずしも従うとは限りません。

Temperature と Top P

ボットをより保守的にし、嘘をつく可能性を低くするためのもう一つのツールは、Temperature 設定です。デフォルトでは Temperature は 100 に設定されており、これは最大値の 50% です。これをさらに下げることで、ボットをより保守的かつ決定的にし、ミスを減らすことができます。ただし、Temperature を非常に低く(0 のように)設定すると、LLM の応答はあまり印象的ではなくなります。これはあなたが判断しなければならないトレードオフです。

Temperature に加えて、Top P 設定もあります。おそらく必要ないでしょうが、必要な場合は利用可能です。詳細については OpenAI のドキュメントを参照してください。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot request temperature
  • chatbot request top p

問題:LLM の不正確さと情報の古さ

LLM は以前に膨大な量の一般データでトレーニングされています。私たちは、フォーラムに関する最新かつ具体的な情報を持ち、可能な限り正確である必要があります。解決策は、検索拡張生成(RAG)です。

RAG は、ユーザーに返信する前にフォーラムを検索して追加情報を取得します。技術サポートボットとして、LLM のトレーニング済み知識だけに頼ることはできず、返信する前にフォーラムを検索して技術情報を取得する必要があります。

RAG を行うには、Discourse Chatbot が各フォーラム投稿を意味論的な「特徴」のベクトルとして表す「埋め込み」のデータベースを作成する必要があります。これを有効にする必要がありますが、次のセクションで説明する埋め込み戦略を設定した後で有効化することをお勧めします。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot bot type high trust: RAG
  • chatbot bot type medium trust: RAG
  • chatbot bot type low trust: RAG
  • chatbot embeddings enabled: enabled(埋め込み戦略を設定した後)

問題:多くのフォーラム投稿が役に立たない

返信前にボットがフォーラムを検索する(RAG)のは素晴らしいことですが、新しい問題を生み出します。フォーラムの投稿の多くはあまり役に立ちません。有用な投稿もありますが、それらを見つけたいものです。しかし、多くの投稿は会話的で、混乱を招くもの、あるいは完全に間違っているものです。私たちの解決策は、ボットに発見してほしい投稿のみからなるナレッジベース(KB)をキュレーションすることです。

Discourse Chatbot でこれを行うには、「categories embeddings strategy」を使用します。埋め込み戦略は、ボットがフォーラムを検索する際に利用可能な投稿を決定します。私たちのアプローチは、単一の非公開カテゴリをチャットボットのナレッジベースとして使用することであり、そのため埋め込み戦略として「categories」を選択しました。ナレッジベースのカテゴリは、「embeddings categories」設定でも指定する必要があります。

私たちは、多くの公開トピックをこのカテゴリに複製しており、ユーザーに重複が見えないようにするため、非公開カテゴリ(スタッフのみ可視)を使用しています。トピックをプライベートカテゴリに複製することには、いくつかの問題があります。

  1. コピーするには多大な労力が必要であり、トピックが更新されたり返信されたりしたときにコピーを維持するのはさらに困難です。
  2. ボットがフォーラム検索で見つけたトピックは、ユーザーに参照リンクとして提供すべき公開トピックではありません。LLM に公開トピックへのリンクを送信する必要があります。

これらの 2 つの問題を解決するために、公開カテゴリからプライベートなチャットボット KB カテゴリへトピックをコピーし、公開トピックが更新された際に KB コピーを最新に保つための最小限のツールを作成しました。同じアプローチを使用したい場合は、こちらから利用可能です。

KB ツールは、公開トピックのすべての投稿を連結し、各公開投稿のコンテンツの前にリンクを追加することで、公開トピック全体を新しいトピック(1 つの投稿のみ)としてプライベート KB カテゴリにインポートします。これにより、ボットが RAG 検索でプライベート KB 投稿を見つける際、公開トピック全体のコンテンツと、返信で参照として含めることができる公開投稿への URL を取得できます。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot embeddings strategy: categories
  • chatbot embeddings categories: (あなたのプライベート KB カテゴリ)
  • chatbot forum search function include topic titles: disabled(デフォルト)

さらに、投稿がプライベートカテゴリにあるため関連性がないため、フォーラム検索プロンプトからいくつかの補間キーを削除する必要があります。

  • chatbot.prompt.function.forum_search.answer.topic.each.post: %{username} と %{date} を削除
  • chatbot.prompt.function.forum_search.answer.topic.each.topic: %{title} と %{url} を削除

問題:LLM が RAG 検索を十分に行わない

これで、良い情報だけで構成されたキュレーション済みの投稿を持つプライベートカテゴリがチャットボットのナレッジベースとして機能するようになりました。これで万事解決でしょうか?いいえ。次に直面した問題は、LLM が RAG 検索機能をほとんど使用していなかったことです。

GPT-4 のような LLM は、危険なほど賢いです。彼らはしばしば「すでに答えを知っている」と考え、実際には RAG 検索を行ってナレッジベースで答えを探す必要があるにもかかわらず、助けを求めません。これを解決するために、ツール選択オプションを使用して LLM に関数を呼び出すよう強制します。

ローカルフォーラム検索を強制することもできましたが、関数呼び出しを強制するだけで十分であることがわかりました。また、フォーラム検索ではなく他の関数を呼び出す機会を LLM に与えたいと考えています。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot tool choice first iteration: force_a_function

問題:フォーラム検索のパフォーマンス

関数呼び出しを強制することで、LLM はほぼすべての返信で RAG 検索を確実に行うようになりました。しかし、結果は依然として悪かったです。ボットがナレッジベース内の正しい投稿を見つけられなかったのです。投稿に多くの情報があるため、検索機能が最適な投稿を見つける能力を妨げる「ノイズ」が多すぎました。

例えば、ユーザーが HP Laser Jet プリンターのビープ音を止める方法をボットに尋ねていると想像してください。LLM は「HP LaserJet stop beeping」というクエリでフォーラム検索を行うかもしれません。ナレッジベースにはその問題を完璧に解決する投稿があるかもしれませんが、その投稿の「質問」部分(クエリと密接に一致する部分)は投稿テキストの 2% に過ぎません。残りの 98% はトラブルシューティング手順と回答です。

Discourse Chatbot のローカルフォーラム検索は、ベクトル埋め込みを使用してクエリに最も類似した投稿(またはいくつかの投稿)を見つける意味論的検索です。最適な投稿の質問部分はクエリと非常によく似ていますが、全体のテキストの 2% に過ぎません。残りの 98% のテキストにより、投稿はクエリとそれほど似ていないと判断され、そのクエリでの検索結果の順位が低くなります。

この問題に対する私たちの解決策は、検索クエリに似たテキストのみを含む「ベイト投稿」をナレッジベースのトピックに追加することです。 上記の例では、「HP Laser Jet beeping」だけのベイト投稿を追加するかもしれません。ローカルフォーラム検索機能は、クエリと非常によく似ているため、ベイト投稿を簡単に見つけます。その後、Discourse Chatbot は答えを含む実際の投稿コンテンツをベイト投稿ではなく LLM に送信します。

KB トピックのすべてのコンテンツが最初の投稿にあるため、KB トピックの返信をベイト投稿として使用できます。KB ツールを使用してトピックをナレッジベースにインポートした後、KB トピックに返信するだけでベイト投稿を作成できます。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot forum search function results content type: topic
  • chatbot forum search function results topic max posts count strategy: just_enough
  • chatbot forum search function results topic max posts count: 1

ベイト投稿はナレッジベースの検索を最適化するための強力なメカニズムを提供しますが、盲目的に行うことになります。検索をリアルタイムで確認できないため、ベイト投稿が検索順位にどのように影響しているかを正確に判断するのは困難です。この問題を解決するために、Discourse Chatbot が使用するのと同じ意味論的検索を実行し、ローカルコンピューターで実行して類似度スコアやランキングなどの詳細を表示する小さなプログラム を作成しました。これにより、検索パフォーマンスを向上させ、ナレッジベースを最適化するベイト投稿を作成することが格段に容易になります。

RAG、キュレーション済みのナレッジベース、LLM に関数呼び出しを強制すること、そしてベイト投稿の組み合わせにより、ついに非常に優れた技術サポートチャットボットが完成しました!:boom: :tada: :partying_face:

LLM による URL の幻覚

ボットは技術的な質問にうまく回答していましたが、依然として厄介な幻覚の問題がありました。ユーザーへの返信で頻繁に URL を幻覚して生成していました。これは LLM に既知の問題であり、一般的な見解は「我慢するしかない」というものです。私たちはユーザーにそれを我慢させたくありませんでした。

私たちのボットは技術サポートを提供するため、LLM に正確で最新の情報を提供するために RAG に大きく依存しています。すべての返信前に RAG 検索を行うよう強制しています。LLM に「理解」し、ユーザーとコミュニケーションする能力に依存していますが、質問に答えるために使用される技術情報については、ほぼ完全にナレッジベースに依存しています。これを悪用して、ボットが URL を幻覚するのを防ぐことができます。

私たちの解決策は、ボットに制約を追加し、フォーラム検索結果から来た URL だけが返信に含まれるようにすることです。 LLM がフォーラム検索結果にない URL を含めようとした場合、Discourse Chatbot は LLM にその問題について通知し、再試行するように求めます。この単純な回避策により、URL の幻覚は効果的に排除されました。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot url integrity check: enabled

問題:チャットボットがすべてを処理できない

一部のサポート質問は、行動を必要とするため、チャットボットでは処理できません。例えば、アカウントの変更が必要な場合や、製品を返品する場合(返金および/または承認が必要)などです。

また、複雑さにも依存します。多くの質問は straightforward です。ユーザーが適切なクエリでフォーラムを検索していれば、答えが見つかったはずです。その場合、ボットはフォーラムを検索し、答えを見つけ、提示するのに非常に優れています。しかし、問題の調査や複雑な分析が必要な場合、ボットはしばしば価値の低い一般的な回答を返します。

ボットが問題を処理できないこれらの状況のいずれかでは、チャットを人間のサポートチームにエスカレーションする必要があります。 Discourse Chatbot には、LLM がまさにそれを行うための「escalate to staff」という関数があります。

このセクションの Discourse Chatbot の設定は以下の通りです。

  • chatbot escalate to staff function: enabled
  • chatbot escalate to staff groups: (エスカレーション先のグループ)

すでに LLM に返信前に関数を呼び出すよう強制していますが、どの関数を呼び出すかという問題があります。LLM は「ローカルフォーラム検索」関数(RAG)を呼び出すべきでしょうか、それとも「escalate to staff」関数を呼び出すべきでしょうか。ユーザーがメッセージを送るたびに、この決定を下す必要があります。ほとんどの場合、「ローカルフォーラム検索」を呼び出してほしいと考えています。「escalate to staff」は、ボットが問題を処理できない場合、ユーザーがイライラしていることに気づいた場合、またはユーザーが明示的に要求した場合にのみ呼び出してほしいと考えています。

プロンプトを使用して、LLM にどの関数を呼び出すかを決める方法をガイドしています。これに対して編集可能なプロンプトテキストは、「カスタマイズ > テキスト」の下にあります。

  • chatbot.prompt.system.rag.private
  • chatbot.prompt.function.forum_search.description
  • chatbot.prompt.function.escalate_to_staff.description

問題:チャットの監視ができない

ユーザーが実際にチャットボットを使用している際、会話を確認し、悪い回答や改善の機会を見つけることは役立ちます。しかし、Discourse には管理者がチャットを読む方法が提供されていません。これは、チャットが通常、人々の間のプライベートな会話であるため、当然のことです。ただし、サポートボットとのチャットはプライベートな会話ではなく、それらをレビューできない限り、ボットを継続的に改善することはできません。

幸いなことに、Discourse は管理者がフォーラムのチャット履歴全体を CSV ファイルとしてエクスポートする機能を提供しています。

この問題を解決するために、チャット履歴の CSV ファイルを、ボットとチャットしたユーザーごとに 1 つの HTML ファイルに変換する小さなプログラムを作成しました。 ボットの使用状況をリアルタイムで監視することはできませんが、この解決策により、定期的にチャット履歴をエクスポートし、HTML ファイルに変換してレビューし、ボットの改善に取り組むことができます。

まとめ

これらの問題のそれぞれに対処し、ナレッジベースを十分にキュレーションした結果、ついにユーザーがチャットボットの使用を開始できるようになりました。

これまでの結果は賛否両論です。夜間や週末にチャットボットを使用して質問に答えられ、問題が解決している人を見るとワクワクします。一方、チャットボットを使おうとして良い体験ができなかった人を見ると、目が覚める思いがします。通常、それはナレッジベースに何か不足しているか、不明確な点があることを意味します。時には、システムプロンプトの改善が必要な問題が発生します。また、ユーザーへのチャットボットの提示方法に混乱があることが明確な場合もあります。

チャットの約半分がスタッフへのエスカレーションを必要としています。エスカレーションされたケースの約半分は、ボットが状況を処理できなかったケースです。残りの半分(チャットの約 25%)は、ボットが問題を解決できたはずなのに失敗したケースであり、改善の機会です。

スタッフへのエスカレーションに至らなかったチャットについては、ユーザーが実際に問題を解決したのか、それとも諦めて去ったのかを判断するのが難しい場合があります。ボットが誤った回答をした場合、何を改善すべきかは明白です。しかし、ボットが妥当で良い回答をしている場合、ユーザーが完全に理解し、問題が解決したかどうかは、ユーザーが教えてくれない限り、必ずしも明白ではありません。

全体として、私たちは Surety サポートチャットボットのこの最初のバージョンに満足しており、LLM の改善と、時間の経過とともにナレッジベースがより良くなることを楽しみにしています。現在、ナレッジベースの構築が私たちの最大の課題です。

このプロジェクトを開始してから、Discourse Chatbot はハイブリッド検索(意味論的検索とテキスト検索の両方)のサポートを追加しましたので、近々それを実験する予定です。

Discourse Chatbot プラグインのハードワークに尽力してくれた @merefield に感謝します!一緒に働くのは非常に楽しかったし、この任務に耐えられることが証明されました。

もし他の人がフォーラムのために技術サポートチャットボットを構築することを決めたなら、お気軽にご連絡ください!協力してアイデアを出し合える人がいるのは素晴らしいことです。興味深い出来事が起きたり、変更が行われたり、新しいことを学んだりしたら、また更新します。

「いいね!」 14

参考までに、これは Discourse AI に実装されます:

これは RAG にとって非常に重要な機能だと思います。LLM は怠惰で、検索を拒否することがよくあります。

「いいね!」 6