以下の内容はhttps://timtoronto634.hatenablog.com/entry/2024/11/29/102214より取得しました。


Slack のスレッドを要約する AI bot を自作する

はじめに

こんにちは、a2 です。

ビジネスツールの AI 活用には Slack AI や Notion AI があります。 これらの利用は追加料金が必要ですが、人数が多いと費用は安くなく、簡単に導入できるものではありません。(裏で動いているGPUや AI エンジニアの市場価格、開発工数を考えれば、値段設定自体は高いとは思いません)

私はこれらの AI 機能をまだ使っていないのですが、特定機能であれば自作できるので作ってみました また、自作しておけば、自分のチームだけのコンテキストで回答して欲しい、コードベースやオレオレ資料を元に回答を生成したいなど、細かい要望も自分で実装することができます。

今回は、私が日常的に欲しいなと思う機能の一つであるスレッド要約を日曜大工で作ってみました。Go で実装していますが、JS / Python の方が楽だと思います。

AI の名前は A1 です。

全体像

slack_a1_outline

sequence_of_slack_a1

コードはこちら

github.com

Amazon Bedrock への要約リクエス

Go で Amazon Bedrock へ request する実装は、以前別の記事の中で触れたのでそちらを参照いただくか、コードを直接読んでいただければ幸いです。

Go で Amazon Bedrock でミニマム Chatbot を作る - Progress of a2

prompt は以下のように作って bedrock API で AI に要約をしてもらいます

prompt := fmt.Sprintf(`
Human:
Summarize the following Conversation while following the restrictions
### restrictions ###
- The summarization must be within 200 words.
- The summarization must be in the same language as the conversation
- The summarization must be completed.
- The summarization immediately starts without leading text

### conversion ###
%s

Assistant:
`, conversation)

実際に値が入るとこんな prompt になるイメージです

Human:
Summarize the following Conversation while following the restrictions
### restrictions ###
- The summarization must be within 200 words.
- The summarization must be in the same language as the conversation
- The summarization must be completed.
- The summarization immediately starts without leading text

### conversion ###
田中: おはようございます、佐藤さん。今日の午後のプレゼン資料、確認していただけましたか?
佐藤: おはようございます、田中さん。はい、昨晩確認しました。全体的にはよくまとまっていると思います。
田中: ありがとうございます。気になる点はありましたか?
佐藤: はい、2点ほど。3ページ目の売上グラフの数値が最新のものと少し異なっているようです。また、5ページ目の競合分析にもう少し詳細があると良いかもしれません。
田中: ご指摘ありがとうございます。すぐに修正します。競合分析については、どの部分を強化すればよいでしょうか?
佐藤: そうですね。主要競合の最近の新製品情報と、それに対する我社の強みをもう少し明確にするといいと思います。
田中: 分かりました。その点を追加して、11時までには修正版をお送りします。
佐藤: ありがとうございます。では、午後のプレゼンで使用する最終版は、その修正版ということでよろしいですね。
田中: はい、そのとおりです。他に準備すべきことはありますか?
佐藤: プロジェクターの接続テストは済んでいますか?前回トラブルがあったので、念のため確認しておきましょう。
田中: そうでしたね。では、昼休みにテストしておきます。ありがとうございます。
佐藤: よろしくお願いします。では、午後のプレゼン成功を祈っています。頑張りましょう。
田中: ありがとうございます。全力で取り組みます。

Assistant:

prompt が対話型 interface を強制されるのは若干不満でした。素のLLMに続きを生成してもらうようなプロンプトを使いたかったのですが、Human: ... Assistant: というフォーマットを強制されています。

求める interface も他の Model を探せばあるかもしれません、知ってる方がいれば教えてください

サーバー側の実装

動作としては、slack app のメンションの event を受け取り、スレッドの履歴を取得して、会話内容を prompt につめて要約リクエストして、レスポンスを slack のスレッドに投稿します。

基本的には逐次的に実装していくだけで、slack-go の client を利用しつつ実装しています。

スレッドの内容取得

messages, _, _, err := api.GetConversationReplies(&slack.GetConversationRepliesParameters{
        ChannelID: channelID,
        Timestamp: threadTimeStamp,
    })

スレッドが 1000 単位を超えるような長い時は paging の実装が必要になりますが、そもそもそんな文字数は LLM の入力に入りません。

slack のスレッドに投稿

api.PostMessageContext(ctx, channelID, slack.MsgOptionText(result, false), slack.MsgOptionTS(threadTimeStamp))

url verification

slack app の作成の際に URL に対して url verification request が来るので、それに response できるよう、といった分岐も必要です。

switch eventsAPIEvent.Type {
    case slackevents.URLVerification:
        return handleURLVerification(slackEvent)
    case slackevents.CallbackEvent:
        return handleCallbackEvent(json.RawMessage(slackEvent))
    }

今回、 parse の実装に手こずったのですが、綺麗に書けたわけでもないので割愛します。 Github の方をご覧ください

AWS Lambda にデプロイ

IAM Role の作成

IAM だけ terraform で作れるようにしておきました。 → https://github.com/timtoronto634/slack_a1/tree/main/terraform

必要な権限はデフォルトで作られる CloudWatch Logs などの権限の他には、 Amazon Bedrock の InvokeModel だけです。

CloudWatch Logs が terraform 管理に入っていないのは書くのが面倒だったからです (´ω`)

AWS Lambda の作成

lambda は開発時に AWS CLI で更新したいので、意図的に terraform 管理にしていません。CLI で作ります。

IAM role を作成して、 zip ファイルを用意できたら、以下のコマンドで lambda を作成します。説明の都合で順番が前後してしまってるのはご了承ください。

aws lambda create-function --function-name slackA1 \
--runtime provided.al2023 --handler bootstrap \
--architectures arm64 \
--role arn:aws:iam::111122223333:role/lambda-ex \
--zip-file fileb://slackA1.zip
--timeout 15

追加設定

Lambda について、以下の処理をしておきます

  • Function URL を有効にする。今回は public に作ります。
  • 環境変数に slack app の Token を入れておく
  • タイムアウトを 10 秒程度に伸ばしておく

Slack App 作成

slack 上でメンションするために App を作ります。

今回は QuickStart の手順にほとんど近しいので、不慣れな方は一度作ってみるのをおすすめします。(私も慣れてはいないです)

api.slack.com

Slack App は画面からぽちぽち作ったのですが、手順をだらだら書きたくもないので、特別に manifest を公開しておきます。 event_subscription の URL は lambda の Function URL を入力してください。

display_information:
 name: A1
  description: A bot that summarizes Slack thread content
  background_color: "#18154a"
features:
  app_home:
    home_tab_enabled: true
    messages_tab_enabled: true
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: A1
    always_online: true
oauth_config:
  scopes:
    bot:
      - app_mentions:read
      - channels:history
      - groups:history
      - chat:write
      - assistant:write
settings:
  event_subscriptions:
    request_url: https://a1a1a1.lambda-url.ap-northeast-1.on.aws/ # replace here with function URL
    bot_events:
      - app_mention
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: false

出来上がったもの

以上で構成要素は完成です。

Slack App がメンションされると、その event をsubscription しているので、Function URL にリクエストが送られます。

AWS Lambda が起動し、 api client がスレッドの情報を取得して、要約、 post まで行います。

スレッドの情報を取得する権限は manifest の oauth_config のところに記載されています。

AI にサンプルの会話を生成してもらい、それを手動でスレッドに打ち込んでみました。"A1" が bot です。

sample_result_1

悪くない要約です。まぁこれくらいの長さのスレッドなら自分で読みますね。

一人が喋っているのもおかしいので、アカウントを二つ作って、会話を再現してみました。 打つのが大変なので会話の長さは変わっていません。

sample_result_2

残念ながら、登場人物が間違っています。それっぽい感じがあるのは、さすが LLM です。

潔PMと内田(開発リーダー)の会話全体

潔PM: 内田さん、お疲れ様です。新機能「AIアシスタント」の導入について、最終判断を下すための議論をしたいと思います。開発チームの現状をお聞かせください。

内田(開発リーダー): 潔さん、こんにちは。はい、開発チームとしては技術的には実装可能な段階まで来ています。ただ、品質保証にはもう少し時間が必要かもしれません。

潔PM: 具体的にどのくらいの時間が必要だと考えていますか?

内田: 現在の見積もりでは、あと2週間ほど余分に時間がかかりそうです。特に、AIモデルの精度向上とユーザーインターフェースの最適化に時間を要しています。

潔PM: なるほど。2週間の遅れが生じた場合、他の開発スケジュールへの影響はどうでしょうか?

内田: 正直なところ、少し厳しいです。他の機能開発にも影響が出る可能性があります。できれば1ヶ月ほどの延期を検討していただけないでしょうか。

潔PM: 1ヶ月の延期ですか。マーケティング部門からは早期リリースの要望が来ているのですが、品質を犠牲にするわけにもいきませんね。

内田: はい、その通りです。品質を落とすと、ユーザーの信頼を失う可能性があります。1ヶ月あれば、十分なテストと最適化が可能になります。

潔PM: 分かりました。では、こういう案はどうでしょうか。リリースを1ヶ月延期し、その間にベータ版として一部のユーザーに提供するのはどうでしょう?

内田: それは良いアイデアですね。ベータ版なら、実際のユーザーフィードバックも得られますし、本番リリースまでに更なる改善ができます。

潔PM: では、そのように決定しましょう。1ヶ月の延期とベータ版リリースを行い、その間に品質向上とユーザーフィードバックの収集に努めることにします。

内田: 承知しました。開発チームにも伝え、すぐに準備を始めます。ベータ版のリリース計画も作成しておきます。

潔PM: ありがとうございます。1週間後に進捗確認の会議を設定しますので、よろしくお願いします。

内田: 了解しました。それでは、1週間後に詳細な計画をお示しします。ありがとうございました。

今後の展望

プロトタイプはできましたが、実装面・精度面でまだやるべきこと・やってみたいことが多くあります。

  • AWS Lambda が即時 response を返しつつ非同期処理で要約と slack への投稿をするように実装を修正する必要があります。
    • 今は実装で誤魔化している部分が多々...
  • ユーザー名を取得して、要約に人の名前を入れられるようにする
  • Slack コマンドに応じて context を分けられるようにする
  • message の timestamp を情報として入れてみる

etc etc...

イデアは無限に湧いてきます

注意点

週末に動くところまで持って行きたかったプロトタイプ実装なので、色々なことに目を瞑っています。但し書きをさせてください。

  1. セキュリティ 今回は Slack Bot API token を使用していますが、他にもいくつか認証方法や権限制御がありそうです。

Signing Token の検証は行なっています。手順は公式の案内を参照してください。

Verifying requests from Slack | Slack

(ありがたいことに)この記事を参考に自社で導入してみる、となった場合は、自社のセキュリティ基準に照らして調整してください。

  1. コードはあまりキレイとはいえません

slack の API が元々複雑なのもありますが、slack-go の client が扱いづらかったです。当初頭に描いた処理順とはかなり乖離しました。

今回は諸般の事情があって Go で実装しましたが、外部連携は Go ではなく js/python で実装するのが扱いやすいと思います。

  1. 運用面

個人的な意見ですが、自作 AI bot を長期で運用していくことはおすすめしません。特に今回私が作ったものはプロトタイプで、それを見越してはいません。

コードはリファクタしようと思っていますが、長期の運用に耐えるような設計にはしていません。 AI による要約を試してみて、費用対効果があるなら、Slack AI の導入を検討するか、専門のチームを用意してイチから開発していくのが良いと思います。

おわりに

手順の記載漏れがあるかもしれないので、再現できなかった場合はごめんなさい。コメントか X mention いただければできるだけ対応したいと思います。

他にも同様の slack app を作っている記事もあるようです。気になる方は調べてみてください。




以上の内容はhttps://timtoronto634.hatenablog.com/entry/2024/11/29/102214より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14