0Pricing
AI Agents · บทเรียน

ระบบการแจ้งเตือนและการเตือนเชิงรุก

เอเจนต์ที่นำเสนอข้อมูลสำคัญโดยไม่ต้องรอให้ผู้ใช้ร้องขอ

ระบบการแจ้งเตือนและการเตือนเชิงรุก เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

เอเจนต์เชิงรุกกับเอเจนต์เชิงรับ

เอเจนต์ส่วนใหญ่เป็นเอเจนต์เชิงรับ ซึ่งตอบสนองต่อคำขอ ส่วนเอเจนต์เชิงรุกจะตรวจติดตามเงื่อนไขและติดต่อผู้ใช้เมื่อเกิดสิ่งที่น่าสนใจ โดยไม่ต้องรอให้ผู้ใช้ร้องขอ ลักษณะนี้คล้ายการมีผู้ช่วยส่วนตัวมากกว่า

ลูปตรวจสอบเบื้องหลัง

รูปแบบเอเจนต์เชิงรุกที่ง่ายที่สุดคือลูปเบื้องหลังที่ตรวจสอบทุก ๆ N นาที และส่งการแจ้งเตือนเมื่อเงื่อนไขเป็นจริง ใช้ Thread หรือลูปแบบอะซิงก์เพื่อหลีกเลี่ยงการบล็อกการทำงาน

import asyncio
import httpx
from datetime import datetime

async def poll_price(ticker: str, alert_threshold: float) -> None:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f'https://api.finance.example.com/quote/{ticker}',
            headers={'Authorization': 'Bearer your-api-key'}
        )
        data = response.json()
        price = float(data.get('price', 0))
        
        if price < alert_threshold:
            await send_push_notification(
                title=f'{ticker} Price Alert',
                message=f'{ticker} is now ${price:.2f}, below your threshold of ${alert_threshold:.2f}'
            )

async def price_alert_loop(ticker: str, threshold: float, interval_seconds: int = 300):
    print(f'Monitoring {ticker} every {interval_seconds}s, alert below ${threshold}')
    while True:
        try:
            await poll_price(ticker, threshold)
        except Exception as e:
            print(f'Polling error: {e}')
        await asyncio.sleep(interval_seconds)

print('Price alert loop defined')

การแจ้งเตือนตามค่าเกณฑ์

การแจ้งเตือนตามค่าเกณฑ์จะทำงานเมื่อค่าตัวชี้วัดข้ามขอบเขตที่กำหนด ค่าเกณฑ์ที่ดีอาจเป็น ค่าสัมบูรณ์ (ราคา < $100) การเปลี่ยนแปลงเป็นเปอร์เซ็นต์ (ลดลง > 5%) หรือการเปรียบเทียบกับค่าเฉลี่ยในอดีต

from dataclasses import dataclass
from typing import Optional, Callable

@dataclass
class AlertRule:
    name: str
    check_fn: Callable  # Returns a float value
    condition: str      # 'lt', 'gt', 'lte', 'gte'
    threshold: float
    cooldown_minutes: int = 60  # Don't re-alert for this long
    last_alerted: Optional[float] = None

def evaluate_rule(rule: AlertRule) -> Optional[str]:
    import time
    
    # Respect cooldown
    if rule.last_alerted:
        elapsed = time.time() - rule.last_alerted
        if elapsed < rule.cooldown_minutes * 60:
            return None
    
    current_value = rule.check_fn()
    
    triggered = (
        (rule.condition == 'lt' and current_value < rule.threshold) or
        (rule.condition == 'gt' and current_value > rule.threshold) or
        (rule.condition == 'lte' and current_value <= rule.threshold) or
        (rule.condition == 'gte' and current_value >= rule.threshold)
    )
    
    if triggered:
        rule.last_alerted = time.time()
        return f'Alert: {rule.name} = {current_value:.2f} ({rule.condition} {rule.threshold})'
    return None

# Example rule
rule = AlertRule(
    name='CPU Usage',
    check_fn=lambda: 85.0,  # In reality: psutil.cpu_percent()
    condition='gt',
    threshold=80.0,
    cooldown_minutes=30
)
print(evaluate_rule(rule))

เกณฑ์จับคู่อีเมลใหม่

เอเจนต์อีเมลเชิงรุกจะตรวจสอบกล่องจดหมายและแจ้งเตือนเมื่อมีข้อความที่ตรงตามเกณฑ์เฉพาะเข้ามา เช่น มาจากผู้ส่งที่เป็น VIP มีคำสำคัญ หรือมีเครื่องหมายระบุความสำคัญสูง

from dataclasses import dataclass
from typing import List
import re

@dataclass
class EmailAlertCriteria:
    from_domains: List[str] = None
    from_emails: List[str] = None
    subject_keywords: List[str] = None
    body_keywords: List[str] = None
    min_importance: str = None  # 'high', 'medium'

def matches_criteria(email: dict, criteria: EmailAlertCriteria) -> bool:
    sender = email.get('from', '').lower()
    subject = email.get('subject', '').lower()
    body = email.get('body', '').lower()
    
    if criteria.from_domains:
        domain_match = any(domain.lower() in sender for domain in criteria.from_domains)
        if not domain_match:
            return False
    
    if criteria.from_emails:
        email_match = any(e.lower() in sender for e in criteria.from_emails)
        if not email_match:
            return False
    
    if criteria.subject_keywords:
        keyword_match = any(kw.lower() in subject for kw in criteria.subject_keywords)
        if not keyword_match:
            return False
    
    return True

criteria = EmailAlertCriteria(
    from_domains=['@important-client.com', '@boss.company.com'],
    subject_keywords=['urgent', 'action required', 'ASAP']
)

email = {'from': 'john@important-client.com', 'subject': 'Urgent: Contract Issue'}
print('Matches:', matches_criteria(email, criteria))

การแจ้งเตือนด้วย Pushover

Pushover ส่งการแจ้งเตือนแบบพุชไปยัง iOS และ Android โดยมี REST API ที่เรียบง่ายและมีแพ็กเกจใช้งานฟรี เหมาะอย่างยิ่งสำหรับเอเจนต์ส่วนตัวที่ต้องแจ้งเตือนผู้ใช้เพียงคนเดียว

import httpx
import os

PUSHOVER_TOKEN = os.environ.get('PUSHOVER_APP_TOKEN', 'your-app-token')
PUSHOVER_USER = os.environ.get('PUSHOVER_USER_KEY', 'your-user-key')

async def send_pushover(title: str, message: str, priority: int = 0, url: str = None) -> bool:
    '''
    priority: -2 (lowest) to 2 (emergency with acknowledgment)
    0 = normal, 1 = high priority (bypass quiet hours)
    '''
    async with httpx.AsyncClient() as client:
        data = {
            'token': PUSHOVER_TOKEN,
            'user': PUSHOVER_USER,
            'title': title,
            'message': message,
            'priority': priority
        }
        if url:
            data['url'] = url
        
        response = await client.post('https://api.pushover.net/1/messages.json', data=data)
        result = response.json()
        
        if result.get('status') == 1:
            print(f'Push sent: {title}')
            return True
        else:
            print(f'Push failed: {result.get("errors")}')
            return False

async def send_push_notification(title: str, message: str):
    await send_pushover(title, message)

การแจ้งเตือนทาง Slack DM

ส่งการแจ้งเตือนเชิงรุกเป็นข้อความส่วนตัวทาง Slack ซึ่งต่างจากข้อความในช่องสนทนา DM ช่วยให้ผู้ใช้ได้รับการแจ้งเตือนแม้ไม่ได้อยู่ในช่องสนทนาใดช่องสนทนาหนึ่ง

from slack_sdk import WebClient
import os

slack_client = WebClient(token=os.environ.get('SLACK_BOT_TOKEN', 'xoxb-...'))

def send_slack_dm(user_id: str, title: str, message: str, urgency: str = 'normal') -> bool:
    # Build blocks for rich formatting
    blocks = [
        {
            'type': 'section',
            'text': {
                'type': 'mrkdwn',
                'text': f'*{title}*\n{message}'
            }
        }
    ]
    
    if urgency == 'high':
        # Add urgent emoji prefix
        blocks[0]['text']['text'] = '🚨 ' + blocks[0]['text']['text']
    
    try:
        response = slack_client.chat_postMessage(
            channel=user_id,  # DM: channel = user_id
            text=f'{title}: {message}',  # Fallback text
            blocks=blocks
        )
        return True
    except Exception as e:
        print(f'Slack DM failed: {e}')
        return False

print('Slack DM function defined')
print('Usage: send_slack_dm("U0123ABCD", "Price Alert", "AAPL dropped below $150")')

การแจ้งเตือนทางอีเมล

อีเมลเหมาะสำหรับการแจ้งเตือนที่ไม่เร่งด่วน ให้ใช้ smtplib ของ Python หรือ API ของ SendGrid เพื่อส่งอีเมลจากเอเจนต์ด้วยโปรแกรม

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os

def send_email_alert(to_email: str, subject: str, html_body: str) -> bool:
    smtp_host = os.environ.get('SMTP_HOST', 'smtp.gmail.com')
    smtp_port = int(os.environ.get('SMTP_PORT', '587'))
    smtp_user = os.environ.get('SMTP_USER', '')
    smtp_pass = os.environ.get('SMTP_PASS', '')
    
    try:
        msg = MIMEMultipart('alternative')
        msg['Subject'] = subject
        msg['From'] = smtp_user
        msg['To'] = to_email
        
        html_part = MIMEText(html_body, 'html')
        msg.attach(html_part)
        
        with smtplib.SMTP(smtp_host, smtp_port) as server:
            server.starttls()
            server.login(smtp_user, smtp_pass)
            server.sendmail(smtp_user, to_email, msg.as_string())
        
        print(f'Email sent to {to_email}: {subject}')
        return True
    except Exception as e:
        print(f'Email failed: {e}')
        return False

html = '<p>Your agent detected a price drop: <strong>AAPL is now $147.50</strong></p>'
print('Email alert function defined')

ตัวกำหนดเส้นทางการแจ้งเตือนหลายช่องทาง

กำหนดเส้นทางการแจ้งเตือนไปยังช่องทางที่เหมาะสมตามระดับความเร่งด่วน การแจ้งเตือนวิกฤตให้ส่งเป็นการแจ้งเตือนแบบพุช การแจ้งเตือนเพื่อให้ข้อมูลให้ส่งทางอีเมล และสรุปประจำวันให้ส่งทาง Slack DM

import asyncio
from enum import Enum

class AlertLevel(Enum):
    INFO = 'info'        # Email/Daily summary
    WARNING = 'warning'  # Slack DM
    CRITICAL = 'critical'  # Push notification immediately

async def route_alert(title: str, message: str, level: AlertLevel, user_config: dict):
    user_id = user_config.get('user_id')
    email = user_config.get('email')
    push_enabled = user_config.get('push_enabled', True)
    
    if level == AlertLevel.CRITICAL and push_enabled:
        success = await send_pushover(title, message, priority=1)
        if not success:
            # Fallback to Slack DM
            slack_user = user_config.get('slack_user_id')
            if slack_user:
                send_slack_dm(slack_user, title, message, urgency='high')
    
    elif level == AlertLevel.WARNING:
        slack_user = user_config.get('slack_user_id')
        if slack_user:
            send_slack_dm(slack_user, title, message)
    
    else:  # INFO
        if email:
            send_email_alert(email, title, f'<p>{message}</p>')

user_config = {
    'user_id': 'user-42',
    'email': 'user@example.com',
    'slack_user_id': 'U0123ABCD',
    'push_enabled': True
}

asyncio.run(route_alert('Price Alert', 'AAPL dropped to $147', AlertLevel.WARNING, user_config))

การกำจัดการแจ้งเตือนซ้ำและช่วงพัก

หากไม่กำจัดการแจ้งเตือนซ้ำ เงื่อนไขที่คงอยู่เป็นเวลาหลายชั่วโมงจะส่งการแจ้งเตือนหลายร้อยครั้ง ช่วงพักจะป้องกันการแจ้งเตือนซ้ำสำหรับเงื่อนไขเดิมภายในช่วงเวลาที่กำหนด

import time
import redis
import json

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

def should_send_alert(alert_key: str, cooldown_seconds: int = 3600) -> bool:
    redis_key = f'alert:cooldown:{alert_key}'
    if r.exists(redis_key):
        ttl = r.ttl(redis_key)
        print(f'Alert {alert_key} on cooldown. {ttl}s remaining')
        return False
    return True

def record_alert_sent(alert_key: str, cooldown_seconds: int = 3600):
    redis_key = f'alert:cooldown:{alert_key}'
    r.setex(redis_key, cooldown_seconds, '1')

def maybe_send_alert(alert_type: str, metric_value: float, user_id: str, cooldown_hours: int = 1):
    # Create unique key per alert type per user
    alert_key = f'{user_id}:{alert_type}'
    
    if not should_send_alert(alert_key, cooldown_seconds=cooldown_hours * 3600):
        return False
    
    # Send the alert
    print(f'Sending alert: {alert_type} = {metric_value} for user {user_id}')
    record_alert_sent(alert_key, cooldown_seconds=cooldown_hours * 3600)
    return True

maybe_send_alert('price_drop_AAPL', 147.50, 'user-42')
maybe_send_alert('price_drop_AAPL', 146.00, 'user-42')  # Blocked by cooldown

การกรองตามการตั้งค่าของผู้ใช้

ผู้ใช้แต่ละคนไม่ได้ต้องการการแจ้งเตือนทุกประเภท ให้จัดเก็บการตั้งค่าของผู้ใช้ว่าต้องการการแจ้งเตือนประเภทใด ที่ค่าเกณฑ์เท่าใด และผ่านช่องทางใด จากนั้นเอเจนต์จะตรวจสอบการตั้งค่าก่อนส่งการแจ้งเตือน

from dataclasses import dataclass, field
from typing import Dict, List

@dataclass
class UserAlertPreferences:
    user_id: str
    enabled_channels: List[str] = field(default_factory=lambda: ['push'])
    alert_rules: Dict[str, dict] = field(default_factory=dict)
    quiet_hours_start: int = 22  # 10pm
    quiet_hours_end: int = 8    # 8am

def is_quiet_hours(prefs: UserAlertPreferences) -> bool:
    from datetime import datetime
    hour = datetime.now().hour
    start = prefs.quiet_hours_start
    end = prefs.quiet_hours_end
    if start > end:  # Spans midnight
        return hour >= start or hour < end
    return start <= hour < end

def should_alert_user(prefs: UserAlertPreferences, alert_type: str, value: float) -> bool:
    rule = prefs.alert_rules.get(alert_type)
    if not rule:
        return False  # User hasn't set up this alert type
    
    threshold = rule.get('threshold')
    condition = rule.get('condition', 'lt')
    urgent = rule.get('urgent', False)
    
    if is_quiet_hours(prefs) and not urgent:
        print(f'Suppressing non-urgent alert during quiet hours')
        return False
    
    return (
        (condition == 'lt' and value < threshold) or
        (condition == 'gt' and value > threshold)
    )

prefs = UserAlertPreferences(
    user_id='user-42',
    alert_rules={'price_drop': {'threshold': 150.0, 'condition': 'lt'}}
)
print('Should alert:', should_alert_user(prefs, 'price_drop', 147.50))

การรวบรวมการแจ้งเตือนเป็นสรุป

แทนที่จะส่งการแจ้งเตือนแยกกันสำหรับแต่ละเหตุการณ์ ให้รวบรวมเหตุการณ์เหล่านั้นแล้วส่งเป็นสรุป วิธีนี้ช่วยลดความเหนื่อยล้าจากการแจ้งเตือนสำหรับผู้ใช้ที่มีเงื่อนไขจำนวนมากที่ต้องติดตาม

import redis
import json
from datetime import datetime

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

def add_to_digest(user_id: str, alert: dict):
    key = f'digest:{user_id}:{datetime.now().strftime("%Y%m%d")}'
    r.rpush(key, json.dumps(alert))
    r.expire(key, 86400 * 2)  # Keep for 2 days

def send_and_clear_digest(user_id: str) -> int:
    key = f'digest:{user_id}:{datetime.now().strftime("%Y%m%d")}'
    raw_alerts = r.lrange(key, 0, -1)
    if not raw_alerts:
        print(f'No alerts for user {user_id} today')
        return 0
    
    alerts = [json.loads(a) for a in raw_alerts]
    digest_text = f'Daily Digest ({len(alerts)} alerts):\n'
    digest_text += '\n'.join([f'- {a["title"]}: {a["message"]}' for a in alerts])
    
    # Send as single notification
    print(f'Sending digest to {user_id}:\n{digest_text}')
    # send_email_alert(user_email, 'Daily Alert Digest', digest_text)
    
    r.delete(key)
    return len(alerts)

add_to_digest('user-42', {'title': 'AAPL Alert', 'message': 'Price at $147.50'})
add_to_digest('user-42', {'title': 'GOOG Alert', 'message': 'Price at $175.00'})
send_and_clear_digest('user-42')

ตรวจสอบความรู้: การแจ้งเตือนเชิงรุก

ทดสอบความเข้าใจเกี่ยวกับระบบการแจ้งเตือนและการแจ้งเตือนเชิงรุก

สรุปการแจ้งเตือนเชิงรุก

เอเจนต์เชิงรุกใช้ลูปตรวจสอบเบื้องหลังเพื่อติดตามเงื่อนไขและส่งการแจ้งเตือนผ่านการแจ้งเตือนแบบพุช (Pushover), Slack DM หรืออีเมล องค์ประกอบสำคัญของการออกแบบ ได้แก่ กฎตามค่าเกณฑ์พร้อมช่วงพักเพื่อป้องกันความเหนื่อยล้าจากการแจ้งเตือน การกรองตามการตั้งค่าของผู้ใช้เพื่อปรับให้เหมาะกับแต่ละบุคคล การกำหนดเส้นทางหลายช่องทางตามระดับความเร่งด่วน การรองรับช่วงเวลางดแจ้งเตือน และสรุปประจำวันสำหรับการแจ้งเตือนที่มีความสำคัญต่ำซึ่งสะสมไว้

คำถามที่พบบ่อย

บทเรียน “ระบบการแจ้งเตือนและการเตือนเชิงรุก” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ระบบการแจ้งเตือนและการเตือนเชิงรุก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ระบบการแจ้งเตือนและการเตือนเชิงรุก”

เอเจนต์ที่นำเสนอข้อมูลสำคัญโดยไม่ต้องรอให้ผู้ใช้ร้องขอ คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ระบบการแจ้งเตือนและการเตือนเชิงรุก” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. รูปแบบการออกแบบเอเจนต์ที่ทำงานตลอดเวลา
  2. ระบบการแจ้งเตือนและการเตือนเชิงรุก
  3. การคงอยู่ของบริบทข้ามเซสชัน
  4. การสร้างเอเจนต์สรุปข้อมูลประจำวัน
← กลับไปที่ AI Agents