일일 브리핑 에이전트 구축
뉴스 + 일정 + 이메일 요약을 아침마다 자동으로 전달하는 에이전트를 만듭니다.
일일 브리핑 에이전트 구축은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
일일 브리핑 에이전트란 무엇인가
일일 브리핑 에이전트는 매일 아침 정해진 시간에 실행되어 여러 출처(캘린더, 이메일, 뉴스)에서 정보를 모으고 LLM으로 종합한 다음 개인화된 요약을 전달합니다. 예약된 개인 에이전트의 대표적인 예입니다.
브리핑 아키텍처
브리핑 처리 흐름은 다섯 단계로 구성됩니다:
- 실행 조건: 오전 8시 cron 작업이 에이전트를 실행합니다
- 가져오기: 캘린더 이벤트, 읽지 않은 이메일, 뉴스 헤드라인을 병렬로 수집합니다
- 종합하기: LLM이 모든 데이터를 바탕으로 일관된 브리핑을 작성합니다
- 개인화하기: 사용자의 설정에 맞게 어조와 내용을 조정합니다
- 전달하기: 이메일이나 Slack DM으로 보냅니다
from dataclasses import dataclass, field
from typing import List, Dict, Any
@dataclass
class DailyBriefingData:
date: str
calendar_events: List[Dict] = field(default_factory=list)
unread_emails: List[Dict] = field(default_factory=list)
news_headlines: List[Dict] = field(default_factory=list)
weather: Dict = field(default_factory=dict)
briefing_text: str = ''
delivery_status: str = 'pending'
print('Daily briefing data structure defined')APScheduler를 사용한 예약
평일마다 오전 8시에 브리핑이 실행되도록 예약하십시오. SQLite 영속성을 사용하는 APScheduler를 사용하면 서버가 재시작되어도 작업이 유지됩니다.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.triggers.cron import CronTrigger
import asyncio
scheduler = BackgroundScheduler(
jobstores={'default': SQLAlchemyJobStore(url='sqlite:///jobs.db')},
timezone='America/New_York'
)
def run_briefing_job():
print('Daily briefing job triggered')
asyncio.run(generate_and_deliver_briefing('user-42'))
# 8am Monday-Friday
scheduler.add_job(
run_briefing_job,
CronTrigger(day_of_week='mon-fri', hour=8, minute=0),
id='daily_briefing_user_42',
replace_existing=True
)
scheduler.start()
print('Briefing scheduler started: runs Mon-Fri at 8am ET')캘린더 이벤트 가져오기
Google Calendar API를 사용하여 오늘의 캘린더 이벤트를 가져오십시오. 브리핑에 포함할 예정된 회의를 파악하려면 에이전트가 어떤 회의가 예약되어 있는지 알아야 합니다.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from datetime import datetime, timedelta
import pytz
def get_todays_calendar_events(token_path: str = 'token.json', timezone: str = 'America/New_York') -> list:
creds = Credentials.from_authorized_user_file(token_path)
service = build('calendar', 'v3', credentials=creds)
tz = pytz.timezone(timezone)
now = datetime.now(tz)
start_of_day = now.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = now.replace(hour=23, minute=59, second=59)
result = service.events().list(
calendarId='primary',
timeMin=start_of_day.isoformat(),
timeMax=end_of_day.isoformat(),
singleEvents=True,
orderBy='startTime'
).execute()
events = []
for item in result.get('items', []):
start = item.get('start', {}).get('dateTime', item.get('start', {}).get('date'))
events.append({
'title': item.get('summary', 'Untitled'),
'start': start,
'attendees': len(item.get('attendees', [])),
'location': item.get('location', '')
})
return events읽지 않은 이메일 가져오기
가장 최근의 읽지 않은 이메일을 가져오십시오. 브리핑 에이전트에는 LLM 컨텍스트를 관리하기 쉽도록 전체 본문이 아니라 제목과 발신자 같은 요약만 필요합니다.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
import base64
def get_email_summaries(token_path: str = 'token.json', max_results: int = 10) -> list:
creds = Credentials.from_authorized_user_file(token_path)
service = build('gmail', 'v1', credentials=creds)
results = service.users().messages().list(
userId='me',
q='is:unread newer_than:1d',
maxResults=max_results
).execute()
summaries = []
for msg in results.get('messages', []):
detail = service.users().messages().get(
userId='me',
id=msg['id'],
format='metadata',
metadataHeaders=['From', 'Subject', 'Date']
).execute()
headers = {h['name']: h['value'] for h in detail['payload']['headers']}
summaries.append({
'from': headers.get('From', ''),
'subject': headers.get('Subject', 'No Subject'),
'date': headers.get('Date', '')
})
return summaries뉴스 헤드라인 가져오기
뉴스 API를 사용하여 관련 뉴스 헤드라인을 가져오십시오. 개인화된 뉴스 섹션을 만들 수 있도록 사용자가 설정한 관심 주제로 필터링하십시오.
import httpx
import os
NEWS_API_KEY = os.environ.get('NEWS_API_KEY', 'your-key')
async def get_news_headlines(topics: list, max_per_topic: int = 3) -> list:
headlines = []
async with httpx.AsyncClient() as client:
for topic in topics:
try:
response = await client.get(
'https://newsapi.org/v2/top-headlines',
params={
'q': topic,
'language': 'en',
'pageSize': max_per_topic,
'apiKey': NEWS_API_KEY
},
timeout=10.0
)
data = response.json()
for article in data.get('articles', []):
headlines.append({
'topic': topic,
'title': article.get('title', ''),
'source': article.get('source', {}).get('name', ''),
'url': article.get('url', '')
})
except Exception as e:
print(f'News fetch failed for {topic}: {e}')
return headlines[:10] # Cap total데이터 병렬 가져오기
캘린더 이벤트, 이메일, 뉴스, 날씨를 모두 동시에 가져오십시오. 서로 독립적이므로 병렬로 가져오면 전체 가져오기 시간이 약 4초에서 약 1초로 줄어듭니다.
import asyncio
from datetime import datetime
async def fetch_all_briefing_data(user_prefs: dict) -> 'DailyBriefingData':
data = DailyBriefingData(date=datetime.now().strftime('%A, %B %d, %Y'))
async def safe_get_calendar():
try:
return get_todays_calendar_events()
except Exception as e:
print(f'Calendar fetch failed: {e}')
return []
async def safe_get_emails():
try:
return get_email_summaries()
except Exception as e:
print(f'Email fetch failed: {e}')
return []
async def safe_get_news():
topics = user_prefs.get('news_topics', ['technology', 'business'])
return await get_news_headlines(topics)
# Run all fetches in parallel
calendar_events, emails, news = await asyncio.gather(
safe_get_calendar(),
safe_get_emails(),
safe_get_news(),
return_exceptions=False
)
data.calendar_events = calendar_events
data.unread_emails = emails
data.news_headlines = news
return dataLLM 종합
가져온 모든 데이터를 LLM에 전달하고 자연스럽고 개인화된 브리핑을 작성하도록 요청하십시오. 프롬프트 구조가 중요합니다. LLM이 잘 구성된 요약을 만들 수 있도록 데이터를 명확하게 정리하십시오.
import openai
import json
client = openai.OpenAI(api_key='sk-...')
def synthesize_briefing(data: 'DailyBriefingData', user_prefs: dict) -> str:
user_name = user_prefs.get('name', 'there')
tone = user_prefs.get('briefing_tone', 'professional') # 'casual', 'professional', 'concise'
calendar_text = json.dumps(data.calendar_events[:5], indent=2) if data.calendar_events else 'No meetings today.'
email_text = json.dumps(data.unread_emails[:5], indent=2) if data.unread_emails else 'No unread emails.'
news_text = '\n'.join([f'- [{h["topic"]}] {h["title"]} ({h["source"]})' for h in data.news_headlines[:6]])
prompt = (
f'Create a {tone} morning briefing for {user_name} for {data.date}.\n\n'
f'Today\'s calendar:\n{calendar_text}\n\n'
f'Unread emails:\n{email_text}\n\n'
f'News headlines:\n{news_text}\n\n'
'Write a concise, actionable briefing in 3-4 paragraphs. '
'Start with today\'s schedule, then email highlights, then relevant news. '
'End with one suggested priority for the day.'
)
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}],
temperature=0.3
)
return response.choices[0].message.content이메일로 전달하기
브리핑을 HTML 이메일 형식으로 구성하여 보내십시오. HTML 이메일 형식을 잘 구성하면 대부분의 사람이 아침 요약을 읽는 모바일 기기에서도 브리핑을 쉽게 읽을 수 있습니다.
def format_briefing_email(briefing_text: str, data: 'DailyBriefingData') -> str:
paragraphs = briefing_text.split('\n\n')
html_paragraphs = ''.join([f'<p>{p}</p>' for p in paragraphs if p.strip()])
calendar_items = ''.join([
f'<li><strong>{e["start"][:16]}</strong> - {e["title"]}</li>'
for e in data.calendar_events[:5]
])
return f'''
<html><body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #333;">Morning Briefing — {data.date}</h2>
{html_paragraphs}
{'<h3>Today\'s Calendar</h3><ul>' + calendar_items + '</ul>' if calendar_items else ''}
<hr>
<p style="color: #666; font-size: 12px;">Generated by your Personal AI Assistant</p>
</body></html>
'''
def deliver_briefing_email(data: 'DailyBriefingData', user_prefs: dict):
html = format_briefing_email(data.briefing_text, data)
to_email = user_prefs.get('email', '')
send_email_alert(
to_email=to_email,
subject=f'Morning Briefing - {data.date}',
html_body=html
)
print('Email delivery function defined')Slack DM으로 전달하기
Slack을 주로 사용하는 사용자라면 브리핑을 형식이 지정된 Slack DM으로 전달하는 방식을 이메일보다 선호하는 경우가 많습니다. 풍부한 형식을 사용하려면 Block Kit을 사용하십시오.
from slack_sdk import WebClient
import os
slack_client = WebClient(token=os.environ.get('SLACK_BOT_TOKEN', 'xoxb-...'))
def deliver_briefing_slack(data: 'DailyBriefingData', user_prefs: dict):
slack_user_id = user_prefs.get('slack_user_id')
if not slack_user_id:
print('No Slack user ID configured')
return
# Split briefing into sections for blocks
paragraphs = [p for p in data.briefing_text.split('\n\n') if p.strip()]
blocks = [
{'type': 'header', 'text': {'type': 'plain_text', 'text': f'Morning Briefing - {data.date}'}},
{'type': 'divider'}
]
for para in paragraphs[:4]: # Max 4 paragraphs
blocks.append({
'type': 'section',
'text': {'type': 'mrkdwn', 'text': para}
})
if data.calendar_events:
event_list = '\n'.join([f'• {e["start"][:16]} - {e["title"]}' for e in data.calendar_events[:3]])
blocks.append({'type': 'section', 'text': {'type': 'mrkdwn', 'text': f'*Meetings*\n{event_list}'}})
slack_client.chat_postMessage(
channel=slack_user_id,
text=f'Morning Briefing - {data.date}',
blocks=blocks
)
print(f'Briefing delivered to Slack user {slack_user_id}')주요 브리핑 조정기
조정기는 모든 단계를 연결합니다. 데이터를 병렬로 가져오고, LLM으로 종합하며, 선호하는 채널로 전달하고, 모니터링을 위해 결과를 기록합니다.
import asyncio
from datetime import datetime
async def generate_and_deliver_briefing(user_id: str):
print(f'Generating briefing for {user_id} at {datetime.now()}')
# Load user preferences
conn = init_db()
user_prefs = load_user_preferences(conn, user_id)
# Step 1: Fetch all data in parallel
data = await fetch_all_briefing_data(user_prefs)
if not data.calendar_events and not data.unread_emails and not data.news_headlines:
print('No data fetched, skipping briefing')
return
# Step 2: Synthesize with LLM
data.briefing_text = synthesize_briefing(data, user_prefs)
# Step 3: Deliver
delivery_channel = user_prefs.get('delivery_channel', 'email')
if delivery_channel == 'slack':
deliver_briefing_slack(data, user_prefs)
else:
deliver_briefing_email(data, user_prefs)
data.delivery_status = 'delivered'
# Step 4: Log
print(f'Briefing delivered via {delivery_channel}')
print(f'Data: {len(data.calendar_events)} events, {len(data.unread_emails)} emails, {len(data.news_headlines)} headlines')
print('Daily briefing orchestrator defined')이해도 확인: 일일 브리핑 에이전트
일일 브리핑 에이전트를 구축하는 방법을 얼마나 이해했는지 확인해 보십시오.
일일 브리핑 에이전트 요약
완전한 일일 브리핑 에이전트는 평일 오전 8시 cron 실행을 위한 APScheduler, 캘린더·이메일·뉴스 API에서 데이터를 병렬로 가져오는 기능, 개인화되고 일관된 브리핑을 만드는 LLM 종합, 사용자 설정에 따른 개인화, 이메일이나 Slack DM을 통한 다중 채널 전달을 결합합니다. 이는 이 과정의 모든 개념을 보여 주는 대표적인 항상 실행되는 개인 에이전트 패턴입니다.
AI 튜터와 함께 AI Agents을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 60
- 레슨
- 239
자주 묻는 질문
“일일 브리핑 에이전트 구축” 강의는 무료인가요?
네 — “일일 브리핑 에이전트 구축” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.
“일일 브리핑 에이전트 구축”에서 뭘 배우나요?
뉴스 + 일정 + 이메일 요약을 아침마다 자동으로 전달하는 에이전트를 만듭니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Agents을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“일일 브리핑 에이전트 구축” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 상시 실행 에이전트 설계 패턴
- 선제적 알림 및 경고 시스템
- 세션 간 맥락 유지
- 일일 브리핑 에이전트 구축