実装ハンズオン
【n8n】ライフサイエンス企業検索・リサーチBot Part3:質疑応答機能の実装

連載シリーズ
ライフサイエンス企業検索・リサーチBot
全4回・n8n × Firecrawl × RAG・Slack常駐Botとして運用するまで
目次(STEP2:スレッド対応編)
- 導入
- 背景と目的
- スレッド対応ワークフローの全体像
- Slack App権限設定の追加
- n8nフロー構成:条件分岐(IFノード)の設定
- スレッド情報の取得(Get Threadノード)
- OpenAIノードによる文脈応答生成
- MergeとSlack返信ノードの設定
- 実行結果
- まとめ
1. 導入
前回の記事では、Slack上で「@bot 企業名」とメンションするだけで、自動的に企業情報を収集・要約し、スレッドにレポートを返すワークフローを紹介しました。
今回はその発展編として、スレッド上での質問応答が可能な機能を追加します。
これにより、同一スレッド内で追加の質問や深掘り分析ができ、チーム内の議論をよりインタラクティブに進めることができます。
2. 背景と目的
通常、Slackボットは単発のメッセージに反応する構成が多く、文脈をまたいだ応答が難しいという課題がありました。
しかし、n8nとSlack APIを組み合わせることで、スレッド構造を検知し、親メッセージ(ルートメッセージ)を参照した上で、文脈を保持した回答を生成することが可能になります。
この仕組みにより、Slack上で「企業調査→補足質問→AIによる再分析」といった流れを1つのスレッド内で完結できます。
3. スレッド対応ワークフローの概要
ワークフローの基本的な流れは以下の通りです:
- Slack上でボットをメンション
- メッセージがスレッドに属するか(親スレッドがあるか)を判定
- スレッドがなければ、新規企業としてWeb検索を開始
- スレッドがあれば、ルートメッセージを取得し、会話全体をLLMに入力
- OpenAIノードが文脈を踏まえた応答を生成
- 結果をスレッドに返信
- (発展)Web検索データをRAG用データベースに保存可能

4. Slack権限設定の追加
スレッド情報を取得するため、Slack Appに以下のBot Token Scopesを追加する必要があります:
• channels:history
• groups:history
• im:history
• mpim:history
これにより、ボットがスレッドの履歴データを取得し、前後文脈を参照可能になります。
権限を変更した場合は、再インストール(Reinstall the App)を忘れずに行います

5. 条件分岐(IFノード)の設定
Slack Triggerノードの直後にIFノードを追加します。
判定条件は以下の通りです:
- 条件:thread_ts が存在するか
- 存在しない → 新規企業検索(STEP1ワークフローへ)
- 存在する → スレッド返信(STEP2ワークフローへ)
この分岐によって、n8nがスレッド内返信か新規検索かを自動で判断できます。

6. スレッド情報の取得
リプライ時の分岐では、Slack APIノード「Get a thread of messages posted to a channel」を使用します。
設定項目:
• Channel:トリガーから受け取ったチャンネルID
• Thread_TS:スレッドの親メッセージID
• Limit:1(親スレッドのみ取得する場合)
これにより、ルートメッセージを取得してLLMに読み込ませることができます。

7. LLMノードによる応答生成
次に、OpenAIノードを追加し、以下のプロンプト構成を設定します:
• system: 企業アナリストとしての役割を指定
• instruction: ルートメッセージとスレッド全体を参照し、質問に応じた補足説明を生成
• input: Slackスレッドの本文
• output: Markdown形式の回答
こうすることで、単発回答ではなく「前回のレポート+質問内容」を踏まえた整合的な回答を出力できます。

8. 結果統合とSlack返信設定
最後に、Mergeノードで両分岐(新規検索/スレッド返信)を統合し、Slack Messageノードでスレッドに返信します。
設定ポイント:
• Send Message To: チャンネルID
• Message Text: OpenAIノードの出力
• Reply to a Message: メッセージID(ts)
これで、新規検索でもスレッド返信でも安定した出力が可能になります。
リンクエラーを避けるため、フィールド指定は手動入力が推奨です。

9. 実行結果
Slack上での実行イメージ:
• 新規メンション → 企業情報レポートを自動返信
• スレッド内質問 → 前回レポートを参照し、AIが文脈に沿って回答
この結果、Slack上での「リサーチBotとしての継続的対話」が実現します。
ユーザーは、複数回の検索やブラウザ操作を行わずに、チャット内で知見を深めることができます。

10. まとめ
今回紹介したスレッド対応機能により、Slack連携ボットが「一問一答型」から「文脈理解型」に進化しました。
次回は、STEP3としてRAG(Retrieval-Augmented Generation)を導入し、企業情報のデータベースを活用した高度な再検索・補足分析を実現します。
Appendix. 詳細ステップ
STEP2. スレッドに関する内容は質問応答ができる

一連の流れ
- Slack上でボットをメンションすることでワークフローが起動
- メッセージが親スレッドを持つか否かで条件分岐
- 親スレッドなし・・・新規企業として新たに情報検索開始
- 1.Firecrawlを用いてWeb検索を実施し、複数のURLを取得(Firecrawl / Split out)
- 2.URL群に対してスクレイピングを実施(Loop Over Items / Firecrawl)
- 3.結果をまとめて企業情報に関するレポートを生成(OpenAI)
- 親スレッドあり・・・スレッドの内容を読み込んで返信する
- 1.スレッドの一番親となるルートメッセージを取得
- 2.メッセージをLLMに読み込ませやすい形に変換
- 3.スレッドの内容も含めてLLMが気レポートを生成(OpenAI)
- 親スレッドなし・・・新規企業として新たに情報検索開始
- LLMが生成したレポートをSlackの返信として送信
- 今回、Web検索によって収集されたデータをRAG用のデータベースに追加
1.まずは質問応答を可能にするためには、メンションされたメッセージの内容だけではなく他のメッセージも取得する必要があるので、SlackAppの権限を設定する。Slack通知の際に設定した権限に加えて、さらに4つの権限を追加する。

この時に、OAuth & Permissionsの権限を変更すると組織への再インストールが必要になるので、reinstall the appボタンで再インストールすることを忘れない。

試してみると上記のように、スレッドの親メッセージにある情報なども含めて全て取得できるようになる。
2.Slack Triggerの後ろにifノードを追加する。

IFノードの中は「thread_ts」が存在するか/しないかを判定させる。thread_tsが存在しない = スレッドではなく単なるメッセージである。逆にthread_ts が存在する = リプライである(つまり、前後関係を踏まえる必要がある)

3.リプライ時の分岐を作成する
- まずはメンションされたメッセージ以外のスレッド情報を取得するために、「Get a thread of messages posted to a channel」ノードを配置。

- 中身は以下のようにセット。今回、親スレッドのみ取得することを念頭に置いてLimit = 1に設定。もしスレッドの内容を全て取得したい場合は、Limit を増やすことで取得可能。1件のみ取得の場合はコードブロックは不要

4.AIノードを追加

- 前のSlack MessageもしくはJavascriptコードの結果を使ってLLMに与えるプロンプトを作成

5.Mergeノードをセットして、どちらの分岐であっても回答が送信されるように結果を統合。

- Mergeノードの中は「Append」を設定

- Slack Messageは「スラック返信ワークフロー」と同様に、Add Optionから「Reply to a message」を追加。一番初め、ワークフローのトリガーとなったSlack MessageのユニークなIDであるts をここに入れる。
連載シリーズ
ライフサイエンス企業検索・リサーチBot
全4回・n8n × Firecrawl × RAG・Slack常駐Botとして運用するまで
