はじめに: Slackでエージェントがメンションなしに働く時代

AIエージェントをSlackに統合して使うことは、もはや一般的になりました。しかし従来は毎回メンション(@)を付けないとエージェントが反応せず、会話が途切れてしまうことがよくありました。VercelのEveエージェントが新たに発表した機能を活用すれば、この問題を解決できます。

今回のアップデートの核心は2つです:

  1. スレッド内自動応答: 一度アクティブになったスレッドでは、メンションなしでもエージェントが継続して応答します。
  2. イベントフック拡張: reaction_addedteam_joinなど、Slackアプリが購読するすべてのイベントに反応できます。

この記事では、実際のコードを通じて実装方法と実務上の注意点を解説します。

なぜこの機能が重要なのか

Slackでエージェントを運用する際、最も大きな不便は「メンション依存」でした。ユーザーが毎回@Eveを付けなければならず、会話が断絶し、チームメンバーがエージェントの存在を忘れてしまうことも多々ありました。今回のアップデートでエージェントがスレッド内で能動的に会話を続けられるようになり、まるで同僚と話しているかのような体験を提供します。

また、イベントフックが追加されたことで、Slackで発生するすべてのイベント(例: 新メンバー参加、リアクション追加)をエージェントのトリガーとして使用できるようになりました。これはオンボーディング自動化や通知処理など、様々なシナリオに拡張可能です。

この記事で扱う内容

  • onMessageフックとヘルパー関数(isBotMentionedisSubscribed
  • スレッド参加者の確認とチャンネル履歴権限
  • ctx.cancel()ctx.reset()によるセッション制御
  • onEventフックによるイベントファンアウト
  • 実務適用時の注意点と次の学習ステップ

Eve agent responding to Slack messages in a thread with session controls

本論1: 核心概念とコード例

1. onMessageフックでメンションなしに会話を続ける

Eveエージェントがスレッドでメンションなしに応答するには、onMessageフックでctx.isSubscribed()を使用します。以下のコードは、DM、明示的メンション、アクティブスレッドのフォローアップメッセージをすべて処理する例です。

// EveエージェントのSlackチャンネル設定
import { slackChannel } from "@vercel/eve";

export default slackChannel({
  credentials: connectSlackCredentials("slack/my-agent"),
  async onMessage(ctx, message) {
    // ボットのメッセージには応答しない
    if (message.author?.isBot) return null;

    // DMかどうかを確認
    const isDirectMessage = message.raw.channel_type === "im";

    // DM、明示的メンション、またはアクティブスレッドのメッセージの場合のみ処理
    const shouldHandle = isDirectMessage || ctx.isBotMentioned() || (await ctx.isSubscribed());
    return shouldHandle ? { auth: null } : null;
  },
});

主要ポイント:

  • ctx.isBotMentioned(): メッセージにボットメンションが含まれるか確認
  • ctx.isSubscribed(): メッセージがアクティブセッションのあるスレッドに属するか確認
  • message.raw.channel_type === "im": DMかどうかを確認

2. スレッド参加者リストの取得

スレッドに誰が参加しているかによってルーティングを変えたい場合は、ctx.thread.listParticipants()を使用します。この関数は、一意な人間ユーザーIDを最初の出現順で返します。

// スレッド参加者リストの取得
const participants = await ctx.thread.listParticipants();
if (participants.includes("U123456")) {
  // 特定ユーザーが参加している場合のロジック
}

権限の注意:

  • 公開チャンネル: message.channelsトリガーイベントとchannels:historyボットスコープが必要
  • プライベートチャンネル: message.groupsgroups:historyが追加で必要

3. セッションのキャンセルとリセット

ユーザーが誤ってメッセージを送信した場合や会話を初期化したい場合、ctx.cancel()ctx.reset()を使用できます。

// 途中で誤ったメッセージが送信された場合 - 現在のターンをキャンセル
export default slackChannel({
  credentials: connectSlackCredentials("slack/my-agent"),
  async onMessage(ctx, message) {
    // "キャンセル"コマンドが来たら現在のターンをキャンセルし、メッセージを新しい入力としてキューイング
    if (message.text.trim() === "!cancel") {
      await ctx.cancel();
      return { auth: null };
    }
    // それ以外は既存のロジックを実行
  },
});

// 会話を完全に初期化したい場合 - セッションリセット
export default slackChannel({
  credentials: connectSlackCredentials("slack/my-agent"),
  async onMessage(ctx, message) {
    if (message.text.trim() !== "!new") return null;
    await ctx.reset({ reason: "Slack user requested !new" });
    await ctx.thread.post("新しい会話を開始します。");
    return null;
  },
});

違い:

  • ctx.cancel(): 現在のターンのみ中断し、セッションは維持、新しいメッセージが代替入力として処理される
  • ctx.reset(): セッションを完全に終了し、次のメッセージは新しいセッションとして開始

4. onEventフックで全てのイベントに反応する

これでreaction_addedteam_joinchannel_createdなど、Slackアプリが購読するすべてのイベントを処理できます。ctx.receive()を呼び出すとエージェントターンが開始され、複数回呼び出すと1つのイベントを複数のターゲットにファンアウトできます。

// 新メンバーが参加したらオンボーディングメッセージを複数チャンネルに送信する例
const onboardingChannels = ["C0123ABC", "C0456DEF"];

export default slackChannel({
  credentials: connectSlackCredentials("slack/my-agent"),
  async onEvent({ receive }, event) {
    // チーム参加イベントのみ処理
    if (event.type !== "team_join") return;

    // 各オンボーディングチャンネルにイベント情報を渡してエージェントターンを開始
    await Promise.all(
      onboardingChannels.map((channelId) =>
        receive({
          message: `新しいメンバーがSlackワークスペースに参加しました。このイベントに基づいてオンボーディングを進めてください:\n${JSON.stringify(event)}`,
          target: { channelId },
          auth: null,
        })
      )
    );
  },
});

活用シナリオ:

  • reaction_added: 特定のリアクションが追加されたら通知処理
  • channel_created: 新しいチャンネルが作成されたらルール案内
  • team_join: 新メンバーのオンボーディング自動化

5. 始め方

  1. Eveエージェントの作成: Eve公式ドキュメントを参照してください。
  2. Slackチャンネルの追加: ターミナルでeve channels add slackコマンドを実行
  3. テンプレート活用: Vercelダッシュボードでテンプレートを選べば数分でデプロイ可能

Slack event hooks and API integration diagram with Eve agent

本論2: 注意点と応用テクニック

注意点

  1. 権限設定: 公開チャンネルとプライベートチャンネルで必要なスコープが異なります。イベントが動作しない場合は、まずスコープを確認してください。
  2. 無限ループ防止: ボットメッセージに反応しないよう、message.author.isBotチェックは必須です。
  3. セッション管理: ctx.reset()はセッションを終了するため、ユーザーに明確なフィードバックを与えることをお勧めします。
  4. イベントファンアウト: 複数チャンネルに同時にメッセージを送る際はPromise.allを使用しますが、API呼び出しの制限に注意してください。

応用テクニック

  • 状態管理: セッションがアクティブなスレッドでのみ動作するため、長い会話が必要な作業はスレッドを維持するのが良いでしょう。
  • エラーハンドリング: onMessageで例外が発生するとデフォルトでエージェントが停止します。try-catchで囲んでログを残しましょう。
  • テスト: Vercelダッシュボードでセッションごとのデバッグが可能なので、デプロイ前に様々なシナリオをテストしましょう。

日本市場での適用コンテキスト

日本ではSlackの導入企業が増えており、特にリモートワークの普及に伴い、Slackベースの自動化への需要が高まっています。今回のアップデートは、従来のメンション依存のエージェント運用を改善し、実際の業務でより自然に活用できる契機となるでしょう。

Developer using Vercel dashboard to debug Eve agent sessions Technical Structure Concept

結論: 実務適用のアドバイスとまとめ

今回のEveエージェントアップデートは、SlackでAIエージェントを運用する方法を一段階引き上げました。メンションなしで会話を継続し、イベントフックで様々な通知に反応する機能は、実務で非常に有用です。

実務適用のヒント

  • オンボーディング自動化: team_joinイベントを活用すれば、新入社員に自動で歓迎メッセージを送り、必要なドキュメントを案内できます。
  • カスタマーサポート: スレッド内で顧客問い合わせを処理する際、ctx.cancel()を活用すれば誤った回答を迅速に修正できます。
  • モニタリング: reaction_addedイベントで特定のリアクションが付いたら管理者に通知するなど、モニタリング自動化が可能です。

次の学習ステップ

  1. Eve公式ドキュメント: Slackチャンネル設定とより多くの例を確認してください。
  2. ADK Go 1.0: GoベースのAIエージェント開発に興味があれば、ADK Go 1.0公開の記事を参照してください。
  3. AIモデル最適化: AIでコンクリート配合を最適化した事例に興味があれば、BOxCreteオープンソースモデル解読を読んでみてください。

合わせて読みたい記事

本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。