Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

Slack エージェント

最終更新 Markdown で表示Agent セットアップ

最初の Slack エージェントをデプロイする

このガイドでは、Cloudflare Workers 上に AI 搭載の Slack ボットを構築してデプロイします。ボットは次ができます。

  • ダイレクトメッセージに応答する
  • チャネルでメンションされたときに返信する
  • スレッド内の会話コンテキストを維持する
  • AI で知的な応答を生成する

Slack エージェントはマルチテナントアプリケーションです。1 回のデプロイで複数の Slack ワークスペースに対応できます。各ワークスペースは、Agents SDK により、専用ストレージを持つ隔離されたエージェントインスタンスを持ちます。

この例の完全なコードは こちら で確認できます。

前提条件

始める前に、次が必要です。

1. Slack アプリを作成する

まず、エージェントが Slack と連携するための新しい Slack アプリを作成します。

  1. api.slack.com/apps に移動し、Create New App を選択します。
  2. From scratch を選択します。
  3. アプリ名を付け(例: "My AI Assistant")、ワークスペースを選びます。
  4. Create App を選択します。

OAuth と権限を設定する

Slack アプリの設定で OAuth & Permissions を開き、次の Bot Token Scopes を追加します。

  • chat:write — ボットとしてメッセージを送信する
  • chat:write.public — 参加せずにチャネルへメッセージを送信する
  • channels:history — 公開チャネルのメッセージを表示する
  • app_mentions:read — メンションを受け取る
  • im:write — ダイレクトメッセージを送信する
  • im:history — ダイレクトメッセージの履歴を表示する

Event Subscriptions を有効にする

Event Subscriptions の URL は、エージェントのデプロイ後に設定します。いまは Slack アプリ設定の Event Subscriptions を開き、有効化の準備だけします。

次のボットイベントを購読します。

  • app_mention — ボットが @メンションされたとき
  • message.im — ボットへのダイレクトメッセージ

まだ有効にしないでください。デプロイ後に有効にします。

Slack の認証情報を取得する

Slack アプリ設定から、次の値を集めます。

  1. Basic Information > App Credentials:
    • Client ID
    • Client Secret
    • Signing Secret

手元に控えておきます。次のステップで使います。

2. Slack エージェントプロジェクトを作成する

  1. Slack エージェント用の新しいプロジェクトを作成します。
npm create cloudflare@latest -- my-slack-agent
  1. プロジェクトへ移動します。
cd my-slack-agent
  1. 必要な依存関係をインストールします。
npm install agents openai

3. 環境変数を設定する

  1. ローカル開発用のシークレットとして、プロジェクトルートに .env ファイルを作成します。
touch .env
  1. 認証情報を .env に追加します。
SLACK_CLIENT_ID="your-slack-client-id"
SLACK_CLIENT_SECRET="your-slack-client-secret"
SLACK_SIGNING_SECRET="your-slack-signing-secret"
OPENAI_API_KEY="your-openai-api-key"
OPENAI_BASE_URL="https://gateway.ai.cloudflare.com/v1/YOUR_ACCOUNT_ID/YOUR_GATEWAY/openai"
  1. エージェントを設定するため、wrangler.jsonc を更新します。
{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "my-slack-agent",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-09-20",
	"compatibility_flags": [
		"nodejs_compat"
	],
	"durable_objects": {
		"bindings": [
			{
				"name": "MyAgent",
				"class_name": "MyAgent",
				"script_name": "my-slack-agent"
			}
		]
	},
	"migrations": [
		{
			"tag": "v1",
			"new_classes": [
				"MyAgent"
			]
		}
	]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "my-slack-agent"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-09-20"
compatibility_flags = [ "nodejs_compat" ]

[[durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
script_name = "my-slack-agent"

[[migrations]]
tag = "v1"
new_classes = [ "MyAgent" ]

4. Slack エージェントを作成する

  1. まず、ベースの SlackAgent クラスを src/slack.ts に作成します。このクラスは OAuth、リクエスト検証、イベントルーティングを扱います。GitHub 上の完全な実装 を確認できます。

  2. 次に、エージェント実装を src/index.ts に作成します。

import { env } from "cloudflare:workers";
import { SlackAgent } from "./slack";
import { OpenAI } from "openai";

const openai = new OpenAI({
	apiKey: env.OPENAI_API_KEY,
	baseURL: env.OPENAI_BASE_URL,
});

type SlackMsg = {
	user?: string;
	text?: string;
	ts: string;
	thread_ts?: string;
	subtype?: string;
	bot_id?: string;
};

function normalizeForLLM(msgs: SlackMsg[], selfUserId: string) {
	return msgs.map((m) => {
		const role = m.user && m.user !== selfUserId ? "user" : "assistant";
		const text = (m.text ?? "").replace(/<@([A-Z0-9]+)>/g, "@$1");
		return { role, content: text };
	});
}

export class MyAgent extends SlackAgent {
	async generateAIReply(conversation: SlackMsg[]) {
		const selfId = await this.ensureAppUserId();
		const messages = normalizeForLLM(conversation, selfId);

		const system = `You are a helpful AI assistant in Slack.
Be brief, specific, and actionable. If you're unsure, ask a single clarifying question.`;

		const input = [{ role: "system", content: system }, ...messages];

		const response = await openai.chat.completions.create({
			model: "gpt-4o-mini",
			messages: input,
		});

		const msg = response.choices[0].message.content;
		if (!msg) throw new Error("No message from AI");

		return msg;
	}

	async onSlackEvent(event: { type: string } & Record<string, unknown>) {
		// Ignore bot messages and subtypes (edits, joins, etc.)
		if (event.bot_id || event.subtype) return;

		// Handle direct messages
		if (event.type === "message") {
			const e = event as unknown as SlackMsg & { channel: string };
			const isDM = (e.channel || "").startsWith("D");
			const mentioned = (e.text || "").includes(
				`<@${await this.ensureAppUserId()}>`,
			);

			if (!isDM && !mentioned) return;

			const conversation = await this.fetchConversation(e.channel);
			const content = await this.generateAIReply(conversation);
			await this.sendMessage(content, { channel: e.channel });
			return;
		}

		// Handle @mentions in channels
		if (event.type === "app_mention") {
			const e = event as unknown as SlackMsg & {
				channel: string;
				text?: string;
			};
			const thread = await this.fetchThread(e.channel, e.thread_ts || e.ts);
			const content = await this.generateAIReply(thread);
			await this.sendMessage(content, {
				channel: e.channel,
				thread_ts: e.thread_ts || e.ts,
			});
			return;
		}
	}
}

export default MyAgent.listen({
	clientId: env.SLACK_CLIENT_ID,
	clientSecret: env.SLACK_CLIENT_SECRET,
	slackSigningSecret: env.SLACK_SIGNING_SECRET,
	scopes: [
		"chat:write",
		"chat:write.public",
		"channels:history",
		"app_mentions:read",
		"im:write",
		"im:history",
	],
});

5. ローカルでテストする

開発サーバーを起動します。

npm run dev

エージェントは http://localhost:8787 で動きます。

Slack Event Subscriptions を設定する

エージェントがローカルで動いているので、Slack から到達できるようにします。安全なトンネルを作るには Cloudflare Tunnel を使います。

npx cloudflared tunnel --url http://localhost:8787

https://random-subdomain.trycloudflare.com のような公開 URL が出力されます。

Slack アプリ設定に戻ります。

  1. Event Subscriptions を開きます。

  2. Enable EventsOn に切り替えます。

  3. Request URL に https://random-subdomain.trycloudflare.com/slack を入力します。

  4. Slack が検証リクエストを送ります。エージェントが正しく動いていれば Verified と表示されます。

  5. Subscribe to bot events で次を追加します。

    • app_mention
    • message.im
  6. Save Changes を選択します。

アプリを Slack にインストールする

ブラウザーで http://localhost:8787/install を開きます。Slack の認可ページへリダイレクトされます。ワークスペースへアプリをインストールするには Allow を選択します。

認可後、ブラウザーに "Successfully registered!" と表示されます。

エージェントをテストする

Slack を開きます。次を試します。

  1. ボットへ DM を送ります。AI が生成したメッセージで応答するはずです。
  2. チャネルでボットをメンションします(例: @My AI Assistant hello)。スレッドで返信するはずです。

問題なければ、本番へのデプロイ準備は完了です。

6. 本番へデプロイする

  1. デプロイ前に、シークレットを Cloudflare へ追加します。
npx wrangler secret put SLACK_CLIENT_ID
npx wrangler secret put SLACK_CLIENT_SECRET
npx wrangler secret put SLACK_SIGNING_SECRET
npx wrangler secret put OPENAI_API_KEY
npx wrangler secret put OPENAI_BASE_URL
  1. エージェントをデプロイします。
npx wrangler deploy

デプロイ後、次のような本番 URL を受け取ります。

https://my-slack-agent.your-account.workers.dev

Slack Event Subscriptions を更新する

Slack アプリ設定に戻ります。

  1. Event Subscriptions を開きます。
  2. Request URL を本番 URL に更新します: https://my-slack-agent.your-account.workers.dev/slack
  3. Save Changes を選択します。

アプリを配布する

エージェントをデプロイしたら、ほかの人とも共有できます。

  • 単一ワークスペース: https://my-slack-agent.your-account.workers.dev/install からインストールします。
  • 公開配布: Slack App Directory にアプリを申請します。

アプリをインストールした各ワークスペースは、専用ストレージを持つ隔離されたエージェントインスタンスを受け取ります。

仕組み

Durable Objects によるマルチテナンシー

Slack エージェントは Durable Objects を使い、Slack ワークスペースごとに隔離されたステートフルインスタンスを提供します。

  • 各ワークスペースの team_id を Durable Object ID として使います。
  • 各エージェントインスタンスは、自身の Slack アクセストークンを KV ストレージに保存します。
  • 会話は、必要になったときに Slack API から取得します。
  • エージェントロジックはすべて、隔離された一貫した環境で走ります。

OAuth フロー

エージェントは Slack の OAuth 2.0 フローを処理します。

  1. ユーザーが /install を開く > Slack 認可へリダイレクトされます。
  2. ユーザーが Allow を選択 > Slack が認可コード付きで /accept へリダイレクトします。
  3. エージェントがコードをアクセストークンに交換します。
  4. エージェントがトークンを、ワークスペースの Durable Object に保存します。

イベント処理

Slack がイベントを送ると、次のように処理します。

  1. リクエストが /slack エンドポイントに到着します。
  2. エージェントが HMAC-SHA256 でリクエスト署名を検証します。
  3. エージェントがイベントを、正しいワークスペースの Durable Object へルーティングします。
  4. onSlackEvent メソッドがイベントを処理し、応答を生成します。

エージェントをカスタマイズする

AI モデルを変更する

src/index.ts のモデルを更新します。

const response = await openai.chat.completions.create({
	model: "gpt-4o", // or any other model
	messages: input,
});

会話メモリを追加する

会話履歴を Durable Object ストレージに保存します。

async storeMessage(channel: string, message: SlackMsg) {
  const history = await this.ctx.storage.kv.get(`history:${channel}`) || [];
  history.push(message);
  await this.ctx.storage.kv.put(`history:${channel}`, history);
}

特定のキーワードに反応する

onSlackEvent にカスタムロジックを追加します。

async onSlackEvent(event: { type: string } & Record<string, unknown>) {
  if (event.type === "message") {
    const e = event as unknown as SlackMsg & { channel: string };

    if (e.text?.includes("help")) {
      await this.sendMessage("Here's how I can help...", {
        channel: e.channel
      });
      return;
    }
  }

  // ... rest of your event handling
}

別の LLM プロバイダーを使う

OpenAI を Workers AI に置き換えます。

import { Ai } from "@cloudflare/ai";

export class MyAgent extends SlackAgent {
	async generateAIReply(conversation: SlackMsg[]) {
		const ai = new Ai(this.ctx.env.AI);
		const response = await ai.run("@cf/meta/llama-3-8b-instruct", {
			messages: normalizeForLLM(conversation, await this.ensureAppUserId()),
		});
		return response.response;
	}
}

次のステップ

関連リソース

Durable Objects

基盤となるステートフルインフラを学びます。

Slack API

公式の Slack API ドキュメントです。

OpenAI API

公式の OpenAI API ドキュメントです。

役に立ちましたか?