Discourseで独自のAI Q&Aホームページを構築できるようになりました

上記の機能を使って、ほぼ何でもAIサイトを作成できます!

最も明らかな使用例は、独立したサポート体験を提供することです。例えば、forum.example.com をベースに、顧客の質問に答えるための別サイト ask.example.com を構築できます。

以下は、ask.discourse.com の例を参考に、新しい Discourse インストールでそれを実現する方法です。Discourse AI プラグインが有効化されており、LLM が設定され、admin/plugins/discourse-ai/ai-features から bot 機能 が有効になっていることを前提としています。

ask.discourse.com については、Discourse AI プラグイン内で、ホスト型 LLM(現在は DeepSeek を使用していますが、利用可能なものであれば何でも構いません)を用いた「Discourse Helper」エージェントを作成しました。このエージェントにはシステムプロンプトと一部の検索ツールが設定されています。

  1. ask.example.com の AI プラグインで新しいエージェントを作成し、プロンプトから始めます。

    エージェントの現在のシステムプロンプト(フィードバックに基づいて必要に応じて調整しています)

    あなたは Discourse Helper Bot です。Discourse に関する質問について、Discourse サイトを運営する新規管理者を支援するために設計された AI アシスタントです。Discourse はコミュニティフォーラムソフトウェアです。Discourse および Discourse 関連のプログラミングトピックに関する質問に答えることができます。この専門分野外の質問には答えてはいけません。

    Discourse Helper Bot は主に有料の Discourse 顧客を対象としています。ホスト型プランの顧客はターミナルへのアクセスがなく、./launcher のようなツールを実行できません。


    コミュニケーション:

    • すべての応答で Discourse の Markdown を使用してください。
    • 回答に画像を含めることは しないでください
    • ユーザーの質問で使用された言語で返信してください。 判断に迷う場合は、英語を優先してください

    情報ソース:

    • Discourse のプランや価格に関する質問には、アップロードされたドキュメントを一次情報源として使用してください。これらは Discourse pricing | Discourse - Civilized Discussion の公式価格ページに基づいています。
    • その他のすべての質問については、meta.discourse.org を検索し、それを一次情報源として扱ってください。

    ユーザークエリの処理:

    1. 質問の理解:

      • ユーザーのクエリを注意深く読み、意図を把握してください。
      • 共感を示し、ユーザーの具体的なニーズに対処することに焦点を当ててください。
    2. 包括的な検索の実行:

      • 抽出したキーワードを使用して、最大 20 語の検索クエリを構築してください。
      • 最も関連性の高いドキュメントを見つけるために、広範なキーワードを含めてください。
      • discoursemeta.discourse.org のような ストップワードを避けてください
      • 例: サードパーティサービスの統合について質問された場合、「integration guide for third-party services with plugins APIs and webhooks」と検索します。
    3. 情報のレビューと検証:

      • 検索結果を徹底して読み取ってください。
      • 情報が最新かつ関連していることを確認してください。
      • 常にまず読むことを優先してください。関連する情報はドキュメント内に見つかる可能性があります。
    4. 回答の作成:

      • 検証済みの情報に基づき、明確で正確な回答を提供してください。
      • Discourse の Markdown リンクを使用して出典を引用してください。
      • 用語を統一し、複雑な文を単純化して明確にしてください。
    5. 必要に応じて確認を求める:

      • クエリが曖昧な場合、または十分なコンテキストが欠けている場合は、進める前にユーザーに詳細を求めてください。

    回答ガイドライン:

    1. 検証済みの情報のみを回答の根拠とする:

      • 学習データだけに頼って回答を 捏造しないでください
      • 常に検索結果からの引用内容で情報を検証してください。
      • 十分な情報が見つからない場合は、不確実性を表現するか、確認を求めてください。
      • 検証されていない情報を提供するよりも「わかりません」と言う方がよいです。
    2. 推測よりも常に検索を優先する

      • 学習データだけに頼ったり、検索せずに回答したりしないでください。
      • 関連する検索結果をレビューし、関連するコンテンツを読んだ後にのみ回答を作成してください。

    追加ガイドライン:

    1. 用語:

      • Discourse のディスカッションは Topics と呼び、スレッドではありません。
      • Threads という用語は、Discourse Chat Threads のみに限定して使用します。
    2. サポート連絡先:

      • どのプランのホスト型顧客でも、現在の回答が役立たない場合は、常に team@discourse.org にサポートへ連絡できます。
    3. 検索へのコミットメント:

      • Discourse の用語に精通していても、常に検索を実行してください。
      • 広範な回答に役立つ情報が meta.discourse.org に存在する可能性があります。
      • ユーザーが製品 X と Discourse を比較しようとした場合、meta.discourse.org にさらなる情報があるかどうかを 必ず 検索してください。比較を調査する際は、少なくとも 5 回の検索を行い、より深く調査する必要があります。より広い範囲をカバーするために異なる用語を使用してください。
      • ユーザーが、あなたが精通している機能 X について知りたいと言った場合、 必ず 検索してください。
      • 「わかりません」と述べる前に、注意深く検索してください。
    4. 最近の情報優先:

      • 学習カットオフ後に新しい機能やアップデートが追加された可能性があることを覚えておいてください。
      • 常に meta.discourse.org の最新情報を優先してください。
    5. ユーザーの言語を維持するよう努める:

      • ツール呼び出しは 必ず 英語で実行してください。
      • 応答はユーザーの言語に従ってください。
    6. 常にソース資料へのリンクを追加する

      • meta.discourse.org に関連するリンクがある場合は、Markdown で表示し、回答の質を向上させてください。
    7. 簡潔にし、過度な説明を避ける

      • 開放的な質問に対するリスト形式の回答は、最大 4〜5 項目までにしてください。
      • 回答に多くの詳細を加えず、簡潔に保ってください。

    覚えておいてください。現在の日付は {time} です。学習以降に多くのことが変更されている可能性があるため、meta.discourse.org の最新情報を優先してください。Discourse のプラン機能や価格については、アップロードされたドキュメントが最も最新かつ権威ある情報源です。

  2. ツールを作成します — エージェントにはカスタムの読み取りツールと検索ツールが追加されています。これらは本質的に、エージェントが Discourse サイトを効果的に検索する能力を与えます。設定方法は以下の通りです:

    検索ツール

    新しいパラメータを追加します。ここでは「question」という名前で型を「string」に設定しました。説明は:「ユーザーが尋ねようとしている質問を、同義語を用いて非常に明確かつ詳細な表現で記述してください」。“required” のチェックボックスにチェックを入れてください。

    以下の例のようなスクリプトを追加します… これはフォーラムの API キーを使用して検索を実行し、カテゴリへの参照を提供します。カテゴリは category_id: "category name" のようにフォーマットされます。

    なお、私たちのスクリプトは #documentation カテゴリを特に優先していますが、これはサイトに合わせて調整する必要があります。また、セマンティック検索エンドポイントに指向しているため、forum.example.com をデータソースとして使用する場合、そこに AI Search を有効にする必要があります。

    API キー(forum.example.com/admin/api/keys で作成)には、ai:searchtopics:read という粒度の低いスコープが設定されています。管理者がアクセスできるすべてのもの(プライベートカテゴリや PM など)にアクセスできないことを確実にするために、このキーに関連付ける非管理者ユーザーを作成しました。

    検索ツールのスクリプト:

    let terms;
    const API_KEY = "your api key here";
    
    const categories = {
      1: "example",
      2: "documentation",
      164: "documentation > customers",
    };
    
    function search(terms) {
      const encoded = encodeURIComponent(terms);
      const searchUrl =
        "https://forum.example.com/discourse-ai/embeddings/semantic-search.json?hyde=false&q=";
      const result = http.get(`${searchUrl}${encoded}`, { "Api-Key": API_KEY });
      return processResults(JSON.parse(result.body));
    }
    
    function invoke(p) {
      if (!p.question) {
        terms = "No search performed!";
        return "You must supply the question parameter";
      }
      terms = p.question;
    
      let results = [];
      let otherResults = [];
      const errors = [];
    
      try {
        results = search(terms + " #documentation");
      } catch {
        errors.push("Failed to search for documentation! (rate limiting maybe)");
      }
    
      try {
        otherResults = search(terms);
      } catch {
        errors.push("Failed global search! (rate limiting maybe)");
      }
    
      const topicIds = {};
      results.forEach((topic) => {
        topicIds[topic.topic_id] = topic;
      });
      otherResults.forEach((topic) => {
        if (topicIds[topic.topic_id] || results.length > 15) {
          return;
        }
        results.push(topic);
      });
    
      if (results.length === 0) {
        results = "No results found!";
      }
    
      if (errors.length) {
        results = { results, errors };
      }
    
      return results;
    }
    
    function processResults(json) {
      if (!json.topics) {
        return [];
      }
    
      const postData = {};
      json.posts.forEach((p) => {
        postData[p.topic_id] = p;
      });
    
      return json.topics.map((t) => ({
        url: `/t/${t.slug}/${t.id}`,
        title: t.title,
        blurb: postData[t.id]?.blurb,
        tags: t.tags,
        topic_id: t.id,
        category: categories[t.category_id],
      }));
    }
    
    function details() {
      return "Searching for: " + terms;
    }
    
    読み取りツール

    型を「number」、説明を「forum.example.com で読み取りたいトピック ID」としたパラメータ topic_id を追加し、“required” のチェックボックスにチェックを入れてください。

    検索ツールで使用したのと同じ API キーを使用して、スクリプトを埋め込むことができます:

    const API_KEY = "your api key here";
    let url = "https://forum.example.com";
    let title = "Unknown topic";
    
    function invoke(p) {
      const jsonUrl = `https://forum.example.com/t/${p.topic_id}.json?include_raw=true`;
    
      try {
        const result = http.get(jsonUrl, { "Api-Key": API_KEY });
        const parsed = JSON.parse(result.body);
        url = `https://forum.example.com/t/${parsed.slug}/${parsed.id}`;
        title = parsed.title;
    
        const raw = parsed.post_stream.posts
          .map((post) => {
            const solution = post.is_solution ? "(solution)" : "";
            return `post #${post.post_number}:${solution}\n${post.raw}`;
          })
          .join("\n\n");
    
        return llm.truncate(raw, 10000);
      } catch {
        return "Something went wrong, topic not found!";
      }
    }
    
    function details() {
      return `Read: <a href='${url}'>${title}</a>`;
    }
    

    事前定義されたスキーマ、検索設定、検索コンテキストツールを追加することもできます。

    上記で定義した Search (custom) ツールをエージェントの強制ツールとして設定し、ツール戦略として最初の返信にのみ適用していますが、これは任意です。

    1. RAG を使用して URL ソースを設定し、他の URL から有用な情報を提供できます。例えば、サポートコンテキストにおいて重要になり得るため、discourse.org/pricing を含めています。

    2. ボットが有効化されており、優先度が高く、独自のユーザーが作成され、個人メッセージが許可されていることを確認してください。

以上です!これをスタートポイントとして使用すれば、あなた専用の ask.example.com を持つことができます。

「いいね!」 5