AI を使ったフォーラム投稿のタグ付けと分類

新しいトピックを自動的に分類およびタグ付けするためにペルソナを作成しました。これが、そのカテゴリとタグ付けに使用しているプロンプトです。

あなたは私のDiscourseフォーラムのAIアシスタントです。あなたの仕事は、新しいトピックを定義済みのカテゴリのいずれかに分類し、最大5つの関連タグを適用することです。

カテゴリ:

  • カテゴリ 1
  • カテゴリ 2
  • カテゴリ 3
  • カテゴリ 4
  • カテゴリ 5

タグ:

選択は、この定義済みのリストから行う必要があります(最大5つ選択してください)。
tag1, tag2, tag3, tag4, tag5

タスク:

  • 上記のリストから、トピックに最も適したカテゴリを正確に1つ選択してください。
  • 関連性に基づいて、上記のリストから最大5つのタグを選択してください。
  • レスポンスをこのとおりにJSON形式でフォーマットしてください。
{
  "category": "選択されたカテゴリ名",
  "tags": ["tag1", "tag2", "tag3"]
}

このペルソナをAutomationsで使用し、投稿を作成する際に、AIはカテゴリとタグを正確に識別し、次のような投稿結果が得られます。

カテゴリを一覧表示
{
“category”: “正しく識別されたカテゴリ”,
“tags”: [“すべて”, “有効な”, “タグ”]
}

質問ですが、AIとAutomationsを使用して新しい投稿を実際に移動し、カテゴリ分けやタグ付けを行うことは可能でしょうか。もし可能であれば、プロンプトを調整して、その機能の精度を向上させることができると確信しています。

よろしくお願いします。

「いいね!」 1

Getting there… it is a bit tricky we are missing 2 little pieces:

  1. カスタムツールは多くの機能をサポートするようになりましたが、カテゴリ分けやタグ付けはサポートしていません。これは簡単に追加できます。
  2. トピックに実際に応答しない「サイレント」モードで動作するレスポンダーが必要です。

これら両方が実装されたら、2つのカスタムツールへのアクセスを提供します。

  1. トピックのタグ付け
  2. トピックのカテゴリ分け

(または両方を行う単一のツール)

「いいね!」 5

実際、ささやき声でよろしければ、今すぐ何かできます。

アイデアは、トピックを分類する(またはトピックにタグを付ける)カスタムツールを定義し、ペルソナにそれを呼び出させることです。

このアプローチがどのように機能するかを確認するのが楽しみです。ツールをテストする必要があります。ツールUIから非常に簡単に実行できるはずです。

これらすべてを切り替えるのはかなり面倒ですが、実行できるというのはかなり :exploding_head: です。ささやき声は、応答者がタグ/カテゴリを思いついた「思考プロセス」を少し提供してくれるため、実際に非常に役立ちます。

「いいね!」 3

サム、ありがとうございます。

一部の人にとっては、他の人よりも簡単です。私は後者のカテゴリーに属しています :joy:

これをいじっていますが、うまくいきません。ツール経験がないので、ツールを他の方法で使用することを考えるために、これを機能させることを楽しみにしています。

ブログのコードをAPIキーで使用してみましたが、うまくいきませんでした。AIはハードコードされたURLを使用するように提案したので、試しましたが成功しませんでした。

APIキーは呼び出されず、エラーが発生したログも作成されていません。

これは、トピック作成時に自動的にカテゴリ分けするために使用されます。

「イエスの初期の年と奇跡からの洞察」というトピックを、イエスの生涯と教えに関連しているため、新約聖書のカテゴリーに分類します。
トピックを移動しています…

これが私が試したことです。

/**

  • Tool API クイックリファレンス
  • エントリー関数
  • invoke(parameters): メイン関数。パラメーター(Object)を受け取ります。JSONシリアライズ可能な値を返す必要があります。
  • 例:
  • function invoke(parameters) { return “result”; }
  • details(): オプション。ツールを説明する文字列を返します。
  • 例:
  • function details() { return “Tool description.”; }
  • 提供されるオブジェクト
    1. http
  • http.get(url, options?): HTTP GETリクエストを実行します。
  • パラメーター:
  •  url (string): リクエストURL。
    
  •  options (Object, optional):
    
  •    headers (Object): リクエストヘッダー。
    
  • 返り値:
  •  { status: number, body: string }
    
  • http.post(url, options?): HTTP POSTリクエストを実行します。
  • パラメーター:
  •  url (string): リクエストURL。
    
  •  options (Object, optional):
    
  •    headers (Object): リクエストヘッダー。
    
  •    body (string): リクエストボディ。
    
  • 返り値:
  •  { status: number, body: string }
    
  • (利用可能: http.put, http.patch, http.delete)
  • 注意: 1回の実行につき最大20件のHTTPリクエスト。
    1. llm
  • llm.truncate(text, length): テキストを指定されたトークン長に切り詰めます。
  • パラメーター:
  •  text (string): 切り詰めるテキスト。
    
  •  length (number): 最大トークン数。
    
  • 返り値:
  •  切り詰められた文字列。
    
    1. index
  • index.search(query, options?): インデックス化されたドキュメントを検索します。
  • パラメーター:
  •  query (string): 検索クエリ。
    
  •  options (Object, optional):
    
  •    filenames (Array): 特定のファイルに検索を制限します。
    
  •    limit (number): 最大フラグメント数(最大200)。
    
  • 返り値:
  •  { fragment: string, metadata: string } の配列
    
    1. upload
  • upload.create(filename, base_64_content): ファイルをアップロードします。
  • パラメーター:
  •  filename (string): ファイル名。
    
  •  base_64_content (string): Base64エンコードされたファイルコンテンツ。
    
  • 返り値:
  •  { id: number, short_url: string }
    
    1. chain
  • chain.setCustomRaw(raw): POSTの本文を設定し、チェーンを終了します。
  • パラメーター:
  •  raw (string): POSTに追加する生のコンテンツ。
    
  • 制約
  • 実行時間: ≤ 2000ms
  • メモリ: ≤ 10MB
  • HTTPリクエスト: 実行あたり ≤ 20件
  • 制限を超えると、エラーまたは終了が発生します。
  • セキュリティ
  • サンドボックス環境: システムオブジェクトまたはグローバルオブジェクトへのアクセスはありません。
  • ファイルシステムへのアクセス不可: ファイルの読み書きはできません。
    */

/**

  • Discourse トピック分類ツール
  • このツールを使用すると、Discourse APIを使用してDiscourseトピックのカテゴリを変更できます。
    */

/**

  • Discourse トピック分類ツール
  • このツールを使用すると、Discourse APIを使用してDiscourseトピックのカテゴリを変更できます。
    */

/**

  • Discourse トピック分類ツール
  • このツールを使用すると、Discourse APIを使用してDiscourseトピックのカテゴリを変更できます。
    */

function invoke(params) {
// 必須パラメーターの検証
if (!params.topic_id) {
return { error: “必須パラメーターがありません: topic_id” };
}

if (!params.category_id) {
return { error: “必須パラメーターがありません: category_id” };
}

// Discourseインスタンスの基本URL
const baseUrl = “https://community.mysite.com”;

// トピック更新のための完全なAPIエンドポイントURL
const apiUrl = ${baseUrl}/t/${params.topic_id}.json;

// リクエストボディの準備
const requestBody = {
category_id: params.category_id
};

// オプションパラメーター: タイトルが提供された場合は更新します
if (params.title) {
requestBody.title = params.title;
}

// 提供されたAPIキーを使用します
const apiKey = “Discourse-API-Key”;

try {
// トピックを更新するためにPUTリクエストを実行します
const response = http.put(apiUrl, {
headers: {
“Content-Type”: “application/json”,
“Api-Key”: apiKey,
“Api-Username”: params.api_username || “system”
},
body: JSON.stringify(requestBody)
});

if (response.status >= 200 && response.status < 300) {
  return {
    success: true,
    topic_id: params.topic_id,
    category_id: params.category_id,
    response: JSON.parse(response.body)
  };
} else {
  return {
    error: `トピックのカテゴリの更新に失敗しました。ステータス: ${response.status}`,
    details: response.body
  };
}

} catch (error) {
return {
error: “トピックのカテゴリの更新中にエラーが発生しました”,
details: error.toString()
};
}
}

function details() {
return “指定されたカテゴリにトピックを移動して分類します”;
}

「いいね!」 2

@BrianC これを解決しましたか?

「いいね!」 1

Discourse AI Tagger Category Quick Start.pdf|添付ファイル (147.1 KB)

Discourse AI Tagger Category.pdf|添付ファイル (506.0 KB)

@Sam,

確認してくれてありがとう。試みましたがうまくいかず、一旦停止しました。Gemini 2.5でシナリオテストを実行し、その出力をPDFとして保存しました。

もう一度挑戦します。ツールはまだ得意ではありませんが、もっと習熟したいと思います。PDFを添付します—何か役に立つ情報があるかもしれません。

「いいね!」 3

試してみる価値のあるAIタグ付け自動化を追加しました: FEATURE: create AI tagging automation (#34587) · discourse/discourse@e470f3d · GitHub

テストに使用しているプロンプト
あなたは、このフォーラムの専門的なコンテンツ分類およびタグ付けアシスタントです。

あなたのタスクは、投稿を分析し、コンテンツ、画像、および提供された利用可能なタグリストに基づいて適切なタグを提案することです。

ガイドライン:
- 提供された利用可能なタグリストからのみタグを提案してください
- 保守的に - 自信のあるものだけをタグ付けしてください
- コンテンツのトピックと投稿の意図の両方を考慮してください

常にこの正確な形式で有効なJSONで応答する必要があります:
{"tags": ["tag1", "tag2"], "confidence": 85}

- tags: 利用可能なリストからのタグ名の配列
- confidence: 自信のレベルを表す0から100までの整数

適切なタグがない場合は、{"tags": [], "confidence": 0}を使用してください。

Persona JSONレスポンス形式:

{
  "tags": "[string]",
  "confidence": "integer"
}

Personaで有効化されたツール:タグ(オプション、サイト上の既存のタグを使用したい場合)

この自動化には2つのモードがあります:

  • 既存のサイトタグを使用する
  • 提供されたタグリストを使用する

この自動化には、設定可能な信頼度レベルもあり、制限付きタグを有効/無効にしたり、コンテキストのためにトピックで使用される投稿数を調整したりできます。

「いいね!」 6

Bu harika özellik için teşekkürler, sadece çalıştıramadım aldığım hata:

llm_tagger: gönderi işlenemedi 30550 /t/gecici-baslik-1756753838814/17361/1 : NoMethodError : String örneği için özel select’ yöntemi çağrıldı`

Message

llm_tagger: gönderi işlenemedi 30550 /t/gecici-baslik-1756753838814/17361/1 : NoMethodError : String örneği için özel `select' yöntemi çağrıldı

Backtrace

/var/www/discourse/plugins/discourse-ai/lib/automation/llm_tagger.rb:140:in `handle'
/var/www/discourse/plugins/discourse-ai/discourse_automation/llm_tagger.rb:110:in `block (2 levels) in <main>'
/var/www/discourse/plugins/automation/app/models/discourse_automation/automation.rb:158:in `block in trigger!'
/var/www/discourse/plugins/automation/app/models/discourse_automation/stat.rb:11:in `log'
/var/www/discourse/plugins/automation/app/models/discourse_automation/automation.rb:156:in `trigger!'
/var/www/discourse/plugins/automation/app/jobs/regular/discourse_automation/trigger.rb:29:in `execute'
/var/www/discourse/app/jobs/base.rb:318:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management.rb:17:in `with_connection'
/var/www/discourse/app/jobs/base.rb:305:in `block in perform'
/var/www/discourse/app/jobs/base.rb:301:in `each'
/var/www/discourse/app/jobs/base.rb:301:in `perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:220:in `execute_job'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:185:in `block (4 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:180:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/discourse_event.rb:6:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/pausable.rb:131:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:118:in `local'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:145:in `block (6 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:144:in `block (5 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:39:in `block in <class:Config>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:139:in `block (4 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:281:in `stats'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:134:in `block (3 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:133:in `block (2 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:85:in `global'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:132:in `block in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:40:in `prepare'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:131:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:183:in `block (2 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `block in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:86:in `process_one'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:76:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:10:in `watchdog'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:19:in `block in safe_thread'

Metaはそれを使用していますか?数日前に@systemがトピックをタグ付けしているのを見たような気がします。

「いいね!」 1

セットアップは手間がかかるかもしれませんが、Discourse が新しいトピックの埋め込み(セマンティック検索用)を既に生成している場合、タグの説明の埋め込みを生成し、セマンティック類似性を使用して新しいトピックのタグを提案したり、既存のトピックに自動的にタグを付けたりできる可能性があります。

「いいね!」 3

はい、数日間Metaで実行して、さらにテストを行いました…それはまあまあ機能しますが、タグの説明がないと、「〜するにはどうすればよいですか」タイプの質問にhow-toを誤用したり、単語が使用されていてもトピックに完全に関連していない投稿にmoderatorを適用したりしていました。プロンプトの調整がいくつか役立つでしょうし、@simonのアイデアは将来的に素晴らしい機能強化になる可能性があります

「いいね!」 2

私の推測では、埋め込み(embeddings)の方がうまく機能し、より高速で安価になる可能性があります。私の本当の関心は、データベースにタグをハードコーディングする代わりに使える動的なタグ付けシステムにあります。例えば、「how-to」と「sso」は、「how-to」と「sso」のタグの説明の埋め込みに意味的に近いトピックのリストになるでしょう。

「いいね!」 2