NTTドコモR&Dの技術ブログです。

Slack botで業務改善してみた

はじめに

ドコモの私のチームで開発しているSlack botとそれを用いた業務改善についてご紹介します。

最近ではSlackに限らず種々のモダンなツールを業務で活用している方も多いでしょう。私のチームでもSlackやConfluence、その他いろいろなOSSを使って業務改善を行っています。特にSlackはAPIも豊富で、日々の業務でほぼ常時使い倒しているからこそいろいろカスタマイズすることで業務改善できるだろう、と目を付けたわけです。

この記事では、botの作り方について簡単に触れつつ、例えばどんな機能をbotで実装したのかご紹介します。「ほかにもこんな機能を実装すると便利だよ!!」というアイデアがあればぜひぜひフィードバックいただけると幸いです。

自己紹介

何者?

この記事に目を止めていただきありがとうございます。NTTドコモ サービスデザイン部の川谷です。普段の業務ではあまりbotやらコーディングとはかかわりの低いインフラの業務をやっています。ここでいうインフラ、というのはドコモのサービスを支えるサーバやネットワーク、データベース、ストレージの設計開発、構築、維持管理、トラブル対応(大好物)の事です。 特に、CiRCUSという古くはiモードのためのシステム、今はdアカウント認証やドコモメールのサービスを支える基盤システムを主に取り扱っています。

経歴的には過去にソフトウェアエンジニアもやっていたり、大学のころからコーディングが大好き。SlackのAPIに触れて半分業務、半分趣味のコーディングが復活できる!ということでここ数年インフラ業務の傍らbotのコーディングをやっています。

過去記事の宣伝

過去にも何度かエンジニアブログや公開記事を書かせていただいています。ここでちょっと宣伝させていただきます。(我ながらテーマがばらんばらん。。w)

去年の記事。何となく日々感じているExcelの使い方で気になることを書いてみました。 nttdocomo-developers.jp

おととしの記事。今回メインでご紹介するbot開発の源流になった記事で、botについても少し触れています。 nttdocomo-developers.jp

3年前の記事。正統派?インフラ屋さんっぽい記事。ご興味があれば。。 qiita.com

では、さっそく行ってみましょう!!

API Token(トークン)の発行

さっそくバリバリコーディング!!とはならず、まずはAPI Tokenの発行が必要になります。ちょっと手間ですが、頑張ってやってみてください。Slack APIのページに行きます。あ、ちなみに当然と言えば当然ですがSlackのアカウントが必要です。。

Slack API トップページ

画面右上の「Your apps」をクリック。初めて入った場合はSign Inが求められると思うので、ご自身のアカウントでSign Inしてください。 SlackのApp一覧が出てきます。この一つ一つがbotになると思ってもらえれば。初めて作る人は空っぽだと思います。筆者はこれまでテスト用を含めていっぱい作っているのでずらっと出てきます。

今回は新規にbotを作るので右肩の「Create New App」を選択。

App一覧

マニフェストから作るかスクラッチから作るかを聞かれます。が、今回はスクラッチから。

Appを作る方法選択

Appの名前とインストールするSlackのワークスペースを指定します。名前はお好みで。ワークスペースは追加したいワークスペースを選んで「Create App」してください。

Appのタイトルとワークスペース

左のメニューの「Basic Information」を選択(画面を開いたら最初から選ばれているはず)。下の方に行くと「App-Level Tokens」というのがあるので、「Generate Token and Scopes」を選択。 開いたウィンドウ絵Tokenに適当な名前を付けて、「authorizations:read」と「connections:write」を選んで「Create」

App-Level Tokens

Tokenが発行されました。これは後で使います。 このTokenは超大事で、流出すると大変なのでくれぐれも取り扱い注意。筆者も一応ぼかしを入れましたが、このTokenは記事の執筆後に削除しています。

Token発行画面

続いて、左のメニューから「Socket Mode」を選択。右の画面に出てきた「Enable Socket Mode」をオンに。

Socket Modeを使うと、SlackのイベントハンドリングにWeb Socketを使うようになります。例えばメンションされたとか、特定の言葉が投稿された時にbotを動かすことができます。Webhookを使うこともできますが、FireWall越えやセキュリティ上の対応もいろいろ必要に。WebSocketだとbot自体がアウトバウンド通信でイベントを拾いに行ってくれるのでとても便利です。

Socket Modeをオン

画面をちょっと下にスクロールすると「Event Subscriptions」があるのでこちらをクリック。

Event Subscriptionsをクリック

「Subscribe to bot events」をクリックして「Add Bot User Event」。とりあえず「app_mention」イベントをサブスクライブしておきましょう。botの開発を進める中で必要なイベントがあれば後で追加すれば大丈夫です。終わったら右下の「Save Changes」。

app_mentionイベントは、Slack上でbotに対して@でメンションをした場合に発動するイベントです。botに話しかけると何か応答してくれる、みたいな動作をさせたいときに使いましょう。

app_mentionイベントをサブスクライブ

左側のメニューから今度は「OAuth & Persiossions」を選択。少し下にスクロールすると「Bot Token Scopes」があるのでそれを選択。「app_mentions:read」と「chat:write」を選択しておきましょう。これもbotの開発を進めながら後で追加可能です。

Bot Token Scopeの設定

ワークスペースにインストール!

いよいよワークスペースにbotをインストールします。画面を少し上にスクロールすると「Instann to <あなたのSlackワークスペース>」があると思うのでここをポチ!遷移した画面で「許可する」を押せばワークスペースにインストール完了!

ワークスペースにインストール

チャンネルに追加する

Slackの追加したいチャンネルを開きます。でチャンネルにユーザを追加する画面で、「インテグレーション」を選択。下の方にある「アプリを追加する」を選びます。

botをチャンネルに追加する

bot(App)の検索画面が出てくるので、自分がつけた名前を検索して「追加」します。この画面に追加したAppが出てくるまで時間がかかることがあるようで。。。もし出てこない場合は少し時間を空けるなりしてみてください。 今回は筆者が使っているbotの実験、デバッグ用のチャンネルに追加してみました。

Bot追加画面

いよいよコーディング!!

開発言語

開発言語を選ばないといけません。対応している言語は下の3つ

  • Python
  • Java
  • JavaScript

どれでもお好みで選んでいただいて大丈夫ですが、私は昔からJavaラー。。ですが、せっかくなのでもっとモダンな言語を!と思ってJava系のKotlinを使いました(KotlinはJavaベースなのでJavaのSlack APIを簡単に使用可能)。 自力でJSonを組み立ててHTTPでRestAPIをたたいて。。。とやれる人は他の言語でも大丈夫です。

開発環境(IDE)

これもお好みで。。。ですが、KotlinならIntelliJ一択でしょう。最初、Eclipseをちょっと使おうとしましたが圧倒的にIntelliJが使いやすかったです。KotlinとIntelliJは開発元が一緒(JetBrains)なので当たり前と言えば当たり前。。

IntelliJはこちらから。もちろんIntelliJじゃなくVSCodeとか使ってもよいと思います。

IntelliJでbotのプロジェクトを作成

以降はIntelliJでのコーディングを前提に書いていきます。ただ、基本的にやることはEclipseだろうがVSCodeだろうが同じはず。

プロジェクト作成画面

名前は適当に。言語は「Kotlin」。Gradle DSLは「Groovy」を。Gradleの説明をし始めると記事がめっちゃ長くなるので、わからない人はまぁおまじない程度に理解いただき、詳しくはネット上の記事を探してみてください。

空のプロジェクト

空のプロジェクトができました。続いてSlack APIのライブラリを入れていきます。SlackのAPIはRestなので、自分でHTTPでJSONを投げるコードを書いてもよいですが手間なので。。

Slack APIライブラリをインポート

ルートディレクトリ直下にあるbuild.gradleを開き、下記のように修正。後半の4行が書き足したものです。

dependencies {
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
    implementation 'com.slack.api:slack-api-client:1.44.1'
    implementation 'com.slack.api:bolt:1.44.1'
    implementation 'com.slack.api:bolt-servlet:1.44.1'
    implementation 'com.slack.api:bolt-socket-mode:1.44.1'
    implementation "javax.websocket:javax.websocket-api:1.1"
    implementation 'org.glassfish.tyrus.bundles:tyrus-standalone-client:1.18'
}

これらはSlackのAPIを使うためのライブラリで、mavenから最新のバージョンが取得できます。この記事を執筆している時点では1.44.1が最新でしたが、今後より新しいものを使いたい場合はここらへんのmavenのリポジトリを直接覗いてみてください。mavenについても説明し始めると大変なのでこの記事では省略。。 右上に象さんマークのアイコンが出ていると思うのでこれをクリック。

Gradleのアイコン

これをクリックすると、build.gradleに書いたライブラリをダウンロードしてきてプロジェクトに取り込んでくれます。右下のプログレスバーのあたりが何やら動いているのがわかると思いますが、これが落ち着いたらライブラリのインポート完了です。

待ちに待ったHello World

まずはIntelliJにTokenを食わせます。 App-Level TokenをSlack APIのページから取ってきます。先ほど設定したApp-Level Tokensの画面から、さっき作成したTokenをクリックするとTokenが表示されるのでそれをコピー。App-Level Tokenは「xapp-」から始まります。

App-Level Tokenの取得方法

続いてBot User OAuth Tokenを取得します。こちらも先ほどのSlack APIの画面。「OAuth & Permissions」のメニューを開くと出てきます。Bot User OAuth Tokenは「xoxb-」から始まります。

Bot User Tokenの取得方法

取得した2つのTokenを環境変数として与えます。IntelliJでの環境変数の与え方。まずは「Run Configuration」を開きます。

実行条件を指定する

環境変数名SLACK_APP_TOKENにApp-Level Tokenを設定します。 同様に、SLACK_BOT_TOKENにBot User OAuth Tokenも設定します。

Tokenの環境変数への設定

続いて、投稿するチャンネルのIDを取得します。チャンネルIDはSlackのチャンネル設定画面の一番下にあります。図の赤枠のところです。

チャンネルIDの取得

こんなコードでいわゆるHello Worldが動きます。XXXXXXXXXXのところは上で取得したチャンネルIDを入れてください。

it.token(SLACK_BOT_TOKEN)のところは取得したTokenを直書きしても動きます。が、コードの中に直接Tokenを書いてしまうとTokenが流出する原因となるので環境変数などに外出しするようにしましょう。

import com.slack.api.bolt.App

val SLACK_BOT_TOKEN = System.getenv("SLACK_BOT_TOKEN")

fun main() {

    val app = App()
    app.client.chatPostMessage {
        it.token(SLACK_BOT_TOKEN)
        it.channel("XXXXXXXXXX")
        it.text("Hello World!!")
    }
}

おおおおおおおお!!動きましたね!!

Hello World

メンションに対してリアクションしてみる

今度はbotに話しかけたらリアクションしてくる例を書いてみましょう。コードをこんな風に書き換えます。

import com.slack.api.app_backend.events.payload.EventsApiPayload
import com.slack.api.bolt.App
import com.slack.api.bolt.context.builtin.EventContext
import com.slack.api.bolt.socket_mode.SocketModeApp
import com.slack.api.model.event.AppMentionEvent

val SLACK_BOT_TOKEN = System.getenv("SLACK_BOT_TOKEN")

fun main() {

    val app = App()
    val socketApp = SocketModeApp(app)
    socketApp.start()

    app.event(AppMentionEvent::class.java) { payload, context ->
        mentionHandler(payload, context)
        context.ack()
    }
}

fun mentionHandler(payload: EventsApiPayload<AppMentionEvent>, context: EventContext) {
    context.say("なんかよう?")
}

話しかけてみました。おおおおおお、レスポンスが!!さみしくなったら話し相手にしてみてもいいですね♪

botによるリアクション

このコードの中のpayloadcontextはSlack APIで定義されているオブジェクトで、中にはイベントの内容、今回だとメンションされた時のメッセージや時刻、スレッドのID、チャンネル、メンションした人のIDなどが入っています。これらをうまく使うことでメンションされた内容に応じて動作を変えたりできます。 また、今回はメンションされたイベントを拾っていますが他にもリアクション(スタンプ)や、いろいろなイベントを拾ってbotを動かすことができます。 もちろんイベント以外にも、自分でタイマーを作って毎日何時にbotがリマインダーを送ってくれる、みたいなのも作ることができます。

ちょっと解説

前述のサンプルコードではapp.client.chatPostMessageでチャンネルに投稿しています。これはAPIリファレンスのこのページにあるchat.postMessageに対応しています。ここを読めば、このapp.client.chatPostMessageがどんな引数を取るのか大体わかると思います。

続いてapp.event(AppMentionEvent::class.java)のところ。botで受け取ることができるイベントは同じくリファレンスがあって、ここで確認できます。 ただ、イベントAPIはこのリファレンスを見てもまだわかりにくいと思います。AppMentionEvent::class.javaのところとか。。ですが、ここは適宜bolt Java(SlackのJAVA API)のチュートリアルなども参考にしてみてください。 また、contextpayloadの中にはいろいろな情報が入っているのですが、何が入っているのかを確認する一番早い方法は、おそらくデバッガを使って変数の中身を見ることです。筆者はデバッガで中身を調べていろいろ実装しました。

さらに知るには

Slack APIはリファレンスが公開されています。JavaのAPIのリファレンスではなく元のRest APIのリファレンスなのでちょっとわかりづらいですが、慣れてくると対応関係はわかるようになると思います。

また、botが投稿するメッセージにボタンやテキスト入力を配置するBlock kitもあります。Slack上で子ウィンドウを開いてフォームを作ったりもこのBlock kitでできたり。

Slackは今なおcanvasやらリストやらいろいろ機能が増えていて、もれなくAPIが公開されているので夢が広がりますね♪

どんなものを作ったのか

ここまでSlack APIを使ったbotの作り方の基礎の基礎をご紹介しました。発展させると色々なものを作ることができます。この記事の残りでは筆者たちがどんなものを作ってきたのか少しご紹介します。

おしえて機能

botに「おしえて」とお願いすると回答をくれる機能。元の辞書はConfluence上に実装しました。検索ワードちょっとしたあいまい検索にかけて教えてくれます。(下の図の例だと「減価償却」で聞いたけど「償却費」でヒットしてますね)

おしえて機能

こういう一般的な用語であればググった方が早かったりしますが、会社や組織、チームの独自用語など新規着任者にはわかりにくかったりしますよね。そういうのを登録しておいて活用しています。

「編集」ボタンや「新しく説明を起こす」というボタンが見えますが、botの回答がイマイチだったり違う回答をしてきたときにはSlack上で回答を改善したり追加することができます。

何より、Slackのようにチームメンバーが見えるオープンな場で使うことで他の先輩や有識者がサポートしてくれる、といった副次効果も生まれています。まさに集合知って感じです♪

ホスト検索機能

わたしたちは設備のホスト管理にデータベースを使っていますが、いちいちそのデータベースにログインしてホストを検索するのは面倒。。ということで、Slackから簡単にホストを検索する機能を実装しました。これもあいまい検索機能に対応しています。ホスト名の検索だけじゃなく、IPアドレスからの逆引きなんかにも対応しています。

ホスト検索機能

これの発展形で、tracerouteを打った結果のIPのホスト名をずらっとtracerouteの結果に付与してくれる機能なんていうのもあります。 tracerouteをパッと見てもどのアドレスがどのホスト、ネットワーク機器なのかってわかりにくかったりしますが、その機能を使うと楽ちんに調べることができます。

ほかにも

わたしたちのシステムは、その設定を変更したりソフトウェアのバージョンアップをする際に承認プロセスを経てから作業をする必要があります。これらも承認プロセスを管理するシステムがあるのですが、botからそういったシステムのAPIをたたくことでSlack上で承認が行えます。 さらに、Confluence上でノーコードで定義したワークフローがSlack上で実行できる、といった機能も実現しています。

ConfluenceもいろいろとAPIを公開しているのでConfluenceとの連携はいろいろと実装しています。例えば、プロジェクトごとのページツリーを自動生成したり。

社内のユーザにいろいろアイデアをもらって今後も機能を追加していきたいと思っています。

筆者の考えるDX

ちょっと話が飛びますw 本記事でご紹介したbotの作り方と私たちが実装したbot、完全に内製でやっています。自分たちで「こういうのがあったら便利だな。。。」「この作業めんどくさいんだよな。。。」というものを自らの手でbotの機能として実装して解決する、という発想。

一昔前、プログラミング(コーディング)は専門業務であり、プロに任せる(外部に委託して開発する)のが一般的だったと思いますし、今でもかなりの部分がそのままだと思います。一方、今の会社の若手~中堅社員はいわゆる「デジタルネイティブ世代」と呼ばれていて、子供のころからコンピュータや学校でプログラミングに触れて育ってきた方も多いと思います。今の時代、もはやプログラミングは素人の手出しができない専門業務ではなく、誰でもちょっと背を伸ばせばできるようになってきてるのではないかと思います。

こんな時代だからこそ、日々の業務で感じた「めんどくさい」「もうちょっと便利に」を、自らの手を動かして解決していけるんじゃないか、という思いでこの取り組みを始めました。現場の課題、それがどうなって欲しい、を一番知っているのは現場のメンバーですし。

今ではこのbotのコードも社内コントリビュータが増え、なかなかの規模に育ってきました。また今度、このbotで面白い機能が実装されたらこの記事のようなブログでご紹介したいと思います。