بناء Agent شخصي يقرأ رسائل بريدك الإلكتروني ويقترح ردوداً ذكية
بناء Agent شخصي يقرأ رسائل بريدك الإلكتروني ويقترح ردوداً ذكية
فكرة هذا المشروع ليست مجرد ربط صندوق البريد مع نموذج لغوي كبير، بل بناء نظام برمجي منظم يفصل بين طبقات الوصول إلى البريد، التحليل الدلالي، استرجاع السياق، ثم توليد رد مهني آمن وقابل للمراجعة البشرية. هذا النوع من التطبيقات يقع ضمن فئة العملاء الأذكياء (AI Agents) لأنه لا يكتفي بتوليد نص، بل يقرر ما الذي يجب قراءته، وما السياق المطلوب، وكيف يصيغ اقتراح الرد وفق القواعد التي تضعها أنت.
عملياً، سنبني Agent شخصياً يقرأ الرسائل الجديدة عبر Gmail API، يستخرج محتواها، يصنف النية، يسترجع رسائل أو معلومات سابقة ذات صلة، ثم يرسل إلى LLM برومبت مضبوطاً لإنتاج رد مهذب ومختصر. والأهم أنه لا يرسل شيئاً تلقائياً؛ بل يقترح مسودة فقط، وهذا قرار هندسي مهم لتقليل المخاطر التشغيلية والامتثال.
المعمارية البرمجية للنظام
أفضل طريقة لبناء هذا التطبيق هي التفكير فيه كخط أنابيب Pipeline متعدد الطبقات، وليس كملف سكربت واحد. المعمارية المقترحة تتكون من:
- طبقة جلب الرسائل من البريد عبر
API. - طبقة تنظيف النص واستخراج
metadataمثل المرسل والموضوع والتاريخ. - طبقة ذاكرة وسياق، ويمكن دعمها بمبادئ الذاكرة في الذكاء الاصطناعي.
- طبقة استرجاع دلالي مبنية على Embeddings وVector Databases لاستحضار رسائل أو ردود سابقة مشابهة.
- طبقة توليد الرد باستخدام
LLM. - طبقة مراجعة بشرية قبل إنشاء مسودة الرد أو حفظها.
هذا التصميم قريب من فلسفة RAG، لأن النموذج لا يعتمد فقط على ذاكرته العامة، بل على معلومات مسترجعة من صندوق بريدك الشخصي. لذلك يصبح الرد أكثر ارتباطاً بسياق عملك ونبرتك المعتادة ويقل خطر الهلوسة.
تدفق البيانات من الرسالة إلى الرد
1) جلب الرسائل الجديدة
تبدأ العملية عبر مراقبة صندوق البريد الوارد، ثم سحب الرسائل غير المقروءة أو الرسائل الواردة ضمن تصنيف معين. يجب هنا إنشاء طبقة وصول مستقلة حتى يسهل لاحقاً تبديل provider البريد إذا انتقلت من Gmail إلى Outlook.
from googleapiclient.discovery import build
def list_unread_messages(creds, max_results=5):
service = build("gmail", "v1", credentials=creds)
results = service.users().messages().list(
userId="me",
q="is:unread category:primary",
maxResults=max_results
).execute()
return results.get("messages", [])
2) استخراج النص الفعلي من الرسالة
الرسائل البريدية غالباً تحتوي HTML وتواقيع وروابط وسلاسل ردود قديمة. لذلك يجب تنظيفها بعناية. هندسياً، جودة هذه المرحلة تؤثر مباشرة على جودة الرد، لأن أي ضجيج نصي يدخل إلى النموذج سيرفع استهلاك Tokens ويشوّه فهم الرسالة. إذا أردت فهم إدارة الاستهلاك، راجع مقال حساب التكلفة وإدارة الرموز.
- فك ترميز جسم الرسالة.
- إزالة التوقيع الآلي.
- حذف الاقتباسات الطويلة من الردود السابقة إن لم تكن مطلوبة.
- توحيد اللغة والأسطر الفارغة.
3) إضافة طبقة استرجاع للسياق الشخصي
إذا كان المطلوب مجرد رد عام، يمكن إرسال الرسالة مباشرة إلى النموذج. لكن الردود الذكية فعلاً تحتاج سياقاً: كيف ترد عادة على عميل معين؟ ما هي الصياغة المفضلة لفريقك؟ هل توجد رسائل سابقة مشابهة؟ هنا ندخل إلى عالم LangChain مع Retriever مبني على الرسائل السابقة.
الخطوات تكون كالتالي:
- أرشفة الرسائل والردود السابقة في مخزن محلي.
- تحويلها إلى
VectorsباستخدامEmbeddings. - تخزينها في قاعدة مثل ChromaDB.
- عند وصول رسالة جديدة، نبحث دلالياً عن أكثر الردود السابقة شبهاً بها.
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(
collection_name="email_threads",
embedding_function=embeddings,
persist_directory="./email_memory_db"
)
def retrieve_similar_context(query, k=3):
docs = vectorstore.similarity_search(query, k=k)
return "\n\n".join(doc.page_content for doc in docs)
هذه الفكرة امتداد عملي لمفاهيم دمج المعلومات المسترجعة مع الـ LLM، لكنها مطبقة على البريد الشخصي بدل المستندات العامة.
هندسة البرومبت لإنتاج رد قابل للاستخدام
مرحلة Prompt Engineering هي الفاصل بين رد إنشائي عام ورد عملي يشبه أسلوبك. البرومبت يجب أن يحدد للنموذج الدور، النبرة، حدود التصرف، وحالات الامتناع عن الإجابة. كما يجب أن يطلب صيغة إخراج ثابتة لتسهيل المعالجة اللاحقة، ويفضل استخدام مبدأ Output Parsers.
أنت مساعد بريد إلكتروني شخصي. حلّل الرسالة الواردة وحدد نية المرسل، ثم اقترح رداً مهنياً قصيراً باللغة نفسها المستخدمة في الرسالة. استخدم السياق المسترجع فقط إذا كان ذا صلة. إذا كانت الرسالة غامضة أو تتطلب قراراً قانونياً أو مالياً، لا تؤلف معلومات، بل اقترح رداً يطلب توضيحاً. أعد النتيجة بصيغة JSON تحتوي على: intent, tone, draft_reply, needs_human_review.
from openai import OpenAI
import json
client = OpenAI()
def generate_reply(email_text, retrieved_context):
prompt = f"""
You are a personal email assistant.
Incoming email:
{email_text}
Retrieved context:
{retrieved_context}
Return valid JSON only with keys:
intent, tone, draft_reply, needs_human_review
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
temperature=0.3,
messages=[{"role": "user", "content": prompt}]
)
content = response.choices[0].message.content
return json.loads(content)
لاحظ أن قيمة temperature منخفضة نسبياً، لأن البريد المهني يحتاج ثباتاً واتساقاً أكثر من الإبداع. ويمكنك التوسع في ذلك عبر مقال التحكم في إبداع الذكاء الاصطناعي.
استخدام LangChain لتجميع المكونات
ميزة LangChain أنه يحول المشروع من سكربتات متفرقة إلى سلسلة منطقية واضحة. يمكنك تعريف Chain تبدأ من النص الخام، ثم تمر بمرحلة استرجاع، ثم توليد، ثم تحقق من المخرجات. هذا ينسجم مع ما شرحناه سابقاً في إنشاء أول سلسلة باستخدام LangChain.
- مكوّن
Loaderللبريد. - مكوّن
Retrieverللرسائل السابقة. - مكوّن
Prompt Template. - مكوّن
Output Parserللتحقق من بنية الرد.
اعتبارات الأمان والخصوصية
بما أن النظام يتعامل مع بيانات شديدة الحساسية، فلا بد من تصميمه بعقلية privacy-first. من الأفضل:
- تخزين أقل قدر ممكن من الرسائل.
- إخفاء البيانات الحساسة قبل إرسالها إلى النموذج عند الحاجة.
- منع الإرسال التلقائي للردود دون مراجعة.
- تسجيل القرارات في
logsداخلية لأغراض التدقيق. - استخدام مفاتيح
APIعبر متغيرات بيئة آمنة، كما في الاتصال الأول وجلب مفاتيح API.
كيف تطور المشروع من مساعد بسيط إلى Agent متقدم؟
بعد بناء النسخة الأولى، يمكنك التوسع تدريجياً:
- إضافة تصنيف تلقائي للأولوية والرسائل العاجلة.
- ربطه بتقويمك لاقتراح مواعيد منسجمة مع جدولك.
- استخدام أسلوب ReAct إذا احتاج الوكيل إلى التفكير ثم استخدام أدوات متعددة.
- بناء ذاكرة مستمرة تحفظ أنماط ردودك المفضلة مع الزمن.
- إظهار الرد بشكل متدفق في الواجهة عبر Streaming Responses.
الخلاصة الهندسية أن مشروع قراءة البريد واقتراح الردود ليس تطبيقاً استعراضياً، بل مثال ممتاز على دمج LLMs مع البيانات الشخصية والسياق التشغيلي الحقيقي. وكلما فصلت المكونات بوضوح بين الجلب، التنظيف، الاسترجاع، والتوليد، حصلت على نظام أكثر موثوقية وقابلية للصيانة. هذه هي الهندسة الحقيقية لتطبيقات Generative AI: ليس فقط أن يكتب النموذج نصاً جميلاً، بل أن يكتب الرد الصحيح، في السياق الصحيح، وبالتحكم الصحيح.
2 comments