Discourse AI - 情感分析

:bookmark: 本指南介绍如何在 Discourse AI 中配置情感和情绪分类,并使用报告来探索社区帖子中的模式。

:person_raising_hand: 所需用户等级:配置需要管理员权限;查看报告需要管理员或版主权限。

情感和情绪分类有助于你探索社区讨论中的模式:

  • 情感 将帖子分类为正面、中性或负面。
  • 情绪 在 28 个标签上分配分数,包括感激、好奇、愤怒和悲伤。

这是两种独立的功能。你可以启用其中一种或两种都启用,并为每种功能选择不同的分类后端。报告统计的是已分类的帖子数量,而不是独立的人或个性类型。使用它们来查找值得阅读的讨论,而不是作为理解上下文内容的替代品。

开始前

你需要通过 discourse_ai_enabled 启用 Discourse AI,并配置分类后端。

由 Discourse 托管? 你的站点可能已经预置了专用的分类端点。在更改之前,请检查现有配置。如果你需要关于可用性、端点配置或回填限制的帮助,请联系 team@discourse.org。

自托管? 配置兼容的专用端点、配备语言模型的 AI 代理或决策模型。仅启用该功能并不提供推理服务。

在启用自动处理之前,请查看提供商的隐私政策、保留规则和费用。分类会将帖子文本发送到所选后端。下面的截图使用测试站点上的虚构帖子和决策模型;它们并不推荐该提供商用于私密社区内容。

配置情感和情绪

  1. 打开 管理员 → 插件 → AI → 功能。
  2. 打开“情感和情绪”。
  3. 在“情感”下,如果你想要正面、中性及负面分类,请选择“已启用”。这控制 ai_sentiment_enabled。
  4. 选择其“后端”,并按照下文所述配置相应的端点、代理或模型。
  5. 在“情绪”下,如果你想要情绪分类,请选择“已启用”。这控制 ai_sentiment_emotion_enabled。
  6. 选择其后端并独立配置它。
  7. 设置下一部分中描述的后台处理限制。
  8. 点击“提交”并检查所选内容是否已保存。

此示例对两种功能都使用决策模型。“每小时帖子数”故意设置为 0,以便在测试期间暂停自动扫描。使用正值以自动处理新帖子和历史帖子。

使用专用分类端点

对于每个你想使用专用模型运行的功能,选择“专用分类端点”。按照“配置专用分类端点”进入 ai_sentiment_model_configs 设置。

参考专用模型如下:

功能 模型
情感 cardiffnlp/twitter-roberta-base-sentiment-latest
情绪 SamLowe/roberta-base-go_emotions

每个配置条目识别其 classification_type(sentiment 或 emotion)、model_name、endpoint 和 api_key。为你使用的每个专用分类器提供一个单独的条目。保持凭据私密;不要将其包含在支持帖子或截图中。

有关推理服务器部署,请参阅 为 Discourse AI 自托管情感和情绪。使用上述控件单独启用并选择每个功能。

专用后端期望一个兼容的分类 API。将 Anthropic、OpenAI 聊天或 Azure 语言端点复制到此设置中并不能使其兼容。在其他地方对语言模型成功的连接测试并不能测试专用情感端点。

使用 AI 代理或决策模型

对于“LLM 代理”,选择一个配备已配置语言模型的适当分类代理。Discourse 包含情感和情绪分类代理。通用的对话代理不能替代配置为返回预期标签分数的代理。

对于“决策模型”,首先 配置并测试兼容的决策模型,然后为每个已启用的功能选择它。决策模型不需要单独的对话语言模型进行此分类。

代理和决策模型请求可能会产生提供商费用或消耗积分。在将其分配给自动处理的功能之前,请查看所选模型的数据处理规则。

控制处理和历史覆盖范围

计划任务每 五分钟 检查一次缺少分类的帖子。新帖子和历史帖子共享此扫描;结果不一定在发布后立即提供。数据出现前没有帖子数量或天数的最低限制:一个成功分类的帖子就可以贡献数据。

控制 站点设置 默认值 效果
每小时帖子数 ai_sentiment_backfill_maximum_posts_per_hour 240 每小时处理的大致帖子数量。0 停止计划扫描,包括新帖子。
帖子年龄限制(天数) ai_sentiment_backfill_post_max_age_days 60 扫描在此年龄窗口内创建的帖子。0 意味着今天,而不是无限历史。

增加年龄限制以包含更旧的帖子。计划任务随时间处理缺失的结果;选择较旧的报告日期范围本身不会对该历史进行分类。

速率是近似值,不是精确的请求或支出上限。启用两个分类器可能会导致每个帖子发出两次请求。失败的请求或拒绝可以被重试。编辑后的帖子会单独检查,不受计划扫描的速率或年龄限制的控制。

私人消息、已删除的帖子、已删除的话题和非普通帖子类型会被排除在计划的回填扫描之外。扫描器和报告中的 PM 排除并不能保证所有分类路径都如此:编辑后帖子的作业不应用相同的 PM 过滤器。在配置外部提供商之前请考虑到这一点。

按类别或标签探索情感

  1. 打开 管理员 → 报告 → 情感分析,或在你的站点上访问 /admin/reports/sentiment_analysis。
  2. 选择开始和结束日期。
  3. 选择“类别”或“标签”以对结果进行分组。
  4. 使用相应的类别或标签过滤器来缩小结果范围。类别过滤还提供了一个包含子类别的选项。
  5. 阅读每组的总数及其正面、负面和中性的细分。
  6. 点击某组的行以检查其图表和底层帖子。

该示例包含九个已分类的帖子:三个正面,三个负面和三个中性。中性帖子包含在此报告中。

在详细视图中:

  • 选择“全部”、“正面”、“中性”或“负面”以过滤已加载的帖子。
  • 打开帖子的主题以阅读周围的讨论。
  • 使用图表旁边的链接图标复制该报告视图的 URL。收件人仍需要工作人员访问权限。
  • 点击“返回”以回到分组结果。

报告日期指的是帖子创建的时间,而不是分类运行的时间。如果主题有多个标签,一个帖子可以贡献给多个标签组,因此添加标签总数可能会多次计算同一个帖子。

阅读整体情感趋势

从 管理员 → 报告 打开“整体情感”报告,或访问 /admin/reports/overall_sentiment。

分数计算方式为:

正面帖子数量 − 负面帖子数量

要使帖子计入该组,正面或负面分数必须 大于 0.6。如果均未超过阈值,分组报告将把该帖子视为中性。阈值是固定的;没有站点设置可以更改它。

整体情感是净帖子计数,不是平均概率或快乐百分比。三个正面帖子和三个负面帖子产生 0 的整体分数,无论有多少中性帖子。在将平坦趋势解释为缺乏强烈观点之前,请检查分组细分和底层讨论。

探索情绪

每种情绪在 管理员 → 报告 下都有一个报告。例如,访问 /admin/reports/emotion_anger 查看“愤怒”或访问 /admin/reports/emotion_curiosity 查看“好奇”。选择日期范围和每日、每周或每月的分组来探索趋势。

情绪报告统计那些该标签分数 大于 0.1 的帖子。此阈值也是固定的。同一个帖子可以有多种符合条件的情绪,因此情绪总数不是互斥的。

你还可以按情绪过滤主题。访问 /filter?q=order:emotion_anger 查找匹配的主题,排名依据是符合条件的愤怒分类帖子数量,而不是平均情绪分数。使用 order:emotion_anger-asc 来反向排序。如果没有 activity-after: 过滤器,此排序统计的是过去一年中符合条件的帖子。常规主题列表访问权限仍然适用。

可用情绪标签

钦佩、娱乐、愤怒、恼怒、批准、关怀、困惑、好奇、渴望、失望、不赞成、厌恶、尴尬、兴奋、恐惧、感激、悲伤、喜悦、爱、紧张、中性、乐观、自豪、领悟、解脱、悔恨、悲伤和惊讶。

了解局限性

  • 分类依赖于模型。 讽刺、引用材料、专业术语和多语言讨论可能会被误解。语言覆盖范围和准确性取决于你选择的模型。不同后端的分数不一定经过相同校准。
  • 报告仅涵盖存储的结果。 已启用的功能如果没有工作的后端、暂停处理或历史覆盖不足,可能会产生空或不完整的报告。
  • 重用现有分类。 编辑已分类的帖子不会自动替换其结果。在同一后端内更改所选代理或决策模型也不会重新分类现有结果。
  • 更改后端会更改报告的结果来源。 旧结果不会转换为所选后端。在缺失分类处理期间,报告可能显示为空。
  • 报告排除私人消息。 此报告排除项与上述数据处理限制是分开的。

排查缺失或意外的结果

问题 检查内容
启用后无结果 确认相关功能已启用,其后端已配置,“每小时帖子数”为正值,并且后台作业正在运行。允许时间为五分钟扫描和处理队列。
情感有效但情绪为空 单独启用并配置“情绪”。仅限情感的专用端点不提供情绪分类。
较旧日期无结果 增加帖子年龄限制,允许处理时间,并检查报告范围是否包含帖子的创建日期。
专用端点返回错误 检查其 URL、凭据、模型和响应格式。适配器期望一个标签和分数的扁平数组,情感标签如 positive、neutral 和 negative,而不是任意聊天响应或 LABEL_0 风格的标签。
无法访问私有网络端点 检查连接,并在需要时,仅将受信任的推理端点主机名或 IP 添加到 allowed_internal_hosts。不要广泛禁用服务器端请求伪造保护。
编辑或模型选择后结果未变化 重用现有结果。不要假设编辑内容或保存另一个模型会安排完整重新分类。
过滤器显示的帖子少于计数 计数描述整个组,而情感标签页过滤已加载的帖子。检查是否有更多结果可加载,并在调查差异时打开原始主题。

管理员可以在 管理员 → 插件 → AI → 日志 中查看代理和决策模型请求记录。检查 /logs 以查找后台分类错误,包括专用端点故障。将日志内容视为敏感信息:它们可能包含帖子文本和模型响应。在共享诊断信息之前删除凭据和私密内容。

附加资源

10 个赞

帖子已合并到现有主题:Problems with Sentiment Backfill

帖子已合并到现有主题:Sentiment Backfill 问题

OP 已更新,新增了一个视频,展示了 Sentiment 的更新功能,包括更多的情绪以及了解哪些主题/帖子与每种情绪相关联。

我使用从 LLM 设置中复制的模型名称、端点和 api_key 配置了情感模型配置,它通过了测试,但在 /logs 中出现以下错误。

(但也许我理解得不对,为什么情感分析不使用已配置的 LLM 之一?)

正在使用 claude-3-5-sonnet。


{"type":"error","error":{"type":"invalid_request_error","message":"anthropic-version: header is required"}} (Net::HTTPBadResponse)
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:71:in `classify'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:142:in `request_with'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:78:in `block (4 levels) in bulk_classify!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1593:in `evaluate_to'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1776:in `block in on_resolvable'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:359:in `run_task'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:350:in `block (3 levels) in create_worker'

<internal:kernel>:187:in `loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in `block (2 levels) in create_worker'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `catch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `block in create_worker'
状态:400

{"type":"error","error":{"type":"invalid_request_error","message":"anthropic-version: header is required"}} (Net::HTTPBadResponse)
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:71:in `classify'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:142:in `request_wit...

情感模块不使用通用 LLM,而是使用专门针对情感分类进行微调的模型。如果您想在自己的环境中运行这些模型,相关文档请参见 Self-Hosting Sentiment and Emotion for DiscourseAI。

3 个赞

@Falco 我刚注意到情感分析从2025年1月开始停止运行。我的猜测是有一个新的设置 ai_sentiment_model,正如上面链接所解释的,它用于运行你自己的专用情感模型/图像。我注意到在更新 discourse 后,现在 ai_sentiment_model_configs 都是空白的(它应该是空的吗?)。当我尝试运行 backfill rake 时,出现错误:

rake ai:sentiment:backfill
rake 中止!
ActiveRecord::StatementInvalid: PG::SyntaxError: 错误:在或附近的语法错误")" (ActiveRecord::StatementInvalid)
LINE 1: ...e_upload_id", "posts"."outbound_message_id" FROM () as posts..

插件默认使用我搭建在 DigitalOcean 上的服务器进行测试,这样更方便。

我已将插件默认设置更改为干净的状态,想要进行 AI 分类的人需要按照 Meta 上的文档运行服务器。

确实如此,但我们为测试目的付出了这些成本。为每个自托管者提供此服务是不可持续的。

值得一提的是,我们作为托管服务的一部分,在 GPU 加速服务器上提供此分类服务。

2 个赞

Discourse AI 情感分析问题:Hugging Face 模型格式与 Azure 端点故障


Discourse 社区和开发者们,大家好,

我在论坛上配置和使用 Discourse AI 插件中的情感分析功能时遇到了严重问题。似乎有两个独立的问题阻碍了其正常工作。


问题 1:Hugging Face 模型响应格式不匹配

我已经为情感分析配置了 Hugging Face 的 cardiffnlp/twitter-roberta-base-sentiment 模型。虽然我的 API 密钥有效,并且我可以使用 curl 命令从 Discourse 实例成功调用 API,但 Discourse AI 插件似乎由于 Hugging Face 模型输出格式的更改而错误地解析了响应。

我的 curl 命令(确认 API 密钥有效和新格式):

Bashcurl -X POST https://api-inference.huggingface.co/models/cardiffnlp/twitter-roberta-base-sentiment \ -H "Authorization: Bearer hf_xxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d "{\"inputs\": \"I love Discourse!\"}"

curl 的输出(显示新的嵌套数组格式):

[[{"label":"LABEL_2","score":0.9891520738601685},{"label":"LABEL_1","score":0.009014752693474293},{"label":"LABEL_0","score":0.0018332178005948663}]]

问题: twitter-roberta-base-sentiment 模型曾经返回一个标签-分数哈希的单个数组:[{"label": "LABEL_2", "score": 0.98}, ...]. 但现在它返回一个嵌套数组:[[{"label": "LABEL_2", "score": 0.98}, ...]]。

Discourse AI 插件的硬编码解析逻辑(特别是,如回溯所示的 classification["label"][/\d+/].to_i)没有考虑到这个外部数组层。这导致在尝试将 Symbol 转换为 Integer 时出现 TypeError。

错误消息(来自 Job Exception):

无法将 Symbol 隐式转换为 Integer (TypeError)
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in block in transform_result' /var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in each’
/var/www/discourse/plugin…`

Hugging Face 问题的完整回溯:

/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `raise'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `wait_until_resolved!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:998:in `value!'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:93:in `bulk_classify!'
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/sentiment_backfill.rb:27:in `execute'
/var/www/discourse/app/jobs/base.rb:316:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.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-6.1.0/lib/rails_multisite/connection_management.rb:21:in `with_connection'
/var/www/discourse/app/jobs/base.rb:303:in `block in perform'
/var/www/discourse/app/jobs/base.rb:299:in `each'
/var/www/discourse/app/jobs/base.rb:299:in `perform'
/var/www/discourse/app/jobs/base.rb:379:in `perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:137:in `process_queue'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:77:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:63:in `block (2 levels) in ensure_worker_threads'
\u003cinternal:kernel\u003e:187:in `loop'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in `block (2 levels) in create_worker'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `catch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `block in create_worker'
无法将 Symbol 隐式转换为 Integer (TypeError)
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in `block in transform_result'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:163:in `each'
/var/www/discourse/plugin...

问题 2:Microsoft Azure 模型配置导致 Hugging Face 错误

当我尝试在 Discourse AI 设置中切换到 Microsoft Text Analytics 模型时,我遇到了 404 Resource not found 错误,令人惊讶的是,回溯仍然指向 hugging_face_text_embeddings.rb。

错误消息(来自 Job Exception):

Job exception: 416 errors
{"error":{"code":"404","message": "Resource not found"}} (Net::HTTPBadResponse)

相关回溯片段(尽管选择了 Microsoft 模型,但仍指向 Hugging Face):

/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:76:in `do_request!'
/var/www/discourse/plugins/discourse-ai/lib/inference/hugging_face_text_embeddings.rb:51:in `classify_by_sentiment!'
/var/www/discourse/plugins/discourse-ai/lib/sentiment/post_classification.rb:156:in `request_with'

观察: 这表明即使我选择了并配置了 Microsoft 模型的端点和 API 密钥,Discourse AI 插件似乎也硬编码或错误地将情感分析请求路由到 Hugging Face 特定的逻辑或端点。这导致 Microsoft 模型根本无法使用。


配置截图:

我附上了 Discourse AI 设置的截图,以展示配置:

这些问题使得情感分析功能实际上无法使用。看来该插件需要更新以处理新的 Hugging Face 响应格式,并在配置了不同的情感提供商时正确路由请求。

非常感谢您在这些问题上的任何帮助或指导。

谢谢!

2 个赞

我想知道其他人是否也遇到了情绪报告的问题,或者是我配置有误。我想知道还需要检查或配置什么才能启用情绪报告,因为我仍然遇到同样的问题。

1 个赞

我们正尝试从我们自托管的 Discourse 实例使用 Azure AI Language 来使用此功能(因为我们已在使用我们的 Azure 订阅将 GPT-4.5 与 Discourse 集成(用于摘要和聊天机器人功能):

……但我们在情绪仪表板中没有看到任何数据,并且在日志中可以看到这些错误:

Discourse AI: Errors during bulk classification: Failed to classify 208 posts (example ids: 2256, 909, 2270, 2260, 2797) : JSON::ParserError : An empty string is not a valid JSON string.

回溯显示 Discourse 可能正在尝试使用 HuggingFace - 目前只支持这些模型吗?

谢谢,

N

1 个赞

那么,使用此功能的唯一方法是设置您自己的模型实例(这需要资源密集型的 GPU 实例,成本很高)吗?此功能看起来非常有用,但似乎设置它的成本比我实际的 Discourse 托管成本还要高。

是的,支持的模型是 OP 中列出的那些。

我们最终将为那些不介意成本的人添加使用 LLM 进行分类的支持。

嗯,整个功能都是围绕使用 ML 模型对帖子进行分类而构建的,所以是的,你需要一个地方来运行它们。

而且,由于 Discourse 可以在最便宜的 VPS 上运行,运行 ML 模型确实更昂贵。如果你想以最便宜的方式使用该功能,可以在只有少量 CPU 核心的服务器上运行它,只要有足够的 RAM 来加载模型即可。

1 个赞

抱歉,如果这个问题以前问过,但我找不到在哪里可以配置阈值分数 :sweat_smile:

1 个赞

不幸的是,阈值分数不是用户或管理员可以配置的内容。它是在代码库中设置的一个特定值。

1 个赞