การสร้างบอตแจ้งเตือนทีม
ข้อความตามกำหนดเวลา สรุป DM และตัวแทนแจ้งเตือนช่อง
การสร้างบอตแจ้งเตือนทีม เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
สถาปัตยกรรมบอตแจ้งเตือนทีม
บอตแจ้งเตือนทีมจะตรวจสอบระบบภายนอก เช่น การปรับใช้ ไปป์ไลน์ CI/CD การแจ้งเตือนจากระบบติดตาม และการติดตามข้อผิดพลาด แล้วโพสต์การอัปเดตที่จัดรูปแบบแล้วไปยังช่อง Slack ที่เกี่ยวข้อง รูปแบบหลักคือ เหตุการณ์ภายนอก → เว็บฮุก → เอเจนต์ → ข้อความ Slack เอเจนต์จะจัดการการกำหนดเส้นทาง การจัดรูปแบบ และการส่งมอบ
# Team Notification Bot Flow:
#
# External System (GitHub, PagerDuty, Sentry, etc.)
# |
# | HTTP POST (webhook)
# v
# Flask/FastAPI webhook endpoint
# |
# | Parse event
# v
# Agent: classify, format, route
# |
# | Slack API
# v
# Team channel / DM / thread
print('Webhook -> Agent -> Slack is the core notification pattern')การรับเว็บฮุกจากภายนอก
บริการภายนอกส่งเหตุการณ์ไปยังบอตของคุณผ่านเว็บฮุก HTTP ตั้งค่าจุดปลายทาง Flask ที่รับคำขอ POST ตรวจสอบความถูกต้อง (ตรวจสอบลายเซ็นหากบริการนั้นรองรับ) แล้วส่งเพย์โหลดไปยังตัวจัดการการแจ้งเตือน
from flask import Flask, request, jsonify
import hmac
import hashlib
import os
flask_app = Flask(__name__)
@flask_app.route('/webhook/github', methods=['POST'])
def github_webhook():
# Verify GitHub signature
signature = request.headers.get('X-Hub-Signature-256', '')
secret = os.environ['GITHUB_WEBHOOK_SECRET'].encode()
body = request.get_data()
expected = 'sha256=' + hmac.new(secret, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, expected):
return jsonify({'error': 'Invalid signature'}), 403
event_type = request.headers.get('X-GitHub-Event', '')
payload = request.json
handle_github_event(event_type, payload)
return jsonify({'status': 'ok'}), 200การกำหนดเส้นทางเหตุการณ์ไปยังช่องที่ถูกต้อง
เหตุการณ์แต่ละประเภทควรส่งไปยังช่องที่แตกต่างกัน กำหนดแผนที่เส้นทางดังนี้ เหตุการณ์ CI/CD ไปที่ #deployments ข้อผิดพลาดไปที่ #alerts และการตรวจสอบ PR ไปที่ #engineering จัดเก็บ ID ช่องไว้ในตัวแปรสภาพแวดล้อม เพื่อให้ปรับเปลี่ยนได้โดยไม่ต้องแก้ไขโค้ด
import os
# Channel routing configuration
CHANNEL_MAP = {
'deploy': os.environ.get('DEPLOY_CHANNEL', 'C0DEPLOY123'),
'error': os.environ.get('ERROR_CHANNEL', 'C0ERROR456'),
'pr_review': os.environ.get('PR_CHANNEL', 'C0PR789'),
'general': os.environ.get('GENERAL_CHANNEL', 'C0GENERAL'),
}
def route_github_event(event_type, payload):
if event_type == 'push':
branch = payload.get('ref', '').replace('refs/heads/', '')
if branch in ('main', 'master'):
return CHANNEL_MAP['deploy']
return CHANNEL_MAP['general']
elif event_type == 'pull_request':
return CHANNEL_MAP['pr_review']
elif event_type == 'workflow_run':
if payload.get('workflow_run', {}).get('conclusion') == 'failure':
return CHANNEL_MAP['error']
return CHANNEL_MAP['deploy']
return CHANNEL_MAP['general']
# --- demo ---
push_payload = {'ref': 'refs/heads/main'}
pr_payload = {}
wf_payload = {'workflow_run': {'conclusion': 'failure'}}
print('push to main ->', route_github_event('push', push_payload))
print('pull_request ->', route_github_event('pull_request', pr_payload))
print('failed workflow_run ->', route_github_event('workflow_run', wf_payload))
การจัดรูปแบบการแจ้งเตือนการปรับใช้
การแจ้งเตือนการปรับใช้ควรแสดงสิ่งที่นำไปใช้ ผู้ที่นำไปใช้ สภาพแวดล้อมที่นำไปใช้ และผลว่าสำเร็จหรือล้มเหลว ใช้บล็อกส่วนและบล็อกบริบทของ Block Kit เพื่อให้รูปแบบสะอาดตาและกวาดสายตาอ่านได้ง่าย
def build_deploy_blocks(repo, branch, commit_sha, deployer, status, env):
status_emoji = ':white_check_mark:' if status == 'success' else ':x:'
status_text = 'Success' if status == 'success' else 'Failed'
blocks = [
{
'type': 'header',
'text': {
'type': 'plain_text',
'text': f'{status_emoji} Deploy {status_text}: {repo}'
}
},
{
'type': 'section',
'fields': [
{'type': 'mrkdwn', 'text': f'*Repo:*\n{repo}'},
{'type': 'mrkdwn', 'text': f'*Environment:*\n{env}'},
{'type': 'mrkdwn', 'text': f'*Branch:*\n{branch}'},
{'type': 'mrkdwn', 'text': f'*Deployed by:*\n{deployer}'},
{'type': 'mrkdwn', 'text': f'*Commit:*\n`{commit_sha[:8]}`'}
]
}
]
return blocks
# --- demo ---
blocks = build_deploy_blocks('coddy-agents', 'main', 'a1b2c3d4e5f6', 'alice', 'success', 'production')
for b in blocks:
print(b)
การส่งสรุป DM ให้บุคคล
การแจ้งเตือนบางอย่างเหมาะที่จะส่งเป็นข้อความโดยตรงให้บุคคลที่เกี่ยวข้อง แทนการประกาศในช่อง ใช้ client.conversations_open(users=[user_id]) เพื่อเปิดช่อง DM จากนั้นโพสต์ไปยัง ID ช่องที่ส่งคืนมา
def send_dm(client, user_id, text, blocks=None):
# Open DM channel with the user
dm_result = client.conversations_open(users=[user_id])
dm_channel = dm_result['channel']['id']
# Post message to the DM channel
msg = {'channel': dm_channel, 'text': text}
if blocks:
msg['blocks'] = blocks
return client.chat_postMessage(**msg)
# Example: DM a developer when their PR build fails
def notify_pr_author_of_failure(client, pr_author_slack_id, pr_title, build_url):
blocks = [
{
'type': 'section',
'text': {
'type': 'mrkdwn',
'text': f'Your PR build failed: *{pr_title}*\n<{build_url}|View build logs>'
}
}
]
send_dm(client, pr_author_slack_id, f'Build failed: {pr_title}', blocks)
# --- demo: minimal stand-in for the Slack client ---
class _FakeClient:
def conversations_open(self, users):
return {'channel': {'id': f'D_{users[0]}'}}
def chat_postMessage(self, **kwargs):
print(f"[slack DM] to {kwargs['channel']}: {kwargs['text']}")
return {'ts': '1700000000.000200'}
notify_pr_author_of_failure(_FakeClient(), 'U_ALICE', 'Add retry logic to fetcher', 'https://ci.example.com/build/42')
การส่งข้อความตามกำหนดเวลา
ใช้ APScheduler เพื่อส่งรายงานตามกำหนดเวลา เช่น สรุปรายวัน สรุปรายสัปดาห์ หรือบทสรุปเช้าวันจันทร์ กำหนดเวลางานให้ทำงานในเวลาที่ระบุด้วยนิพจน์รูปแบบ cron ตัวจัดกำหนดการจะทำงานในเธรดเบื้องหลังควบคู่ไปกับตัวจัดการเหตุการณ์
from apscheduler.schedulers.background import BackgroundScheduler
from slack_sdk import WebClient
import os
client = WebClient(token=os.environ['SLACK_BOT_TOKEN'])
def send_daily_summary():
stats = fetch_daily_stats() # query your data source
blocks = [
{
'type': 'header',
'text': {'type': 'plain_text', 'text': 'Daily Team Summary'}
},
{
'type': 'section',
'text': {'type': 'mrkdwn',
'text': f'*PRs merged:* {stats["prs"]}\n'
f'*Deploys:* {stats["deploys"]}\n'
f'*Incidents:* {stats["incidents"]}'}
}
]
client.chat_postMessage(
channel=os.environ['DAILY_CHANNEL'],
text='Daily Team Summary',
blocks=blocks
)
scheduler = BackgroundScheduler()
scheduler.add_job(send_daily_summary, 'cron', hour=9, minute=0)
scheduler.start()
print('Scheduler started: daily summary at 9:00 AM')การรวบรวมการแจ้งเตือน — หลีกเลี่ยงความเหนื่อยล้าจากการแจ้งเตือน
การส่งข้อความ Slack สำหรับข้อผิดพลาดทุกครั้งจะทำให้เกิดความเหนื่อยล้าจากการแจ้งเตือนได้อย่างรวดเร็ว ให้รวบรวมการแจ้งเตือน โดยเก็บข้อผิดพลาดในช่วงเวลาหนึ่ง เช่น 5 นาที แล้วโพสต์ข้อความสรุปเพียงข้อความเดียว ใช้ตัวนับและล้างข้อมูลตามกำหนดเวลา
import threading
import time
from collections import defaultdict
class AlertAggregator:
def __init__(self, client, channel, flush_interval=300):
self.client = client
self.channel = channel
self.flush_interval = flush_interval
self.buffer = defaultdict(int) # error_type -> count
self.lock = threading.Lock()
self._start_flusher()
def add_alert(self, error_type):
with self.lock:
self.buffer[error_type] += 1
def _flush(self):
with self.lock:
if not self.buffer:
return
lines = [f'• {err}: {count}x' for err, count in self.buffer.items()]
self.buffer.clear()
self.client.chat_postMessage(
channel=self.channel,
text=f'Alert summary ({len(lines)} error types):\n' + '\n'.join(lines)
)
def _start_flusher(self):
def loop():
while True:
time.sleep(self.flush_interval)
self._flush()
threading.Thread(target=loop, daemon=True).start()
# --- demo (flush immediately instead of waiting flush_interval seconds) ---
class _FakeClient:
def chat_postMessage(self, **kwargs):
print(f"[slack] postMessage to {kwargs['channel']}: {kwargs['text']}")
agg = AlertAggregator(_FakeClient(), '#alerts', flush_interval=9999)
agg.add_alert('TimeoutError')
agg.add_alert('TimeoutError')
agg.add_alert('ConnectionError')
agg._flush() # normally the background thread does this every flush_interval seconds
การจัดรูปแบบบล็อกการแจ้งเตือนแบบครบถ้วน
การแจ้งเตือนต้องสื่อระดับความรุนแรงได้อย่างรวดเร็ว ใช้บริบทที่มีรหัสสี อีโมจิ และฟิลด์ที่มีโครงสร้าง เพิ่มปุ่มการกระทำที่เชื่อมโยงไปยังคู่มือแก้ไขปัญหาหรือแดชบอร์ดการแจ้งเตือน เพื่อให้วิศวกรเวรดูแลดำเนินการได้ทันทีจาก Slack
def build_incident_alert_blocks(service, error_rate, threshold,
runbook_url, pagerduty_url):
blocks = [
{
'type': 'header',
'text': {'type': 'plain_text', 'text': ':rotating_light: Incident Alert'}
},
{
'type': 'section',
'text': {
'type': 'mrkdwn',
'text': (
f'*Service:* `{service}`\n'
f'*Error Rate:* {error_rate:.1f}% (threshold: {threshold}%)\n'
f'*Status:* Investigating'
)
}
},
{
'type': 'actions',
'elements': [
{
'type': 'button',
'text': {'type': 'plain_text', 'text': 'View Runbook'},
'url': runbook_url,
'action_id': 'view_runbook'
},
{
'type': 'button',
'text': {'type': 'plain_text', 'text': 'PagerDuty'},
'url': pagerduty_url,
'style': 'danger',
'action_id': 'view_pagerduty'
}
]
}
]
return blocks
# --- demo ---
blocks = build_incident_alert_blocks('checkout-api', 12.4, 5.0,
'https://runbooks.example.com/checkout-api',
'https://pagerduty.example.com/incidents/1')
for b in blocks:
print(b)
การกล่าวถึงเวรดูแล
การแจ้งเตือนสำคัญควรกล่าวถึงวิศวกรเวรดูแลด้วยชื่อ ใช้การกล่าวถึงกลุ่มผู้ใช้ของ Slack (<!subteam^SUBTEAM_ID>) สำหรับกลุ่มเวรดูแล หรือค้นหาผู้ใช้เวรดูแลจาก PagerDuty/OpsGenie แล้วกล่าวถึงโดยตรงด้วย <@USER_ID>
import requests
import os
def get_oncall_slack_user():
# Query PagerDuty for current on-call
headers = {'Authorization': f'Token token={os.environ["PAGERDUTY_TOKEN"]}'}
r = requests.get(
'https://api.pagerduty.com/oncalls?include[]=users&limit=1',
headers=headers
)
oncalls = r.json().get('oncalls', [])
if not oncalls:
return None
email = oncalls[0]['user']['email']
return email
def send_oncall_alert(client, channel, alert_text):
oncall_email = get_oncall_slack_user()
if oncall_email:
# Look up Slack user by email
user_result = client.users_lookupByEmail(email=oncall_email)
user_id = user_result['user']['id']
mention = f'<@{user_id}>'
else:
mention = '<!channel>'
client.chat_postMessage(
channel=channel,
text=f'{mention} - CRITICAL ALERT: {alert_text}'
)การจัดข้อความเป็นเธรดสำหรับการแจ้งเตือนที่เกี่ยวข้อง
เมื่อมีการแจ้งเตือนหลายรายการที่เกี่ยวข้องกับเหตุการณ์เดียวกัน ให้โพสต์เป็นการตอบกลับในเธรดของข้อความแจ้งเตือนต้นฉบับ วิธีนี้ช่วยให้ช่องหลักดูสะอาด ขณะเดียวกันก็ยังเก็บประวัติการแจ้งเตือนทั้งหมดไว้ในเธรด จัดเก็บการประทับเวลาของข้อความต้นฉบับเพื่อใช้กับการติดตามผลในเธรด
class IncidentThread:
def __init__(self, client, channel):
self.client = client
self.channel = channel
self.active_incidents = {} # service_name -> thread_ts
def open_incident(self, service, initial_text, blocks=None):
msg = self.client.chat_postMessage(
channel=self.channel,
text=initial_text,
blocks=blocks
)
self.active_incidents[service] = msg['ts']
return msg['ts']
def update_incident(self, service, update_text):
thread_ts = self.active_incidents.get(service)
if thread_ts:
self.client.chat_postMessage(
channel=self.channel,
thread_ts=thread_ts,
text=update_text
)
else:
self.open_incident(service, f'[New] {update_text}')
def close_incident(self, service, resolution_text):
thread_ts = self.active_incidents.pop(service, None)
if thread_ts:
self.client.chat_postMessage(
channel=self.channel,
thread_ts=thread_ts,
text=f':white_check_mark: RESOLVED: {resolution_text}'
)
# --- demo: minimal stand-in for the Slack client ---
class _FakeClient:
def __init__(self):
self._counter = 0
def chat_postMessage(self, **kwargs):
self._counter += 1
ts = f'ts_{self._counter}'
print(f"[slack] {kwargs.get('text')} (thread_ts={kwargs.get('thread_ts')})")
return {'ts': ts}
thread = IncidentThread(_FakeClient(), '#incidents')
thread.open_incident('checkout-api', 'Checkout API error rate spiking')
thread.update_incident('checkout-api', 'Rolled back the last deploy')
thread.close_incident('checkout-api', 'Error rate back to normal')
การทดสอบบอตแจ้งเตือน
ทดสอบบอตแจ้งเตือนของคุณก่อนนำไปใช้งานจริง โดยส่งเว็บฮุกทดสอบด้วย requests.post() และตรวจสอบว่าข้อความปรากฏในช่อง #bot-testing เขียนสคริปต์ทดสอบที่จำลองเหตุการณ์แต่ละประเภทและตรวจสอบรูปแบบผลลัพธ์
import requests
import json
def test_webhook(webhook_url, event_type, payload):
response = requests.post(
webhook_url,
json=payload,
headers={'X-GitHub-Event': event_type, 'Content-Type': 'application/json'}
)
print(f'Webhook test {event_type}: {response.status_code}')
return response
# Test a deploy notification
test_webhook(
webhook_url='http://localhost:3000/webhook/github',
event_type='push',
payload={
'ref': 'refs/heads/main',
'pusher': {'name': 'alice'},
'repository': {'full_name': 'myorg/myapp'},
'head_commit': {'id': 'abc12345', 'message': 'Fix: auth bug'}
}
)
print('Check #bot-testing channel for the notification')ตรวจสอบความเข้าใจอย่างรวดเร็ว: ข้อความชั่วคราวเทียบกับข้อความในช่อง
ทดสอบความเข้าใจเกี่ยวกับการกำหนดเส้นทางการแจ้งเตือน
สรุปบอตแจ้งเตือนของทีม
ขณะนี้คุณสามารถสร้างบอตแจ้งเตือนของทีมได้ครบถ้วนแล้ว:
- ปลายทางเว็บฮุก: รับและตรวจสอบเหตุการณ์จากระบบภายนอก (ตรวจสอบลายเซ็น)
- การกำหนดเส้นทางไปยังช่อง: จับคู่ประเภทเหตุการณ์กับช่อง Slack ที่เหมาะสมผ่านพจนานุกรมการตั้งค่า
- การแจ้งเตือน Block Kit: ส่วนหัว + ช่องข้อมูล + ปุ่มการดำเนินการแบบมีโครงสร้าง พร้อมลิงก์คู่มือปฏิบัติงาน
- การส่งผ่าน DM:
conversations_open(users=[id])จากนั้นใช้chat_postMessageส่งไปยังช่อง DM - รายงานตามกำหนดเวลา: ใช้ APScheduler ร่วมกับนิพจน์กำหนดเวลาแบบ cron สำหรับสรุปรายวัน/รายสัปดาห์
- การรวมการแจ้งเตือน: บัฟเฟอร์ข้อผิดพลาดภายในช่วงเวลา แล้วส่งออกเป็นสรุปเดียว
- การจัดการเธรด: ส่งการแจ้งเตือนติดตามผลเข้าเธรดเพื่อให้ช่องหลักเป็นระเบียบ
เรียนรู้ AI Agents ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 60
- บทเรียน
- 239
คำถามที่พบบ่อย
บทเรียน “การสร้างบอตแจ้งเตือนทีม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสร้างบอตแจ้งเตือนทีม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสร้างบอตแจ้งเตือนทีม”
ข้อความตามกำหนดเวลา สรุป DM และตัวแทนแจ้งเตือนช่อง คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การสร้างบอตแจ้งเตือนทีม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน Slack Bolt SDK
- การรับฟังเหตุการณ์และคำสั่งแบบเฉือน
- การส่งข้อความและบล็อกแบบ Rich
- การสร้างบอตแจ้งเตือนทีม