0Pricing
AI Agents · 강의

이벤트 및 슬래시 명령 수신

Slack Bolt에서 app_mention, 슬래시 명령, 작업 처리기를 사용하는 방법을 알아봅니다.

이벤트 및 슬래시 명령 수신은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

Slack 이벤트 구독 개요

Slack은 메시지가 게시되거나 누군가 봇을 언급하거나 사용자가 채널에 참여하는 등 이벤트가 발생하면 앱에 이벤트를 보냅니다. Slack 앱 대시보드에서 특정 이벤트 유형을 구독한 다음, Bolt에서 @app.event() 데코레이터를 사용해 처리기를 등록합니다.

from slack_bolt import App
import os

app = App(
    token=os.environ['SLACK_BOT_TOKEN'],
    signing_secret=os.environ['SLACK_SIGNING_SECRET']
)

# Register event handlers with @app.event()
# The string argument must match the Slack event type exactly

@app.event('app_mention')
def handle_mention(event, say, logger):
    logger.info(f'Mention event: {event}')
    say(f'Hello <@{event["user"]}>!')

@app.event('message')
def handle_message(event, say):
    # Fires for every message in subscribed channels
    if event.get('subtype') is None:  # ignore bot messages
        print(f'Message: {event["text"]}')

app_mention 이벤트 처리

채널에서 누군가 @YourBot을 입력하면 app_mention 이벤트가 발생합니다. event['text']에는 멘션을 포함한 전체 메시지가 들어 있습니다. 멘션 접두사를 제거하면 사용자의 실제 질의를 얻을 수 있습니다.

import re

@app.event('app_mention')
def handle_mention(event, say, client):
    # event['text'] example: '<@U0123BOT> summarize this'
    text = event.get('text', '')
    user_id = event['user']
    channel = event['channel']

    # Remove the @mention to get the clean query
    clean_text = re.sub(r'<@[A-Z0-9]+>', '', text).strip()
    print(f'User {user_id} asked: {clean_text}')

    if not clean_text:
        say(f'Hi <@{user_id}>! How can I help you today?')
        return

    # Process the query
    response = process_user_query(clean_text, user_id)
    say(response)

이벤트 페이로드에 액세스하기

모든 이벤트 처리기는 원본 Slack 이벤트 페이로드가 들어 있는 event 딕셔너리를 받습니다. 주요 필드는 다음과 같습니다. event['user'](사용자 ID), event['channel'](채널 ID), event['text'](메시지 내용), event['ts'](타임스탬프/메시지 ID)입니다.

@app.event('app_mention')
def handle_mention(event, say, client):
    print('Event type:', event.get('type'))
    print('User ID:', event.get('user'))     # e.g. 'U0123ABC'
    print('Channel:', event.get('channel'))   # e.g. 'C0456DEF'
    print('Text:', event.get('text'))          # full message text
    print('Timestamp:', event.get('ts'))       # '1234567890.123456'
    print('Thread TS:', event.get('thread_ts')) # if in a thread

    # Get full user info from the user ID
    user_info = client.users_info(user=event['user'])
    real_name = user_info['user']['real_name']
    email = user_info['user']['profile'].get('email', '')
    say(f'Hello {real_name}!')

슬래시 명령 — 등록 및 응답

슬래시 명령을 사용하면 사용자가 모든 Slack 채널에서 에이전트 작업을 실행할 수 있습니다. Slack 앱 대시보드의 Slash Commands에서 명령 URL을 등록한 다음, @app.command('/command-name')으로 처리합니다. 항상 ack()을 즉시 호출해야 합니다. 호출하지 않으면 Slack이 3초 후 시간 초과를 발생시킵니다.

@app.command('/summarize')
def handle_summarize(ack, body, say, respond):
    # CRITICAL: ack() must be called within 3 seconds
    ack()  # acknowledge the command immediately

    # body contains the command payload
    user_id = body['user_id']
    channel_id = body['channel_id']
    text = body.get('text', '').strip()  # text after the command

    print(f'User {user_id} ran /summarize with: "{text}"')

    if not text:
        respond('Usage: /summarize <text or URL to summarize>')
        return

    # Process and respond
    summary = generate_summary(text)
    say(f'Summary by <@{user_id}>:\n{summary}')

ack() — 3초 규칙

Slack은 모든 수신 슬래시 명령과 대화형 페이로드를 3초 이내에 ack()으로 확인하도록 요구합니다. 그렇게 하지 않으면 Slack이 사용자에게 오류를 표시합니다. 오래 걸리는 작업이라면 즉시 ack하고 백그라운드 스레드에서 처리를 시작한 다음, 결과와 함께 respond()를 사용해 응답합니다.

import threading

@app.command('/analyze')
def handle_analyze(ack, body, respond):
    ack()  # Must be within 3 seconds!

    text = body.get('text', '').strip()
    if not text:
        respond('Please provide text to analyze.')
        return

    # For slow operations: run in background thread
    def process_in_background():
        result = slow_ai_analysis(text)  # may take 10+ seconds
        respond(f'Analysis complete:\n{result}')

    thread = threading.Thread(target=process_in_background)
    thread.daemon = True
    thread.start()

    # respond() is safe to call from a different thread
    # ack() already sent, Slack won't time out

say()와 respond() — 각각 사용하는 경우

두 함수가 Slack에 메시지를 다시 게시합니다.

  • say() — 이벤트가 발생한 채널에 게시하며 모든 사람이 볼 수 있습니다
  • respond() — 슬래시 명령 처리기에서만 사용할 수 있으며, 명령을 실행한 사용자에게만 보이는 임시 메시지를 게시할 수 있습니다

공개 응답에는 respond(response_type='in_channel')을 사용하고, 비공개 응답에는 respond(response_type='ephemeral')을 사용합니다.

@app.command('/status')
def handle_status(ack, respond, body):
    ack()

    # Ephemeral: only visible to the user who ran the command
    respond(
        text='Agent status: Running | Queue: 3 tasks | Uptime: 4h 22m',
        response_type='ephemeral'  # private to command user
    )

@app.command('/broadcast')
def handle_broadcast(ack, say, respond, body):
    ack()
    text = body.get('text', '')

    # Public: visible to everyone in the channel
    say(
        text=f'<@{body["user_id"]}> broadcast: {text}',
        channel=body['channel_id']
    )

    # Confirm privately to the sender
    respond('Broadcast sent!', response_type='ephemeral')

메시지 이벤트와 하위 유형

일반 message 이벤트는 봇 메시지, 수정, 삭제를 포함한 모든 메시지에 대해 발생합니다. 필터링하려면 subtype 필드를 사용합니다. 일반적인 하위 유형으로는 bot_message, message_changed, message_deleted가 있습니다. subtype이 없으면 일반 사용자의 메시지입니다.

@app.event('message')
def handle_message(event, say, client):
    subtype = event.get('subtype')

    # Ignore bot messages to prevent loops
    if subtype == 'bot_message':
        return

    # Ignore message edits and deletes
    if subtype in ('message_changed', 'message_deleted'):
        return

    # Only process direct messages (DMs) to the bot
    channel_type = event.get('channel_type', '')
    if channel_type == 'im':
        text = event.get('text', '').strip()
        user = event['user']
        print(f'DM from {user}: {text}')
        say(f'You said: {text}')

반응 수신하기

누군가 메시지에 이모지 반응을 추가하면 reaction_added 이벤트가 발생합니다. 이를 사용해 에이전트 작업을 실행할 수 있습니다. 예를 들어 📌 반응을 추가해 메시지를 저장하거나 ✅ 반응을 추가해 작업 완료를 표시할 수 있습니다.

@app.event('reaction_added')
def handle_reaction(event, client, say):
    reaction = event['reaction']  # e.g. 'thumbsup', 'white_check_mark'
    user_id = event['user']  # who reacted
    item = event['item']  # what was reacted to

    print(f'User {user_id} reacted :{reaction}: to {item["type"]}')

    if reaction == 'white_check_mark' and item['type'] == 'message':
        # Fetch the original message
        result = client.conversations_history(
            channel=item['channel'],
            oldest=item['ts'],
            latest=item['ts'],
            inclusive=True,
            limit=1
        )
        messages = result.get('messages', [])
        if messages:
            text = messages[0].get('text', '')
            print(f'Task completed: {text[:100]}')

대화형 구성 요소의 action 페이로드

사용자가 버튼을 클릭하거나 메뉴 항목을 선택하면 Slack이 action 페이로드를 보냅니다. @app.action('action_id')으로 처리합니다. action ID는 Block Kit 구성 요소를 생성할 때 설정한 문자열입니다. 항상 ack()을 즉시 호출해야 합니다.

@app.action('approve_task')
def handle_approve(ack, body, respond, client):
    ack()  # acknowledge within 3 seconds

    action = body['actions'][0]  # the button that was clicked
    action_id = action['action_id']  # 'approve_task'
    value = action.get('value', '')  # data attached to the button
    user_id = body['user']['id']

    print(f'User {user_id} clicked {action_id} with value: {value}')

    # Update the original message to show it was approved
    client.chat_update(
        channel=body['container']['channel_id'],
        ts=body['container']['message_ts'],
        text=f'Task approved by <@{user_id}>',
        blocks=[]  # remove buttons after action
    )
    respond('Task approved!', response_type='ephemeral')

채널 또는 사용자별 이벤트 필터링

대규모 워크스페이스에서는 봇이 여러 채널에서 이벤트를 받을 수 있습니다. 처리기에서 초기에 필터링하여 관련 이벤트만 처리하십시오. event['channel']을 허용 목록과 비교하거나 event['user']를 확인하여 특정 사용자(예: 다른 봇)를 무시할 수 있습니다.

import os

# Only respond in designated channels
ALLOWED_CHANNELS = set(
    os.environ.get('ALLOWED_CHANNELS', '').split(',')
)

BOT_USER_IDS = set()  # will be populated at startup

@app.event('app_mention')
def handle_mention(event, say, client):
    channel = event.get('channel', '')
    user = event.get('user', '')

    # Skip if channel not in allowed list (if list is configured)
    if ALLOWED_CHANNELS and channel not in ALLOWED_CHANNELS:
        return

    # Skip if the 'user' is actually a bot
    if user in BOT_USER_IDS:
        return

    text = event.get('text', '').strip()
    say(f'Processing: {text[:50]}')

스레드 답글 지원

기본 채널 대신 스레드에 답글을 달려면 say()에 thread_ts를 전달합니다. 스레드 타임스탬프를 가져오려면 event.get('thread_ts', event['ts'])을 사용하십시오. thread_ts는 메시지가 이미 스레드에 있을 때만 존재하며, 그렇지 않으면 새 스레드를 시작하기 위해 메시지 자체의 ts를 사용합니다.

@app.event('app_mention')
def handle_mention_in_thread(event, say):
    user = event['user']
    text = event.get('text', '').strip()

    # Reply in the same thread (or start a new one)
    thread_ts = event.get('thread_ts') or event.get('ts')

    response_text = f'<@{user}>, processing your request...'

    say(
        text=response_text,
        thread_ts=thread_ts  # keeps the reply in the thread
    )

    # Do the actual work
    result = do_agent_work(text)

    say(
        text=f'Done! Result:\n{result}',
        thread_ts=thread_ts
    )

빠른 확인: ack() 타이밍

Slack 이벤트 처리에 대한 이해도를 확인해 보십시오.

이벤트와 슬래시 명령 복습

이제 Slack 에이전트가 모든 사용자 상호 작용에 응답할 수 있습니다.

  • @app.event('app_mention') — @bot 멘션을 처리하며 정규식으로 멘션 접두사를 제거합니다
  • @app.command('/cmd') — 슬래시 명령을 처리하며 항상 3초 이내에 ack()합니다
  • say() — 채널에 공개적으로 게시하고, respond() — 슬래시 명령에 응답하며 임시 응답을 사용할 수 있습니다
  • @app.action('id') — 버튼 클릭과 대화형 구성 요소 상호 작용을 처리합니다
  • @app.event('reaction_added') — 이모지 반응이 추가될 때 실행합니다
  • say()에서 thread_ts를 사용해 답글을 스레드 안에 유지합니다
  • 관련 없는 이벤트 처리를 피하도록 초기에 채널 또는 사용자별로 필터링합니다

자주 묻는 질문

“이벤트 및 슬래시 명령 수신” 강의는 무료인가요?

네 — “이벤트 및 슬래시 명령 수신” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

“이벤트 및 슬래시 명령 수신”에서 뭘 배우나요?

Slack Bolt에서 app_mention, 슬래시 명령, 작업 처리기를 사용하는 방법을 알아봅니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Agents을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“이벤트 및 슬래시 명령 수신” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Slack Bolt SDK 기초
  2. 이벤트 및 슬래시 명령 수신
  3. 메시지 및 서식 있는 블록 보내기
  4. 팀 알림 봇 만들기
← AI Agents(으)로 돌아가기