blog

DeNAのエンジニアが考えていることや、担当しているサービスについて情報発信しています

2025.09.12 技術記事

社内問合せはSlackに集約!AIチャットボットと連携した新ツールの開発事例

by higashi

#情シス #ai #slack

はじめに

こんにちは、 IT戦略部システム開発グループ higashi です。
今回は私がエンジニアとしてPoC開発から関わっていた社内問合せツール「Findout」について紹介させていただきます。

多くの従業員が日常的に利用するツールと社内の問合せ窓口が異なると、問合せのハードルが上がり、問題解決までの時間が長くなってしまうことがあります。

今回は、そのような課題を解決するために、社内問合せの仕組みを刷新した事例を紹介します。
具体的には、多くの従業員が使い慣れたSlackに問合せ窓口を集約し、Slackだけでは不十分な情報管理や検索機能などを補うWebUIを内製しました。

この記事では、私たちが開発した社内問合せツール「Findout」が、どのようにしてSlackと連携し、これらの課題を解決したのかを解説します。
普段から使うツール、特にSlackを業務に連携させて活用したいと考えている方の参考になれば幸いです。

社内問合せツール「Findout」とは

「Findout」とはDeNA社内で利用されている社内問合せツールの名称です。

元々はSaaSを利用して社内問合せツールを運用していましたが、2025年6月にツールを内製化、「Findout」としてサービスを開始しました。

FindoutはDeNAの従業員約4000人が利用可能で、大小様々なトラブルが相談されます。
持ち込まれる問題は「VPNに繋がらない」、「オフィスに入る方法」など個人の業務進行に関係する問題から、事業への影響がある大きい問題まで様々です。
それらの問題をユーザーが問合せとして起票し、人事や総務、セキュリティ部、IT戦略と相談しながら解決していくためのツールです。

Findoutの内製化にあたり、利用者の利便性を重視し、多くの社員が日常的に利用しているSlackを中心とした設計にしました。

問合せはSlack上のSlackAppから行います。
まず、社内の情報を元に回答を行うAIが質問に答え、ユーザーの自己解決をサポートします。
AIからの回答で解決しなかった場合に、対応者とやり取りをするための専用のSlackチャンネルが作成されます。
その後のやり取りはSlackチャンネル内で行い、問題解決を目指します。

Slackを中心とすることで、問合せから解決までを普段から使うツールで完結させることが可能になりました。
また、Slack上でのやり取りのため、関係者の招待や資料の共有も容易です。
やり取りもリアクションやメンションを使い、カジュアルに行えるため、問合せの流れがスムーズになるという狙いもあります。

対応者と利用者のコミュニケーションはSlack上で行いますが、対応者向けには別途WebUIを用意しています。
Slack上でのやり取りとWebUIの詳細な情報管理・検索というそれぞれの長所を活かすためです。

問合せ毎に管理する情報は大量にあり、それらをSlackのチャンネルのみで管理するのは困難です。
また、Slackチャンネルでのやり取りはチャンネル内で閉じてしまうため、他の担当者が閲覧できません。

そこでWebUI上ではこれらの情報を一元的に管理・閲覧できるようにし、情報管理の効率化、担当者間のスムーズな連携、ナレッジ蓄積を実現しています。

システム構成の概要と意図

ここではFindout全体のシステム構成について説明させていただきます。

先述の通り、Findoutは主に「SlackApp」と「対応者向けWebUI」の2つから成り立っています。

以下は簡易的な構成図になります。

以降で図を元に社内ネットワークへの接続設定、SlackAppの設定、対応者向けWebUIの設定について説明します。

社内ネットワークへの接続設定

FindoutのDBは社内ネットワーク内にあるEC2上に構築しています。
これにより他のDBサービスと比較して、コストを抑えつつ、CloudSQLなどでは利用できないプラグインを利用できます。

また、DBへのアクセスに加え、社員に関する情報を社内ネットワーク内のシステムから取得するため、社内ネットワークとGCPを接続する必要があります。
そこで、VPC Direct Egressを利用し、ShardVPC経由でGCP上から社内ネットワークにアクセスできるよう設定しています。

SlackApp

SlackAppを動かすためのサーバーにはCloudRunを選択しています。
bolt.jsを利用して構築しており、先述のDBアクセス部分以外は特殊な設定は行っていない一般的なSlackAppのサーバーです。

ここではSlackからのイベントをWebhookで受けとり、処理しています。

受けとるイベントとそれに応じて行う処理の例

  • イベント: チャンネルへのメッセージの送信
    • 処理: メッセージの保存
  • イベント: DMへのメッセージ送信
    • 処理: AIによる回答機能
  • イベント: formの送信
    • 処理: 問合せの起票
    • 処理: 情報の更新
  • イベント: スラッシュコマンド
    • 処理: formの表示
対応者向けWebUI

対応者向けWebUIはSlackAppと同様にCloudRun上で動作しています。
フロントエンドはReactとreact-routerを使って開発しており、ビルド結果をExpressで構築されたバックエンドで配信する形を取っています。
ビジネスロジックの処理、DBとの接続はバックエンドが行い、必要に応じてフロントエンド側からAPIを呼び出しています。
また、後述するファイル保存のためにCloudStorageをマウントさせています。

管理者向けWebUIの特徴として、Load Balancerを経由してのみアクセス可能という点が挙げられます。
Load Balancerを経由してのアクセスにする一番の目的は 「社外からのアクセスを遮断する」 です。
Findoutはシステムの性質上、社外秘のやり取りが多く行われます。
過去分も含め、社外に出せないやり取りを閲覧可能な対応者向けWebUIを外に出すのはリスクが高く、メリットも無いと判断し、このような設定を実施しています。

ここまででFindoutの構成について技術的な側面を説明しました。
次のセクションではユーザー体験の核となるUIであるSlackを選定した理由とその連携について掘り下げていきます。

UIとしてのSlack

UIとしてSlackを選定した理由

Findoutではユーザーがやり取りをするためのUIとしてSlackを採用し、SlackAppを用いて連携する方針を取りました。

SlackをUIとして採用した理由としては 社内問合せツール「Findout」とは で紹介させていただいた物以外にも以下が挙げられます。

  1. 0からチャットシステムを構築する必要がない
  2. 既にあるAI SlackAppの実装を引き継げる

特に「0からチャットシステムを構築する必要がない」という点は大きく、大きく工数を減らしつつ、SlackAppを活用した高い拡張性を実現できました。

Slackを採用したことにより、ユーザーの利便性は向上しました。
しかし、対応者向けWebUIで情報を表示するために、Slack上の情報とチケット情報を紐付けて管理する必要があります。
そのため、FindoutではSlackの投稿を取得し、DBに保存する仕組みを構築しています。

また、AIによる1次回答機能も重要な要素です。
IT戦略内ではFindoutとは別に「ChatAI」という社内のドキュメントを元にAIが回答を行うSlackAppを提供しています。
AIを使った1次回答はそのChatAIの実装が元になっています。

次以降のセクションではAIによる1次回答機能やSlack上の情報を連携する流れについて解説します。

AIによる1次回答機能

FindoutのDMに質問を投稿すると、AIが社内情報を元に回答を生成します。

現在はRAGという仕組みを用いて、LLMが社内ドキュメントの情報を元にした回答生成を行えるようにしています。
以下は簡単な連携図になります。

AIによる回答はbatch部分で行われる処理とユーザーからのメッセージを起点に行われる処理に分かれています。

batchではドキュメントをAPI経由で取得し、テキストへ変換。
取得したテキストを適切な長さに分割し、ベクトル化します。
ベクトルと学習元のドキュメントはセットでPostgreSQLに保存されます。
この処理を週に1回実施し、更新されたドキュメントや新しいドキュメントを回答生成に利用できる形にしています。

回答の作成はユーザーが質問文をSlackに投稿したタイミングで行われます。
投稿された文章はChatGPTにより要約されます。
要約した文章はベクトル化され、PostgreSQL上のベクトルと照らし合わせるベクトル検索にかけられます。
ベクトルが類似しているドキュメント上位10件と質問をChatGPTに渡し、回答を生成させています。

なおこの回答生成の仕組みは今後大きく改善し、より良い回答を行えるようにする予定です。

生成された回答に満足できなかった場合はAIの回答に付く「ヘルプデスクへ問合せ」ボタンからシームレスに問合せを行えます。
この機能により、AIを活用しつつ、AIの回答を入口とした問合せが行えるようになりました。

Slackで行われたやり取りの保存

Findoutでのやり取りはチケット毎に作成されるSlackチャンネルで行われます。

チャンネルにメッセージが投稿されると以下のようなイベントが送信されます。

{
  user: 'SlackのUserId',
  type: 'message',
  ts: '1755509902.929159',
  text: 'メッセージのテキスト',
  team: 'ワークスペースのID',
  blocks: [],
  channel: 'チャンネルのID',
  event_ts: '1755509902.929159',
  channel_type: 'group'
}

ファイルを添付すると以下のようなイベントが送信されます。

{
  text: 'ファイル付き',
  files: [
    {
      id: 'SlackのファイルID',
      created: 1755510113,
      timestamp: 1755510113,
      name: '1000001093.png',
      title: '1000001093.png',
      mimetype: 'image/png',
      filetype: 'png',
      pretty_type: 'PNG',
      user: 'SlackのUserId',
      url_private: 'ファイルのURL',
      url_private_download: 'ファイルのURL',
      media_display_type: 'unknown',
      thumb_64: 'ファイルのURL',
    }
  ],
  upload: false,
  user: 'SlackのUserId',
  display_as_bot: false,
  blocks: [],
  type: 'message',
  ts: '1755510119.458239',
  channel: 'チャンネルのID',
  subtype: 'file_share',
  event_ts: '1755510119.458239',
  channel_type: 'group'
}

メッセージ毎にsubtypeというものが設定されるため、subtype毎に適切な処理を実施します。
以下はsubtype毎に行っている処理の例です。

subtypeなし

通常のメッセージやスレッドに投稿されたメッセージが該当します。
Findoutでは送信されたユーザーやテキストの情報を保存しています。

file_share

ファイルを添付した際のsubtypeです。
Findoutの場合は以下の3つに分けて保存しています。

  • ファイルが添付されたメッセージの情報
  • ファイルの情報
  • ファイルの実体
thread_broadcast

以下にも投稿するオプションを有効にしてスレッドに投稿したメッセージ。

通常のスレッドメッセージとは別のsubtypeのため、通常のスレッドメッセージと同じように表示したい場合や個別に表示したい場合は注意が必要です。
Findoutではsubtypeが無かったときと同様に扱っています。

channel_join/channel_leave

チャンネルにユーザーが参加したり、抜けた場合に出るメッセージにつくsubtypeです。
Findoutではこういったメッセージの保存はしないため、意図的に無視するような処理を挟む必要があります。

subtype毎に処理を行う場合の注意点

Slackのsubtypeは上げたもの以外にも多数あり、検証段階で見逃してしまう可能性があります。
Findoutではthread_broadcastの検証が漏れてしまい、一部メッセージが取得できない不具合が発生しました。

この不具合の対応として全subtypeの再チェックを実施しました。
その後、改めて保存の必要/不要毎にsubtypeを分けました。
どちらにも含まれないsubtypeの場合はエラーを出すようにし、新たにsubtypeが追加された場合も即座に検知できるようにしています。

このようにしてSlackでのやり取りをDBに保存しています。
そして保存したやり取りを有効的に活用するために次のセクションで紹介する対応者向けWebUIがあります。

対応者向けWebUI

対応者向けWebUIの必要性

情報の管理

Findoutで扱うチケット情報は複数あり、Slackのスラッシュコマンドなどで管理するには限界があります。
問合せに関する情報を一括で入力、確認できるツールがないと業務の進行に影響が出てしまいます。

会話ログ

起票者と担当者がやり取りをしているチャンネルはプライベートチャンネルになります。
通常チャンネルに入っている人以外はやり取りを確認することはできません。
そのため、チャンネルクローズ後は元々入っていたメンバーしか情報を閲覧できません。
それでは過去のやり取りを参照したり、現在行われているやり取りを他の対応者が確認することができず、業務進行に影響が出ます。

例:

  • 担当者の休暇中の対応
  • 問合せ中のやり取りでのトラブル
  • 過去案件を参照し、同様の対応を取る

そこで何らかの形でSlack内のやり取りを確認できるようにする必要が出てきました。

最終的な判断

当初はタスク管理サービスを利用し、チケットを起票、その中に書き留めていくという方針で進めていました。
しかし、開発中に社内でそのSaaSが非推奨となり、他SaaSに乗り換えるか、WebUIを内製するかの選択をする必要が出てきました。

他SaaSのAPI検証は行っていましたが、最終的に拡張性の観点からWebUIは内製化されることになりました。

次以降のセクションでWebUIの中でも重要な機能を3つ紹介させて頂きます。

閲覧可能範囲の管理

1つ目は閲覧可能範囲の制御です。

Findoutにはカテゴリという概念があります。
これは問合せの大項目のようなもので、問合せに対して一つ設定されます。
カテゴリにはそれぞれGoogle Groupが設定されています。
カテゴリの問合せを閲覧するためにはそのカテゴリに設定されているGoogle Groupに入っている必要があります。

Google Groupに入っているユーザーは以下のような形でDBに保存され、リクエストの際に検証されます。

     category_key      |       created_at        |       updated_at        | user_id
-----------------------+-------------------------+-------------------------+---------
 ITS_PC                | 2025-06-23 02:00:21.795 | 2025-06-23 02:00:21.795 |      27
 ITS_NETWORK           | 2025-06-23 02:00:22.14  | 2025-06-23 02:00:22.14  |      27

問合せの検索と結果の表示

2つ目に問合せの検索と結果の表示を紹介します。

検索画面は以下のようになっています。

検索画面

問合せ者や担当者に関する情報など様々な情報を元に検索できます。
検索は先述した閲覧可能な範囲に絞った上で行われるため、権限が無い問合せは結果にも表示されません。

表示にはmaterial-uiのDataGridを利用しています。
ページネーションやソートもDataGrid内の機能を利用することで実現しています。

Slackで行われたやり取りの表示

3つ目に紹介させて頂く機能がSlackで行われたやり取りの表示です。

対応者向けWebUIでは以下のようにチャンネルで行われたやり取りをUI上から確認できます。

Slack上のやり取り

上記のやり取りをWebUIで確認した際のスクリーンショット

文字修飾への対応

太字や斜体など、Slackの文字修飾にも対応しています。

画像1枚目のようなメッセージはDBに以下のような形で保存されます。

*hoge*
_fuga_
~poyo~
`piyo`

このテキストを react-markdown というライブラリを利用し、2枚目のような形で表示しています。

ファイル表示/ダウンロードへの対応

ファイルが添付されているメッセージについては以下3つに分けて保存しています。

  • ファイルが添付されたメッセージの情報
  • ファイルの情報
  • ファイルの実体
ファイルが添付されたメッセージの情報/ファイルの情報

これらの情報はDBに保存されています。
ファイルの情報はメッセージの情報に依存する形で保存されており、WebUIでファイルを表示する際に一緒に呼び出されます。

ファイル情報の例

slack_message_file_id | 176
slack_message_id      | 581
slack_file_id         | DUMMY_FILE_ID
file_name             | DUMMY_FILE_ID_diffモードでログ比較をしよう.pdf
file_name_thumbnail   |
fileType              | pdf

この情報を元にUI側でfileTypeに合わせ、表示を切り替えます。

写真を投稿した場合

動画を投稿した場合

ファイルを投稿した場合

ファイルの実体とダウンロード

WebUI上でアイコンをクリックするとfileTypeに合わせてモーダルでの表示やダウンロードが行われます。

ファイルの実体はCloudRunにマウントされたCloud Storage上に保存されています。

フロントエンド側は操作に合わせてバックエンドにダウンロードのリクエストを送ります。
サーバー側の処理でリクエストに合わせ、ダウンロード処理を実施します。

なお、CloudRunはHTTP/1リクエストサイズが最大32MBと設定されているため、32MB以上のファイルを扱う場合は一工夫が必要です。
FindoutではNode.jsのcreateReadStreamを利用し、段階的に送信することでこの制限を回避しています。

内製化後の反応と稼動

頂いた反応

全社的に「体験が良くなった」と肯定的な意見を頂けています。
また、対応者からは起票者の返信が早くなったというお話も頂いています。

しかし、問合せ毎に作られるSlackチャンネルによる圧迫、WebUIのUXなど問題も見え始めています。
これらの課題については今後のアップデートで対応していく予定です。

リリースから2ヶ月間の稼動

Findoutは2025/6/23にリリースし、約2ヶ月が経過しました。
この2ヶ月間でユーザー影響のあったトラブルは軽微な2件に留まり、これにより影響を受けた問合せは1700件中4件のみでした。
元々不具合0件を目指していたため、悔しい気持ちはありますが、ここまで少なくなったのには以下の理由があると考えています。

  • チャットツール部分をSlackという既存の安定したシステムに乗っかった
  • リリース一ヶ月前から徹底した検証を実施した

もちろんSlackの豊富な機能の再現する/しないを判断していくのは大変でしたし、見落して不具合になってしまった場面もありました。
しかし、Slackに乗っかることでユーザー体験、システムの安定性を確保できたのは事実で良い判断だったと思っています。

おわりに

この記事では社内ヘルプデスク「Findout」の概要、Slackと業務の連携について紹介させていただきました。
本記事で紹介した内容が、皆さんの業務改善のヒントになれば嬉しく思います。

私たちは今後もFindoutの改善を続け、社員がより快適に業務に取り組めるよう尽力してまいります。

最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。

recruit

DeNAでは、失敗を恐れず常に挑戦し続けるエンジニアを募集しています。