การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย
ครบทุกขั้นตอน: อ่านกล่องจดหมาย → สรุป → ร่างคำตอบ → รอการอนุมัติ
การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
สถาปัตยกรรมเอเจนต์ผู้ช่วยอีเมล
เอเจนต์ผู้ช่วยอีเมลใช้กระบวนการมาตรฐาน: ดึงข้อมูล → จัดหมวดหมู่ → ตัดสินใจ → ร่าง → อนุมัติ → ส่ง เอเจนต์จะอ่านอีเมลที่ยังไม่ได้อ่าน ใช้ LLM เพื่อจัดหมวดหมู่และร่างคำตอบ จากนั้นรอการอนุมัติจากมนุษย์ก่อนส่ง การออกแบบที่มีมนุษย์ร่วมตรวจสอบนี้ช่วยป้องกันข้อผิดพลาดที่มีค่าใช้จ่ายสูงจากการส่งอีเมลโดยอัตโนมัติทั้งหมด
# Email Assistant Pipeline:
#
# 1. FETCH: Pull unread emails from Gmail API
# 2. CLASSIFY: LLM labels each email
# - 'action_needed': requires a reply
# - 'fyi': informational, no reply needed
# - 'spam': should be archived
# 3. DRAFT: LLM generates reply for 'action_needed' emails
# 4. APPROVE: Human reviews drafts in Gmail UI
# 5. SEND: Agent sends approved drafts
#
# Tools: Gmail API, Anthropic/OpenAI API, json, base64
print('Email assistant pipeline: fetch -> classify -> draft -> approve -> send')การกำหนดเครื่องมือของเอเจนต์
วางโครงสร้างเอเจนต์ด้วยคำจำกัดความของเครื่องมือที่ชัดเจน เครื่องมือแต่ละรายการเป็นฟังก์ชัน Python ที่มีหน้าที่เฉพาะ การแบ่งเป็นส่วนย่อยเช่นนี้ทำให้เอเจนต์สามารถทดสอบ แก้ไขข้อบกพร่อง และขยายความสามารถใหม่ได้ง่าย
class EmailAssistantTools:
def __init__(self, gmail_service, llm_client):
self.gmail = gmail_service
self.llm = llm_client
def fetch_unread(self, max_emails=10):
'''Fetch unread emails from inbox.'''
pass
def classify_email(self, subject, body, sender):
'''Ask LLM to classify: action_needed / fyi / spam.'''
pass
def draft_reply(self, subject, body, sender, context):
'''Ask LLM to draft a reply to an email.'''
pass
def create_draft(self, message_id, reply_text):
'''Save draft reply in Gmail for human review.'''
pass
def send_approved_drafts(self):
'''Send all drafts marked as approved.'''
pass
print('Tool-based architecture enables testing each step independently')ขั้นตอนที่ 1: การดึงข้อมูลและแยกวิเคราะห์อีเมล
เครื่องมือแรกจะดึงอีเมลที่ยังไม่ได้อ่านและแยกฟิลด์สำคัญที่ LLM ต้องใช้ ได้แก่ หัวเรื่อง ผู้ส่ง และเนื้อหาข้อความล้วน ควรทำให้เนื้อหาสั้น โดยตัดให้เหลือ 2,000 อักขระแรก เพื่อให้อยู่ภายในขีดจำกัดบริบทของ LLM และลดค่าใช้จ่าย API
import base64
def fetch_emails_for_classification(gmail_service, max_emails=10):
messages_list = gmail_service.users().messages().list(
userId='me',
q='is:unread label:inbox',
maxResults=max_emails
).execute().get('messages', [])
emails = []
for ref in messages_list:
msg = gmail_service.users().messages().get(
userId='me', id=ref['id'], format='full'
).execute()
headers = {h['name'].lower(): h['value']
for h in msg['payload'].get('headers', [])}
body = extract_plain_text_body(msg)[:2000] # trim for LLM
emails.append({
'id': msg['id'],
'thread_id': msg['threadId'],
'from': headers.get('from', ''),
'subject': headers.get('subject', '(no subject)'),
'body': body
})
print(f'Fetched {len(emails)} unread emails')
return emailsขั้นตอนที่ 2: การจัดหมวดหมู่ด้วย LLM
ส่งอีเมลแต่ละฉบับไปยัง LLM เพื่อจัดหมวดหมู่ ใช้พรอมต์ที่มีโครงสร้างและขอให้โมเดลส่งคืนออบเจ็กต์ JSON ที่มีหมวดหมู่และเหตุผล ระบุคำขอเอาต์พุตเป็น JSON อย่างชัดเจน เพราะเชื่อถือได้มากกว่าการแยกวิเคราะห์ข้อความอิสระ
import json
import anthropic
import os
client = anthropic.Anthropic(api_key=os.environ['ANTHROPIC_API_KEY'])
def classify_email(subject, sender, body):
prompt = (
'Classify this email as exactly one of: action_needed, fyi, spam.\n'
'Return JSON only: {"category": "...", "reason": "..."}\n\n'
f'From: {sender}\n'
f'Subject: {subject}\n\n'
f'Body:\n{body[:1500]}'
)
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=200,
messages=[{'role': 'user', 'content': prompt}]
)
try:
result = json.loads(response.content[0].text)
return result.get('category', 'fyi'), result.get('reason', '')
except json.JSONDecodeError:
return 'fyi', 'Could not parse LLM response'ขั้นตอนที่ 3: การสร้างฉบับร่างคำตอบ
สำหรับอีเมลที่จัดหมวดหมู่เป็น action_needed ให้ขอ LLM สร้างฉบับร่างคำตอบ ระบุบริบทเกี่ยวกับบทบาทและโทนของเอเจนต์ ขอคำตอบที่เป็นมืออาชีพแต่กระชับ และใส่ตัวยึดตำแหน่งสำหรับข้อมูลที่มนุษย์ต้องกรอก
def draft_reply(subject, sender, body, agent_context):
prompt = (
'You are an email assistant drafting a professional reply.\n'
'Guidelines:\n'
'- Be concise and professional\n'
'- Use [FILL IN] for any info you don\'t know\n'
'- Start with a greeting, end with a sign-off\n\n'
f'Context about the recipient\'s work: {agent_context}\n\n'
f'Original email from {sender}:\n'
f'Subject: {subject}\n\n'
f'{body[:1500]}\n\n'
'Draft a reply:'
)
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=500,
messages=[{'role': 'user', 'content': prompt}]
)
return response.content[0].text.strip()ขั้นตอนที่ 4: การบันทึกฉบับร่างเพื่อให้มนุษย์ตรวจสอบ
อย่าส่งอีเมลที่สร้างโดย AI โดยไม่มีการตรวจสอบจากมนุษย์ ให้บันทึกเป็นdrafts ของ Gmail เพื่อให้มนุษย์เปิด Gmail ตรวจสอบ แก้ไขเมื่อจำเป็น และส่งได้ API สำหรับสร้างฉบับร่างเหมือนกับ API สำหรับส่ง เพียงใช้ drafts().create()
import base64
from email.mime.text import MIMEText
def save_draft_reply(gmail_service, original_message, reply_text):
sender_header = next(
(h['value'] for h in original_message['payload'].get('headers', [])
if h['name'].lower() == 'from'), ''
)
subject = next(
(h['value'] for h in original_message['payload'].get('headers', [])
if h['name'].lower() == 'subject'), ''
)
msg_id_header = next(
(h['value'] for h in original_message['payload'].get('headers', [])
if h['name'].lower() == 'message-id'), ''
)
mime_msg = MIMEText(reply_text, 'plain', 'utf-8')
mime_msg['To'] = sender_header
mime_msg['Subject'] = 'Re: ' + subject
mime_msg['In-Reply-To'] = msg_id_header
mime_msg['References'] = msg_id_header
raw = base64.urlsafe_b64encode(mime_msg.as_bytes()).decode()
draft = gmail_service.users().drafts().create(
userId='me',
body={'message': {'raw': raw, 'threadId': original_message['threadId']}}
).execute()
print(f'Draft saved: {draft["id"]}')
return draft['id']
# --- demo: minimal stand-in for the Gmail API's service object ---
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeDrafts:
def create(self, userId, body):
return _Exec({'id': 'r9000abc'})
class _FakeUsers:
def drafts(self):
return _FakeDrafts()
class _FakeGmailService:
def users(self):
return _FakeUsers()
original_message = {
'threadId': 'thread_1',
'payload': {'headers': [
{'name': 'From', 'value': 'customer@example.com'},
{'name': 'Subject', 'value': 'Question about my order'},
{'name': 'Message-ID', 'value': '<abc123@mail.example.com>'}
]}
}
save_draft_reply(_FakeGmailService(), original_message, 'Thanks for reaching out, we will look into it.')
ขั้นตอนที่ 5: การทำเครื่องหมายอีเมลที่ประมวลผลแล้ว
หลังประมวลผลอีเมลแล้ว (จัดหมวดหมู่และสร้างฉบับร่างหรือเก็บถาวร) ให้ทำเครื่องหมายเพื่อป้องกันการประมวลผลซ้ำ เพิ่มป้ายกำกับแบบกำหนดเอง เช่น AgentProcessed และนำป้ายกำกับ UNREAD ออก สร้างป้ายกำกับเพียงครั้งเดียวหากยังไม่มี
def get_or_create_label(gmail_service, label_name):
labels = gmail_service.users().labels().list(userId='me').execute()
for label in labels.get('labels', []):
if label['name'] == label_name:
return label['id']
# Create the label
new_label = gmail_service.users().labels().create(
userId='me',
body={
'name': label_name,
'labelListVisibility': 'labelShow',
'messageListVisibility': 'show'
}
).execute()
print(f'Created label: {label_name}')
return new_label['id']
def mark_processed(gmail_service, message_id, agent_label_id):
gmail_service.users().messages().modify(
userId='me',
id=message_id,
body={
'addLabelIds': [agent_label_id],
'removeLabelIds': ['UNREAD']
}
).execute()
# --- demo: minimal stand-in for the Gmail API's service object ---
class _Exec:
def __init__(self, result):
self._result = result
def execute(self):
return self._result
class _FakeUsers:
def __init__(self):
self._labels = [{'id': 'Label_1', 'name': 'Processed'}]
def labels(self):
return self
def list(self, userId):
return _Exec({'labels': self._labels})
def create(self, userId, body):
print(f'Created label: {body["name"]}')
return _Exec({'id': 'Label_2', 'name': body['name']})
def messages(self):
return self
def modify(self, userId, id, body):
print(f'Marked {id} processed with {body}')
return _Exec({'id': id})
class _FakeGmailService:
def users(self):
return _FakeUsers()
gmail_service = _FakeGmailService()
label_id = get_or_create_label(gmail_service, 'Processed')
print(f'Label id: {label_id}')
new_label_id = get_or_create_label(gmail_service, 'AgentHandled')
mark_processed(gmail_service, 'msg_99', new_label_id)
วงจรการทำงานทั้งหมดของเอเจนต์
เชื่อมต่อทุกขั้นตอนเข้าด้วยกันในเมธอด run() เดียว เอเจนต์จะวนทำงานกับอีเมลแต่ละฉบับ จัดหมวดหมู่ สร้างฉบับร่างสำหรับรายการที่ต้องดำเนินการ เก็บสแปมถาวร และทำเครื่องหมายว่าประมวลผลแล้วทั้งหมด จากนั้นบันทึกสรุป
def run_email_agent(gmail_service, agent_context, max_emails=10):
processed_label = get_or_create_label(gmail_service, 'AgentProcessed')
emails = fetch_emails_for_classification(gmail_service, max_emails)
summary = {'action_needed': 0, 'fyi': 0, 'spam': 0, 'drafts_created': 0}
for email in emails:
category, reason = classify_email(
email['subject'], email['from'], email['body']
)
summary[category] += 1
print(f'[{category}] {email["subject"][:60]} - {reason[:50]}')
if category == 'action_needed':
# Fetch full message for reply context
full_msg = gmail_service.users().messages().get(
userId='me', id=email['id'], format='full'
).execute()
reply = draft_reply(
email['subject'], email['from'],
email['body'], agent_context
)
save_draft_reply(gmail_service, full_msg, reply)
summary['drafts_created'] += 1
mark_processed(gmail_service, email['id'], processed_label)
print('\nAgent run complete:')
for k, v in summary.items():
print(f' {k}: {v}')
return summaryการจัดการข้อผิดพลาดและความทนทาน
ครอบแต่ละขั้นตอนการประมวลผลอีเมลด้วย try/except ความล้มเหลวของอีเมลฉบับหนึ่งต้องไม่ทำให้เอเจนต์หยุดประมวลผลฉบับที่เหลือ บันทึกข้อผิดพลาดพร้อม ID และหัวเรื่องของอีเมล เพื่อให้ตรวจสอบได้ในภายหลัง
from googleapiclient.errors import HttpError
def process_email_safely(gmail_service, email, agent_context, label_id):
try:
category, reason = classify_email(
email['subject'], email['from'], email['body']
)
if category == 'action_needed':
full_msg = gmail_service.users().messages().get(
userId='me', id=email['id'], format='full'
).execute()
reply = draft_reply(
email['subject'], email['from'],
email['body'], agent_context
)
save_draft_reply(gmail_service, full_msg, reply)
mark_processed(gmail_service, email['id'], label_id)
return category
except HttpError as e:
print(f'Gmail API error on {email["id"]}: {e.resp.status}')
return 'error'
except Exception as e:
print(f'Unexpected error on {email["subject"][:50]}: {e}')
return 'error'การตั้งเวลาให้เอเจนต์ทำงานเป็นระยะ
ให้เอเจนต์อีเมลทำงานตามกำหนดเวลาโดยใช้ลูปง่าย ๆ และเรียก time.sleep() ระหว่างการทำงานแต่ละครั้ง สำหรับการใช้งานจริง ให้ใช้ตัวจัดกำหนดการงาน เช่น cron, APScheduler หรือฟังก์ชันบนคลาวด์ ควรเพิ่มการตรวจสอบเพื่อหลีกเลี่ยงการทำงานนอกเวลาทำการและเคารพเขตเวลาของผู้รับเสมอ
import time
import datetime
def is_business_hours():
now = datetime.datetime.now()
# Mon-Fri, 9am-6pm local time
return (now.weekday() < 5 and 9 <= now.hour < 18)
def run_scheduler(gmail_service, agent_context,
interval_minutes=30, max_emails=20):
print(f'Email agent started. Checking every {interval_minutes} min.')
while True:
if is_business_hours():
print(f'\n[{datetime.datetime.now().strftime("%H:%M")}] Running agent...')
try:
run_email_agent(gmail_service, agent_context, max_emails)
except Exception as e:
print(f'Agent run failed: {e}')
else:
print('Outside business hours, skipping run')
time.sleep(interval_minutes * 60)การบันทึกและเส้นทางการตรวจสอบ
เก็บบันทึก JSON ของอีเมลทุกฉบับที่เอเจนต์ประมวลผล ซึ่งจะสร้างเส้นทางการตรวจสอบที่คุณใช้ทบทวนเพื่อยืนยันพฤติกรรมของเอเจนต์ วินิจฉัยการจัดหมวดหมู่ผิด และปรับปรุงพรอมต์ได้ในระยะยาว
import json
import datetime
from pathlib import Path
LOG_FILE = Path('agent_audit.jsonl')
def log_action(email_id, subject, sender, category, action, draft_id=None):
entry = {
'timestamp': datetime.datetime.now().isoformat(),
'email_id': email_id,
'subject': subject[:100],
'from': sender,
'category': category,
'action': action,
'draft_id': draft_id
}
with open(LOG_FILE, 'a', encoding='utf-8') as f:
f.write(json.dumps(entry) + '\n')
# Usage in the main loop:
log_action(
email_id='18abc123',
subject='Invoice #1234',
sender='billing@vendor.com',
category='action_needed',
action='draft_created',
draft_id='r9000abc'
)
# --- demo ---
print('Audit log contents:')
print(LOG_FILE.read_text(encoding='utf-8'))
ตรวจสอบความเข้าใจอย่างรวดเร็ว: มนุษย์ร่วมตรวจสอบ
ทดสอบความเข้าใจเกี่ยวกับการออกแบบผู้ช่วยอีเมล
สรุปเอเจนต์ผู้ช่วยอีเมล
คุณได้สร้างกระบวนการของเอเจนต์ผู้ช่วยอีเมลที่สมบูรณ์แล้ว:
- ดึงข้อมูล: ดึงอีเมลที่ยังไม่ได้อ่านด้วยคำค้นการค้นหาของ Gmail API
- จัดหมวดหมู่: LLM จัดหมวดหมู่อีเมลแต่ละฉบับเป็นต้องดำเนินการ/แจ้งให้ทราบ/สแปม พร้อมเอาต์พุต JSON
- ร่าง: LLM สร้างคำตอบด้วยโทนที่เป็นมืออาชีพและตัวยึดตำแหน่ง [FILL IN]
- บันทึกฉบับร่าง: เก็บไว้ใน Gmail เพื่อให้มนุษย์ตรวจสอบ — ห้ามส่งอัตโนมัติ
- ทำเครื่องหมายว่าประมวลผลแล้ว: เพิ่มป้ายกำกับแบบกำหนดเองและนำ UNREAD ออกเพื่อป้องกันการประมวลผลซ้ำ
- แยกข้อผิดพลาด: ครอบอีเมลแต่ละฉบับด้วย try/except เพื่อป้องกันไม่ให้ความล้มเหลวหนึ่งรายการหยุดทั้งชุด
- บันทึกการตรวจสอบ: ไฟล์ JSONL ที่บันทึกทุกการดำเนินการเพื่อการตรวจสอบและปรับปรุง
คำถามที่พบบ่อย
บทเรียน “การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย”
ครบทุกขั้นตอน: อ่านกล่องจดหมาย → สรุป → ร่างคำตอบ → รอการอนุมัติ คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเชื่อมต่อ Gmail ผ่าน API
- การอ่านและส่งอีเมลด้วยโปรแกรม
- การสร้างและค้นหาเหตุการณ์ในปฏิทิน
- การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย