إنشاء وكلاء موثوق بهم للمؤسسات الخيرية باستخدام Google ADK وAP2

1. بناء الثقة لإطلاق العنان للكرم

بانر

لحظة الإلهام

يهتز هاتفك. تطّلع على خبر عن برنامج ناجح لمحو الأمية يساعد الأطفال في المجتمعات المحرومة على تعلّم القراءة. تشعر برغبة قوية في المساهمة. تفتح المتصفّح وتبحث عن "تبرّعات لبرامج محو الأمية لدى الأطفال".

بحث Google

تظهر مئات النتائج.

تنقر على الرابط الأول. يبدو الموقع الإلكتروني احترافيًا. انتقِل إلى أسفل الصفحة للاطّلاع على البيانات المالية. "التكاليف الإدارية: %28" أوقِف الفيديو مؤقتًا. سيتم تمويل البرنامج بـ 72 سنتًا فقط من كل دولار تتبرّع به. هل هذا جيد؟ لست متأكدًا.

جرِّب مؤسسة أخرى. لم يسبق لك أن سمعت بهما. هل هي شرعية؟ يؤدي البحث السريع إلى نتائج غير متوقّعة. تجد سلسلة محادثات على Reddit من عامين يزعم فيها أحد المستخدمين أنّ "هذا الموقع الإلكتروني مخادع، ولم تصل تبرعاتي إلى أي مكان". بينما يدافع آخر بشدة عنهم قائلاً: "إنّهم يعملون على أرض الواقع ويقومون بعمل حقيقي". والغموض يسبب الشلل.

بعد ثلاثين دقيقة، تجد نفسك غارقًا في متاهة من المراجعات المتضاربة وتقييمات الكفاءة وسجلات مصلحة الضرائب الأمريكية، ولم تتبرّع بعد. وقد تم استبدال هذه الشرارة الأولى من الكرم بالصعوبات التي يواجهها الباحثون. تبقى علامة التبويب مفتوحة لبضعة أيام، وهي تذكير بسيط بنية حسنة، إلى أن تغلقها في النهاية.

هذا ليس خطأ شخصيًا، بل خطأ في النظام

هذه التجربة عالمية. الرغبة في التبرّع كبيرة، ولكنّ العملية مليئة بالعقبات التي تسبّب التردد والشك:

  • صعوبة البحث: تتطلّب كل مؤسسة خيرية إجراء تحقيق خاص بها.
  • التحقّق من المصداقية: يصعب التمييز بين المؤسسات الفعّالة جدًا والمؤسسات غير الفعّالة أو حتى عمليات الاحتيال الصريحة.
  • شلل التحليل: يؤدي العدد الهائل من الخيارات إلى إرهاق اتخاذ القرار.
  • فقدان الحماس: يتلاشى الدافع العاطفي للعطاء مع ازدياد الأعباء اللوجستية.

ويترتّب على هذا الاحتكاك تكلفة باهظة في العالم الحقيقي. تُعدّ التبرّعات الفردية في الولايات المتحدة هائلة، فقد قدّم المتبرّعون الأفراد حوالي 374 مليار دولار أمريكي في عام 2023 وحده، وفقًا لتقرير Giving USA 2024. ومع ذلك، تُظهر الأبحاث أنّ الحواجز التي تعيق التبرّع، بما في ذلك تكاليف البحث والاحتكاك النفسي وقيود الوقت، تقلّل بشكل كبير من المبلغ الذي يصل إلى المؤسسات الخيرية. أظهرت دراسات شملت ملايين المتبرّعين أنّ حتى العقبات البسيطة في عملية التبرّع على الإنترنت تمنع الأشخاص من تحقيق نواياهم الخيرية.

يمثّل ذلك مليارات الدولارات من التبرّعات المقصودة التي لا تصل أبدًا إلى الجهات التي تحتاج إليها.

The Vision

تخيَّل تجربة مختلفة. بدلاً من جلسة بحث مدتها 30 دقيقة، يمكنك ببساطة قول:

"أريد التبرّع بمبلغ 50 دولارًا أمريكيًا لبرنامج محو أمية للأطفال. ابحث لي عن مؤسسة خيرية موثوقة وفعّالة وحاصلة على تقييم عالٍ".

وفي غضون ثوانٍ، ستحصل على ردّ يعزّز ثقتك بنفسك:

بطاقة نتائج المؤسسات الخيرية

هذا هو الهدف من "وكيل التبرّع المستنِد إلى الذكاء الاصطناعي". ولكن لتحقيق هذه الرؤية، يجب أن نحلّ تحديًا أساسيًا: عندما يتعامل وكيل الذكاء الاصطناعي المستقل مع الأموال، لا يكون عنصر الثقة اختياريًا، بل هو الأساس الكامل.

  • كيف يمكننا إثبات ما وافق عليه المستخدم؟
  • مَن يتحمّل المسؤولية في حال حدوث خطأ؟
  • كيف نمنح المتبرّعين والمؤسسات الخيرية وشبكات الدفع الثقة للمشاركة؟

مهمتك اليوم

في ورشة العمل هذه، ستنشئ هذا الوكيل الموثوق به من خلال الجمع بين تقنيتَين فعّالتَين:

Google Agent Development Kit (ADK)

بروتوكول دفعات الوكلاء (AP2)

Role

المصنع لإنشاء وكلاء الذكاء الاصطناعي الجاهزين للاستخدام

المخطط المعماري للثقة في معاملات الذكاء الاصطناعي

ما يوفّره

• إطار عمل لتنسيق عمل عدة وكلاء
• ميزات أمان مدمَجة، مثل تأكيد الأداة
• إمكانية المراقبة والتتبُّع الجاهزة للاستخدام
• واجهة بسيطة بلغة Python لسلوكيات الوكلاء المعقّدة

• حدود الأمان المستندة إلى الأدوار
• بيانات الاعتماد الرقمية التي يمكن التحقّق منها (التفويضات)
• إثبات الموافقة باستخدام التشفير
• سجلّات تدقيق كاملة للمساءلة

مزيد من المعلومات

مستندات ADK

بروتوكول AP2

ما ستنشئه

الهندسة المعمارية

في نهاية ورشة العمل هذه، ستكون قد أنشأت ما يلي:

‫✅ نظام متعدد الوكلاء بأدوار متخصصة:

  • وكيل تسوّق يعثر على مؤسسات خيرية تم التحقّق منها
  • وكيل تاجر ينشئ عروض تبرّع ملزمة
  • مقدّم بيانات اعتماد يعالج الدفعات بأمان
  • أداة تنسيق تدير عملية التنفيذ بأكملها

ثلاثة أنواع من بيانات الاعتماد التي يمكن إثبات صحتها:

  • IntentMandate: "ابحث لي عن مؤسسة خيرية تعليمية"
  • CartMandate: "50 دولار أمريكي لصالح مؤسسة Room to Read، بتوقيع التاجر"
  • PaymentMandate: "المعالجة من خلال عملية دفع محاكاة"

الأمان على كل المستويات:

  • حدود الثقة المستندة إلى الدور
  • موافقة المستخدم الصريحة

‫✅ مسار تدقيق كامل:

  • تتبُّع كل قرار
  • كل موافقة تم تسجيلها
  • كل عملية تسليم مرئية

🔒 ملاحظة مهمة: هذه بيئة تعلّم آمنة

هل أنت مستعد لكسب الثقة؟

في الوحدة التالية، سنعمل على إعداد بيئة التطوير وإنشاء أول وكيل يعمل بالذكاء الاصطناعي. ستكتشف سريعًا سبب عدم موثوقية البرامج البسيطة، ثم ستقضي بقية ورشة العمل في تعلُّم كيفية حلّ هذه المشكلة.

لنبدأ بفهم المشكلة مباشرةً.

2. إعداد مساحة العمل

مؤسسة الوكلاء الموثوق بهم

قبل أن نتمكّن من إنشاء "وكيل التبرّع الذكي" المستند إلى الذكاء الاصطناعي، علينا إعداد بيئة تطوير نظيفة ومتسقة ومضبوطة بشكلٍ صحيح. هذه الوحدة هي خطوة مركّزة لضمان توفّر جميع الأدوات والخدمات اللازمة.

يعني إكمال عملية الإعداد هذه بنجاح أنّه يمكنك التركيز بالكامل على العمل المثير المتمثل في إنشاء منطق الوكيل في الوحدات النمطية القادمة، بدون القلق بشأن مشاكل الإعداد.

الوصول إلى Cloud Shell

أولاً، سنفتح Cloud Shell، وهي وحدة طرفية مستندة إلى المتصفّح مع تثبيت مسبق لحزمة تطوير البرامج (SDK) من Google Cloud وأدوات أساسية أخرى.

هل تحتاج إلى أرصدة Google Cloud؟

انقر على تفعيل Cloud Shell في أعلى Google Cloud Console (رمز الوحدة الطرفية في شريط التنقّل أعلى يسار الصفحة).

cloud shell

ابحث عن رقم تعريف مشروعك على Google Cloud:

  • افتح Google Cloud Console: https://console.cloud.google.com
  • اختَر المشروع الذي تريد استخدامه في ورشة العمل هذه من القائمة المنسدلة للمشروع في أعلى الصفحة.
  • يظهر رقم تعريف مشروعك في بطاقة معلومات المشروع على لوحة البيانات رقم تعريف المشروع

بعد فتح Cloud Shell، تأكَّد من مصادقتك:

# Check that you are logged in
gcloud auth list

من المفترض أن يظهر حسابك على أنّه (ACTIVE).

إعداد مشروعك

لنبدأ الآن بإعداد مشروعك على Google Cloud وتفعيل واجهات برمجة التطبيقات اللازمة.

تحديد رقم تعريف مشروعك

# Set your project using the auto-detected environment variable in Cloud Shell
gcloud config set project $GOOGLE_CLOUD_PROJECT

# Verify the project has been set
echo "Your active Google Cloud project is: $(gcloud config get-value project)"

تفعيل واجهات برمجة التطبيقات المطلوبة

يحتاج وكلاؤك إلى الوصول إلى العديد من خدمات Google Cloud:

gcloud services enable \
    aiplatform.googleapis.com \
    secretmanager.googleapis.com \
    cloudtrace.googleapis.com

قد يستغرق ذلك دقيقة أو دقيقتين. وسترى ما يلي:

Operation "operations/..." finished successfully.

الميزات التي توفّرها واجهات برمجة التطبيقات هذه:

  • aiplatform.googleapis.com: الوصول إلى نماذج Gemini لاستخدامها في الاستدلال
  • secretmanager.googleapis.com: تخزين آمن لمفاتيح واجهة برمجة التطبيقات (أفضل ممارسة في مرحلة الإنتاج)
  • cloudtrace.googleapis.com: إمكانية المراقبة لمسار إثبات المسؤولية

استنساخ الرمز المُعد مسبقًا للمبتدئين

يمكنك الحصول على مستودع ورشة العمل الذي يتضمّن جميع رموز النماذج والموارد:

git clone https://github.com/ayoisio/adk-ap2-charity-agents
cd adk-ap2-charity-agents
git checkout codelab

لنتأكّد من المعلومات المتوفّرة لدينا:

ls -la

سيظهر لك ما يلي:

  • charity_advisor/: المكان الذي سننشئ فيه الوكلاء والأدوات
  • scripts/: نصوص برمجية مساعدة للاختبار والتحقّق
  • deploy.sh - نص برمجي مساعد للنشر
  • setup.py - نص برمجي مساعد لتثبيت الوحدة
  • .env.template - ملف متغيرات البيئة

إعداد بيئة Python

سننشئ الآن بيئة Python معزولة لمشروعنا.

إنشاء بيئة افتراضية وتفعيلها

# Create the virtual environment
python3 -m venv venv

# Activate it
source venv/bin/activate

التحقّق: من المفترض أن يظهر الآن البادئة (venv) في طلبك.

تثبيت الحِزم التابعة

pip install -r charity_advisor/requirements.txt
pip install -e .

يتم تثبيت ما يلي:

  • google-adk: إطار عمل "حزمة تطوير الوكيل"
  • google-cloud-aiplatform: دمج Vertex AI وGemini
  • ap2: حزمة تطوير البرامج (SDK) لبروتوكول دفعات الوكلاء (من GitHub)
  • python-dotenv: إدارة المتغيرات البيئية

تتيح لك العلامة -e استيراد وحدات adk_ap2_charity_agents من أي مكان.

ضبط ملف البيئة

أنشئ إعداداتك من النموذج:

# Copy the template
cp .env.template .env

# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)

# Replace the placeholder with your actual project ID
sed -i "s/your-project-id/$PROJECT_ID/g" .env

# Verify the replacement worked
grep GOOGLE_CLOUD_PROJECT .env

سيظهر لك ما يلي:

GOOGLE_CLOUD_PROJECT=your-actual-project-id

التحقّق

شغِّل نص التحقّق البرمجي للتأكّد من ضبط كل شيء بشكل صحيح:

python scripts/verify_setup.py

يجب أن تظهر لك كل علامات الاختيار الخضراء:

======================================================================
SETUP VERIFICATION
======================================================================

✓ Python version: 3.11.x
✓ google-adk: 1.17.0
✓ google-cloud-aiplatform: 1.111.0+
✓ ap2: 0.1.0
✓ python-dotenv: 1.0.0+
✓ .env file found and contains project ID
✓ Google Cloud project configured: your-project-id

✓ Mock charity database found
✓ Agent templates ready
✓ All directories present

======================================================================
✓ Setup complete! You are ready to build trustworthy agents.
======================================================================

تحديد المشاكل وحلّها

الخطوات التالية:

أصبحت بيئتك جاهزة الآن بالكامل. يجب أن يتوفّر لديك ما يلي:

  • ✅ تم إعداد مشروع Google Cloud
  • ✅ تم تفعيل واجهات برمجة التطبيقات المطلوبة
  • ✅ تم تثبيت مكتبتَي ADK وAP2
  • ‫✅ رمز النموذج جاهز للتعديل

في الوحدة التالية، ستنشئ أول وكيل يعمل بالذكاء الاصطناعي باستخدام بضعة أسطر من الرموز البرمجية، وستتعرّف على سبب عدم موثوقية الوكلاء البسيطين عند التعامل مع المعاملات المالية.

3- وكيلك الأول واكتشاف فجوة الثقة

بانر

من الفكرة إلى التفاعل

في الوحدة السابقة، أعددنا بيئة التطوير. الآن، يبدأ العمل المثير. سننشئ ونشغّل أول وكيل لنا، ونمنحه أول قدرة له، وخلال ذلك، سنتعرّف على التحديات الأساسية التي يجب حلّها لجعله موثوقًا حقًا.

هذه الوحدة هي صورة "قبل"، وهي اللحظة التي تكشف عن أنّ بناء وكلاء موثوق بهم يتطلّب أكثر من مجرد منح نموذج لغوي كبير إذن الوصول إلى الأدوات.

الخطوة 1: فحص "الوكيل المبتدئ"

لنلقِ نظرة أولاً على نموذج الوكيل الأول. يحتوي على بنية أساسية تتضمّن عناصر نائبة سنكملها في الخطوات التالية.

👉 افتح الملف

charity_advisor/simple_agent/agent.py

في المحرِّر.

وسترى ما يلي:

"""
A simple agent that can research charities using Google Search.
"""

# MODULE_3_STEP_2_IMPORT_COMPONENTS


simple_agent = Agent(
    name="SimpleAgent",
    model="gemini-2.5-flash",
    
    # MODULE_3_STEP_3_WRITE_INSTRUCTION
    instruction="""""",
    
    # MODULE_3_STEP_4_ADD_TOOLS
    tools=[]
)

لاحظ أنّ التعليقات النائبة تتّبع نمطًا معيّنًا: MODULE_3_STEP_X_DESCRIPTION. سنستبدل هذه العلامات من أجل إنشاء الوكيل بشكل تدريجي.

الخطوة 2: استيراد المكوّنات المطلوبة

قبل أن نتمكّن من إنشاء مثيل لفئة Agent أو استخدام أداة google_search، علينا استيرادهما إلى ملفنا.

👉 البحث:

# MODULE_3_STEP_2_IMPORT_COMPONENTS

👉 استبدِل هذا السطر الواحد بما يلي:

from google.adk.agents import Agent
from google.adk.tools import google_search

أصبح الآن الصف Agent والأداة google_search متاحَين في ملفنا.

الخطوة 3: كتابة "تعليمات الوكيل"

التعليمات هي "الوصف الوظيفي" للوكيل، فهي تخبر النموذج اللغوي الكبير متى وكيف يستخدم أدواته. لنكتب طلبًا يوجّه الوكيل للبحث عن معلومات حول المؤسسات الخيرية.

👉 البحث:

# MODULE_3_STEP_3_WRITE_INSTRUCTION
instruction="""""",

👉 استبدِل هذين السطرَين بما يلي:

instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",

الخطوة 4: إضافة "شريط البحث"

الوكيل الذي لا يتضمّن أدوات هو مجرد محاور. لنمنح وكيلنا قدرته الأولى: البحث على الويب.

👉 البحث:

# MODULE_3_STEP_4_ADD_TOOLS
tools=[]

👉 استبدِل هذين السطرَين بما يلي:

tools=[google_search]

الخطوة 5: تأكيد صحة معلومات الوكيل

دعنا نتأكّد من توفّر جميع العناصر قبل إجراء الاختبار.

👉

charity_advisor/simple_agent/agent.py

من المفترض أن يبدو ملف الآن على النحو التالي تمامًا:

"""
A simple agent that can research charities using Google Search.
"""

from google.adk.agents import Agent
from google.adk.tools import google_search


simple_agent = Agent(
    name="SimpleAgent",
    model="gemini-2.5-flash",
    instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",
    tools=[google_search]
)

الخطوة 6: اختبار "الوكيل" - الكشف عن فجوات الثقة

بعد ضبط إعدادات الوكيل بالكامل، لنختبره ونحلّل سلوكه. وهنا نكتشف سبب عدم موثوقية البرامج البسيطة عند اتخاذ القرارات المالية.

الاختبار 1: مشكلة الاستكشاف

👉 في وحدة Cloud Shell الطرفية، شغِّل الأمر التالي:

adk run charity_advisor/simple_agent

من المفترَض أن تظهر لك نتيجة مثل:

INFO:google.adk.agents:Loading agent from charity_advisor/simple_agent
INFO:google.adk.agents:Agent 'SimpleAgent' ready

[user]:

إنّ الطلب [user]: ينتظر إدخالك الآن.

👉 في طلب [المستخدم]:، اكتب:

Can you find me a verified, highly-rated charity for children's literacy?

👉 اضغط على Enter ولاحظ الرد.

بعد لحظات، سيجمع الوكيل نتائج البحث في ردّ على النحو التالي:

استنادًا إلى بحث على الويب، يبدو أنّ بعض المؤسسات الخيرية المعروفة في مجال تعليم الأطفال القراءة والكتابة هي Reading Is Fundamental وRoom to Read. ننصح غالبًا بالرجوع إلى مصادر مثل Charity Navigator وGuideStar للتحقّق من حالة المؤسسات وتقييماتها. عثرتُ أيضًا على العديد من المناقشات على الإنترنت، بما في ذلك في منتديات مثل Reddit، حيث يشارك المستخدمون تجاربهم الشخصية مع برامج محو الأمية المحلية الأصغر حجمًا.

لنحلّل هذه الحالة. هل حلّ الموظّف مشكلتنا؟

لا، فقد نجح في محاكاة التجربة الإنسانية التي وصفناها في الوحدة 1. لقد نجح في أتمتة عملية "البحث على Google" وأعاد إلينا مشكلة "شلل التحليل".

يكشف ذلك عن فجوة الثقة الأولى: عدم توفّر بيانات موثوقة.

يبحث الوكيل في الويب المفتوح، ما يعني ما يلي:

  • ✅ عثرت على النتائج بسرعة (تجربة مستخدم محسّنة)
  • ❌ يخلط بين المؤسسات الحائزة على تقييمات عالية والمناقشات على Reddit (مصادر غير موثوقة)
  • ❌ لا يمكنه التمييز بين المؤسسات الخيرية التي تم التحقّق منها وعمليات الاحتيال المحتملة (لا يتم التحقّق من المؤسسات)
  • ❌ يطلب منّا التحقّق من المعلومات التي قدّمها للتو (إعادة المسؤولية)

الاختبار 2: مشكلة التنفيذ

والآن، لننتقل إلى الاختبار الثاني المهم. في طلب [user]:، حاوِل إكمال عملية التبرّع باتّباع الخطوات التالية:

Okay, please donate $50 to Room to Read for me.

سيردّ الوكيل باعتذار، معترفًا بحدوده:

ندرك أنّك تريد التبرّع، وهذا أمر رائع. مع ذلك، أنا مساعد بحثي ولا يمكنني التعامل مع المعاملات المالية أو معالجة الدفعات. للتبرّع، عليك الانتقال مباشرةً إلى الموقع الإلكتروني الرسمي لمؤسسة Room to Read.

هذه هي لحظة "الإدراك" الثانية، وهي مهمة بالقدر نفسه.

لا يمكن الوثوق بالوكيل للعثور على المؤسسة الخيرية المناسبة، كما لا يمكن الوثوق به لتنفيذ عملية التبرّع.

👉 اضغط على

Ctrl+C

للخروج عند الانتهاء من الاختبار

تمثيل الفجوتين بيانيًا

مشكلة الثقة

ما تعلّمته للتو

في هذه الوحدة، تمكّنت بنجاح من إنشاء وكيل الذكاء الاصطناعي الأول وتجهيزه. وبذلك، تكون قد اكتشفت التحديين الأساسيين اللذين يواجهان عملية إنشاء نظام موثوق به.

المفاهيم الرئيسية التي تم إتقانها

فئة الوكيل:

  • الوحدة الأساسية في حزمة تطوير التطبيقات (ADK)
  • يجمع بين قدرات الاستدلال في النماذج اللغوية الكبيرة (العقل) والأدوات (اليدين)
  • تم إعداده باستخدام نموذج وتعليمات وأدوات

البنية المستندة إلى المجلدات:

  • يكون كل وكيل في مجلد خاص به
  • يبحث ADK عن agent_folder/agent.py
  • ممارسة رياضة الجري مع adk run agent_folder

قائمة الأدوات:

  • تحديد إمكانات الوكيل
  • يقرّر النموذج اللغوي الكبير متى وكيف يستخدم الأدوات
  • يمكن أن تحتوي على أدوات متعددة لإجراءات مختلفة

طلب التعليمات:

  • توجيه سلوك الوكيل مثل الوصف الوظيفي
  • تحديد الدور والمشغّلات والإجراءات وتنسيق الإخراج
  • عامل أساسي لاستخدام الأدوات بشكل موثوق

مشكلة الثقة:

  • فجوة في إمكانية العثور على المحتوى: مصادر غير معتمدة، جودة مختلطة
  • فجوة التنفيذ: لا تتوفّر إمكانات آمنة ولا موافقة ولا سجلّ تدقيق

الخطوات التالية

في الوحدة التالية، سنبدأ في إنشاء الحلّ من خلال تنفيذ البنية المستندة إلى الأدوار في AP2.

لننشئ الوكيل الأول ونرى فصل الأدوار عمليًا.

4. إنشاء "وكيل التسوّق" - الاكتشاف المستند إلى الدور

بانر

أساس الثقة: فصل الأدوار

في الوحدة الأخيرة، تبيّن لك أنّ الوكيل البسيط المتعدّد الأغراض لا ينجح في مجالَين: لا يمكنه توفير عملية استكشاف موثوقة، ولا يمكنه تنفيذ معاملات آمنة. سنبدأ الآن في حلّ هذه المشاكل من خلال تطبيق المبدأ الأول من "بروتوكول دفعات الوكيل": البنية المستندة إلى الأدوار.

قبل كتابة أي تعليمات برمجية، لنفهم أهمية هذا المبدأ.

مبدأ AP2: فصل الأدوار

المشكلة في الوكلاء الذين "يفعلون كل شيء"

لنفترض أنّك استعنت بشخص واحد ليكون مستشارك المالي ومحاسبك ووسيطك الاستثماري. هل هذا مناسب؟ نعم. هل هي آمنة؟ قطعًا لا ستتضمّن ما يلي:

  • أهدافك الاستثمارية (دور المستشار)
  • إذن الوصول إلى حساباتك (دور المحاسب)
  • إذن بتحويل أموالك (دور الوسيط)

إذا تم اختراق حساب هذا الشخص أو ارتكب خطأً، ستكون كل البيانات في خطر.

حلّ AP2: موظّف دعم واحد، مهمة واحدة

تطبّق AP2 مبدأ فصل الاهتمامات لإنشاء حدود الثقة:

الهندسة المعمارية

سبب أهمية ذلك:

  • نطاق تأثير محدود: في حال اختراق "مساعد التسوّق"، لا يمكن للمهاجم الوصول إلى بيانات اعتماد الدفع.
  • الخصوصية: لا يرى موفّر بيانات الاعتماد محادثة التسوّق أبدًا.
  • ‫✅ الامتثال: يسهل استيفاء متطلبات معيار أمان بيانات قطاع بطاقات الدفع (PCI-DSS) عند عزل بيانات الدفع
  • ‫✅ المساءلة: تحديد المسؤولية بوضوح عن كل خطوة

طريقة تواصل العملاء: الحالة كدفتر ملاحظات مشترك

بما أنّ العملاء لا يمكنهم الوصول مباشرةً إلى بيانات بعضهم البعض، فإنّهم يتواصلون من خلال الحالة المشتركة. يمكنك التفكير في الأمر على أنّه لوحة بيضاء يمكن لجميع الموظفين الكتابة عليها والقراءة منها:

# Shopping Agent writes:
state["intent_mandate"] = {
    "natural_language_description": "Donate $50 to Room to Read",
    "merchants": ["Room to Read"],
    "intent_expiry": "2024-11-07T15:32:16Z",
    "amount": 50.0
}

# Merchant Agent reads:
intent = state["intent_mandate"]
charity_name = intent["merchants"][0]
amount = intent["amount"]
# Creates CartMandate based on IntentMandate...

# Credentials Provider reads:
cart_mandate = state["cart_mandate"]
# Processes payment...

هذه هي الطريقة التي نحافظ بها على حدود الثقة مع إتاحة التعاون.

أول وكيل لدينا: وكيل التسوّق

تتسم مسؤولية "وكيل التسوّق" بالبساطة والتركيز:

  1. استخدام أداة find_charities للاستعلام عن قاعدة البيانات الموثوقة
  2. عرض خيارات للمستخدم
  3. استخدِم الأداة save_user_choice لإنشاء IntentMandate وحفظها في الحالة
  4. تسليم المحادثة إلى الممثل التالي (التاجر)

انتهيت! لا يتم التعامل مع الدفعات أو إنشاء سلّة التسوّق، بل يتم فقط اكتشاف التطبيق وإحالته إلى المستخدم.

لننشئها خطوة بخطوة.

الخطوة 1: إضافة أداة مساعدة للتحقّق من صحة الإدخال

عند إنشاء أدوات إنتاج، تكون عملية التحقّق من صحة الإدخال أمرًا بالغ الأهمية. لننشئ دالة مساعدة تتحقّق من صحة بيانات المؤسسة الخيرية قبل حفظها في الحالة.

👉 فتح

charity_advisor/tools/charity_tools.py

ستظهر الدالة find_charities (المكتملة) في أعلى الصفحة. انتقِل للأسفل للعثور على ما يلي:

# MODULE_4_STEP_1_ADD_VALIDATION_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _validate_charity_data(charity_name: str, charity_ein: str, amount: float) -> tuple[bool, str]:
    """
    Validates charity selection data before saving to state.
    
    This helper function performs basic validation to ensure data quality
    before it gets passed to other agents in the pipeline.
    
    Args:
        charity_name: Name of the selected charity
        charity_ein: Employer Identification Number (should be format: XX-XXXXXXX)
        amount: Donation amount in USD
        
    Returns:
        (is_valid, error_message): Tuple where is_valid is True if all checks pass,
                                    and error_message contains details if validation fails
    """
    # Validate charity name
    if not charity_name or not charity_name.strip():
        return False, "Charity name cannot be empty"
    
    # Validate EIN format (should be XX-XXXXXXX)
    if not charity_ein or len(charity_ein) != 10 or charity_ein[2] != '-':
        return False, f"Invalid EIN format: {charity_ein}. Expected format: XX-XXXXXXX"
    
    # Validate amount
    if amount <= 0:
        return False, f"Donation amount must be positive, got: ${amount}"
    
    if amount > 1_000_000:
        return False, f"Donation amount exceeds maximum of $1,000,000: ${amount}"
    
    # All checks passed
    return True, ""

الخطوة 2: إضافة IntentMandate Creation Helper

لننشئ الآن أداة المساعدة التي تنشئ بنية AP2 IntentMandate. هذه هي إحدى الشهادات الرقمية القابلة للتحقّق الثلاث في AP2.

👉 في الملف نفسه، ابحث عن:

# MODULE_4_STEP_2_ADD_INTENTMANDATE_CREATION_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _create_intent_mandate(charity_name: str, charity_ein: str, amount: float) -> dict:
    """
    Creates an IntentMandate - AP2's verifiable credential for user intent.
    
    This function uses the official Pydantic model from the `ap2` package
    to create a validated IntentMandate object before converting it to a dictionary.
    
    Args:
        charity_name: Name of the selected charity
        charity_ein: Employer Identification Number
        amount: Donation amount in USD
        
    Returns:
        Dictionary containing the IntentMandate structure per AP2 specification
    """
    from datetime import datetime, timedelta, timezone
    from ap2.types.mandate import IntentMandate
    
    # Set the expiry for the intent
    expiry = datetime.now(timezone.utc) + timedelta(hours=1)
    
    # Step 1: Instantiate the Pydantic model with official AP2 fields
    intent_mandate_model = IntentMandate(
        user_cart_confirmation_required=True,
        natural_language_description=f"Donate ${amount:.2f} to {charity_name}",
        merchants=[charity_name],
        skus=None,
        requires_refundability=False,
        intent_expiry=expiry.isoformat()
    )
    
    # Step 2: Convert the validated model to a dictionary for state storage
    intent_mandate_dict = intent_mandate_model.model_dump()
    
    # Step 3: Add the codelab's custom fields to the dictionary
    timestamp = datetime.now(timezone.utc)
    intent_mandate_dict.update({
        "timestamp": timestamp.isoformat(),
        "intent_id": f"intent_{charity_ein.replace('-', '')}_{int(timestamp.timestamp())}",
        "charity_ein": charity_ein,
        "amount": amount,
        "currency": "USD"
    })
    
    return intent_mandate_dict

الخطوة 3: إنشاء أداة نقل الحالة باستخدام IntentMandate

لننشئ الآن الأداة التي تنشئ IntentMandate وتحفظها في الحالة.

👉 في الملف نفسه، انتقِل للأسفل إلى

save_user_choice

. البحث:

# MODULE_4_STEP_3_COMPLETE_SAVE_TOOL

👉 استبدِل هذا السطر الواحد بما يلي:

    # Validate inputs before creating IntentMandate
    is_valid, error_message = _validate_charity_data(charity_name, charity_ein, amount)
    if not is_valid:
        logger.error(f"Validation failed: {error_message}")
        return {"status": "error", "message": error_message}
    
    # Create AP2 IntentMandate using our updated helper function
    intent_mandate = _create_intent_mandate(charity_name, charity_ein, amount)
    
    # Write the IntentMandate to shared state for the next agent
    tool_context.state["intent_mandate"] = intent_mandate
    
    logger.info(f"Successfully created IntentMandate and saved to state")
    logger.info(f"Intent ID: {intent_mandate['intent_id']}")
    logger.info(f"Intent expires: {intent_mandate['intent_expiry']}")
    
    # Return success confirmation
    return {
        "status": "success",
        "message": f"Created IntentMandate: ${amount:.2f} donation to {charity_name} (EIN: {charity_ein})",
        "intent_id": intent_mandate["intent_id"],
        "expiry": intent_mandate["intent_expiry"]
    }

الخطوة 4: إضافة أداة مساعدة لتنسيق العرض

قبل إنشاء الوكيل، لنضِف أداة مساعدة أخرى تعمل على تنسيق بيانات المؤسسات الخيرية لعرضها بشكل سهل الاستخدام.

👉 انتقِل إلى:

# MODULE_4_STEP_4_ADD_FORMATTING_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _format_charity_display(charity: dict) -> str:
    """
    Formats a charity dictionary into a user-friendly display string.
    
    This helper function demonstrates how to transform structured data
    into readable text for the user.
    
    Args:
        charity: Dictionary containing charity data (name, ein, mission, rating, efficiency)
        
    Returns:
        Formatted string suitable for display to the user
    """
    name = charity.get('name', 'Unknown')
    ein = charity.get('ein', 'N/A')
    mission = charity.get('mission', 'No mission statement available')
    rating = charity.get('rating', 0.0)
    efficiency = charity.get('efficiency', 0.0)
    
    # Format efficiency as percentage
    efficiency_pct = int(efficiency * 100)
    
    # Build formatted string
    display = f"""
**{name}** (EIN: {ein})
⭐ Rating: {rating}/5.0
💰 Efficiency: {efficiency_pct}% of funds go to programs
📋 Mission: {mission}
    """.strip()
    
    return display

الخطوة 5: إنشاء "وكيل Shopping" - استيراد المكوّنات

بعد أن أصبحت أدواتنا كاملة وفعّالة، لننشئ الوكيل الذي سيستخدمها.

👉 فتح

charity_advisor/shopping_agent/agent.py

سيظهر لك نموذج يتضمّن تعليقات عنصر نائب. لننشئها خطوة بخطوة.

👉 البحث:

# MODULE_4_STEP_5_IMPORT_COMPONENTS

👉 استبدِل هذا السطر الواحد بما يلي:

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice

الخطوة 6: كتابة تعليمات الوكيل

في التعليمات، نحدّد الوصف الوظيفي للوكيل وسير العمل. هذا أمر بالغ الأهمية، لأنّ التعليمات المكتوبة بشكل سيئ تؤدي إلى سلوك غير موثوق به.

👉 البحث:

# MODULE_4_STEP_6_WRITE_INSTRUCTION
instruction="""""",

👉 استبدِل هذين السطرَين بما يلي:

    instruction="""You are a research specialist helping users find verified charities.

Your workflow:

1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
   use the find_charities tool to search our vetted database.

2. Present the results clearly. The tool returns formatted charity information that you should
   show to the user.

3. When the user selects a charity and specifies an amount, use the save_user_choice tool
   to create an IntentMandate and record their decision. You MUST call save_user_choice with:
   - charity_name: The exact name of the chosen charity
   - charity_ein: The EIN of the chosen charity  
   - amount: The donation amount in dollars (as a number, not a string)

4. After successfully saving, inform the user:
   - That you've created an IntentMandate (mention the intent ID if provided)
   - When the intent expires
   - That you're passing their request to the secure payment processor

IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done

WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required

This is the first of three verifiable credentials in our secure payment system.

If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",

الخطوة 7: إضافة أدوات إلى "الوكيل"

لنمنح الآن الوكيل إذن الوصول إلى كلتا الأداتين.

👉 البحث:

# MODULE_4_STEP_7_ADD_TOOLS

👉 استبدِل هذين السطرَين بما يلي:

    tools=[
        FunctionTool(func=find_charities),
        FunctionTool(func=save_user_choice)
    ]

الخطوة 8: تأكيد صحة معلومات الوكيل

دعنا نتأكّد من أنّ كل شيء موصول بشكل صحيح.

👉

charity_advisor/shopping_agent/agent.py

من المفترض أن يظهر بالشكل التالي:

"""
Shopping Agent - Finds charities from a trusted database and saves the user's choice.
This agent acts as our specialized "Research Analyst."
"""

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice


shopping_agent = Agent(
    name="ShoppingAgent",
    model="gemini-2.5-pro",
    description="Finds and recommends vetted charities from a trusted database, then creates an IntentMandate capturing the user's donation intent.",
    instruction="""You are a research specialist helping users find verified charities.

Your workflow:

1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
   use the find_charities tool to search our vetted database.

2. Present the results clearly. The tool returns formatted charity information that you should
   show to the user.

3. When the user selects a charity and specifies an amount, use the save_user_choice tool
   to create an IntentMandate and record their decision. You MUST call save_user_choice with:
   - charity_name: The exact name of the chosen charity
   - charity_ein: The EIN of the chosen charity  
   - amount: The donation amount in dollars (as a number, not a string)

4. After successfully saving, inform the user:
   - That you've created an IntentMandate (mention the intent ID if provided)
   - When the intent expires
   - That you're passing their request to the secure payment processor

IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done

WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required

This is the first of three verifiable credentials in our secure payment system.

If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",
    tools=[
        FunctionTool(func=find_charities),
        FunctionTool(func=save_user_choice)
    ]
)

ممتاز! لقد أنشأت وكيلًا متوافقًا مع AP2 وبجودة إنتاج عالية باستخدام ما يلي:

  • التحقّق من صحة البيانات المُدخَلة
  • إنشاء IntentMandate بشكل صحيح باستخدام نماذج AP2 Pydantic
  • الناتج المنسَّق
  • حدود الأدوار الواضحة
  • التعليمات التفصيلية
  • معالجة الأخطاء

الخطوة 9: اختبار "مساعد التسوّق"

لنتأكّد من أنّ الوكيل يعمل بشكلٍ صحيح، وينشئ IntentMandates مناسبة، ويحترم حدوده.

👉 في وحدة Cloud Shell الطرفية، نفِّذ ما يلي:

adk run charity_advisor/shopping_agent

ستظهر رسالة الطلب [user]:.

الاختبار 1: الاكتشاف باستخدام "قاعدة البيانات الموثوقة"

👉 النوع:

I want to donate to an education charity. What are my options?

بعد لحظات، سيقدّم الوكيل ردًا. بفضل _format_charity_display المساعد، يتم تنسيق النتائج بشكل جميل:

لقد عثرتُ على 3 مؤسسات خيرية معتمَدة في قاعدة بياناتنا:

مؤسسة Room to Read (رقم تعريف صاحب العمل: 77-0479905)
⭐ التقييم: 4.9/5.0
💰 الكفاءة: %88 من الأموال تُستخدم في البرامج
📋 المهمة: تغيير حياة ملايين الأطفال في المجتمعات المنخفضة الدخل من خلال التركيز على محو الأمية والمساواة بين الجنسين في التعليم

Teach For America (رقم تعريف صاحب العمل: 13-3541913)
⭐ التقييم: 4.7/5.0
💰 الكفاءة: %81 من الأموال تُخصّص للبرامج
📋 المهمة: تعمل هذه المؤسسة على توسيع فرص التعليم للأطفال الذين يواجهون صعوبات.

Tech Education Alliance (رقم تعريف صاحب العمل: 45-2345678)
⭐ التقييم: 4.8/5.0
💰 الكفاءة: %92 من الأموال تُستخدم في البرامج
📋 المهمة: توفير تعليم علوم الكمبيوتر للمدارس المحرومة

ما هي المؤسسة الخيرية التي تريد دعمها، وما هو المبلغ الذي تريد التبرّع به؟

قارِن هذا بالوكيل البسيط في الوحدة 3 الذي قدّم لك نتائج غير مدقَّقة من Google. هذا هو الفرق بين الاكتشاف غير الموثوق والاكتشاف الموثوق.

الاختبار 2: تسجيل خيار المستخدم وإنشاء IntentMandate

👉 النوع:

I'll donate $50 to Room to Read.

من المفترض أن ترى الوكيل يستدعي الأداة save_user_choice مع المَعلمات الصحيحة. بفضل ميزة إنشاء IntentMandate باستخدام نماذج AP2، ستظهر لك استجابة أكثر تنظيمًا:

ممتاز. لقد أنشأتُ IntentMandate لتبرّعك:

تفاصيل النية:

  • معرّف النية: intent_774795905_1730927536
  • المبلغ: 50.00 دولار أمريكي لصالح مؤسسة Room to Read (رقم تعريف صاحب العمل: 77-0479905)
  • تاريخ انتهاء الصلاحية: 2024-11-07T15:32:16Z (بعد ساعة واحدة)

تسجّل IntentMandate نية التبرّع وتتضمّن قيودًا لضمان معالجة المعاملة بأمان. سأرسل الآن هذه المعلومات إلى معالج الدفع الآمن لإنشاء عرض رسمي وإكمال تبرّعك.

في الخلفية، حدثت عدة أمور:

  1. _validate_charity_data() تم التحقّق من صحة الإدخالات
  2. استخدمت _create_intent_mandate() نموذج AP2 Pydantic لإنشاء البنية:
   # Created and validated via Pydantic
   intent_mandate_model = IntentMandate(
       user_cart_confirmation_required=True,
       natural_language_description="Donate $50.00 to Room to Read",
       merchants=["Room to Read"],
       skus=None,
       requires_refundability=False,
       intent_expiry="2024-11-07T15:32:16Z"
   )
   
   # Converted to dict and extended with custom fields
   intent_mandate_dict = intent_mandate_model.model_dump()
   intent_mandate_dict.update({
       "charity_ein": "77-0479905",
       "amount": 50.0,
       "currency": "USD"
   })
  1. كتبت الأداة IntentMandate فقط إلى الحالة المشتركة:
   state["intent_mandate"] = intent_mandate_dict
  1. تم عرض رسالة نجاح تتضمّن تفاصيل النية للنموذج اللغوي الكبير
  2. أنشأ النموذج اللغوي الكبير رسالة المستخدم النهائية

أصبحت IntentMandate جاهزة الآن ليتولّاها وكيل التاجر (الوحدة 5). سيستخرج التاجر اسم المؤسسة الخيرية والمبلغ من IntentMandate ويتأكّد من عدم انتهاء صلاحيته.

الاختبار 3: التحقّق من صحة البيانات أثناء التنفيذ

لنتأكّد من أنّ أداة التحقّق من الصحة ترصد الإدخالات غير الصالحة.

👉 النوع:

I'll donate -$25 to Room to Read.

على الوكيل رصد المبلغ غير الصالح:

واجهتُ مشكلة: يجب أن يكون مبلغ التبرّع موجبًا، ولكنّي تلقّيت: $-25.0

يُرجى تحديد مبلغ تبرّع موجب وسأُنشئ لك IntentMandate.

هذا هو أسلوب البرمجة الدفاعية في العمل. منع برنامج _validate_charity_data المساعد إدخال بيانات غير صالحة إلى النظام وإنشاء IntentMandate غير صالح.

الاختبار 4: التحقّق من حدود الثقة

👉 جرِّب أن تطلب من الوكيل معالجة الدفعة:

Now process my credit card payment.

على الوكيل رفض الطلب، مع احترام حدود دوره:

لا يمكنني معالجة الدفعات، فهذا ليس من مهامي. مهمتي هي مساعدتك في العثور على مؤسسات خيرية معتمَدة وإنشاء IntentMandate الذي يسجّل نية التبرّع.

تمّ إنشاء IntentMandate وإرساله إلى الجهة المسؤولة عن معالجة المعاملات الآمنة. سيُنشئ وكيل التاجر عرضًا رسميًا (CartMandate)، ثم سيتولّى مقدّم بيانات الاعتماد عملية الدفع الفعلية بموافقتك الصريحة.

هذا هو حد الثقة في العمل. يدرك الوكيل أنّه غير مسموح له بالتعامل مع بيانات الدفع، وتوجّهه تعليماته صراحةً إلى شرح ذلك للمستخدمين وتعريفهم بمفهوم IntentMandate.

👉 اضغط على

Ctrl+C

للخروج عند الانتهاء من الاختبار

ما أنشأته للتو

لقد نفّذت بنجاح الجزء الأول من بنية AP2 من خلال إنشاء IntentMandate بشكلٍ سليم باستخدام نماذج AP2 Pydantic.

المفاهيم الرئيسية التي تم إتقانها

البنية المستنِدة إلى الأدوار:

  • لكل وكيل مهمة واحدة محددة بوضوح
  • تتواصل البرامج من خلال الحالة المشتركة، وليس من خلال الوصول المباشر
  • تحدّ حدود الثقة من تأثير الاختراق

IntentMandate (AP2 Credential #1):

  • تم إنشاؤها باستخدام نماذج AP2 Pydantic الرسمية للتحقّق من الصحة
  • التقاط نية المستخدم بشكل منظَّم
  • يتضمّن تاريخ انتهاء صلاحية الأمان (يمنع هجمات إعادة الإرسال)
  • تحدّد هذه السمة القيود (التجّار وإمكانية استرداد الأموال والتأكيد).
  • وصف باللغة الطبيعية للبشر
  • تنسيق قابل للقراءة آليًا للوكلاء
  • التحقّق من صحة النموذج قبل تحويله إلى قاموس

الحالة كذاكرة مشترَكة:

  • tool_context.state هي "المفكرة" التي يمكن لجميع الوكلاء الوصول إليها
  • الكتابة إلى الحالة = إتاحة بيانات الاعتماد القابلة للتحقّق
  • القراءة من الحالة = استخدام بيانات الاعتماد والتحقّق من صحتها
  • تستخرج البرامج الوسيطة ما تحتاج إليه من بيانات الاعتماد

FunctionTool:

  • تحويل دوال Python إلى أدوات يمكن استدعاؤها من خلال النموذج اللغوي الكبير
  • الاعتماد على سلاسل المستندات وتلميحات الأنواع لفهم النموذج اللغوي الكبير
  • التعامل مع الاستدعاء تلقائيًا
  • إمكانية تركيب الأدوات: أدوات صغيرة ومركزة > أدوات شاملة

تعليمات الوكيل:

  • إرشادات مفصّلة لسير العمل
  • الحدود الواضحة ("لا تفعل...")
  • مواصفات المَعلمات لتجنُّب الأخطاء
  • التعريفات الفنية (ما هو IntentMandate)
  • التعامل مع الحالات القصوى (ماذا نقول عندما...)

الخطوات التالية

في الوحدة التالية، سننشئ وكيل التاجر لتلقّي IntentMandate وإنشاء بيانات الاعتماد الثانية التي يمكن التحقّق منها: CartMandate.

أنشأ "مساعد التسوّق" IntentMandate الذي يسجّل نية المستخدم مع تاريخ انتهاء الصلاحية. نحتاج الآن إلى وكيل لقراءة بيانات الاعتماد هذه والتحقّق من عدم انتهاء صلاحيتها وإنشاء عرض رسمي موقّع ينص على ما يلي: "أنا، التاجر، سألتزم بهذا السعر وسأقدّم هذه السلع".

لننشئ Merchant Agent ونرى بيانات اعتماد AP2 الثانية عمليًا.

5- إنشاء "وكيل التاجر" - عروض ملزمة وCartMandate

بانر

من الاكتشاف إلى الالتزام

في الوحدة السابقة، أنشأت "وكيل التسوّق"، وهو أداة متخصّصة في العثور على مؤسسات خيرية معتمَدة وإنشاء IntentMandate لتسجيل نية المستخدم. نحتاج الآن إلى وكيل لتلقّي IntentMandate وإنشاء عرض رسمي ملزِم.

هنا يأتي دور المبدأ الأساسي الثاني في AP2: المستندات القابلة للتحقّق من خلال CartMandate.

المبدأ 2 من AP: CartMandate & Binding Offers

سبب الحاجة إلى دور التاجر

في الوحدة 4، أنشأ "وكيل التسوّق" IntentMandate وحفظه في الحالة التالية:

state["intent_mandate"] = {
    "natural_language_description": "Donate $50 to Room to Read",
    "merchants": ["Room to Read"],
    "amount": 50.0,
    "intent_expiry": "2024-11-07T15:32:16Z"
}

لكنّ هذا مجرّد اهتمام المستخدم. قبل معالجة أي دفعة، نحتاج إلى ما يلي:

  • بنية عرض رسمي تفهمها أنظمة الدفع
  • مستند يثبت أنّ التاجر سيلتزم بهذا السعر
  • التزام ملزِم لا يمكن تغييره في منتصف المعاملة
  • التحقّق من عدم انتهاء صلاحية الغرض

هذه هي مهمة وكيل التاجر.

ما هي CartMandate؟

CartMandate هو مصطلح تستخدمه AP2 للإشارة إلى "سلة تسوّق رقمية" تعمل كعرض ملزِم. يتم تنظيمها وفقًا لمعيار PaymentRequest الصادر عن W3C، ما يعني:

  • تتعرّف الجهات المسؤولة عن معالجة المعاملات في جميع أنحاء العالم على هذا التنسيق
  • يحتوي على جميع تفاصيل المعاملات بطريقة موحّدة
  • يمكن توقيعها باستخدام التشفير لإثبات صحتها

يمكنك التفكير في الأمر على أنّه عرض أسعار مكتوب من مقاول:

  • ❌ لفظي: "نعم، يمكنني تنفيذ هذه المهمة مقابل حوالي خمسين دولارًا أمريكيًا"
  • ✅ عرض أسعار مكتوب: التكاليف المفصّلة والإجمالي والتوقيع والتاريخ

عرض الأسعار المكتوب ملزم. ‫CartMandate هو المكافئ الرقمي.

الرغبة في إضافة منتج إلى سلة التسوّق

بنية CartMandate

يحتوي CartMandate في AP2 على بنية متداخلة محدّدة:

cart_mandate = {
    "contents": {  # ← AP2 wrapper
        "id": "cart_xyz123",
        "cart_expiry": "2024-11-07T15:47:16Z",
        "merchant_name": "Room to Read",
        "user_cart_confirmation_required": False,
        
        "payment_request": {  # ← W3C PaymentRequest nested inside
            "method_data": [...],
            "details": {...},
            "options": {...}
        }
    },
    "merchant_authorization": "SIG_a3f7b2c8"  # ← Merchant signature
}

ثلاثة مكوّنات رئيسية:

‫1. contents: حاوية سلّة التسوّق التي تتضمّن:

  • معرّف سلة التسوّق وتاريخ انتهاء صلاحيتها
  • اسم التاجر
  • ‫PaymentRequest من W3C

‫2. payment_request (داخل المحتوى) - المنتج الذي يتم شراؤه:

  • method_data: أنواع الدفع المقبولة
  • التفاصيل: السلع والمجموع
  • خيارات: الشحن، متطلبات معلومات الدافع

‫3. merchant_authorization: التوقيع المشفّر

توقيعات التاجر: إثبات الالتزام

توقيع التاجر مهم للغاية. ويثبت ذلك ما يلي:

  • هذا العرض مقدَّم من بائع معتمَد
  • يلتزم التاجر بتطبيق هذا السعر الدقيق
  • لم يتم التلاعب بالعرض منذ إنشائه

في مرحلة الإنتاج، سيكون هذا توقيعًا مشفّرًا باستخدام PKI (البنية التحتية للمفاتيح العامة) أو JWT (رموز JSON المميّزة للويب). في ورشة العمل التعليمية، سنحاكي ذلك باستخدام تجزئة SHA-256.

# Production (real signature):
signature = sign_with_private_key(cart_data, merchant_private_key)

# Workshop (simulated signature):
cart_hash = hashlib.sha256(cart_json.encode()).hexdigest()
signature = f"SIG_{cart_hash[:16]}"

مهمتنا: إنشاء "وكيل التاجر"

سيتولّى وكيل التاجر المهام التالية:

  1. قراءة IntentMandate من الحالة (ما كتبه Shopping Agent)
  2. التحقّق من عدم انتهاء صلاحية Intent
  3. استخراج اسم المؤسسة الخيرية والمبلغ والتفاصيل الأخرى
  4. إنشاء بنية PaymentRequest متوافقة مع W3C باستخدام نماذج AP2 Pydantic
  5. Wrap it in AP2's CartMandate with expiry
  6. إضافة توقيع تاجر محاكى
  7. اكتب CartMandate إلى الحالة الخاصة بمزوّد بيانات الاعتماد (الوحدة التالية)

لننشئها خطوة بخطوة.

الخطوة 1: إضافة Expiry Validation Helper

أولاً، لنعدّ ملف الأدوات المتعلّقة بالتاجر ونضيف أداة مساعدة للتحقّق من انتهاء صلاحية IntentMandate.

👉 فتح

charity_advisor/tools/merchant_tools.py

لنضِفْ عملية التحقّق من تاريخ انتهاء الصلاحية:

👉 البحث:

# MODULE_5_STEP_1_ADD_EXPIRY_VALIDATION_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _validate_intent_expiry(intent_expiry_str: str) -> tuple[bool, str]:
    """
    Validates that the IntentMandate hasn't expired.
    
    This is a critical security check - expired intents should not be processed.
    
    Args:
        intent_expiry_str: The ISO 8601 timestamp string from the IntentMandate.
        
    Returns:
        (is_valid, error_message): Tuple indicating if intent is still valid.
    """
    try:
        # The .replace('Z', '+00:00') is for compatibility with older Python versions
        expiry_time = datetime.fromisoformat(intent_expiry_str.replace('Z', '+00:00'))
        now = datetime.now(timezone.utc)
        
        if expiry_time < now:
            return False, f"IntentMandate expired at {intent_expiry_str}"
        
        time_remaining = expiry_time - now
        logger.info(f"IntentMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
        
        return True, ""
        
    except (ValueError, TypeError) as e:
        return False, f"Invalid intent_expiry format: {e}"

الخطوة 2: إضافة أداة مساعدة لإنشاء التوقيع

لننشئ الآن دالة مساعدة تنشئ توقيع التاجر المحاكى.

👉 البحث:

# MODULE_5_STEP_2_ADD_SIGNATURE_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _generate_merchant_signature(cart_contents: CartContents) -> str:
    """
    Generates a simulated merchant signature for the CartMandate contents.
    
    In production, this would use PKI or JWT with the merchant's private key.
    For this codelab, we use a SHA-256 hash of the sorted JSON representation.
    
    Args:
        cart_contents: The Pydantic model of the cart contents to sign.
        
    Returns:
        Simulated signature string (format: "SIG_" + first 16 chars of hash).
    """
    # Step 1: Dump the Pydantic model to a dictionary. The `mode='json'` argument
    # ensures that complex types like datetimes are serialized correctly.
    cart_contents_dict = cart_contents.model_dump(mode='json')
    
    # Step 2: Use the standard json library to create a stable, sorted JSON string.
    # separators=(',', ':') removes whitespace for a compact and canonical representation.
    cart_json = json.dumps(cart_contents_dict, sort_keys=True, separators=(',', ':'))
    
    # Step 3: Generate SHA-256 hash.
    cart_hash = hashlib.sha256(cart_json.encode('utf-8')).hexdigest()
    
    # Step 4: Create signature in a recognizable format.
    signature = f"SIG_{cart_hash[:16]}"
    
    logger.info(f"Generated merchant signature: {signature}")
    return signature

الخطوة 3 (أ): إنشاء توقيع الأداة وإعدادها

لنبدأ الآن بإنشاء الأداة الرئيسية. سننشئها بشكل تدريجي على أربع خطوات فرعية. أولاً، توقيع الدالة والإعداد الأولي.

👉 البحث:

# MODULE_5_STEP_3A_CREATE_TOOL_SIGNATURE

👉 استبدِل هذا السطر الواحد بما يلي:

async def create_cart_mandate(tool_context: Any) -> Dict[str, Any]:
    """
    Creates a W3C PaymentRequest-compliant CartMandate from the IntentMandate.
    
    This tool reads the IntentMandate from shared state, validates it, and
    creates a formal, signed offer using the official AP2 Pydantic models.
    
    Returns:
        Dictionary containing status and the created CartMandate.
    """
    logger.info("Tool called: Creating CartMandate from IntentMandate")
    
    # MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC

الخطوة 3 (ب): إضافة منطق التحقّق

لنضِف الآن منطقًا لقراءة IntentMandate والتحقّق من صحتها باستخدام نماذج AP2 Pydantic، واستخراج البيانات التي نحتاج إليها.

👉 البحث:

# MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC

👉 استبدِل هذا السطر الواحد بما يلي:

    # 1. Read IntentMandate dictionary from state
    intent_mandate_dict = tool_context.state.get("intent_mandate")
    if not intent_mandate_dict:
        logger.error("No IntentMandate found in state")
        return {
            "status": "error",
            "message": "No IntentMandate found. Shopping Agent must create intent first."
        }
    
    # 2. Parse dictionary into a validated Pydantic model
    try:
        intent_mandate_model = IntentMandate.model_validate(intent_mandate_dict)
    except Exception as e:
        logger.error(f"Could not validate IntentMandate structure: {e}")
        return {"status": "error", "message": f"Invalid IntentMandate structure: {e}"}
    
    # 3. Validate that the intent hasn't expired (CRITICAL security check)
    is_valid, error_message = _validate_intent_expiry(intent_mandate_model.intent_expiry)
    if not is_valid:
        logger.error(f"IntentMandate validation failed: {error_message}")
        return {"status": "error", "message": error_message}
    
    # 4. Extract data. Safely access standard fields from the model, and
    # custom fields (like 'amount') from the original dictionary.
    charity_name = intent_mandate_model.merchants[0] if intent_mandate_model.merchants else "Unknown Charity"
    amount = intent_mandate_dict.get("amount", 0.0)
    
    # MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE

الخطوة 3C: إنشاء بنية CartMandate

الآن، لننشئ بنية PaymentRequest متوافقة مع W3C ونضمّنها في AP2 CartMandate باستخدام نماذج Pydantic.

👉 البحث:

# MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE

👉 استبدِل هذا السطر الواحد بما يلي:

    # 5. Build the nested Pydantic models for the CartMandate
    timestamp = datetime.now(timezone.utc)
    cart_id = f"cart_{hashlib.sha256(f'{charity_name}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}"
    cart_expiry = timestamp + timedelta(minutes=15)
    
    payment_request_model = PaymentRequest(
        method_data=[PaymentMethodData(
            supported_methods="CARD",
            data={"supported_networks": ["visa", "mastercard", "amex"], "supported_types": ["debit", "credit"]}
        )],
        details=PaymentDetailsInit(
            id=f"order_{cart_id}",
            display_items=[PaymentItem(
                label=f"Donation to {charity_name}",
                amount=PaymentCurrencyAmount(currency="USD", value=amount)  # Pydantic v2 handles float -> str conversion
            )],
            total=PaymentItem(
                label="Total Donation",
                amount=PaymentCurrencyAmount(currency="USD", value=amount)
            )
        ),
        options=PaymentOptions(request_shipping=False)
    )
    
    cart_contents_model = CartContents(
        id=cart_id,
        cart_expiry=cart_expiry.isoformat(),
        merchant_name=charity_name,
        user_cart_confirmation_required=False,
        payment_request=payment_request_model
    )
    
    # MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE

الخطوة 3D: إضافة التوقيع والحفظ في الحالة

أخيرًا، لنوقّع CartMandate باستخدام نموذج Pydantic ونحفظه في الحالة للوكيل التالي.

👉 البحث:

# MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE

👉 استبدِل هذا السطر الواحد بما يلي:

    # 6. Generate signature from the validated Pydantic model
    signature = _generate_merchant_signature(cart_contents_model)
    
    # 7. Create the final CartMandate model, now including the signature
    cart_mandate_model = CartMandate(
        contents=cart_contents_model,
        merchant_authorization=signature
    )
    
    # 8. Convert the final model to a dictionary for state storage and add the custom timestamp
    cart_mandate_dict = cart_mandate_model.model_dump(mode='json')
    cart_mandate_dict["timestamp"] = timestamp.isoformat()
    
    # 9. Write the final dictionary to state
    tool_context.state["cart_mandate"] = cart_mandate_dict
    
    logger.info(f"CartMandate created successfully: {cart_id}")
    
    return {
        "status": "success",
        "message": f"Created signed CartMandate {cart_id} for ${amount:.2f} donation to {charity_name}",
        "cart_id": cart_id,
        "cart_expiry": cart_expiry.isoformat(),
        "signature": signature
    }

الخطوة 4: إنشاء Merchant Agent - استيراد المكوّنات

لننشئ الآن الوكيل الذي سيستخدم هذه الأداة.

👉 فتح

charity_advisor/merchant_agent/agent.py

سيظهر لك نموذج يتضمّن علامات العناصر النائبة. لنبدأ باستيراد ما نحتاجه.

👉 البحث:

# MODULE_5_STEP_4_IMPORT_COMPONENTS

👉 استبدِل هذا السطر الواحد بما يلي:

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate

الخطوة 5: كتابة تعليمات "وكيل التاجر"

الآن، لنكتب التعليمات التي تحدّد للوكيل متى وكيف يستخدم أداته.

👉 البحث:

# MODULE_5_STEP_5_WRITE_INSTRUCTION
instruction="""""",

👉 استبدِل هذين السطرَين بما يلي:

    instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).

Your workflow:

1. Read the IntentMandate from shared state.
   The IntentMandate was created by the Shopping Agent and contains:
   - merchants: List of merchant names
   - amount: Donation amount
   - charity_ein: Tax ID
   - intent_expiry: When the intent expires

2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
   This tool will:
   - Validate the IntentMandate hasn't expired (CRITICAL security check)
   - Extract the charity name and amount from the IntentMandate
   - Create a structured offer with payment methods, transaction details, and merchant info
   - Generate a merchant signature to prove authenticity
   - Save the CartMandate to state for the payment processor

3. After creating the CartMandate, inform the user:
   - That you've created a formal, signed offer
   - The cart ID
   - When the cart expires (15 minutes)
   - That you're passing it to the secure payment processor

IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done

WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."

This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)

This is the second of three verifiable credentials in our secure payment system.""",

الخطوة 6: إضافة أدوات إلى "وكيل Merchant"

👉 البحث:

# MODULE_5_STEP_6_ADD_TOOLS
tools=[],

👉 استبدِل هذين السطرَين بما يلي:

    tools=[
        FunctionTool(func=create_cart_mandate)
    ],

الخطوة 7: التحقّق من اكتمال عملية دمج التاجر

لنؤكّد أنّ كل شيء موصول بشكل صحيح.

👉

charity_advisor/merchant_agent/agent.py

من المفترض أن يظهر بالشكل التالي:

"""
Merchant Agent - Creates W3C-compliant CartMandates with merchant signatures.
This agent acts as our "Contract Creator."
"""

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate


merchant_agent = Agent(
    name="MerchantAgent",
    model="gemini-2.5-flash",
    description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
    tools=[
        FunctionTool(func=create_cart_mandate)
    ],
    instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).

Your workflow:

1. Read the IntentMandate from shared state.
   The IntentMandate was created by the Shopping Agent and contains:
   - merchants: List of merchant names
   - amount: Donation amount
   - charity_ein: Tax ID
   - intent_expiry: When the intent expires

2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
   This tool will:
   - Validate the IntentMandate hasn't expired (CRITICAL security check)
   - Extract the charity name and amount from the IntentMandate
   - Create a structured offer with payment methods, transaction details, and merchant info
   - Generate a merchant signature to prove authenticity
   - Save the CartMandate to state for the payment processor

3. After creating the CartMandate, inform the user:
   - That you've created a formal, signed offer
   - The cart ID
   - When the cart expires (15 minutes)
   - That you're passing it to the secure payment processor

IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done

WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."

This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)

This is the second of three verifiable credentials in our secure payment system."""
)

نقطة التحقّق: لديك الآن "وكيل تاجر" كامل مع إنشاء CartMandate مناسب في AP2 باستخدام نماذج Pydantic.

الخطوة 8: اختبار "وكيل التاجر"

لننتحقق الآن من أنّ وكيلنا ينشئ CartMandates بشكل صحيح مع التواقيع ويتحقّق من تاريخ انتهاء الصلاحية.

إعداد الاختبار: تنفيذ نص الاختبار البرمجي

👉 في وحدة Cloud Shell الطرفية، نفِّذ ما يلي:

python scripts/test_merchant.py

الناتج المتوقّع:

======================================================================
MERCHANT AGENT TEST
======================================================================

Simulated IntentMandate from Shopping Agent:
  charity: Room to Read
  amount: $50.00
  expiry: 2024-11-07T16:32:16Z

----------------------------------------------------------------------
Merchant Agent Response:
----------------------------------------------------------------------
Perfect! I've received your IntentMandate and created a formal, signed offer (CartMandate) for your donation.

**CartMandate Details:**
- **Cart ID**: cart_3b4c5d6e7f8a
- **Donation Amount**: $50.00 to Room to Read
- **Payment Methods Accepted**: Credit/debit cards (Visa, Mastercard, Amex) or bank transfer
- **Cart Expires**: 2024-11-07T15:47:16Z (in 15 minutes)
- **Merchant Signature**: SIG_a3f7b2c8d9e1f4a2

This signed CartMandate proves my commitment to accept this donation amount. I'm now passing this to the secure payment processor to complete your transaction.

======================================================================
CARTMANDATE CREATED:
======================================================================
  ID: cart_3b4c5d6e7f8a
  Amount: 50.00
  Merchant: Room to Read
  Expires: 2024-11-07T15:47:16Z
  Signature: SIG_a3f7b2c8d9e1f4a2
======================================================================

الاختبار 2: التحقّق من الامتثال لمعايير W3C

لنتأكّد من أنّ بنية CartMandate متوافقة تمامًا مع كلّ من معيارَي AP2 وW3C PaymentRequest.

👉 تشغيل نص التحقّق من الصحة:

python scripts/validate_cartmandate.py

الناتج المتوقّع:

======================================================================
AP2 & W3C PAYMENTREQUEST VALIDATION
======================================================================
✅ CartMandate is AP2 and W3C PaymentRequest compliant

Structure validation passed:
  ✓ AP2 'contents' wrapper present
  ✓ AP2 'merchant_authorization' signature present
  ✓ cart_expiry present
  ✓ payment_request nested inside contents
  ✓ method_data present and valid
  ✓ details.total.amount present with currency and value
  ✓ All required W3C PaymentRequest fields present
======================================================================

ما أنشأته للتو

لقد نفّذت CartMandate من خلال AP2 بنجاح باستخدام نماذج Pydantic للحصول على البنية المناسبة والتحقّق من تاريخ انتهاء الصلاحية وتوقيعات التاجر.

المفاهيم الرئيسية التي تم إتقانها

‫✅ CartMandate (شهادة الاعتماد AP2 رقم 2):

  • تم إنشاؤها باستخدام نماذج AP2 Pydantic الرسمية
  • بنية AP2 مع غلاف المحتوى
  • W3C PaymentRequest متداخلة داخل
  • انتهاء صلاحية سلة التسوّق (أقصر من مدة النية)
  • توقيع التاجر على الالتزام الملزِم
  • يضمن التحقّق من صحة بيانات النموذج الامتثال للمواصفات

التحقّق من تاريخ انتهاء الصلاحية:

  • Reading IntentMandate from state
  • التحقّق من صحة البنية باستخدام IntentMandate.model_validate()
  • تحليل الطوابع الزمنية بتنسيق ISO 8601
  • المقارنة بالوقت الحالي
  • ميزة أمان تمنع المعالجة القديمة

توقيع التاجر:

  • إثبات الأصالة والالتزام
  • تم إنشاؤها من نموذج Pydantic تم التحقّق من صحته
  • استخدام model_dump(mode='json') للتمثيل الأساسي
  • محاكاة باستخدام SHA-256 لأغراض تعليمية
  • تستخدم مرحلة الإنتاج البنية الأساسية للمفتاح العام أو رمز JSON المميّز على الويب
  • توقيع نموذج المحتوى وليس القواميس

W3C PaymentRequest:

  • تم الإنشاء باستخدام نموذج PaymentRequest Pydantic الخاص بـ AP2
  • المعيار المتّبع في المجال لبيانات الدفع
  • متداخلة داخل بنية AP2
  • يحتوي على method_data والتفاصيل والخيارات
  • تفعيل إمكانية التشغيل التفاعلي

سلسلة بيانات الاعتماد مع النماذج:

  • Shopping → IntentMandate (تم التحقّق من صحته)
  • يقرأ التاجر IntentMandate → CartMandate (تم التحقّق من صحة كلا النموذجين)
  • سيقرأ "مزوّد بيانات الاعتماد" CartMandate → PaymentMandate
  • تتحقّق كل خطوة من صحة بيانات الاعتماد السابقة باستخدام Pydantic

‫✅ التطوير المستند إلى النماذج:

  • التحقّق من صحة البيانات المُدخَلة عبر model_validate()
  • إنشاء آمن من حيث النوع
  • التسلسل التلقائي من خلال model_dump()
  • أنماط جاهزة للاستخدام في بيئة الإنتاج

الخطوات التالية

في الوحدة التالية، سننشئ مزوّد بيانات الاعتماد لمعالجة الدفعات بأمان.

أنشأ "وكيل التاجر" عرضًا ملزمًا مع تاريخ انتهاء صلاحية باستخدام نماذج AP2. نحتاج الآن إلى وكيل لقراءة CartMandate والحصول على موافقة المستخدم وتنفيذ عملية الدفع.

لننشئ "مزوّد بيانات الاعتماد" ونكمل سلسلة بيانات اعتماد AP2.

6. إنشاء "مقدّم بيانات الاعتماد" - تنفيذ الدفع الآمن

بانر

من العرض الملزم إلى تنفيذ الدفع

في الوحدة التدريبية 5، أنشأت "وكيل التاجر"، وهو متخصص يقرأ IntentMandates ويتأكّد من أنّها لم تنتهِ صلاحيتها، وينشئ CartMandates ملزمة بتوقيعات التاجر. الآن، نحتاج إلى وكيل لتلقّي CartMandate وتنفيذ عملية الدفع الفعلية.

هنا يأتي دور المبدأ الثالث والأخير من مبادئ AP2، وهو تنفيذ الدفع الآمن من خلال PaymentMandate.

مبدأ AP2: تفويض الدفع وتنفيذه

سبب حاجتنا إلى دور مزوّد بيانات الاعتماد

في الوحدة 5، أنشأ "وكيل التاجر" CartMandate وحفظه في الحالة:

state["cart_mandate"] = {
    "contents": {
        "id": "cart_abc123",
        "cart_expiry": "2025-11-07:15:47:16Z",
        "payment_request": {
            "details": {
                "total": {
                    "amount": {"currency": "USD", "value": "50.00"}
                }
            }
        }
    },
    "merchant_authorization": "SIG_a3f7b2c8"
}

لكنّ هذا مجرّد عرض ملزِم. قبل تنفيذ عملية الدفع، نحتاج إلى:

  • التحقّق من عدم انتهاء صلاحية سلة التسوّق
  • موافقة المستخدم على مواصلة عملية الدفع
  • بيانات اعتماد تتيح تنفيذ الدفع
  • معالجة الدفعات الفعلية (أو المحاكاة في ورشة العمل)

هذه هي مهمة "مقدّم بيانات الاعتماد".

ما هي PaymentMandate؟

PaymentMandate هو مصطلح تستخدمه AP2 للإشارة إلى التفويض النهائي الذي يسمح بتنفيذ عملية الدفع. هذه هي شهادة الاعتماد الثالثة والأخيرة التي يمكن التحقّق منها في سلسلة AP2.

يمكنك اعتبار بيانات الاعتماد الثلاث بمثابة عملية توقيع عقد:

  • IntentMandate: "أريد شراء هذا المنتج" (خطاب إبداء الاهتمام)
  • CartMandate: "أنا التاجر، وأعرض البيع بهذا السعر" (عرض أسعار مكتوب)
  • PaymentMandate: "أفوّضك بخصم المبلغ من طريقة الدفع الخاصة بي" (عقد موقّع)

لا يمكن تنفيذ الدفع إلا بعد توفّر جميع بيانات الاعتماد الثلاث.

سلسلة بيانات الاعتماد الكاملة

The Structure of a PaymentMandate

يحتوي PaymentMandate في AP2 على بنية محدّدة:

payment_mandate = {
    "payment_mandate_contents": {  # ← AP2 wrapper
        "payment_mandate_id": "payment_xyz123",
        "payment_details_id": "cart_abc123",  # Links to CartMandate
        "user_consent": True,
        "consent_timestamp": "2025-11-07T15:48:00Z",
        "amount": {
            "currency": "USD",
            "value": "50.00"
        },
        "merchant_name": "Room to Read"
    },
    "agent_present": True,  # Human-in-the-loop flow
    "timestamp": "2025-11-07T15:48:00Z"
}

المكوّنات الرئيسية:

‫1. payment_mandate_contents: هو غلاف التفويض الذي يتضمّن:

  • payment_mandate_id: معرّف فريد
  • payment_details_id: رابط يؤدي إلى CartMandate
  • user_consent: ما إذا كان المستخدم قد وافق
  • المبلغ: مبلغ الدفعة (مستخرَج من CartMandate)

2. agent_present: ما إذا كان هذا مسارًا يتضمّن مشاركة بشرية

‫3. الطابع الزمني: وقت إنشاء التفويض

مهمتنا: إنشاء "مزوّد بيانات الاعتماد"

سيتولّى "مزوّد بيانات الاعتماد" ما يلي:

  1. قراءة CartMandate من الحالة (ما كتبه "وكيل التاجر")
  2. التحقّق من عدم انتهاء صلاحية سلة التسوّق باستخدام نماذج AP2 Pydantic
  3. استخراج تفاصيل الدفع من البنية المتداخلة
  4. إنشاء PaymentMandate مع موافقة المستخدم باستخدام نماذج AP2
  5. محاكاة معالجة الدفع (في مرحلة الإنتاج، سيتم استدعاء واجهة برمجة تطبيقات الدفع الحقيقية)
  6. كتابة PaymentMandate ونتيجة الدفع إلى الحالة

لننشئها خطوة بخطوة.

الخطوة 1: إضافة أداة مساعدة للتحقّق من صلاحية سلة التسوّق

أولاً، لننشئ أداة مساعدة للتأكّد من أنّ صلاحية CartMandate لم تنتهِ، تمامًا كما تأكّدنا من انتهاء صلاحية IntentMandate في الوحدة 5.

👉 فتح

charity_advisor/tools/payment_tools.py

لنضِفْ عملية التحقّق من تاريخ انتهاء الصلاحية:

👉 البحث:

# MODULE_6_STEP_1_ADD_CART_EXPIRY_VALIDATION_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _validate_cart_expiry(cart: CartMandate) -> tuple[bool, str]:
    """
    Validates that the CartMandate hasn't expired.
    
    This is a critical security check - expired carts should not be processed.
    
    Args:
        cart: The Pydantic CartMandate model to validate.
        
    Returns:
        (is_valid, error_message): Tuple indicating if cart is still valid.
    """
    try:
        expiry_str = cart.contents.cart_expiry
        expiry_time = datetime.fromisoformat(expiry_str.replace('Z', '+00:00'))
        now = datetime.now(timezone.utc)
        
        if expiry_time < now:
            return False, f"CartMandate expired at {expiry_str}"
        
        time_remaining = expiry_time - now
        logger.info(f"CartMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
        
        return True, ""
        
    except (ValueError, TypeError, AttributeError) as e:
        return False, f"Invalid cart_expiry format or structure: {e}"

الخطوة 2: إضافة PaymentMandate Creation Helper

لننشئ الآن أداة مساعدة تنشئ بنية PaymentMandate باستخدام نماذج AP2 Pydantic الرسمية.

👉 البحث:

# MODULE_6_STEP_2_ADD_PAYMENT_MANDATE_CREATION_HELPER

👉 استبدِل هذا السطر الواحد بما يلي:

def _create_payment_mandate(cart: CartMandate, consent_granted: bool) -> dict:
    """
    Creates a PaymentMandate using the official AP2 Pydantic models.
    
    It links to the CartMandate and includes user consent status.
    
    Args:
        cart: The validated Pydantic CartMandate model being processed.
        consent_granted: Whether the user has consented to the payment.
        
    Returns:
        A dictionary representation of the final, validated PaymentMandate.
    """
    timestamp = datetime.now(timezone.utc)
    
    # Safely extract details from the validated CartMandate model
    cart_id = cart.contents.id
    merchant_name = cart.contents.merchant_name
    total_item = cart.contents.payment_request.details.total
    
    # Create the nested PaymentResponse model for the mandate
    payment_response_model = PaymentResponse(
        request_id=cart_id,
        method_name="CARD",  # As per the simulated flow
        details={"token": "simulated_payment_token_12345"}
    )
    
    # Create the PaymentMandateContents model
    payment_mandate_contents_model = PaymentMandateContents(
        payment_mandate_id=f"payment_{hashlib.sha256(f'{cart_id}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}",
        payment_details_id=cart_id,
        payment_details_total=total_item,
        payment_response=payment_response_model,
        merchant_agent=merchant_name,
        timestamp=timestamp.isoformat()
    )
    
    # Create the top-level PaymentMandate model
    # In a real system, a user signature would be added to this model
    payment_mandate_model = PaymentMandate(
        payment_mandate_contents=payment_mandate_contents_model
    )
    
    # Convert the final Pydantic model to a dictionary for state storage
    final_dict = payment_mandate_model.model_dump(mode='json')
    
    # Add any custom/non-standard fields required by the codelab's logic to the dictionary
    # The spec does not have these fields, but your original code did. We add them
    # back to ensure compatibility with later steps.
    final_dict['payment_mandate_contents']['user_consent'] = consent_granted
    final_dict['payment_mandate_contents']['consent_timestamp'] = timestamp.isoformat() if consent_granted else None
    final_dict['agent_present'] = True
    
    return final_dict

الخطوة 3 (أ): إنشاء توقيع الأداة وإعدادها

لنبدأ الآن بإنشاء الأداة الرئيسية بشكل تدريجي. أولاً، توقيع الدالة والإعداد الأولي.

👉 البحث:

# MODULE_6_STEP_3A_CREATE_TOOL_SIGNATURE

👉 استبدِل هذا السطر الواحد بما يلي:

async def create_payment_mandate(tool_context: Any) -> Dict[str, Any]:
    """
    Creates a PaymentMandate and simulates payment processing using Pydantic models.
    
    This tool now reads the CartMandate from state, parses it into a validated model,
    and creates a spec-compliant PaymentMandate.
    """
    logger.info("Tool called: Creating PaymentMandate and processing payment")
    
    # MODULE_6_STEP_3B_VALIDATE_CARTMANDATE

الخطوة 3 (ب): التحقّق من صحة CartMandate

لنضِف الآن منطقًا لقراءة CartMandate والتحقّق من صحتها باستخدام نماذج AP2 Pydantic والتحقّق من تاريخ انتهاء الصلاحية.

👉 البحث:

# MODULE_6_STEP_3B_VALIDATE_CARTMANDATE

👉 استبدِل هذا السطر الواحد بما يلي:

    # 1. Read CartMandate dictionary from state
    cart_mandate_dict = tool_context.state.get("cart_mandate")
    if not cart_mandate_dict:
        logger.error("No CartMandate found in state")
        return { "status": "error", "message": "No CartMandate found. Merchant Agent must create cart first." }
    
    # 2. Parse dictionary into a validated Pydantic model
    try:
        cart_model = CartMandate.model_validate(cart_mandate_dict)
    except Exception as e:
        logger.error(f"Could not validate CartMandate structure: {e}")
        return {"status": "error", "message": f"Invalid CartMandate structure: {e}"}
    
    # 3. Validate that the cart hasn't expired using the Pydantic model
    is_valid, error_message = _validate_cart_expiry(cart_model)
    if not is_valid:
        logger.error(f"CartMandate validation failed: {error_message}")
        return {"status": "error", "message": error_message}
    
    # MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS

الخطوة 3C: استخراج تفاصيل الدفع من بنية متداخلة

لننتقل الآن إلى نموذج CartMandate الذي تم التحقّق من صحته لاستخراج تفاصيل الدفع التي نحتاج إليها.

👉 البحث:

# MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS

👉 استبدِل هذا السطر الواحد بما يلي:

    # 4. Safely extract data from the validated model
    cart_id = cart_model.contents.id
    merchant_name = cart_model.contents.merchant_name
    amount_value = cart_model.contents.payment_request.details.total.amount.value
    currency = cart_model.contents.payment_request.details.total.amount.currency
    consent_granted = True  # Assume consent for this codelab flow
    
    # MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE

الخطوة 3D: إنشاء PaymentMandate ومحاكاة الدفع

أخيرًا، لننشئ PaymentMandate باستخدام أداة المساعدة المستندة إلى Pydantic، ونحاكي عملية معالجة الدفع، ونحفظ كل شيء في الحالة.

👉 البحث:

# MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE

👉 استبدِل هذا السطر الواحد بما يلي:

    # 5. Create the spec-compliant PaymentMandate using the validated CartMandate model
    payment_mandate_dict = _create_payment_mandate(cart_model, consent_granted)
    
    # 6. Simulate payment processing
    transaction_id = f"txn_{hashlib.sha256(f'{cart_id}{datetime.now(timezone.utc).isoformat()}'.encode()).hexdigest()[:16]}"
    payment_result = {
        "transaction_id": transaction_id,
        "status": "completed",
        "amount": amount_value,
        "currency": currency,
        "merchant": merchant_name,
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "simulation": True
    }
    
    # 7. Write the compliant PaymentMandate dictionary and result to state
    tool_context.state["payment_mandate"] = payment_mandate_dict
    tool_context.state["payment_result"] = payment_result
    
    logger.info(f"Payment processed successfully: {transaction_id}")
    
    return {
        "status": "success",
        "message": f"Payment of {currency} {amount_value:.2f} to {merchant_name} processed successfully",
        "transaction_id": transaction_id,
        "payment_mandate_id": payment_mandate_dict["payment_mandate_contents"]["payment_mandate_id"]
    }

الخطوة 4: إنشاء "وكيل موفّر بيانات الاعتماد" - استيراد المكوّنات

لننشئ الآن الوكيل الذي يستخدم هذه الأداة.

👉 فتح

charity_advisor/credentials_provider/agent.py

سيظهر لك نموذج يتضمّن علامات العناصر النائبة. لنبدأ باستيراد ما نحتاجه.

👉 البحث:

# MODULE_6_STEP_4_IMPORT_COMPONENTS

👉 استبدِل هذا السطر الواحد بما يلي:

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate

الخطوة 5: كتابة تعليمات موفّر بيانات الاعتماد

الآن، لنكتب التعليمات التي توجّه الوكيل.

👉 البحث:

# MODULE_6_STEP_5_WRITE_INSTRUCTION
instruction="""""",

👉 استبدِل هذين السطرَين بما يلي:

    instruction="""You are a payment specialist responsible for securely processing payments with user consent.

Your workflow:

1. Read the CartMandate from shared state.
   The CartMandate was created by the Merchant Agent and has this structure:
   - contents: AP2 wrapper containing:
     - id: Cart identifier
     - cart_expiry: When the cart expires
     - merchant_name: Who is receiving payment
     - payment_request: W3C PaymentRequest with transaction details
   - merchant_authorization: Merchant's signature

2. Extract payment details from the nested structure:
   - Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
   - This gives you the currency and value

3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
   Before calling create_payment_mandate, you MUST:
   - Present the payment details clearly to the user
   - Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
   - WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
   - ONLY call create_payment_mandate AFTER receiving explicit confirmation
   - If user says "no" or "cancel", DO NOT call the tool

4. After user confirms, use the create_payment_mandate tool to:
   - Validate the CartMandate hasn't expired (CRITICAL security check)
   - Create a PaymentMandate (the third AP2 credential)
   - Simulate payment processing
   - Record the transaction result

5. After processing, inform the user:
   - That payment was processed successfully (this is a simulation)
   - The transaction ID
   - The amount and merchant
   - That this completes the three-agent AP2 credential chain

IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust

WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction

This is the third and final verifiable credential in our secure payment system.

THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)

Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust""",

الخطوة 6: إضافة "أدوات" إلى "موفّر بيانات الاعتماد"

👉 البحث:

# MODULE_6_STEP_6_ADD_TOOLS
tools=[],

👉 استبدِل هذين السطرَين بما يلي:

    tools=[
        FunctionTool(func=create_payment_mandate)
    ],

الخطوة 7: التحقّق من موفّر بيانات الاعتماد الكاملة

لنؤكّد أنّ كل شيء موصول بشكل صحيح.

👉

charity_advisor/credentials_provider/agent.py

من المفترض أن يظهر بالشكل التالي:

"""
Credentials Provider Agent - Handles payment processing with user consent.
This agent acts as our "Payment Processor."
"""

from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate


credentials_provider = Agent(
    name="CredentialsProvider",
    model="gemini-2.5-flash",
    description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
    tools=[
        FunctionTool(func=create_payment_mandate)
    ],
    instruction="""You are a payment specialist responsible for securely processing payments with user consent.

Your workflow:

1. Read the CartMandate from shared state.
   The CartMandate was created by the Merchant Agent and has this structure:
   - contents: AP2 wrapper containing:
     - id: Cart identifier
     - cart_expiry: When the cart expires
     - merchant_name: Who is receiving payment
     - payment_request: W3C PaymentRequest with transaction details
   - merchant_authorization: Merchant's signature

2. Extract payment details from the nested structure:
   - Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
   - This gives you the currency and value

3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
   Before calling create_payment_mandate, you MUST:
   - Present the payment details clearly to the user
   - Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
   - WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
   - ONLY call create_payment_mandate AFTER receiving explicit confirmation
   - If user says "no" or "cancel", DO NOT call the tool

4. After user confirms, use the create_payment_mandate tool to:
   - Validate the CartMandate hasn't expired (CRITICAL security check)
   - Create a PaymentMandate (the third AP2 credential)
   - Simulate payment processing
   - Record the transaction result

5. After processing, inform the user:
   - That payment was processed successfully (this is a simulation)
   - The transaction ID
   - The amount and merchant
   - That this completes the three-agent AP2 credential chain

IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust

WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction

This is the third and final verifiable credential in our secure payment system.

THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)

Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust"""
)

نقطة التحقّق: لديك الآن "مقدّم بيانات اعتماد" كامل مع إمكانية قراءة CartMandate وإنشاء PaymentMandate بشكل صحيح باستخدام نماذج AP2 Pydantic.

الخطوة 8: اختبار موفِّر بيانات الاعتماد

لننتحقق الآن من أنّ وكيلنا يعالج الدفعات بشكل صحيح ويكمل سلسلة بيانات الاعتماد.

👉 في وحدة Cloud Shell الطرفية، نفِّذ ما يلي:

python scripts/test_credentials_provider.py

الناتج المتوقّع:

======================================================================
CREDENTIALS PROVIDER TEST (MOCK - NO CONFIRMATION)
======================================================================

Simulated CartMandate from Merchant Agent:
  - Cart ID: cart_test123
  - Merchant: Room to Read
  - Amount: $50.00
  - Expires: 2025-11-07T15:47:16Z
  - Signature: SIG_test_signature

Calling Credentials Provider to process payment...
======================================================================
INFO:charity_advisor.tools.payment_tools:Tool called: Creating PaymentMandate and processing payment
INFO:charity_advisor.tools.payment_tools:CartMandate valid. Expires in 900 seconds
INFO:charity_advisor.tools.payment_tools:Payment processed successfully: txn_a3f7b2c8d9e1f4a2

======================================================================
CREDENTIALS PROVIDER RESPONSE:
======================================================================
I've successfully processed your payment. Here are the details:

**Payment Completed** (Simulated)
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Amount: USD 50.00
- Merchant: Room to Read
- Status: Completed

This completes the three-agent AP2 credential chain:
1.  Shopping Agent created IntentMandate (your intent)
2.  Merchant Agent created CartMandate (binding offer)
3.  Credentials Provider created PaymentMandate (payment authorization)

Your donation has been processed securely through our verifiable credential system.

======================================================================
PAYMENTMANDATE CREATED:
======================================================================
  Payment Mandate ID: payment_3b4c5d6e7f8a
  Linked to Cart: cart_test123
  User Consent: True
  Amount: USD 50.00
  Merchant: Room to Read
  Agent Present: True
======================================================================

======================================================================
PAYMENT RESULT:
======================================================================
  Transaction ID: txn_a3f7b2c8d9e1f4a2
  Status: completed
  Amount: USD 50.00
  Merchant: Room to Read
  Simulation: True
======================================================================

الخطوة 9: اختبار مسار المبيعات الكامل الذي يتضمّن ثلاثة وكلاء

لنختبر الآن جميع البرامج الثلاثة وهي تعمل معًا.

👉 تشغيل اختبار خط الأنابيب الكامل:

python scripts/test_full_pipeline.py

الناتج المتوقّع:

======================================================================
THREE-AGENT PIPELINE TEST (AP2 CREDENTIAL CHAIN)
======================================================================

[1/3] SHOPPING AGENT - Finding charity and creating IntentMandate...
----------------------------------------------------------------------
✓ IntentMandate created
  - Intent ID: intent_774799058_1730927536
  - Description: Donate $75.00 to Room to Read
  - Merchant: Room to Read
  - Amount: $75.0
  - Expires: 2025-11-07T16:32:16Z

[2/3] MERCHANT AGENT - Reading IntentMandate and creating CartMandate...
----------------------------------------------------------------------
✓ CartMandate created
  - ID: cart_3b4c5d6e7f8a
  - Expires: 2025-11-07T15:47:16Z
  - Signature: SIG_a3f7b2c8d9e1f4a2

[3/3] CREDENTIALS PROVIDER - Creating PaymentMandate and processing...
----------------------------------------------------------------------
NOTE: In the web UI, this would show a confirmation dialog
      For this test, consent is automatically granted
✓ Payment processed (SIMULATED)
  - Transaction ID: txn_a3f7b2c8d9e1f4a2
  - Amount: $75.0
  - Status: completed

======================================================================
COMPLETE AP2 CREDENTIAL CHAIN
======================================================================

✓ Credential 1: IntentMandate (User's Intent)
  - Intent ID: intent_774799058_1730927536
  - Description: Donate $75.00 to Room to Read
  - Expiry: 2025-11-07T16:32:16Z

✓ Credential 2: CartMandate (Merchant's Offer)
  - Cart ID: cart_3b4c5d6e7f8a
  - Cart Expiry: 2025-11-07T15:47:16Z
  - Merchant Signature: SIG_a3f7b2c8d9e1f4a2

✓ Credential 3: PaymentMandate (Payment Execution)
  - Payment Mandate ID: payment_3b4c5d6e7f8a
  - Linked to Cart: cart_3b4c5d6e7f8a
  - Agent Present: True

✓ Transaction Result:
  - Transaction ID: txn_a3f7b2c8d9e1f4a2
  - Simulation: True

======================================================================
✅ COMPLETE PIPELINE TEST PASSED
======================================================================

هذه هي سلسلة بيانات اعتماد AP2 الكاملة أثناء العمل!

كل وكيل:

  1. قراءة بيانات اعتماد من الحالة
  2. يتم التحقّق من صحة الرمز باستخدام نماذج Pydantic (البنية والتحقّق من تاريخ انتهاء الصلاحية).
  3. تنشئ هذه السمة بيانات الاعتماد التالية باستخدام نماذج AP2
  4. كتابة الحالة لموظف الدعم التالي

ما أنشأته للتو

لقد أكملت بنجاح سلسلة بيانات اعتماد AP2 الثلاثية مع التحقّق من صحة البنية باستخدام نماذج Pydantic ومحاكاة الدفع.

المفاهيم الرئيسية التي تم إتقانها

PaymentMandate (AP2 Credential #3):

  • تم إنشاؤها باستخدام نماذج AP2 Pydantic الرسمية
  • بيانات الاعتماد النهائية التي تسمح بتنفيذ الدفع
  • روابط إلى CartMandate من خلال payment_details_id
  • تسجيل موافقة المستخدم والطابع الزمني
  • تحتوي على مبلغ الدفع المستخرَج من CartMandate
  • تتضمّن علامة agent_present للإشارة إلى مشاركة الإنسان
  • يضمن التحقّق من صحة بيانات النموذج الامتثال للمواصفات

القراءة من CartMandate:

  • التحقّق من صحة البنية باستخدام CartMandate.model_validate()
  • الوصول إلى السمات الآمنة من حيث النوع: cart_model.contents.payment_request.details.total.amount
  • فهم الفرق بين أداة تضمين AP2 وفصل معيار W3C
  • استخراج merchant_name والمبلغ والعملة بأمان من النموذج
  • يرصد Pydantic أخطاء البنية تلقائيًا

التحقّق من تاريخ انتهاء صلاحية سلة التسوّق:

  • يقبل CartMandate نموذج Pydantic تم التحقّق من صحته
  • القراءة من cart.contents.cart_expiry (إذن الوصول إلى السمة)
  • ميزة الأمان التي تمنع معالجة سلة التسوق القديمة
  • مدة أقصر (15 دقيقة) من مدة البحث عن النية (ساعة واحدة)

محاكاة الدفع:

  • محاكاة تعليمية لجهة مسؤولة عن معالجة المعاملات
  • إنشاء معرّف المعاملة
  • تسجيل payment_result في الحالة
  • يجب أن يتم تصنيفها بوضوح على أنّها محاكاة (العلامة: True)

إكمال سلسلة AP2 باستخدام النماذج:

  • ثلاثة وكلاء وثلاثة بيانات اعتماد وثلاث عمليات تحقق من صحة Pydantic
  • يتحقّق كل وكيل من بنية بيانات الاعتماد السابقة باستخدام النماذج
  • يرتبط كل مستند اعتماد بالمستند السابق لتتبُّع سجلّ التدقيق
  • تحافظ عمليات التسليم المستندة إلى الحالة على فصل الأدوار
  • منع أخطاء الكتابة في جميع مراحل السلسلة

‫✅ التطوير المستند إلى النماذج:

  • التحقّق من صحة البيانات المُدخَلة عبر model_validate()
  • إنشاء آمن من حيث النوع باستخدام نماذج متداخلة
  • التسلسل التلقائي من خلال model_dump(mode='json')
  • أنماط جاهزة للاستخدام في مرحلة الإنتاج من البداية

الخطوات التالية

في الوحدة التالية، سننشئ وكيل التنسيق الذي ينسّق عمل جميع الوكلاء المتخصّصين الثلاثة.

لقد أنشأت ثلاثة وكلاء متخصصين فعّالين باستخدام نماذج AP2 Pydantic. لننشئ الآن أداة التنسيق التي تنظّم هذه الخطوات في تجربة تبرّع سلسة.

لننشئ Orchestrator ونرى النظام الكامل أثناء العمل.

7. التنسيق: الجمع بين كل العناصر

مسار التعلّم التسلسلي

من المتخصّصين إلى التجربة السلسة

في الوحدات السابقة، أنشأت ثلاثة وكلاء متخصصين:

  • Shopping Agent: يعثر على مؤسسات خيرية وينشئ IntentMandate
  • وكيل التاجر: ينشئ CartMandate من IntentMandate
  • موفّر بيانات الاعتماد: ينشئ PaymentMandate ويعالج عملية الدفع

وتنقسم هذه البرامج إلى مرحلتَين:

  • المرحلة 1 (التسوّق): محادثة متعدّدة الأدوار للعثور على مؤسسة خيرية واختيارها
  • المرحلة 2 (المعالجة): التنفيذ الذري لعملية إنشاء العرض الترويجي والدفع

ولكن في الوقت الحالي، عليك تنسيق هذه المراحل يدويًا.

وهنا تبرز أنماط التنسيق في "مجموعة أدوات تطوير التطبيقات".

المبدأ 2 من AP: يفرض التنظيم حدود الثقة

أهمية التنسيق في مجال الأمان

لا يقتصر التنسيق على توفير الراحة، بل يهدف أيضًا إلى فرض حدود الثقة من خلال البنية.

بدون تنظيم:

# User could accidentally skip steps or reorder them
shopping_agent.run("Find charity")
# Oops, forgot to create CartMandate!
credentials_provider.run("Process payment")  # No offer to validate!

باستخدام التنسيق:

# Pipeline enforces correct order
donation_processing_pipeline = SequentialAgent(
    sub_agents=[
        merchant_agent,      # Must run first
        credentials_provider # Must run second
    ]
)
# Steps ALWAYS run in order, no skipping allowed

يضمن مسار المعالجة التسلسلي ما يلي:

  • ‫✅ IntentMandate تم إنشاؤه قبل CartMandate
  • ‫✅ تم إنشاء تفويض CartMandate قبل معالجة الدفع
  • ‫✅ يتم تشغيل كل وكيل في سياقه المعزول
  • ‫✅ تنتقل الحالة إلى الأمام خلال سلسلة بيانات الاعتماد

مهمتنا: إنشاء نظام متكامل

سننشئ طبقتَين:

الطبقة 1: مسار المعالجة (SequentialAgent)

  • Wires together Merchant → Credentials
  • يتم تشغيلها تلقائيًا بالتسلسل بعد اختيار المؤسسة الخيرية
  • التنفيذ الذري للعرض والدفع

الطبقة 2: أداة التنسيق الرئيسية (الوكيل الذي يتفاعل معه المستخدم)

  • شخصية ودودة
  • تفويض إلى shopping_agent لاختيار مؤسسة خيرية
  • يتم تفويض عملية المعالجة إلى مسار المعالجة بعد إنشاء IntentMandate
  • التعامل مع المحادثات والتغيّرات الطورية

يتطابق هذا النهج المكوّن من طبقتين مع التدفق الطبيعي:

  • مرحلة التسوّق: محادثة متعدّدة الأدوار (يتصفّح المستخدم، ويطرح أسئلة، ويتّخذ قرارًا)
  • مرحلة المعالجة: التنفيذ الذري (العرض → الدفع)

لننشئ كليهما.

الخطوة 1: استيراد مكوّنات التنسيق

أولاً، لنعدّ ملف التنسيق مع عمليات الاستيراد اللازمة.

👉 فتح

charity_advisor/agent.py

لنبدأ بعمليات الاستيراد:

👉 البحث:

# MODULE_7_STEP_1_IMPORT_COMPONENTS

👉 استبدِل هذا السطر الواحد بما يلي:

from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider

الخطوة 2: إنشاء مسار المعالجة

لننشئ الآن مسار العرض الذي ينفّذ عملية إنشاء العروض ومعالجة الدفعات بشكل متزامن.

👉 البحث:

# MODULE_7_STEP_2_CREATE_SEQUENTIAL_PIPELINE

👉 استبدِل هذين السطرَين بما يلي:

# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
    name="DonationProcessingPipeline",
    description="Creates signed offer and processes payment after charity is selected",
    sub_agents=[
        merchant_agent,
        credentials_provider
    ]
)

الخطوة 3 (أ): إنشاء إعدادات وكيل الجذر

الآن، لننشئ الوكيل المخصّص للمستخدمين والذي ينسّق كلتا المرحلتين. سننشئ هذا النظام على ثلاثة أجزاء: الإعداد (3A) والتعليمات (3B) والوكلاء الفرعيون (3C).

👉 البحث:

# MODULE_7_STEP_3A_CREATE_ROOT_AGENT_SETUP

👉 استبدِل هذا السطر الواحد بما يلي:

# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
    name="CharityAdvisor",
    model="gemini-2.5-pro",
    description="A friendly charity giving assistant that helps users donate to verified organizations.",
    # MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION

الخطوة 3 (ب): كتابة تعليمات الوكيل الأساسي

لنضِف الآن التعليمات التي توجّه سلوك مستشار المؤسسة الخيرية في كلتا المرحلتين.

👉 البحث:

# MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION

👉 استبدِل هذا السطر الواحد بما يلي:

    instruction="""You are a helpful and friendly charity giving advisor.

Your workflow has TWO distinct phases:

PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
   - Search for charities matching their cause
   - Present verified options with ratings
   - Engage in conversation (user may ask questions, change their mind)
   - Wait for user to select a specific charity and amount
   - Create an IntentMandate when user decides
3. Wait for shopping_agent to complete

You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx" 
- Charity name and donation amount

PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
   "Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
   - Create signed cart offer (MerchantAgent)
   - Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction

CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically

EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"

Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS

الخطوة 3C: إضافة الوكلاء الفرعيين

أخيرًا، لنمنح مستشار المؤسسة الخيرية إذن الوصول إلى كل من وكيل التسوّق ومسار المعالجة، ولنغلق تعريف الوكيل.

👉 البحث:

# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS

👉 استبدِل هذا السطر الواحد بما يلي:

    sub_agents=[
        shopping_agent,
        donation_processing_pipeline
    ]
)

الخطوة 4: التحقّق من اكتمال النظام

دعنا نتأكّد من أنّ عملية التنسيق تم إعدادها بشكلٍ صحيح.

👉

charity_advisor/agent.py

من المفترض أن يظهر بالشكل التالي:

"""
Main orchestration: The donation processing pipeline and root orchestrator agent.
"""

from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider

# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
    name="DonationProcessingPipeline",
    description="Creates signed offer and processes payment after charity is selected",
    sub_agents=[
        merchant_agent,
        credentials_provider
    ]
)

# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
    name="CharityAdvisor",
    model="gemini-2.5-flash",
    description="A friendly charity giving assistant that helps users donate to verified organizations.",
    instruction="""You are a helpful and friendly charity giving advisor.

Your workflow has TWO distinct phases:

PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
   - Search for charities matching their cause
   - Present verified options with ratings
   - Engage in conversation (user may ask questions, change their mind)
   - Wait for user to select a specific charity and amount
   - Create an IntentMandate when user decides
3. Wait for shopping_agent to complete

You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx" 
- Charity name and donation amount

PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
   "Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
   - Create signed cart offer (MerchantAgent)
   - Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction

CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically

EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"

Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
    sub_agents=[
        shopping_agent,
        donation_processing_pipeline
    ]
)

الخطوة 5: تعزيز الأمان باستخدام عمليات ردّ الاتصال للتحقّق من الصحة (يمكن الانتقال إلى الخطوة 7)

عمليات إعادة الاستدعاء

يضمن SequentialAgent ترتيب التنفيذ، ولكن ماذا لو:

  • تعطُّل Shopping Agent بدون إظهار أي رسالة خطأ (لم يتم إنشاء IntentMandate أبدًا)
  • مرّت ساعة بين Shopping وMerchant (انتهت صلاحية النية)
  • تلف الحالة أو محوها
  • يحاول مستخدم الاتصال بالتاجر مباشرةً بدون استخدام Shopping

عمليات رد الاتصال تضيف فرضًا معماريًا: تتحقّق من المتطلبات الأساسية قبل أن يبدأ الوكيل حتى في طلب LLM. هذا هو الدفاع المتعمّق: تتحقّق الأدوات من صحة البيانات أثناء التنفيذ، وتتحقّق عمليات معاودة الاتصال من صحة البيانات قبل التنفيذ.

لنضِف الآن عمليات ردّ الاتصال الخاصة بالتحقّق من الصحة إلى وكيلَي Merchant وCredentials Provider.

الخطوة 5 (أ): إضافة عملية التحقّق من التاجر - استيراد أنواع عمليات ردّ الاتصال

أولاً، لنضِف عمليات الاستيراد اللازمة لوظائف معاودة الاتصال.

👉 فتح

charity_advisor/merchant_agent/agent.py

في أعلى الملف، بعد عمليات الاستيراد الحالية، أضِف ما يلي:

from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging

logger = logging.getLogger(__name__)

الخطوة 5B: إنشاء دالة التحقّق من صحة الغرض

لننشئ الآن دالة ردّ تتأكّد من صحة IntentMandate قبل أن يتم تشغيل Merchant Agent.

👉 في

charity_advisor/merchant_agent/agent.py

، أضِف هذه الدالة قبل

merchant_agent = Agent(...)

التعريف:

def validate_intent_before_merchant(
    callback_context: CallbackContext,
) -> Optional[Content]:
    """
    Validates IntentMandate exists and hasn't expired before Merchant runs.
    
    This callback enforces that the Shopping Agent completed successfully
    before the Merchant Agent attempts to create a CartMandate.
    
    Returns:
        None: Allow Merchant Agent to proceed normally
        Content: Skip Merchant Agent and return error to user
    """
    state = callback_context.state
    
    # Check credential exists
    if "intent_mandate" not in state:
        logger.error("❌ IntentMandate missing - Shopping Agent may have failed")
        return Content(parts=[Part(text=(
            "Error: Cannot create cart. User intent was not properly recorded. "
            "Please restart the donation process."
        ))])
    
    intent_mandate = state["intent_mandate"]
    
    # Validate expiry (critical security check)
    try:
        expiry_time = datetime.fromisoformat(
            intent_mandate["intent_expiry"].replace('Z', '+00:00')
        )
        now = datetime.now(timezone.utc)
        
        if expiry_time < now:
            logger.error(f"❌ IntentMandate expired at {intent_mandate['intent_expiry']}")
            return Content(parts=[Part(text=(
                "Error: Your donation intent has expired. "
                "Please select a charity again to restart."
            ))])
        
        time_remaining = expiry_time - now
        logger.info(f"✓ IntentMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
        
    except (KeyError, ValueError) as e:
        logger.error(f"❌ Invalid IntentMandate structure: {e}")
        return Content(parts=[Part(text=(
            "Error: Invalid intent data. Please restart the donation."
        ))])
    
    # All checks passed - allow Merchant Agent to proceed
    logger.info(f"✓ Prerequisites met for Merchant Agent: {intent_mandate['intent_id']}")
    return None

الخطوة 5 (ج): ربط ميزة "معاودة الاتصال" بموظف دعم التاجر

لنربط الآن معاودة الاتصال بموظف الدعم.

👉 في

charity_advisor/merchant_agent/agent.py

، عدِّل

merchant_agent = Agent(...)

التعريف:

ابحث عن هذا السطر في تعريف الوكيل:

merchant_agent = Agent(
    name="MerchantAgent",
    model="gemini-2.5-flash",
    description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",

أضِف هذا السطر بعد مباشرةً

description

line:

    before_agent_callback=validate_intent_before_merchant,

يجب أن يبدو تعريف الموظف الآن على النحو التالي:

merchant_agent = Agent(
    name="MerchantAgent",
    model="gemini-2.5-flash",
    description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
    before_agent_callback=validate_intent_before_merchant,
    tools=[
        FunctionTool(func=create_cart_mandate)
    ],
    instruction="""..."""
)

الخطوة 6: إضافة عملية التحقّق من صحة موفّر بيانات الاعتماد (يمكن الانتقال إلى الخطوة 7)

النمط نفسه - لنضِف عملية التحقّق من صحة البيانات في خطوة الدفع.

الخطوة 6 (أ): استيراد أنواع معاودة الاتصال

👉 فتح

charity_advisor/credentials_provider/agent.py

في أعلى الملف، بعد عمليات الاستيراد الحالية، أضِف ما يلي:

from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging

logger = logging.getLogger(__name__)

الخطوة 6 (ب): إنشاء وظيفة التحقّق من صحة سلة التسوّق

👉 في

charity_advisor/credentials_provider/agent.py

، أضِف هذه الدالة قبل

credentials_provider = Agent(...)

التعريف:

def validate_cart_before_payment(
    callback_context: CallbackContext,
) -> Optional[Content]:
    """
    Validates CartMandate exists and hasn't expired before payment processing.
    
    This callback enforces that the Merchant Agent completed successfully
    before the Credentials Provider attempts to process payment.
    
    Returns:
        None: Allow Credentials Provider to proceed
        Content: Skip payment processing and return error
    """
    state = callback_context.state
    
    # Check credential exists
    if "cart_mandate" not in state:
        logger.error("❌ CartMandate missing - Merchant Agent may have failed")
        return Content(parts=[Part(text=(
            "Error: Cannot process payment. Cart was not properly created. "
            "Please restart the donation process."
        ))])
    
    cart_mandate = state["cart_mandate"]
    
    # Validate AP2 structure
    if "contents" not in cart_mandate:
        logger.error("❌ CartMandate missing AP2 contents wrapper")
        return Content(parts=[Part(text=(
            "Error: Invalid cart structure. Please restart."
        ))])
    
    # Validate expiry
    try:
        contents = cart_mandate["contents"]
        expiry_time = datetime.fromisoformat(
            contents["cart_expiry"].replace('Z', '+00:00')
        )
        now = datetime.now(timezone.utc)
        
        if expiry_time < now:
            logger.error(f"❌ CartMandate expired at {contents['cart_expiry']}")
            return Content(parts=[Part(text=(
                "Error: Your cart has expired (15 minute limit). "
                "Please restart the donation to get a fresh offer."
            ))])
        
        time_remaining = expiry_time - now
        logger.info(f"✓ CartMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
        
    except (KeyError, ValueError) as e:
        logger.error(f"❌ Invalid CartMandate structure: {e}")
        return Content(parts=[Part(text=(
            "Error: Invalid cart data. Please restart the donation."
        ))])
    
    # All checks passed - allow payment processing
    logger.info(f"✓ Prerequisites met for Credentials Provider: {contents['id']}")
    return None

الخطوة 6C: ربط دالة معاودة الاتصال بموفّر بيانات الاعتماد

👉 في

charity_advisor/credentials_provider/agent.py

، عدِّل

credentials_provider = Agent(...)

التعريف:

ابحث عن هذا السطر في تعريف الوكيل:

credentials_provider = Agent(
    name="CredentialsProvider",
    model="gemini-2.5-flash",
    description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",

أضِف هذا السطر بعد مباشرةً

description

line:

    before_agent_callback=validate_cart_before_payment,

يجب أن يبدو تعريف الموظف الآن على النحو التالي:

credentials_provider = Agent(
    name="CredentialsProvider",
    model="gemini-2.5-flash",
    description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
    before_agent_callback=validate_cart_before_payment,
    tools=[
        FunctionTool(func=create_payment_mandate)
    ],
    instruction="""..."""
)

الخطوة 7: الاختبار باستخدام واجهة مستخدم الويب الخاصة بـ ADK

لنختبر الآن النظام الكامل المحسّن مع تفعيل عمليات معاودة الاتصال للتحقّق من الصحة.

👉 في وحدة Cloud Shell الطرفية، نفِّذ ما يلي:

adk web

من المفترَض أن تظهر لك نتيجة مثل:

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 بعد ذلك، للوصول إلى واجهة مستخدم ADK على الويب من المتصفّح، اتّبِع الخطوات التالية:

من رمز معاينة الويب (يبدو كعين أو مربّع يحتوي على سهم) في شريط أدوات Cloud Shell (عادةً في أعلى يسار الصفحة)، اختَر تغيير المنفذ. في النافذة المنبثقة، اضبط المنفذ على 8000 وانقر على "تغيير ومعاينة". سيفتح Cloud Shell بعد ذلك علامة تبويب متصفّح جديدة تعرض واجهة مستخدم الويب الخاصة بـ ADK.

webpreview

👉 اختَر وكيلك من القائمة المنسدلة:

في واجهة مستخدم الويب الخاصة بـ ADK، ستظهر قائمة منسدلة في أعلى الصفحة. اختَر charity_advisor من القائمة.

agent-select

ستظهر لك واجهة ADK على الويب مع ما يلي:

  • لوحة المحادثة: على الجانب الأيمن، لعرض المحادثة
  • لوحة التتبُّع: على يسار الصفحة، تُستخدَم في إمكانية المراقبة (سنستخدمها في الوحدة التدريبية 9)

الاختبار 1: إكمال خطوات التبرّع (الحالة العادية)

👉 في واجهة المحادثة، اكتب:

I want to donate to an education charity

يمكنك مشاهدة العملية الكاملة:

وكيل التسوّق على الويب من ADK

adk web donation processing pipeline

ما يحدث (يظهر في لوحة التتبُّع على يسار الصفحة):

1. تفويض المستشار إلى ShoppingAgent:

  • يبحث ShoppingAgent عن مؤسسات خيرية تعليمية
  • تعرض لك هذه الميزة 3 خيارات تم التحقّق منها مع التفاصيل

2. التفاعل مع ShoppingAgent (قد يستغرق عدة جولات):

User: "Tell me more about Room to Read"
Shopping: [explains mission and impact]
User: "I'll donate $50 to Room to Read"

3. ينشئ ShoppingAgent IntentMandate:

  • إنشاء النية وتوقيعها
  • تأكيد عمليات الإرجاع باستخدام معرّف Intent

4. انتقال "الأداة الاستشارية" إلى مرحلة المعالجة:

ممتاز. جارٍ معالجة تبرّعك بقيمة 50 دولار أمريكي إلى مؤسسة Room to Read...

5. يتم تفعيل DonationProcessingPipeline عند:

  • يتحقّق برنامج ردّ الاتصال الخاص بالتاجر من صحة IntentMandate (تمت الموافقة ✓) ← جديد
  • ينشئ "وكيل التاجر" CartMandate مع توقيع
  • تتحقّق وظيفة معاودة الاتصال الخاصة ببيانات الاعتماد من صحة CartMandate (تمت الموافقة ✓) ← جديد
  • يُعدّ "مزوّد بيانات الاعتماد" عملية الدفع

6- عمليات الدفع:

  • ينشئ "مزوّد بيانات الاعتماد" مستند PaymentMandate
  • محاكاة معالجة الدفعات
  • معرّف معاملة المرتجعات

7- ملخّص من "المستشار":

ممتاز. تمت معالجة تبرّعك بنجاح. 🎉

التفاصيل:

  • المبلغ: 50.00 دولار أمريكي
  • مؤسسة Room to Read الخيرية (رقم تعريف صاحب العمل: ‎77-0479905)
  • معرّف المعاملة: txn_a3f7b2c8d9e1f4a2

الاختبار 2: التحقّق من أنّ عمليات معاودة الاتصال ترصد حالات الأعطال (اختبار متقدّم اختياري)

هل تريد الاطّلاع على عمليات معاودة الاتصال أثناء رصد الأخطاء؟ عليك إتلاف الحالة يدويًا (تصحيح الأخطاء المتقدّم)، ولكن في مرحلة الإنتاج، ستلتقط عمليات معاودة الاتصال ما يلي:

  • تعذُّر استخدام أداة "مساعد التسوّق" → حظر عمليات معاودة الاتصال من التاجر: "خطأ: لا يمكن إنشاء سلّة التسوّق..."
  • بعد مرور ساعتين → يتم حظر معاودة الاتصال من التاجر: "Error: Intent expired..."
  • انتهاء صلاحية سلة التسوّق → حظر معاودة الاتصال ببيانات الاعتماد: "Error: Cart expired (15 min limit)..."

يتم الآن فرض هذه الحالات الحدّية من الناحية المعمارية من خلال عمليات معاودة الاتصال الخاصة بالتحقّق من الصحة.

ما أنشأته للتو

لقد تمكّنت بنجاح من تنسيق ثلاثة وكلاء متخصصين في نظام سلس وموثوق به مع التحقّق من صحة التصميم.

الخطوات التالية

لقد أكملت الآن الجزء الفني الأساسي من إنشاء وكلاء موثوق بهم:

لقد أنشأت نظامًا كاملاً موثوقًا به يفرض سلسلة بيانات الاعتماد محليًا. لنُتح الآن إمكانية الوصول إلى هذا التطبيق للمستخدمين الفعليين من خلال عملية نشر الإنتاج، ولنفعّل سجلّ التدقيق الذي يتيح استخدام الوحدة 9.

لنبدأ بنشر الوكيل المحسّن على Google Cloud.

8. التفعيل

بانر

اكتمل الآن نظام التبرّع الموثوق به من خلال ثلاثة وكلاء متخصصين يعملون محليًا:

ولكنّه لا يعمل إلا على جهاز التطوير. ولكي يكون هذا النظام مفيدًا للمستخدمين الفعليين، ولكي يتم تسجيل مسارات المسؤولية التي تثبت الجدارة بالثقة، عليك نشره في مرحلة الإنتاج.

توضّح لك هذه الوحدة كيفية نشر برنامجك على Google Cloud مع تفعيل إمكانية المراقبة من اليوم الأول. إنّ العلامة --trace_to_cloud التي ستستخدمها أثناء النشر هي ما يتيح إمكانية تتبُّع المسؤولية في الوحدة التدريبية 9.

التعرّف على خيارات النشر

تتوافق حزمة تطوير التطبيقات (ADK) مع أهداف نشر متعددة. لكلّ منها خصائص مختلفة من حيث التعقيد وإدارة الجلسات والتوسّع والتكلفة:

العامل

محلي (adk web)

Agent Engine

Cloud Run

التعقيد

مبسَّط

منخفض

متوسط

استمرار الجلسة

في الذاكرة فقط (يتم فقدانها عند إعادة التشغيل)

إدارة Vertex AI (تلقائية)

‫Cloud SQL (PostgreSQL) أو في الذاكرة

البنية الأساسية

لا شيء (جهاز التطوير فقط)

مُدار بالكامل

الحاوية + قاعدة البيانات الاختيارية

التشغيل على البارد

لا ينطبق

‫100-500 ملي ثانية

من 100 إلى 2000 ملي ثانية

تغيير الحجم

مثيل واحد

تلقائي

تلقائي (إلى صفر)

نموذج التكلفة

مجاني (الحوسبة المحلية)

استنادًا إلى الحوسبة

الاستخدام حسب الطلب + الفئة المجانية

دعم واجهة المستخدم

نعم (مضمّن)

لا (واجهة برمجة التطبيقات فقط)

نعم (من خلال علامة --with_ui)

إعداد إمكانية المراقبة

أداة عرض عمليات التتبُّع المحلية

تلقائي باستخدام --trace_to_cloud

تتطلّب السمة --trace_to_cloud

الأفضل لـ

التطوير والاختبار

وكلاء الإنتاج

وكلاء الإنتاج

اقتراح: لنظام التبرّع الموثوق هذا، ننصحك باستخدام Agent Engine كعملية نشر أساسية للإنتاج لأنّه يوفّر ما يلي:

  • بنية تحتية مُدارة بالكامل (لا حاجة إلى إدارة الحاويات)
  • استمرار الجلسة المضمّن من خلال VertexAiSessionService
  • التدرّج التلقائي بدون عمليات بدء بارد
  • نشر مبسّط (لا حاجة إلى معرفة Docker)
  • دمج Cloud Trace بدون أي إعدادات إضافية

خيار إضافي: Google Kubernetes Engine (GKE)

بالنسبة إلى المستخدمين المتقدّمين الذين يحتاجون إلى التحكّم على مستوى Kubernetes أو الشبكات المخصّصة أو تنسيق الخدمات المتعددة، تتوفّر عملية نشر GKE. يوفّر هذا الخيار أقصى قدر من المرونة، ولكنّه يتطلّب المزيد من الخبرة التشغيلية (إدارة المجموعات، وبيانات البيان، وحسابات الخدمة).

لا يغطّي هذا الدرس العملي عملية نشر GKE، ولكنّه موثّق بالكامل في دليل نشر ADK على GKE.

المتطلبات الأساسية

1. إعداد مشروع Google Cloud

يجب أن يكون لديك مشروع على Google Cloud تم تفعيل الفوترة فيه. إذا لم يكن لديك حساب:

  1. إنشاء مشروع: وحدة تحكّم Google Cloud
  2. تفعيل الفوترة: تفعيل الفوترة
  3. دوِّن رقم تعريف المشروع (وليس اسم المشروع أو رقمه).

2. إعادة المصادقة (اختياري)

المصادقة باستخدام Google Cloud:

gcloud auth application-default login
gcloud config set project YOUR_PROJECT_ID

استبدِل YOUR_PROJECT_ID برقم تعريف مشروعك الفعلي على Google Cloud.

أكِّد مصادقتك باتّباع الخطوات التالية:

gcloud config get-value project
# Should output: YOUR_PROJECT_ID

3- متغيّرات البيئة

استخدِم الأوامر التالية لتعبئة ملف .env تلقائيًا:

# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)
STAGING_BUCKET_VALUE="gs://${PROJECT_ID}-staging"
ENV_FILE=".env"

# Check if STAGING_BUCKET is already set in the .env file
if grep -q "^STAGING_BUCKET=" "${ENV_FILE}"; then
  # If it exists, replace the line
  # The sed command finds the line starting with STAGING_BUCKET= and replaces the entire line.
  # Using | as a delimiter to avoid issues with slashes in the bucket name.
  sed -i "s|^STAGING_BUCKET=.*|STAGING_BUCKET=${STAGING_BUCKET_VALUE}|" "${ENV_FILE}"
  echo "Updated STAGING_BUCKET in ${ENV_FILE}"
else
  # If it doesn't exist, add it to the end of the file
  echo "STAGING_BUCKET=${STAGING_BUCKET_VALUE}" >> "${ENV_FILE}"
  echo "Added STAGING_BUCKET to ${ENV_FILE}"
fi

# Verify it was added or updated correctly
echo "Current STAGING_BUCKET setting:"
grep "^STAGING_BUCKET=" "${ENV_FILE}"

سيظهر لك ما يلي:

STAGING_BUCKET=gs://your-actual-project-id-staging

ملاحظات مهمّة:

  • استبدِل YOUR_PROJECT_ID برقم تعريف مشروعك الفعلي (أو استخدِم الأوامر أعلاه).
  • بالنسبة إلى GOOGLE_CLOUD_LOCATION، استخدِم منطقة متوافقة.
  • سيتم إنشاء حزمة الإعداد تلقائيًا إذا لم تكن متوفّرة عند تشغيل نص برمجي للنشر

4. تفعيل واجهات برمجة التطبيقات المطلوبة

تتطلّب عملية النشر تفعيل العديد من واجهات Google Cloud API. نفِّذ الأمر التالي لتفعيلها:

gcloud services enable \
    aiplatform.googleapis.com \
    storage.googleapis.com \
    cloudbuild.googleapis.com \
    cloudtrace.googleapis.com \
    compute.googleapis.com

يتيح هذا الأمر ما يلي:

  • AI Platform API: لمحرك الوكلاء ونماذج Vertex AI
  • Cloud Storage API: لحزمة التخزين المؤقت
  • Cloud Build API: لإنشاء الحاويات (Cloud Run)
  • Cloud Trace API: لتتبُّع إمكانية المراقبة والمساءلة
  • واجهة برمجة التطبيقات Compute Engine API: لإدارة حسابات الخدمة

الخطوة 1: فهم البنية الأساسية للنشر

يتضمّن مشروعك نص برمجي موحّد للنشر (deploy.sh) يتعامل مع جميع أوضاع النشر.

👉 مراجعة نص النشر البرمجي (اختياري):

cat deploy.sh

يوفّر النص البرمجي ثلاثة أوضاع نشر:

  • ./deploy.sh local: التشغيل محليًا باستخدام مساحة تخزين داخل الذاكرة
  • ./deploy.sh agent-engine - النشر في "محرك وكلاء Vertex AI" (يُنصح به)
  • ./deploy.sh cloud-run - النشر على Cloud Run باستخدام واجهة مستخدم اختيارية

طريقة عمل الميزة:

عند نشر Agent Engine، ينفّذ النص البرمجي ما يلي:

adk deploy agent_engine \
  --project=$GOOGLE_CLOUD_PROJECT \
  --region=$GOOGLE_CLOUD_LOCATION \
  --staging_bucket=$STAGING_BUCKET \
  --display_name="Charity Advisor" \
  --trace_to_cloud \
  charity_advisor

بالنسبة إلى عملية النشر على Cloud Run، يتم تنفيذ ما يلي:

adk deploy cloud_run \
  --project=$GOOGLE_CLOUD_PROJECT \
  --region=$GOOGLE_CLOUD_LOCATION \
  --service_name="charity-advisor" \
  --app_name="charity_advisor" \
  --with_ui \
  --trace_to_cloud \
  charity_advisor

تُعدّ العلامة --trace_to_cloud ضرورية لكلا نوعَي النشر، فهي تتيح دمج Cloud Trace في سجلّ التدقيق الذي ستتعرّف عليه في الوحدة 9.

الخطوة 2: إعداد Agent Engine Wrapper

يتطلّب Agent Engine نقطة دخول محدّدة تغلف الوكيل لوقت التشغيل المُدار. تم إنشاء هذا الملف لك.

👉 مراجعة

charity_advisor/agent_engine_app.py

:

"""Agent Engine application wrapper.

This file prepares the Charity Advisor agent for deployment to Vertex AI Agent Engine.
"""

from vertexai import agent_engines
from .agent import root_agent

# Wrap the agent in an AdkApp object for Agent Engine deployment
app = agent_engines.AdkApp(
    agent=root_agent,
    enable_tracing=True,  # Enables Cloud Trace integration automatically
)

سبب الحاجة إلى هذا الملف:

  • يتطلّب Agent Engine أن يكون الوكيل مضمّنًا في عنصر AdkApp
  • تتيح المَعلمة enable_tracing=True دمج Cloud Trace تلقائيًا
  • تتم الإشارة إلى هذا البرنامج المغلّف من خلال واجهة سطر الأوامر (CLI) لحزمة تطوير التطبيقات (ADK) أثناء عملية النشر.
  • تضبط هذه السياسة VertexAiSessionService لإبقاء الجلسة نشطة تلقائيًا.

‫Agent Engine هو عملية النشر المقترَحة في مرحلة الإنتاج لنظام التبرّع الموثوق به لأنّه يوفّر بنية أساسية مُدارة بالكامل مع إمكانية استمرار الجلسة المضمّنة.

تشغيل عملية النشر

من جذر مشروعك:

chmod +x deploy.sh
./deploy.sh agent-engine

مراحل النشر

شاهِد النص البرمجي وهو ينفّذ المراحل التالية:

Phase 1: API Enablement
   aiplatform.googleapis.com
   storage.googleapis.com
   cloudbuild.googleapis.com
   cloudtrace.googleapis.com
   compute.googleapis.com

Phase 2: IAM Setup
   Getting project number
   Granting Storage Object Admin
   Granting Vertex AI User
   Granting Cloud Trace Agent

Phase 3: Staging Bucket
   Creating gs://your-project-id-staging (if needed)
   Setting permissions

Phase 4: Validation
   Checking agent.py exists
   Verifying root_agent defined
   Checking agent_engine_app.py exists
   Validating requirements.txt

Phase 5: Build & Deploy
   Packaging agent code
   Uploading to staging bucket
   Creating Agent Engine instance
   Configuring session persistence
   Setting up Cloud Trace integration
   Running health checks

تستغرق هذه العملية من 5 إلى 10 دقائق لأنّها تحزّم الوكيل وتنشره في البنية الأساسية لـ Vertex AI.

حفظ رقم تعريف محرك وكيلك

بعد عملية نشر ناجحة:

✅ Agent Engine created successfully!

   Agent Engine ID: 7917477678498709504
   Resource Name: projects/123456789/locations/us-central1/reasoningEngines/7917477678498709504
   Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...

   ⚠️  IMPORTANT: Save the Agent Engine ID from the output above
   Add it to your .env file as:
   AGENT_ENGINE_ID=7917477678498709504

   This ID is required for:
   - Testing the deployed agent
   - Updating the deployment later
   - Accessing logs and traces

عدِّل ملف ‎ .env على الفور:

echo "AGENT_ENGINE_ID=7917477678498709504" >> .env

ما تم نشره

يتضمّن نشر Agent Engine الآن ما يلي:

‫✅ جميع الوكلاء الثلاثة (التسوّق، التاجر، بيانات الاعتماد) الذين يتم تشغيلهم في وقت التشغيل المُدار
‫✅ منطق سلسلة بيانات الاعتماد الكاملة (النية → سلة التسوّق → تفويضات الدفع)
‫✅ آلية موافقة المستخدم مع سير عمل التأكيد
‫✅ استمرار الجلسة تلقائيًا من خلال VertexAiSessionService
‫✅ البنية الأساسية للتوسيع التلقائي التي تديرها Google
‫✅ عملية الدمج مع Cloud Trace لإمكانية المراقبة الكاملة

الخطوة 4: اختبار الوكيل الذي تم نشره

تعديل بيئتك

تأكَّد من أنّ .env يتضمّن معرّف Agent Engine:

AGENT_ENGINE_ID=7917477678498709504  # From deployment output
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://your-project-id-staging

تشغيل النص البرمجي للاختبار

يتضمّن مشروعك نص اختبار مخصّصًا لعمليات نشر Agent Engine.

👉 إجراء الاختبار:

python scripts/test_deployed_agent.py

الناتج المتوقّع

Testing Agent Engine deployment...
Project: your-project-id
Location: us-central1
Agent Engine ID: 7917477678498709504
Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...

Creating session...
✓ Session created: 4857885913439920384

Sending donation query...
✓ Response received:
  Event 1: I'll help you donate $50 to a children's education charity...
  Event 2: Here are some highly-rated children's education charities...
  Event 3: Which charity would you like to support?...

✅ Test completed successfully!

Session ID: 4857885913439920384

This donation generated a trace in Cloud Trace.
View it in Module 9: Observability

To view traces:
https://console.cloud.google.com/traces/list?project=your-project-id

قائمة التحقّق من إثبات الملكية

بعد الاختبار، تحقَّق مما يلي:

✅ يستجيب الوكيل للاستعلامات
✅ يتم تنفيذ جميع الوكلاء الثلاثة بالتسلسل (Shopping → التاجر → بيانات الاعتماد)
✅ يتم تفعيل آلية الموافقة (يُطلب التأكيد)
✅ تستمر الجلسة في جميع الطلبات
✅ لا توجد أخطاء في المصادقة
✅ لا تنتهي مهلة الاتصال

في حال مواجهة أخطاء:

  • التأكّد من ضبط متغيّرات البيئة بشكلٍ صحيح
  • تأكَّد من تفعيل واجهات برمجة التطبيقات: gcloud services list --enabled
  • الاطّلاع على سجلّات Agent Engine في Vertex AI Console
  • تأكَّد من أنّ الملف agent_engine_app.py موجود في مجلد charity_advisor

الخطوة 5: النشر على Cloud Run (اختياري)

مع أنّنا ننصح باستخدام Agent Engine لتسهيل عملية نشر الإنتاج، يوفّر Cloud Run المزيد من التحكّم ويتوافق مع واجهة مستخدم ADK على الويب. هذا القسم اختياري.

حالات استخدام Cloud Run

اختَر Cloud Run إذا كنت بحاجة إلى:

  • واجهة مستخدم ADK على الويب للتفاعل مع المستخدم
  • التحكّم الكامل في بيئة الحاوية
  • إعدادات قاعدة البيانات المخصّصة
  • التكامل مع خدمات Cloud Run الحالية

تشغيل عملية النشر

chmod +x deploy.sh
./deploy.sh cloud-run

الاختلافات:

سيتم تلقائيًا تنفيذ ما يلي في النص البرمجي:

  • إنشاء حاوية Docker باستخدام رمز الوكيل
  • إنشاء قاعدة بيانات Cloud SQL PostgreSQL (إذا لزم الأمر)
  • ضبط عملية ربط قاعدة البيانات
  • النشر مع تفعيل واجهة مستخدم الويب الخاصة بـ ADK

يستغرق النشر من 10 إلى 15 دقيقة بسبب توفير Cloud SQL.

إدارة الجلسات:

  • استخدام DatabaseSessionService بدلاً من VertexAiSessionService
  • يتطلّب بيانات اعتماد قاعدة البيانات في .env (أو يتم إنشاؤها تلقائيًا)
  • تستمر الحالة في قاعدة بيانات PostgreSQL

دعم واجهة المستخدم:

  • تتوفّر واجهة مستخدم الويب على الرابط: https://charity-advisor-xyz.a.run.app

اختبار عملية النشر على Cloud Run

إذا نشرت تطبيقك على Cloud Run باستخدام --with_ui، يمكنك اختباره مباشرةً في المتصفّح باتّباع الخطوات التالية:

  1. انتقِل إلى عنوان URL الخاص بالخدمة (المقدَّم في ناتج النشر).
  2. ستظهر لك واجهة ADK على الويب. اختَر وكيلك من القائمة المنسدلة.
  3. بدء تبرّع تجريبي:
   I want to donate $50 to a children's education charity
  1. مراقبة مسار التنفيذ:
    • تعثر ShoppingAgent على مؤسسات خيرية وتحفظ نيتك
    • ينشئ MerchantAgent تفويض سلة التسوّق
    • تنشئ CredentialsProvider تفويض الدفع وتطلب تأكيده
    • بعد التأكيد، تتم معالجة الدفعة
  2. تأكَّد من أنّ الردّ يتضمّن ما يلي:
    • اقتراحات بشأن المؤسسات الخيرية
    • طلب التأكيد
    • رسالة النجاح بعد الموافقة

تحديد المشاكل وحلّها

المشاكل الشائعة

المشكلة: ERROR: GOOGLE_CLOUD_PROJECT is not set

الحلّ: تأكَّد من أنّ ملف .env يتضمّن رقم تعريف المشروع الصحيح:

GOOGLE_CLOUD_PROJECT=your-actual-project-id

المشكلة: عدم إنشاء حزمة مرحلية تلقائيًا

الحل: يجب أن ينشئ النص البرمجي الحزمة تلقائيًا. إذا لم يكن لديك حساب، أنشئ حسابًا يدويًا باتّباع الخطوات التالية:

gsutil mb -p $GOOGLE_CLOUD_PROJECT -l $GOOGLE_CLOUD_LOCATION $STAGING_BUCKET

ملخّص

لقد نفّذت الإجراءات التالية بنجاح:

✅ فهم البنية الأساسية للنشر التي توفّرها deploy.sh
✅ مراجعة إعدادات برنامج تضمين Agent Engine
✅ نشر نظام التبرّع الموثوق به في Agent Engine (إجراء يُنصح به)
✅ تفعيل عملية الدمج مع Cloud Trace
✅ التأكّد من إمكانية الوصول إلى الوكيل ومن عمله بشكل سليم
✅ إنشاء الأساس لمسارات المساءلة في الوحدة 9--trace_to_cloud

في الوحدة التالية، ستتعرّف على الميزات التي يتيحها هذا الخيار، وهي: إمكانية الاطّلاع الكامل على كل تبرّع وكل لحظة موافقة وكل خطوة من خطوات سلسلة بيانات الاعتماد.

9- إمكانية تتبّع البيانات

بانر

تتبُّع الرسم البياني

في الوحدة 1، تعرّفت على مشكلة أساسية: عندما يتعامل وكيل الذكاء الاصطناعي مع الأموال، كيف يمكنك إثبات ما حدث؟

يمكن للمستخدم المطالبة بما يلي:

  • "لم أختار هذه المؤسسة الخيرية أبدًا"
  • "لم أمنح الإذن بالدفع!"
  • "لقد فرض عليّ النظام رسومًا بدون موافقتي"

في نظام الذكاء الاصطناعي التقليدي ذي الصندوق الأسود، لن يكون بإمكانك إثبات عكس ذلك. لكن نظام التبرّع الموثوق به يختلف. في الوحدة التدريبية 8، نفّذت عملية نشر باستخدام العلامة --trace_to_cloud، ما يعني أنّ كل تبرّع ينشئ الآن سجلّ تدقيق كاملاً ومضادًا للتلاعب في Cloud Trace.

تعلّمك هذه الوحدة كيفية قراءة عمليات التتبُّع هذه واستخدامها كدليل. سيتم شرح كيفية:

  • الانتقال إلى Cloud Trace Explorer للعثور على عمليات تتبُّع الإنتاج
  • قراءة عرض الشلال لفهم تسلسل التنفيذ
  • العثور على سلسلة بيانات الاعتماد (Intent → Cart → Payment mandates)
  • تحديد لحظات الموافقة باستخدام إثبات الطابع الزمني
  • استخدام عمليات التتبُّع لحلّ النزاعات
  • تصدير عمليات التتبُّع لأغراض الامتثال والتدقيق

وهذا ما يميّز الأنظمة الجديرة بالثقة عن الأنظمة القادرة ولكن غير الشفافة: القدرة على إثبات ما حدث بدقة الطب الشرعي.

فهم عمليات التتبُّع والنطاقات

قبل عرض عمليات التتبُّع في Cloud Trace، عليك فهم ما تراه.

ما هي "مسارات التطوير"؟

التتبُّع هو المخطط الزمني الكامل لوكيلك الذي يعالج طلبًا واحدًا. تسجّل هذه السمة كل شيء بدءًا من وقت إرسال المستخدم لطلب البحث وحتى تسليم الرد النهائي.

يعرض كل تتبُّع ما يلي:

  • إجمالي مدة الطلب
  • جميع العمليات التي تم تنفيذها
  • كيفية ارتباط العمليات ببعضها البعض (العلاقات بين العناصر الرئيسية والعناصر الفرعية)
  • وقت بدء كل عملية وانتهائها
  • حالة النجاح أو الفشل

بالنسبة إلى وكيلك الخيري: عملية تتبُّع واحدة = مسار تبرّع كامل واحد من "أريد التبرّع" إلى "تم الدفع بنجاح".

ما هو Span؟

يمثّل النطاق وحدة عمل واحدة ضمن عملية تتبُّع. يمكن اعتبار الفترات الزمنية اللبنات الأساسية للتتبُّع.

أنواع الفترات الزمنية الشائعة في نظام التبرّع:

نوع الفاصل الزمني

ما يمثّله

مثال

agent_run

تنفيذ وكيل

ShoppingAgent.run، MerchantAgent.run

call_llm

طلب إلى نموذج لغوي

gemini-2.5-flash طلب اختيار مؤسسة خيرية

execute_tool

تنفيذ وظيفة الأداة

find_charities، create_payment_mandate

state_read

القراءة من ذاكرة الجلسة

جارٍ استرداد intent_mandate من الولاية

state_write

الكتابة إلى ذاكرة الجلسة

تخزين cart_mandate في الحالة

يحتوي كل نطاق على ما يلي:

  • الاسم: العملية التي يمثّلها هذا الحقل
  • المدة المستغرقة (وقت البدء → وقت الانتهاء)
  • السمات: البيانات الوصفية، مثل مدخلات الأدوات وردود النماذج وعدد الرموز المميزة
  • الحالة: ناجحة (OK) أو خطأ (ERROR)
  • العلاقات بين العمليات الرئيسية والفرعية: العمليات التي أدّت إلى تشغيل عمليات أخرى

كيف تشكّل الفترات الزمنية مسار تتبُّع؟

تتداخل الفترات مع بعضها البعض لإظهار السببية:

Root Span: CharityAdvisor.run (entire request)
  └─ Child: DonationPipeline.run (sequential workflow)
      ├─ Child: ShoppingAgent.run
         ├─ Grandchild: call_llm (Gemini processes charity search)
         ├─ Grandchild: execute_tool (find_charities)
         └─ Grandchild: execute_tool (save_user_choice)
      ├─ Child: MerchantAgent.run
         ├─ Grandchild: call_llm (Gemini generates cart)
         └─ Grandchild: execute_tool (create_cart_mandate)
      └─ Child: CredentialsProvider.run
          ├─ Grandchild: call_llm (Gemini processes payment)
          └─ Grandchild: execute_tool (create_payment_mandate) [CONSENT!]

يوضّح هذا التدرّج الهرمي بالضبط ما حدث والترتيب الذي حدثت به الأحداث. يمكنك ملاحظة أنّه تم إنشاء تفويض الدفع بعد تفويض سلة التسوّق، الذي تم بعد أن اختار المستخدم مؤسسة خيرية.

الخطوة 1: الوصول إلى Cloud Trace Explorer

لنطّلع الآن على عمليات التتبُّع الفعلية من الوكيل الذي تم نشره.

  1. افتح Google Cloud Console: console.cloud.google.com
  2. اختَر مشروعك من القائمة المنسدلة في أعلى الصفحة (يجب أن يكون محدّدًا مسبقًا إذا كنت تعمل فيه)
  3. انتقِل إلى Cloud Trace Explorer:
    • في الشريط الجانبي الأيمن، انتقِل إلى قسم إمكانية المراقبة.
    • انقر على تتبُّع.
    • أو استخدِم الرابط المباشر: console.cloud.google.com/traces/list

ما تنظر إليه

يعرض "مستكشف عمليات التتبُّع" قائمة بجميع عمليات التتبُّع من مشروعك:

العمود

ما يعرضه

الطلب

طريقة HTTP ونقطة النهاية (لطلبات البيانات من واجهة برمجة التطبيقات)

وقت البدء

وقت بدء الطلب

وقت الاستجابة

إجمالي مدة الطلب

الفترات الزمنية

عدد العمليات في التتبُّع

يمثّل كل صف طلبًا كاملاً واحدًا إلى الوكيل الذي تم نشره.

إنشاء عمليات تتبُّع الاختبار (إذا لزم الأمر)

إذا لم تظهر لك أي آثار حتى الآن، قد تكون القائمة فارغة للأسباب التالية:

  • لم يتم تقديم أي طلبات إلى الوكيل الذي تم نشره بعد
  • يستغرق ظهور عمليات التتبُّع من دقيقة إلى دقيقتَين بعد تقديم الطلب.

إنشاء تتبُّع تجريبي:

إذا تم النشر إلى Cloud Run with UI، انتقِل إلى عنوان URL الخاص بالخدمة وأكمِل عملية التبرّع في المتصفّح.

إذا تم النشر إلى Agent Engine، شغِّل النص البرمجي للاختبار من الوحدة 8:

python scripts/test_deployed_agent.py

انتظِر من دقيقة إلى دقيقتين، ثم أعِد تحميل صفحة Cloud Trace Explorer. من المفترض أن تظهر لك الآن آثار.

فلترة عمليات التتبُّع

استخدِم خيارات الفلتر في أعلى الصفحة للعثور على عمليات تتبُّع معيّنة:

  • النطاق الزمني: يمكنك التغيير من "آخر ساعة" إلى "آخر 24 ساعة" إذا لزم الأمر.
  • الحدّ الأدنى لوقت الاستجابة / الحدّ الأقصى لوقت الاستجابة: فلترة الطلبات البطيئة
  • فلتر الطلبات: يمكنك البحث حسب عمليات معيّنة (مثل DonationPipeline")

بالنسبة إلى هذا النموذج، ركِّز على عمليات التتبُّع التي تستغرق مددًا أطول (أكثر من 5 ثوانٍ)، لأنّها تمثّل مسارات التبرّع الكاملة التي يتم تنفيذها من خلال جميع الوكلاء الثلاثة.

الخطوة 2: فحص مسار التبرّع الكامل

انقر على أي تتبُّع في القائمة لفتح عرض الشلال. هذا هو المكان الذي ستقضي فيه معظم وقتك في تحليل سلوك الوكيل.

فهم "عرض التسلسل الهرمي"

طريقة العرض الانحدارية هي مخطط Gantt يعرض المخطط الزمني الكامل للتنفيذ:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
              Timeline (horizontal = time) 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

invocation                           ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.2s
  agent_run: CharityAdvisor          ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.1s
    agent_run: DonationPipeline      ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 7.9s
      agent_run: ShoppingAgent       ▓▓▓▓▓▓ 2.1s
        call_llm: gemini-2.5-flash   ▓▓▓▓ 1.2s
        execute_tool: find_charities ▓▓ 0.5s
        execute_tool: save_user_choice  0.3s
      agent_run: MerchantAgent       ▓▓▓ 1.8s
        call_llm: gemini-2.5-flash   ▓▓ 0.9s
        execute_tool: create_cart_mandate  0.7s
      agent_run: CredentialsProvider ▓▓▓▓▓▓▓▓ 4.0s
        call_llm: gemini-2.5-flash   ▓▓ 0.8s
        execute_tool: create_payment_mandate ▓▓▓▓▓ 3.0s [CONSENT]

قراءة الرسم البياني

يمثّل كل شريط فترة زمنية:

  • الموضع الأفقي: وقت بدء العرض
  • المدة: المدة التي استغرقتها
  • المسافة البادئة: تعرض العلاقات بين العناصر الرئيسية والعناصر التابعة
  • اللون: يكون عادةً أزرقًا في الحالة العادية وأحمرًا في حال حدوث أخطاء

الملاحظات الرئيسية من عملية التتبُّع هذه:

المدة الإجمالية: 8.2 ثانية
التنفيذ التسلسلي: أكمل ShoppingAgent مهمته قبل أن يبدأ MerchantAgent مهمته
أكمل MerchantAgent مهمته

قبل

بدء CredentialsProvider
كانت عملية الموافقة هي الأطول: استغرقت 3.0 ثانية في create_payment_mandate (لأنّها كانت تنتظر تأكيد المستخدم)
يمكن الاطّلاع على طلبات النموذج اللغوي الكبير: قدّم كل وكيل طلبًا واحدًا إلى Gemini
تم تسجيل طلبات الأدوات: تم تنفيذ جميع الأدوات الست بنجاح

يوضّح لك هذا الرسم البياني على الفور الوقت المستغرَق وترتيب تنفيذ العمليات.

النقر على فترة زمنية للاطّلاع على التفاصيل

انقر على النطاق invocation (النطاق الجذر في الأعلى). في اللوحة اليمنى، ستظهر لك السمات التفصيلية:

{
  "http.method": "POST",
  "http.status_code": 200,
  "http.url": "https://charity-advisor-xyz.a.run.app/api/run",
  "user_id": "test_user_123",
  "session_id": "4857885913439920384",
  "trace_id": "a1b2c3d4e5f6...",
  "span_id": "1234567890abcdef"
}

تقدّم هذه السمات سياقًا حول الطلب بأكمله.

الخطوة 3: العثور على "سلسلة بيانات الاعتماد"

يستخدم نظامك الموثوق سلسلة بيانات اعتماد لإثبات التفويض في كل خطوة:

IntentMandate (User chose charity)
    ↓
CartMandate (Merchant created cart, signed IntentMandate)
    ↓
PaymentMandate (Payment provider created payment, signed CartMandate)

لنبحث عن كل تفويض في التتبُّع.

العثور على IntentMandate

انقر على عنصر execute_tool: save_user_choice (ضمن ShoppingAgent).

في لوحة السمات، ستظهر لك:

{
  "tool.name": "save_user_choice",
  "tool.input.charity_name": "Save the Children",
  "tool.input.amount": 50,
  "tool.output.status": "success",
  "tool.output.intent_mandate": {
    "charity_name": "Save the Children",
    "amount": 50,
    "timestamp": "2024-11-08T15:30:12.345Z",
    "signature": "a3f7b9c1d2e4..."
  }
}

يثبت ذلك ما يلي:

  • ✅ اختار المستخدم "منظمة إنقاذ الطفولة"
  • ✅ كان المبلغ 50 دولارًا أمريكيًا
  • ✅ تم تسجيل الاختيار في الساعة 15:30:12 بالتوقيت العالمي المتفق عليه
  • ✅ تم إنشاء التوقيع (في مرحلة الإنتاج، سيكون هذا التوقيع مشفّرًا)

أصبحت IntentMandate الآن في حالة الجلسة ومتاحة للوكلاء اللاحقين.

العثور على CartMandate

انقر على عنصر execute_tool: create_cart_mandate (ضمن MerchantAgent).

في لوحة السمات:

{
  "tool.name": "create_cart_mandate",
  "tool.input.intent_mandate": {
    "charity_name": "Save the Children",
    "amount": 50,
    "signature": "a3f7b9c1d2e4..."
  },
  "tool.output.status": "success",
  "tool.output.cart_mandate": {
    "cart_id": "cart_7893",
    "intent_signature": "a3f7b9c1d2e4...",
    "cart_signature": "e8f2a9b3c7d1...",
    "timestamp": "2024-11-08T15:30:14.789Z"
  }
}

يثبت ذلك ما يلي:

  • ‫✅ تلقّى MerchantAgent تفويض IntentMandate (يظهر الإدخال ذلك)
  • ✅ تم إنشاء سلة التسوق بالمعرّف "cart_7893"
  • ‫✅ يشير توقيع سلة التسوّق إلى توقيع IntentMandate (رابط سلسلة!)
  • ✅ تم إنشاؤه في الساعة 15:30:14 بالتوقيت العالمي المتفق عليه (بعد 2.4 ثانية من الهدف)

يشير CartMandate الآن إلى IntentMandate، ما يؤدي إلى إنشاء السلسلة.

العثور على PaymentMandate

انقر على عنصر execute_tool: create_payment_mandate (ضمن CredentialsProvider).

في لوحة السمات:

{
  "tool.name": "create_payment_mandate",
  "tool.input.cart_mandate": {
    "cart_id": "cart_7893",
    "intent_signature": "a3f7b9c1d2e4...",
    "cart_signature": "e8f2a9b3c7d1..."
  },
  "tool.confirmation_required": true,
  "tool.confirmation_timestamp": "2024-11-08T15:30:17.891Z",
  "tool.user_response": "CONFIRMED",
  "tool.wait_duration_ms": 29168,
  "tool.output.status": "success",
  "tool.output.payment_mandate": {
    "payment_id": "pay_9821",
    "cart_signature": "e8f2a9b3c7d1...",
    "payment_signature": "b4c9e2a7f8d3...",
    "timestamp": "2024-11-08T15:30:47.059Z"
  }
}

يثبت ذلك السلسلة الكاملة:

  • ‫✅ CredentialsProvider تلقّى CartMandate (يظهر ذلك في الإدخال)
  • ‫✅ تشير عملية الدفع إلى توقيع CartMandate (رابط السلسلة!)
  • كان مطلوبًا تأكيد الحساب (confirmation_required: true)
  • ‫✅ تم تأكيد المستخدم في الساعة 15:30:17 بالتوقيت العالمي المنسَّق
  • انتظر النظام لمدة 29.2 ثانية لاتّخاذ المستخدم قرارًا
  • ✅ تم إنشاء الدفعة بعد التأكيد (الطابع الزمني: 15:30:47)

عرض السلسلة

تثبت عملية التتبُّع أنّ سلسلة بيانات الاعتماد تم تنفيذها بشكل صحيح:

15:30:12 UTC  IntentMandate created (signature: a3f7...)
                  
15:30:14 UTC  CartMandate created (references: a3f7...)
                  
15:30:17 UTC  User consent requested
                  
15:30:47 UTC  PaymentMandate created (references: e8f2...)

يشير كل تفويض إلى توقيع التفويض السابق. هذه السلسلة مقاومة للتلاعب، ويمكنك التحقّق منها من خلال التأكّد من تطابق التواقيع.

الخطوة 4: تحليل الأداء ومواضع الاختناق

لا يقتصر دور Cloud Trace على إثبات ما حدث، بل يوضّح لك أيضًا مواضع استغراق الوقت حتى تتمكّن من إجراء التحسينات.

تحديد المسار الحرج

في طريقة العرض الشلالية، ابحث عن أطول الفترات في الحزمة العمودية. وهي تمثّل المؤثِّرات السلبية على أدائك.

من عملية التتبُّع النموذجية:

Total: 8.2 seconds

Breakdown:
  - ShoppingAgent:         2.1s (26%)
  - MerchantAgent:         1.8s (22%)
  - CredentialsProvider:   4.0s (49%)   Bottleneck
  - Other overhead:        0.3s (3%)

إحصاءات مهمة: تمثّل حسابات CredentialsProvider% 49 من إجمالي الوقت. لماذا؟

انتقِل إلى النطاق CredentialsProvider:

CredentialsProvider: 4.0s
  - call_llm:              0.8s (20%)
  - create_payment_mandate: 3.0s (75%)   User consent wait
  - Other:                 0.2s (5%)

التأخير لمدة 3 ثوانٍ متوقّع وجيّد، لأنّ المستخدم يفكّر مليًا قبل التأكيد. هذه ليست مشكلة في الأداء، بل هي دليل على الموافقة المدروسة.

تتبُّع تكاليف النماذج اللغوية الكبيرة

انقر على أي جزء من call_llm للاطّلاع على استخدام الرمز المميّز:

{
  "llm.model": "gemini-2.5-flash",
  "llm.usage.prompt_tokens": 487,
  "llm.usage.completion_tokens": 156,
  "llm.usage.total_tokens": 643,
  "llm.response_time_ms": 1243
}

يمكنك استخدام هذه الميزة لإجراء ما يلي:

  • تتبُّع التكلفة لكل طلب (الرموز المميزة × سعر النموذج)
  • تحديد الطلبات الطويلة بشكل غير ضروري
  • مقارنة أداء النماذج (Flash مقابل Pro)
  • تحسين السرعة مقابل الجودة

مثال على العملية الحسابية:

Gemini 2.5 Flash pricing (as of Nov 2024):
  Input:  $0.075 per 1M tokens
  Output: $0.30 per 1M tokens

This request:
  Input:  487 tokens × $0.075 / 1M = $0.000037
  Output: 156 tokens × $0.30 / 1M  = $0.000047
  Total:                            = $0.000084 (~$0.00008)

For 10,000 donations/month:
  10,000 × 3 agents × $0.00008 = $2.40/month in LLM costs

تساعدك هذه الرؤية التفصيلية في اتّخاذ قرارات مستنيرة بشأن اختيار النماذج.

المقارنة بين عمليات التتبُّع

فلترة عمليات تتبُّع متعددة ومقارنة المدد:

Trace 1: 8.2s  (with consent wait: 3.0s)
Trace 2: 12.5s (with consent wait: 7.8s)  ← User took longer
Trace 3: 5.1s  (with consent wait: 0.2s)  ← User clicked fast
Trace 4: 6.3s  (with consent wait: 1.5s)

المعلومات المفصّلة: يعود معظم التفاوت إلى الوقت الذي يستغرقه المستخدم في اتخاذ القرار، وليس إلى أداء النظام. يظلّ تنفيذ "الوكيل الأساسي" (باستثناء الموافقة) ثابتًا عند 5 ثوانٍ تقريبًا.

يشير ذلك إلى أنّ النظام يعمل بشكل موثوق.

بالنسبة إلى أنظمة الإنتاج، يمكنك إعداد تنبيهات لرصد المشاكل قبل أن يشتكي المستخدمون.

تنبيه بشأن معدّلات الخطأ المرتفعة

إنشاء تنبيه عند احتواء أكثر من% 5 من عمليات التتبُّع على أخطاء:

  1. انتقِل إلى Cloud Monitoring.
  2. انقر على "التنبيه""إنشاء سياسة"
  3. الضبط:
    Resource: Cloud Trace Span
    Metric: Span error count
    Condition: Rate > 5% over 5 minutes
    Notification: Email your-team@example.com
    

تنبيه بشأن وقت الاستجابة الطويل

إنشاء تنبيه عندما يتجاوز وقت الاستجابة p95 15 ثانية:

Resource: Cloud Trace
Metric: Span duration (95th percentile)
Condition: > 15000ms for 5 minutes
Notification: PagerDuty

يساعد ذلك في رصد انخفاض الأداء قبل أن يؤثر في تجربة المستخدم.

إنشاء تنبيه في حال إجراء أي عمليات دفع بدون تأكيد:

Resource: Cloud Trace Span
Filter: tool.name="create_payment_mandate" AND tool.confirmation_required!=true
Condition: Any match
Notification: Critical alert to security team

هذه أداة رصد لانتهاكات الأمان، وإذا تم تفعيلها، يعني ذلك أنّ هناك مشكلة كبيرة في آلية الموافقة.

ما تعلّمته

من خلال Cloud Trace، يمكنك الآن معرفة كيفية تنفيذ ما يلي:

التنقّل في Cloud Trace Explorer للعثور على عمليات التتبُّع في مرحلة الإنتاج
قراءة طرق العرض المتسلسلة للاطّلاع على مسار التنفيذ الكامل
تتبُّع سلسلة بيانات الاعتماد من خلال IntentMandate → CartMandate → PaymentMandate ✅ استخدام عمليات التتبُّع كدليل لحلّ النزاعات
تحليل الأداء لتحديد المؤثّرات السلبية في الأداء
تتبُّع تكاليف النماذج اللغوية الكبيرة على مستوى دقيق

التغيير الذي سيحدث

قارِن بين نظامَين يتعاملان مع الشكوى نفسها "لم أسمح بذلك أبدًا":

النظام بدون إمكانية تتبُّع البيانات

User: "I never authorized that $50 donation!"
You:  "Our logs show the transaction completed successfully."
User: "But I didn't approve it!"
You:  "The system requires confirmation before processing."
User: "I never saw any confirmation!"
You:  "..." [no way to prove what happened]

Result: Refund issued, trust lost, user never returns.

النظام الذي يتضمّن Cloud Trace

User: "I never authorized that $50 donation!"
You:  "Let me pull up the trace from your session..."
      [Shows waterfall with consent span]
You:  "Here's the evidence:
       - 15:30:17 UTC: System asked for confirmation
       - Message shown: 'You are about to donate $50...'
       - 15:30:47 UTC: You clicked 'CONFIRM'
       - Wait time: 29.2 seconds
       
       The system waited almost 30 seconds for your decision.
       Here's the exact timestamp of your confirmation."
       
User: "Oh... I remember now. My mistake. Sorry!"

Result: Trust preserved, no refund needed, user continues using service.

هذه هي أهمية سجلات التدقيق. تنتقل من "الثقة بنا" إلى "دعنا نوضّح لك ما حدث بالضبط".

الخطوات التالية

لقد أكملت الآن الجزء الفني الأساسي من إنشاء وكلاء موثوق بهم:

الوحدات من 1 إلى 6: تصميم بنية موثوقة (الأدوار وبيانات الاعتماد والموافقة)
الوحدة 7: تنظيم مهام سير العمل المعقّدة (SequentialAgent)
الوحدة 8: النشر مع تفعيل إمكانية المراقبة
الوحدة 9: تعلُّم كيفية قراءة مسارات التدقيق واستخدامها

إنّ البنية التي أنشأتها، بما في ذلك فصل الأدوار وسلاسل بيانات الاعتماد وآليات الموافقة وإمكانية المراقبة الكاملة، تنتقل مباشرةً إلى أنظمة الإنتاج التي تتعامل مع أموال حقيقية وبيانات حقيقية وعواقب حقيقية.

10. رحلتك نحو التقدّم

المحتوى الذي أنشأته

بدأنا ورشة العمل هذه بسؤال: "كيف يمكنني إنشاء وكلاء يعملون بالذكاء الاصطناعي يمكنني الوثوق بهم في ما يتعلق بالمال؟"

أصبحت لديك الإجابة الآن.

مستوى البداية (الوحدة 3):

simple_agent = Agent(
    model="gemini-2.5-flash",
    instruction="Find charities and donate",
    tools=[google_search]
)

مستواك الحالي (الوحدة 10):

  • ‫✅ ثلاثة وكلاء متخصصون مع فصل الأدوار
  • ‫✅ ثلاث شهادات اعتماد يمكن التحقّق منها (النية → عربة التسوّق → تفويضات الدفع)
  • ‫✅ إكمال سلسلة بيانات الاعتماد مع التحقّق من تاريخ انتهاء الصلاحية في كل خطوة
  • ‫✅ آلية الحصول على موافقة صريحة مع إثبات الطابع الزمني
  • ‫✅ نشر الإصدار المتاح للاستخدام في Agent Engine مع إمكانية المراقبة
  • ✅ سجلّ كامل للمساءلة في Cloud Trace
  • ✅ أدلة جنائية لحلّ النزاعات

ورشة العمل في مقابل الإنتاج: الفجوة

يُظهر نظامك البنية والأنماط الصحيحة، ولكنّه يستخدم تبسيطات تعليمية يجب ترقيتها لاستخدامها مع أموال حقيقية ومستخدمين حقيقيين.

في ما يلي توضيح لما تم تبسيطه وما تتطلّبه عملية الإنتاج:

المكوّن

تنفيذ ورشة العمل

متطلبات الإنتاج

التواقيع

تجزئات SHA-256 (SIG_abc123) للتوضيح

توقيعات تشفير حقيقية باستخدام البنية التحتية للمفتاح العام (PKI) أو رمز JWT مع مفاتيح خاصة

معالجة الدفعات

عمليات الإرجاع المحاكية (العلامة simulation: True)

الدمج مع واجهات برمجة تطبيقات الدفع الحقيقية (Stripe وPayPal وSquare)

مصادقة المستخدم

الثقة الضمنية (لا يلزم تسجيل الدخول)

بروتوكول OAuth 2.0 أو WebAuthn أو إدارة الجلسات

إدارة الأسرار

متغيرات البيئة في ملف .env

‫Google Secret Manager أو Cloud KMS مع التشفير

قاعدة بيانات المؤسسات الخيرية

ملف JSON وهمي يتضمّن 9 مؤسسات خيرية

دمج واجهة برمجة التطبيقات المباشرة (ميزة "البحث عن المؤسسات المعفاة من الضرائب" في مصلحة الضرائب الأمريكية، وواجهة برمجة تطبيقات Charity Navigator)

التعامل مع الأخطاء

تجربة أساسية لـ try-catch مع رسائل الخطأ

منطق إعادة المحاولة مع خوارزمية الرقود الأسي الثنائي وقواطع الدائرة وقوائم انتظار الرسائل غير القابلة للتسليم

الاختبار

إثبات الملكية يدويًا باستخدام النصوص البرمجية

مجموعة شاملة من اختبارات الوحدات/الدمج/الاختبارات الشاملة مع مسار التكامل المستمر/التسليم المستمر

استمرار الجلسة

في الذاكرة (محلية) أو تلقائية (Agent Engine)

قاعدة بيانات الإنتاج مع النسخ الاحتياطية واستعادة البيانات في حالات الكوارث

الحدّ من عدد الطلبات

لا شيء (بيئة تعليمية)

حدود المعدّل لكل مستخدم، والحدّ من عدد الطلبات المستند إلى عنوان IP، ورصد إساءة الاستخدام

أنماط التصميم المعماري الرئيسية التي أتقنتها

الأنماط التي تعلّمتها في ورشة العمل هذه هي أنماط إنتاج. لا تشكّك فيهم.

فصل الأدوار (المبدأ رقم 1 من مبادئ AP2)

لكل وكيل مهمة واحدة واضحة ولا يرى إلا ما يحتاج إليه. في حال اختراق أحد الوكلاء، لا يمكن للمهاجم الوصول إلى بيانات الوكلاء الآخرين. يحدّ ذلك من نطاق التأثير.

أنظمة الإنتاج التي تستخدم هذه الميزة: معالجة الدفعات، وسير عمل المستندات، وسلاسل الموافقة، والنماذج المتعددة الخطوات التي تتضمّن بوابات التحقّق

بيانات الاعتماد التي يمكن التحقّق منها (المبدأ رقم 2 من مبادئ AP2)

لكل بيانات اعتماد وقت انتهاء صلاحية، وتشير إلى بيانات الاعتماد السابقة، وتتطلّب التحقّق من الصحة قبل الخطوة التالية. يؤدي ذلك إلى إنشاء سلسلة تدقيق غير قابلة للتلاعب.

قيمة الإنتاج: دليل كامل على ما حدث ومتى وبأي ترتيب. وهي ضرورية لحلّ النزاعات والامتثال للوائح التنظيمية.

طابع زمني يثبت موافقة المستخدم على الإجراء لا يمكن الاعتراض عليها.

القيمة الإنتاجية: شرط قانوني للمعاملات المالية يحمي كلاً من المستخدم والشركة.

التنظيم المتسلسل (نمط ADK)

يفرض ترتيب التنفيذ الصحيح. يمنع تخطّي الخطوات. يضمن أن يرى كل وكيل ناتج الوكيل السابق.

قيمة الإنتاج: مثالية للأنظمة التي تتطلّب تدخّل الإنسان حيث يتوقّع المستخدمون الحصول على نتائج فورية. هذا هو النمط المناسب لمسارات التبرّع وعمليات الدفع وسلاسل الموافقة.

إمكانية تتبُّع البيانات الكاملة (OpenTelemetry وCloud Trace)

يتم تلقائيًا تسجيل كل قرار واستدعاء أداة ولحظة موافقة وتسليم بيانات الاعتماد.

القيمة الإنتاجية: دليل الطب الشرعي لتسوية النزاعات بيانات تحسين الأداء مسارات تدقيق الامتثال تحديد المشاكل في مرحلة الإنتاج وحلّها بدقة

مراجع لمواصلة التعلّم

مستندات ADK:

المعيار AP2 والمعايير ذات الصلة:

خدمات Google Cloud:

مراجع التنظيف

لتجنُّب تحصيل رسوم مستمرة، احذف عملية النشر باتّباع الخطوات التالية:

Agent Engine: اتّبِع الخطوات الواردة في المستندات الخاصة بـ Agent Engine.

‫Cloud Run (في حال تم النشر):

gcloud run services delete charity-advisor \
    --region=$GOOGLE_CLOUD_LOCATION

حِزم التخزين:

gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-staging
gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-artifacts

رحلتك مستمرة

لقد بدأت بسؤال بسيط وأنشأت إجابة كاملة. لقد أتقنت الأنماط الأساسية لوكلاء الذكاء الاصطناعي الموثوق بهم. وتنتقل هذه الأنماط إلى أي مجال تتعامل فيه وكلاء الذكاء الاصطناعي مع عمليات حساسة، مثل المعاملات المالية وقرارات الرعاية الصحية والمستندات القانونية وعمليات سلسلة التوريد.

يتم نقل المبادئ. نموذج الثقة فعّال.

حان الوقت الآن لبناء شيء جدير بالثقة! ❤️

بانر