1. مقدمة
تم تصميم بروتوكول "من وكيل إلى وكيل" (A2A) لتوحيد التواصل بين وكلاء الذكاء الاصطناعي، لا سيما أولئك الذين يتم نشرهم في أنظمة خارجية. في السابق، تم وضع بروتوكولات مماثلة للأدوات تحت اسم بروتوكول سياق النموذج (MCP)، وهو معيار ناشئ لربط النماذج اللغوية الكبيرة بالبيانات والموارد. تحاول A2A أن تكمل MCP، حيث تركّز A2A على مشكلة مختلفة، بينما تركّز MCP على تقليل التعقيد لربط الوكلاء بالأدوات والبيانات، وتركز A2A على كيفية تمكين الوكلاء من التعاون في طرائقهم الطبيعية. تتيح هذه الميزة للوكلاء التواصل كوكلاء (أو كمستخدمين) بدلاً من التواصل كأدوات، على سبيل المثال، تتيح إجراء محادثة ذهابًا وإيابًا عندما تريد طلب شيء ما.
تم تصميم A2A لتكمّل MCP، وفي المستندات الرسمية، يُنصح بأن تستخدم التطبيقات MCP للأدوات وA2A للوكلاء، ويتم تمثيلهم من خلال AgentCard ( سنتناول هذا الموضوع لاحقًا). ويمكن للأُطر بعد ذلك استخدام A2A للتواصل مع المستخدمين والوكلاء البعيدين والوكلاء الآخرين.
في هذا العرض التوضيحي، سنبدأ بتنفيذ ميزة "التطبيق إلى التطبيق" باستخدام حزمة تطوير البرامج (SDK) الخاصة بلغة Python. سنتناول حالة استخدام عندما يكون لدينا مساعد شخصي للتسوّق يمكنه مساعدتنا في التواصل مع وكلاء بائعي البرغر والبيتزا للتعامل مع طلبنا.
تستخدِم A2A مبدأ العميل والخادم. في ما يلي مسار A2A النموذجي الذي نتوقّعه في هذا العرض التوضيحي
- سيجري برنامج A2A Client أولاً عملية البحث عن جميع بطاقات وكيل خادم A2A التي يمكن الوصول إليها، وسيستخدم معلوماتها لإنشاء برنامج اتصال.
- عند الحاجة، سيرسل تطبيق A2A Client رسالة إلى خادم A2A، وسيقيّم الخادم هذه الرسالة على أنّها مهمة يجب إكمالها. إذا تم ضبط عنوان URL الخاص بمستلِم الإشعارات الفورية على عميل A2A وكان متوافقًا مع خادم A2A، سيتمكّن الخادم أيضًا من نشر حالة تقدّم المهمة إلى نقطة النهاية المستلِمة على العميل.
- بعد انتهاء المهمة، سيرسل خادم A2A عنصر الردّ إلى عميل A2A.
خلال هذا الدرس العملي، ستتّبع نهجًا خطوة بخطوة على النحو التالي:
- إعداد مشروعك على Google Cloud وتفعيل جميع واجهات برمجة التطبيقات المطلوبة فيه
- إعداد مساحة العمل لبيئة الترميز
- إعداد متغيرات البيئة لخدمات وكيل البرغر والبيتزا وتجربتها محليًا
- نشر وكيل البرغر والبيتزا على Cloud Run
- فحص تفاصيل كيفية إنشاء خادم A2A
- إعداد متغيرات البيئة لشراء خدمة الاستقبال والتجربة محليًا
- نشر "مرشد التسوّق" في Agent Engine
- الاتصال بمحرّك الوكيل من خلال واجهة محلية
- الاطّلاع على تفاصيل حول كيفية إنشاء عميل A2A ونمذجة بياناته
- فحص الحمولة والتفاعل بين تطبيق A2A وخادمه
نظرة عامة على البنية
سننفّذ بنية الخدمة التالية
سننشر خدمتَين ستعملان كخادم A2A، وهما وكيل Burger ( الذي يستند إلى إطار عمل وكيل CrewAI) ووكيل Pizza ( الذي يستند إلى إطار عمل وكيل Langgraph). سيتفاعل المستخدم مباشرةً مع خدمة Purchasing concierge فقط، والتي سيتم تشغيلها باستخدام إطار عمل Agent Development Kit (ADK) الذي سيعمل كعميل A2A.
سيكون لكلّ من هؤلاء الوكلاء بيئة وعملية نشر خاصة به.
المتطلبات الأساسية
- إجادة العمل باستخدام لغة Python
- فهم بنية أساسية كاملة الميزات باستخدام خدمة HTTP
ما ستتعلمه
- البنية الأساسية لخادم A2A
- البنية الأساسية لبرنامج A2A Client
- نشر خدمة الوكيل على Cloud Run
- نشر خدمة الوكيل في "محرك الوكيل"
- كيفية ربط تطبيق A2A بخادم A2A
- بنية الطلب والاستجابة عند استخدام اتصال غير متواصل
المتطلبات
- متصفّح الويب Chrome
- حساب Gmail
- مشروع على السحابة الإلكترونية تم تفعيل الفوترة فيه
يستخدم هذا الدرس العملي، المصمّم للمطوّرين من جميع المستويات (بما في ذلك المبتدئين)، لغة Python في التطبيق النموذجي. ومع ذلك، لا يُشترط معرفة لغة Python لفهم المفاهيم المقدَّمة.
2. قبل البدء
اختيار المشروع النشط في Cloud Console
يفترض هذا الدرس العملي أنّه لديك مشروع على Google Cloud تم تفعيل الفوترة فيه. إذا لم تكن هذه الميزة متاحة لك بعد، يمكنك اتّباع التعليمات أدناه للبدء.
- في Google Cloud Console، في صفحة اختيار المشروع، اختَر أو أنشِئ مشروعًا على Google Cloud.
- تأكَّد من تفعيل الفوترة لمشروعك على Cloud. تعرَّف على كيفية التحقّق مما إذا كانت الفوترة مفعَّلة في مشروع.
إعداد مشروع Cloud في نافذة Cloud Shell
- ستستخدم Cloud Shell، وهي بيئة سطر أوامر تعمل في Google Cloud ومحمَّلة مسبقًا بأداة bq. انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud". إذا طُلب منك التفويض، انقر على تفويض.
- بعد الاتصال بـ Cloud Shell، يمكنك التأكّد من أنّك قد أثبتّ هويتك وأنّ المشروع مضبوط على معرّف مشروعك باستخدام الأمر التالي:
gcloud auth list
- نفِّذ الأمر التالي في Cloud Shell للتأكّد من أنّ أمر gcloud يعرف مشروعك.
gcloud config list project
- إذا لم يتم ضبط مشروعك، استخدِم الأمر التالي لضبطه:
gcloud config set project <YOUR_PROJECT_ID>
بدلاً من ذلك، يمكنك أيضًا الاطّلاع على معرّف PROJECT_ID
في وحدة التحكّم.
انقر عليه وسيظهر لك كل مشروعك ورقم تعريف المشروع على الجانب الأيسر
- فعِّل واجهات برمجة التطبيقات المطلوبة من خلال الأمر الموضّح أدناه. قد تستغرق هذه العملية بضع دقائق، لذا يُرجى الانتظار.
gcloud services enable aiplatform.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
cloudresourcemanager.googleapis.com
عند تنفيذ الأمر بنجاح، من المفترض أن تظهر لك رسالة مشابهة للرسالة الموضّحة أدناه:
Operation "operations/..." finished successfully.
يمكنك بدلاً من استخدام أمر gcloud، البحث عن كل منتج في وحدة التحكّم أو استخدام هذا الرابط.
في حال عدم توفّر أي واجهة برمجة تطبيقات، يمكنك تفعيلها في أي وقت أثناء عملية التنفيذ.
راجِع المستندات لمعرفة أوامر gcloud وطريقة استخدامها.
الانتقال إلى Cloud Shell Editor وإعداد دليل عمل التطبيق
الآن، يمكننا إعداد محرّر الرموز البرمجية لتنفيذ بعض مهام الترميز. سنستخدم "محرّر Cloud Shell" لهذا الغرض.
- انقر على الزر "فتح المحرِّر" (Open Editor)، وسيؤدي ذلك إلى فتح "محرِّر Cloud Shell" (Cloud Shell Editor)، ويمكننا كتابة الرمز هنا
- تأكَّد من ضبط مشروع Cloud Code في أسفل يمين (شريط الحالة) محرر Cloud Shell، كما هو موضّح في الصورة أدناه، ومن ضبطه على مشروع Google Cloud النشط الذي تم تفعيل الفوترة فيه. امنح الإذن إذا طُلب منك ذلك. إذا كنت قد اتّبعت الأمر السابق، قد يشير الزر أيضًا مباشرةً إلى مشروعك المفعّل بدلاً من زر تسجيل الدخول.
- بعد ذلك، لنستنسخ دليل العمل الخاص بالنموذج لهذا الدرس العملي من Github، وننفّذ الأمر التالي. سيتم إنشاء دليل العمل في الدليل purchasing-concierge-a2a
git clone https://github.com/alphinside/purchasing-concierge-intro-a2a-codelab-starter.git purchasing-concierge-a2a
- بعد ذلك، انتقِل إلى القسم العلوي من "محرّر Cloud Shell" وانقر على ملف->فتح مجلد (File->Open Folder)، وابحث عن دليل اسم المستخدم وابحث عن دليل purchasing-concierge-a2a ثم انقر على الزر "حسنًا" (OK). سيؤدي ذلك إلى جعل الدليل الذي تم اختياره هو دليل العمل الرئيسي. في هذا المثال، اسم المستخدم هو alvinprayuda، وبالتالي يظهر مسار الدليل أدناه
من المفترض أن يظهر "محرّر Cloud Shell" الآن على النحو التالي
إعداد البيئة
الخطوة التالية هي إعداد بيئة التطوير. يجب أن تكون وحدة التحكّم النشطة الحالية داخل دليل العمل purchasing-concierge-a2a. سنستخدم الإصدار 3.12 من لغة Python في هذا الدرس العملي، كما سنستخدم أداة إدارة مشاريع Python uv لتسهيل عملية إنشاء إصدار Python وبيئته الافتراضية وإدارتهما.
- إذا لم تكن قد فتحت المحطة الطرفية بعد، افتحها بالنقر على المحطة الطرفية -> محطة طرفية جديدة، أو استخدِم Ctrl + Shift + C، وسيؤدي ذلك إلى فتح نافذة محطة طرفية في الجزء السفلي من المتصفح.
- لنبدأ الآن بتهيئة البيئة الافتراضية لخدمة الاستشارة بشأن الشراء باستخدام
uv
(مثبّتة مسبقًا على الجهاز الطرفي السحابي). شغِّل هذا الأمر
uv sync --frozen
سيؤدي ذلك إلى إنشاء الدليل .venv وتثبيت الموارد التابعة. ستمنحك نظرة خاطفة سريعة على pyproject.toml معلومات عن التبعيات المعروضة على النحو التالي
dependencies = [ "a2a-sdk>=0.2.16", "google-adk>=1.8.0", "gradio>=5.38.2", ]
- لاختبار البيئة الافتراضية، أنشئ ملفًا جديدًا باسم main.py وانسخ الرمز التالي
def main():
print("Hello from purchasing-concierge-a2a!")
if __name__ == "__main__":
main()
- بعد ذلك، شغِّل الأمر التالي
uv run main.py
ستظهر لك نتيجة مشابهة لما يلي
Using CPython 3.12 Creating virtual environment at: .venv Hello from purchasing-concierge-a2a!
يشير ذلك إلى أنّه يتم إعداد مشروع Python بشكل صحيح.
يمكننا الآن الانتقال إلى الخطوة التالية، وهي ضبط وكيل البائع عن بُعد ونشره.
3- نشر وكيل البائع عن بُعد - خادم A2A إلى Cloud Run
في هذه الخطوة، سننفّذ وكيلَي البائعَين البعيدَين المحدّدَين بالمربّع الأحمر. سيتم تشغيل وكيل البرغر باستخدام إطار عمل الوكيل CrewAI، وسيتم تشغيل وكيل البيتزا باستخدام وكيل Langgraph، وكلاهما يعملان بنموذج Gemini Flash 2.0.
نشر Remote Burger Agent
يتوفّر رمز مصدر وكيل البرجر ضمن الدليل remote_seller_agents/burger_agent. يمكن فحص عملية إعداد الوكيل في النص البرمجي agent.py. إليك مقتطف الرمز الخاص بالوكيل الذي تمّت تهيئته
from crewai import Agent, Crew, LLM, Task, Process
from crewai.tools import tool
...
model = LLM(
model="vertex_ai/gemini-2.5-flash-lite", # Use base model name without provider prefix
)
burger_agent = Agent(
role="Burger Seller Agent",
goal=(
"Help user to understand what is available on burger menu and price also handle order creation."
),
backstory=("You are an expert and helpful burger seller agent."),
verbose=False,
allow_delegation=False,
tools=[create_burger_order],
llm=model,
)
agent_task = Task(
description=self.TaskInstruction,
agent=burger_agent,
expected_output="Response to the user in friendly and helpful manner",
)
crew = Crew(
tasks=[agent_task],
agents=[burger_agent],
verbose=False,
process=Process.sequential,
)
inputs = {"user_prompt": query, "session_id": sessionId}
response = crew.kickoff(inputs)
return response
...
جميع الملفات المتوفّرة في الدليل remote_seller_agents/burger_agent كافية لنشر الوكيل على Cloud Run لكي يمكن الوصول إليه كخدمة. سنتناول هذا الموضوع لاحقًا. نفِّذ الأمر التالي لنشره
gcloud run deploy burger-agent \
--source remote_seller_agents/burger_agent \
--port=8080 \
--allow-unauthenticated \
--min 1 \
--region us-central1 \
--update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
--update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}
إذا طُلب منك إنشاء مستودع حاويات للنشر من المصدر، أجب بـ Y. يحدث ذلك فقط إذا لم يسبق لك نشر تطبيق على Cloud Run من المصدر. بعد نشر التطبيق بنجاح، سيظهر سجلّ على النحو التالي.
Service [burger-agent] revision [burger-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic. Service URL: https://burger-agent-xxxxxxxxx.us-central1.run.app
سيكون الجزء xxxx
هنا معرّفًا فريدًا عند نشر الخدمة. الآن، لنحاول الانتقال إلى https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
مسار خدمات وكيل البرجر التي تم نشرها من خلال المتصفح. هذا هو عنوان URL للوصول إلى بطاقة وكيل خادم A2A التي تم نشرها.
في حال تم نشرها بنجاح، ستظهر لك الاستجابة كما هو موضّح أدناه في المتصفّح عند الوصول إلى https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
:
هذه هي معلومات بطاقة وكيل البرغر التي يجب أن تكون متاحة لأغراض الاكتشاف. سنتناول هذا الموضوع لاحقًا. لاحظ أنّ قيمة url
لا تزال مضبوطة على http://0.0.0.0:8080/
هنا. يجب أن تكون قيمة url
هذه هي المعلومات الرئيسية التي يستخدمها تطبيق A2A Client لإرسال الرسائل من العالم الخارجي، ولكن لم يتم ضبطها بشكل صحيح. في هذا العرض التوضيحي، سنحتاج إلى تعديل هذه القيمة إلى عنوان URL لخدمة وكيل البرغر من خلال إضافة متغير بيئة إضافي HOST_OVERRIDE
.
تعديل قيمة عنوان URL الخاص بـ Burger Agent على بطاقة Agent Card من خلال متغير البيئة
لإضافة HOST_OVERRIDE
إلى خدمة وكيل البرغر، اتّبِع الخطوات التالية
- ابحث عن Cloud Run في شريط البحث أعلى وحدة تحكّم السحابة الإلكترونية
- انقر على خدمة burger-agent التي تم نشرها سابقًا على Cloud Run
- انسخ عنوان URL الخاص بخدمة البرجر، ثم انقر على تعديل ونشر مراجعة جديدة.
- بعد ذلك، انقر على قسم المتغيرات والأسرار.
- بعد ذلك، انقر على إضافة متغيّر واضبط قيمة
HOST_OVERRIDE
على عنوان URL للخدمة ( العنوان الذي يتضمّن النمطhttps://burger-agent-xxxxxxxxx.us-central1.run.app
).
- أخيرًا، انقر على الزر نشر لإعادة نشر خدمتك.
الآن، عند الوصول إلى بطاقة وكيل burger-agent مرة أخرى في المتصفّح https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
، سيتم ضبط القيمة url
بشكلٍ سليم.
نشر وكيل البيتزا عن بُعد
وبالمثل، يقع رمز مصدر وكيل البيتزا ضمن الدليل remote_seller_agents/pizza_agent. يمكن فحص عملية إعداد الوكيل في النص البرمجي agent.py. إليك مقتطف الرمز الخاص بالوكيل الذي تمّت تهيئته
from langchain_google_vertexai import ChatVertexAI
from langgraph.prebuilt import create_react_agent
...
self.model = ChatVertexAI(
model="gemini-2.5-flash-lite",
location=os.getenv("GOOGLE_CLOUD_LOCATION"),
project=os.getenv("GOOGLE_CLOUD_PROJECT"),
)
self.tools = [create_pizza_order]
self.graph = create_react_agent(
self.model,
tools=self.tools,
checkpointer=memory,
prompt=self.SYSTEM_INSTRUCTION,
)
...
على غرار خطوة نشر وكيل البرغر السابقة، تكفي جميع الملفات المتوفرة ضمن الدليل remote_seller_agents/pizza_agent لنشر الوكيل على Cloud Run كي يمكن الوصول إليه كخدمة. نفِّذ الأمر التالي لنشره
gcloud run deploy pizza-agent \
--source remote_seller_agents/pizza_agent \
--port=8080 \
--allow-unauthenticated \
--min 1 \
--region us-central1 \
--update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
--update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}
بعد نشر التطبيق بنجاح، سيظهر سجلّ على النحو التالي.
Service [pizza-agent] revision [pizza-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic. Service URL: https://pizza-agent-xxxxxxxxx.us-central1.run.app
سيكون الجزء xxxx
هنا معرّفًا فريدًا عند نشر الخدمة. ينطبق الأمر نفسه على وكيل البرغر، فعند محاولة الانتقال إلى مسار https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
لخدمات وكيل البيتزا التي تم نشرها من خلال المتصفّح للوصول إلى بطاقة وكيل الخادم A2A، لم يتم ضبط قيمة وكيل البيتزا url
على بطاقة الوكيل بشكل صحيح بعد. علينا أيضًا إضافة HOST_OVERRIDE
إلى متغير البيئة
تعديل قيمة عنوان URL الخاص بـ "وكيل البيتزا" على بطاقة الوكيل من خلال متغير البيئة
لإضافة HOST_OVERRIDE
إلى خدمة وكيل البيتزا، اتّبِع الخطوات التالية
- ابحث عن Cloud Run في شريط البحث أعلى وحدة تحكّم السحابة الإلكترونية
- انقر على خدمة pizza-agent التي تم نشرها سابقًا على Cloud Run
- انقر على تعديل ونشر نسخة جديدة.
- انسخ عنوان URL الخاص بخدمة البيتزا، ثم انقر على قسم المتغيرات والأسرار.
- بعد ذلك، انقر على إضافة متغيّر واضبط قيمة
HOST_OVERRIDE
على عنوان URL للخدمة ( العنوان الذي يتضمّن النمطhttps://pizza-agent-xxxxxxxxx.us-central1.run.app
).
- أخيرًا، انقر على الزر نشر لإعادة نشر خدمتك.
الآن، عند الوصول إلى بطاقة وكيل pizza-agent مرة أخرى في المتصفح https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
، ستكون قيمة url
قد تم ضبطها بشكل صحيح
في هذه المرحلة، نكون قد نشرنا بنجاح كلاً من خدمة البرغر وخدمة البيتزا على Cloud Run. لنناقش الآن المكوّنات الأساسية لخادم A2A
4. المكوّنات الأساسية لخادم A2A
لنناقش الآن المفهوم الأساسي ومكوّنات خادم A2A
بطاقة الوكيل
يجب أن يحتوي كل خادم A2A على بطاقة وكيل يمكن الوصول إليها من خلال المرجع /.well-known/agent.json
. يهدف ذلك إلى دعم مرحلة الاستكشاف على تطبيق "العميل من التطبيق إلى التطبيق"، والذي من المفترض أن يقدّم معلومات وسياقات كاملة حول كيفية الوصول إلى الوكيل ومعرفة جميع إمكاناته. الأمر مشابه إلى حدّ ما مع توفّر وثائق واجهة برمجة تطبيقات موثّقة بشكل جيد باستخدام Swagger أو Postman.
هذا هو محتوى بطاقة وكيل برجر التي تم نشرها
{
"capabilities": {
"streaming": true
},
"defaultInputModes": [
"text",
"text/plain"
],
"defaultOutputModes": [
"text",
"text/plain"
],
"description": "Helps with creating burger orders",
"name": "burger_seller_agent",
"protocolVersion": "0.2.6",
"skills": [
{
"description": "Helps with creating burger orders",
"examples": [
"I want to order 2 classic cheeseburgers"
],
"id": "create_burger_order",
"name": "Burger Order Creation Tool",
"tags": [
"burger order creation"
]
}
],
"url": "https://burger-agent-109790610330.us-central1.run.app",
"version": "1.0.0"
}
تُبرز بطاقات الوكيل هذه العديد من المكوّنات المهمة، مثل مهارات الوكيل وإمكانات البث والوسائط المتوافقة وإصدار البروتوكول وغير ذلك.
يمكن استخدام كل هذه المعلومات لتطوير آلية تواصل مناسبة كي يتمكّن عميل A2A من التواصل بشكلٍ سليم. تضمن طريقة التواصل وآلية المصادقة المتوافقتان إمكانية إنشاء التواصل بشكل صحيح، ويمكن تضمين معلومات skills
الوكيل في طلب نظام عميل A2A لمنح وكيل العميل سياقًا حول إمكانات ومهارات الوكيل البعيد التي سيتم استدعاؤها. يمكنك العثور على حقول أكثر تفصيلاً لبطاقة الوكيل هذه في هذا المستند.
في الرمز البرمجي، يتم إنشاء بطاقة الوكيل باستخدام حزمة تطوير البرامج (SDK) الخاصة بلغة Python في A2A. اطّلِع على مقتطف الرمز البرمجي remote_seller_agents/burger_agent/main.py أدناه لمعرفة طريقة التنفيذ.
...
capabilities = AgentCapabilities(streaming=True)
skill = AgentSkill(
id="create_burger_order",
name="Burger Order Creation Tool",
description="Helps with creating burger orders",
tags=["burger order creation"],
examples=["I want to order 2 classic cheeseburgers"],
)
agent_host_url = (
os.getenv("HOST_OVERRIDE")
if os.getenv("HOST_OVERRIDE")
else f"http://{host}:{port}/"
)
agent_card = AgentCard(
name="burger_seller_agent",
description="Helps with creating burger orders",
url=agent_host_url,
version="1.0.0",
defaultInputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
defaultOutputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
capabilities=capabilities,
skills=[skill],
)
...
يمكننا الاطّلاع على عدّة حقول، مثل:
-
AgentCapabilities
: بيان بالوظائف الاختيارية الإضافية التي توفّرها خدمة الوكيل، مثل إمكانية بث المحتوى و/أو إتاحة الإشعارات الفورية -
AgentSkill
: الأدوات أو الوظائف التي يتيحها الوكيل -
Input/OutputModes
: نوع الوسائط المتوافق مع الإدخال/الإخراج Url
: عنوان للتواصل مع الوكيل
في هذا الإعداد، نوفّر إنشاء عنوان URL ديناميكي لمضيف الوكيل، ما يسهّل التبديل بين الاختبار المحلي والنشر على السحابة الإلكترونية، ولهذا السبب نحتاج إلى إضافة المتغيّر HOST_OVERRIDE
في الخطوة السابقة.
قائمة انتظار المهام ووكيل التنفيذ
قد يعالج خادم A2A الطلبات من وكلاء أو مستخدمين مختلفين، وقد يكون قادرًا على عزل كل مهمة بشكلٍ مثالي. للاطّلاع على سياقات هذه الصور بشكل أفضل، يمكنك فحص الصورة أدناه
وبالتالي، يجب أن يكون كل خادم A2A قادرًا على تتبُّع المهام الواردة وتخزين المعلومات المناسبة عنها. توفّر حزمة تطوير البرامج (SDK) من A2A وحدات لمواجهة هذا التحدي في خادم A2A. أولاً، يمكننا إنشاء منطق حول كيفية التعامل مع الطلب الوارد. من خلال وراثة فئة AgentExecutor المجردة، يمكننا التحكّم في كيفية إدارة تنفيذ المهام وإلغائها. يمكن فحص عملية التنفيذ هذه في الوحدة remote_seller_agents/burger_agent/agent_executor.py
( مسار مشابه لحالة بائع البيتزا)
...
class BurgerSellerAgentExecutor(AgentExecutor):
"""Burger Seller AgentExecutor."""
def __init__(self):
self.agent = BurgerSellerAgent()
async def execute(
self,
context: RequestContext,
event_queue: EventQueue,
) -> None:
query = context.get_user_input()
try:
result = self.agent.invoke(query, context.context_id)
print(f"Final Result ===> {result}")
parts = [Part(root=TextPart(text=str(result)))]
await event_queue.enqueue_event(
completed_task(
context.task_id,
context.context_id,
[new_artifact(parts, f"burger_{context.task_id}")],
[context.message],
)
)
except Exception as e:
print("Error invoking agent: %s", e)
raise ServerError(error=ValueError(f"Error invoking agent: {e}")) from e
async def cancel(
self, request: RequestContext, event_queue: EventQueue
) -> Task | None:
raise ServerError(error=UnsupportedOperationError())
...
في الرمز أعلاه، ننفّذ مخطط معالجة أساسيًا يتم فيه استدعاء الوكيل مباشرةً عند ورود الطلب وإرسال أحداث المهام المكتملة بعد انتهاء الاستدعاء. ومع ذلك، لم ننفّذ طريقة الإلغاء هنا لأنّها كانت تُعتبر عملية قصيرة الأمد.
بعد إنشاء المنفّذ، يمكننا الاستفادة مباشرةً من DefaultRequestHandler وInMemoryTaskStore وA2AStarletteApplication المضمّنة لتشغيل خادم HTTP. يمكن فحص عملية التنفيذ هذه في remote_seller_agents/burger_agent/__main__.py
...
request_handler = DefaultRequestHandler(
agent_executor=BurgerSellerAgentExecutor(),
task_store=InMemoryTaskStore(),
)
server = A2AStarletteApplication(
agent_card=agent_card, http_handler=request_handler
)
uvicorn.run(server.build(), host=host, port=port)
...
سيتيح لك هذا النموذج تنفيذ المسار /.well-known/agent.json
للوصول إلى بطاقة الوكيل، بالإضافة إلى نقطة النهاية POST لدعم بروتوكول A2A.
ملخّص
باختصار، حتى الآن، تم نشر خادم A2A باستخدام حزمة تطوير البرامج (SDK) للغة Python التي يمكنها توفير الوظيفتَين أدناه:
- نشر بطاقة الوكيل على المسار
/.well-known/agent.json
- التعامل مع طلب JSON-RPC باستخدام نظام صفوف انتظار المهام في الذاكرة
يمكن فحص نقطة الدخول عند بدء هذه الوظائف في النص البرمجي __main__.py
( على remote_seller_agents/burger_agent
أو remote_seller_agents/pizza_agent
) .
5- نشر "مرشد التسوّق" - عميل A2A إلى "محرك الوكيل"
في هذه الخطوة، سننفّذ وكيل خدمة التسوق. هذا هو الوكيل الذي سنتفاعل معه.
يتوفّر رمز المصدر الخاص بوكيل خدمة التسوّق في الدليل purchasing_concierge. يمكن فحص عملية تهيئة الوكيل في النص البرمجي purchasing_agent.py. في ما يلي مقتطف الرمز البرمجي للعامل الذي تمّت تهيئته.
from google.adk import Agent
...
def create_agent(self) -> Agent:
return Agent(
model="gemini-2.5-flash-lite",
name="purchasing_agent",
instruction=self.root_instruction,
before_model_callback=self.before_model_callback,
before_agent_callback=self.before_agent_callback,
description=(
"This purchasing agent orchestrates the decomposition of the user purchase request into"
" tasks that can be performed by the seller agents."
),
tools=[
self.send_task,
],
)
...
سننشر هذا الوكيل في محرك الوكيل. Vertex AI Agent Engine هي مجموعة من الخدمات التي تتيح للمطوّرين نشر وكلاء الذكاء الاصطناعي وإدارتهم وتوسيع نطاق عملهم في مرحلة الإنتاج. يتولّى هذا الإطار البنية الأساسية لتوسيع نطاق الوكلاء في مرحلة الإنتاج، ما يتيح لنا التركيز على إنشاء التطبيقات. يمكنك الاطّلاع على مزيد من المعلومات حول هذا الموضوع في هذا المستند . إذا كنّا نحتاج سابقًا إلى إعداد الملفات اللازمة لنشر خدمة الوكيل (مثل نص خادم main وDockerfile)، يمكننا في هذه الحالة نشر الوكيل مباشرةً من نص Python البرمجي بدون الحاجة إلى تطوير خدمة الخلفية الخاصة بنا باستخدام مجموعة من ADK وAgent Engine. اتّبِع الخطوات التالية لتفعيلها :
- أولاً، علينا إنشاء مساحة تخزين مؤقتة في Cloud Storage
gcloud storage buckets create gs://purchasing-concierge-{your-project-id} --location=us-central1
- الآن، علينا إعداد المتغير .env أولاً، لننسخ الملف .env.example إلى الملف .env
cp .env.example .env
- الآن، افتح ملف .env وسيظهر لك المحتوى التالي
GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT={your-project-id} GOOGLE_CLOUD_LOCATION=us-central1 STAGING_BUCKET=gs://purchasing-concierge-{your-project-id} PIZZA_SELLER_AGENT_URL={your-pizza-agent-url} BURGER_SELLER_AGENT_URL={your-burger-agent-url} AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}
سيتواصل هذا الوكيل مع وكيل البرغر والبيتزا، لذا علينا تقديم بيانات الاعتماد المناسبة لكليهما. علينا تعديل PIZZA_SELLER_AGENT_URL وBURGER_SELLER_AGENT_URL باستخدام عنوان URL لخدمة Cloud Run من الخطوات السابقة.
إذا نسيت ذلك، لننتقل إلى وحدة تحكّم Cloud Run. اكتب "Cloud Run" في شريط البحث أعلى وحدة التحكّم وانقر بزر الماوس الأيمن على رمز Cloud Run لفتحه في علامة تبويب جديدة.
من المفترض أن تظهر لك خدمات وكيل البيع عن بُعد التي تم نشرها سابقًا كما هو موضّح أدناه
للاطّلاع على عنوان URL المتاح للجميع لهذه الخدمات، انقر على إحدى الخدمات وسيتمّ إعادة توجيهك إلى صفحة "تفاصيل الخدمة". يمكنك الاطّلاع على عنوان URL في المنطقة العلوية بجانب معلومات المنطقة.
يجب أن يبدو متغير البيئة النهائي مشابهًا لهذا المتغير
GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT={your-project-id} GOOGLE_CLOUD_LOCATION=us-central1 STAGING_BUCKET=gs://purchasing-concierge-{your-project-id} PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}
- أصبحنا الآن جاهزين لنشر وكيل خدمة التسوق. في هذا العرض التوضيحي، سننفّذ عملية النشر باستخدام النص البرمجي
deploy_to_agent_engine.py
الذي يظهر المحتوى أدناه.
"""
Copyright 2025 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import vertexai
from vertexai.preview import reasoning_engines
from vertexai import agent_engines
from dotenv import load_dotenv
import os
from purchasing_concierge.agent import root_agent
load_dotenv()
PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT")
LOCATION = os.getenv("GOOGLE_CLOUD_LOCATION")
STAGING_BUCKET = os.getenv("STAGING_BUCKET")
vertexai.init(
project=PROJECT_ID,
location=LOCATION,
staging_bucket=STAGING_BUCKET,
)
adk_app = reasoning_engines.AdkApp(
agent=root_agent,
)
remote_app = agent_engines.create(
agent_engine=adk_app,
display_name="purchasing-concierge",
requirements=[
"google-cloud-aiplatform[adk,agent_engines]",
"a2a-sdk==0.2.16",
],
extra_packages=[
"./purchasing_concierge",
],
env_vars={
"GOOGLE_GENAI_USE_VERTEXAI": os.environ["GOOGLE_GENAI_USE_VERTEXAI"],
"PIZZA_SELLER_AGENT_URL": os.environ["PIZZA_SELLER_AGENT_URL"],
"BURGER_SELLER_AGENT_URL": os.environ["BURGER_SELLER_AGENT_URL"],
},
)
print(f"Deployed remote app resource: {remote_app.resource_name}")
في ما يلي الخطوات اللازمة لنشر وكيل ADK في محرك الوكيل. أولاً، علينا إنشاء كائن AdkApp
من حزمة تطوير البرامج (ADK) root_agent
. بعد ذلك، يمكننا تنفيذ طريقة agent_engines.create
من خلال توفير عنصر adk_app
، وتحديد المتطلبات في الحقل requirements
، وتحديد مسار دليل الوكيل في extra_packages
، وتوفير متغيرات env اللازمة.
يمكننا نشرها عن طريق تنفيذ النص البرمجي:
uv run deploy_to_agent_engine.py
بعد نشر التطبيق بنجاح، سيظهر سجلّ على النحو التالي. ملاحظات بأنّ xxxx هو معرّف مشروعك وyyyy هو معرّف مورد محرك الوكيل
AgentEngine created. Resource name: projects/xxxx/locations/us-central1/reasoningEngines/yyyy To use this AgentEngine in another session: agent_engine = vertexai.agent_engines.get('projects/xxxx/locations/us-central1/reasoningEngines/yyyy) Deployed remote app resource: projects/xxxx/locations/us-central1/reasoningEngines/xxxx
وعندما نفحصه في لوحة بيانات Agent Engine (ابحث عن "Agent Engine" في شريط البحث)، سيظهر النشر السابق.
اختبار الوكيل الذي تم نشره على Agent Engine
يمكن التفاعل مع محرّك الوكيل من خلال الأمر curl
وحزمة تطوير البرامج (SDK). على سبيل المثال، شغِّل الأمر التالي لمحاولة التفاعل مع الوكيل الذي تم نشره.
يمكنك محاولة إرسال هذا الاستعلام للتحقّق مما إذا تم نشر الوكيل بنجاح
curl \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://us-central1-aiplatform.googleapis.com/v1/projects/{YOUR_PROJECT_ID}/locations/us-central1/reasoningEngines/{YOUR_AGENT_ENGINE_RESOURCE_ID}:streamQuery?alt=sse -d '{
"class_method": "stream_query",
"input": {
"user_id": "user_123",
"message": "List available burger menu please",
}
}'
في حال نجاح العملية، سيتم عرض عدة أحداث استجابة يتم بثها على وحدة التحكّم على النحو التالي
{ "content": { "parts": [ { "text": "Here is our burger menu:\n- Classic Cheeseburger: IDR 85K\n- Double Cheeseburger: IDR 110K\n- Spicy Chicken Burger: IDR 80K\n- Spicy Cajun Burger: IDR 85K" } ], "role": "model" }, "usage_metadata": { "candidates_token_count": 51, "candidates_tokens_details": [ { "modality": "TEXT", "token_count": 51 } ], "prompt_token_count": 907, "prompt_tokens_details": [ { "modality": "TEXT", "token_count": 907 } ], "total_token_count": 958, "traffic_type": "ON_DEMAND" }, "invocation_id": "e-14679918-af68-45f1-b942-cf014368a733", "author": "purchasing_agent", "actions": { "state_delta": {}, "artifact_delta": {}, "requested_auth_configs": {} }, "id": "dbe7fc43-b82a-4f3e-82aa-dd97afa8f15b", "timestamp": 1754287348.941454 }
سنحاول استخدام واجهة المستخدم في الخطوة التالية، ولكن دعنا نناقش أولاً المكوّنات الأساسية والمسار النموذجي لبرامج A2A.
6. المكوّنات الأساسية لعميل A2A
الصورة المعروضة أعلاه هي التدفق النموذجي لتفاعلات التطبيق مع تطبيق آخر:
- سيحاول العميل العثور على أي بطاقة وكيل منشورة في عنوان URL الخاص بالوكيل البعيد المقدَّم في المسار
/.well-known/agent.json
- بعد ذلك، سيرسل الخادم رسالة إلى هذا الوكيل تتضمّن الرسالة ومعلمات البيانات الوصفية اللازمة ( مثل معرّف الجلسة والسياق السابق وما إلى ذلك) عند الضرورة، وسيتعامل الخادم مع هذه الرسالة على أنّها مهمة يجب إكمالها.
- يعالج خادم A2A الطلب، وإذا كان الخادم يتيح إرسال الإشعارات الفورية، سيكون بإمكانه أيضًا نشر بعض الإشعارات أثناء معالجة المهمة ( لا تتضمّن ورشة العمل البرمجية هذه هذه الوظيفة).
- بعد الانتهاء، سيرسل خادم A2A عنصر الردّ إلى العميل.
بعض العناصر الأساسية للتفاعلات المذكورة أعلاه هي ما يلي (يمكنك الاطّلاع على مزيد من التفاصيل هنا) :
- الرسالة: هي تبادل للمعلومات بين العميل وموظف الدعم عن بُعد
- المهمة: هي وحدة العمل الأساسية التي تديرها A2A، ويتم تحديدها من خلال معرّف فريد.
- الناتج: هو نتيجة (مثل مستند أو صورة أو بيانات منظَّمة) ينشئها الوكيل نتيجةً لمهمة، ويتألف من أجزاء.
- الجزء: هو أصغر وحدة محتوى ضمن "رسالة" أو "عنصر". يمكن أن يكون الجزء نصًا أو صورة أو فيديو أو ملفًا أو غير ذلك.
استكشاف البطاقات
عند إعداد خدمة A2A Client، تتمثل العملية النموذجية في محاولة الحصول على معلومات بطاقة الوكيل وتخزينها لتسهيل الوصول إليها عند الحاجة. في هذا الدرس العملي، ننفّذها على before_agent_callback
، ويمكنك الاطّلاع على التنفيذ في purchasing_concierge/purchasing_agent.py
من خلال مقتطف الرمز البرمجي أدناه.
...
async def before_agent_callback(self, callback_context: CallbackContext):
if not self.a2a_client_init_status:
httpx_client = httpx.AsyncClient(timeout=httpx.Timeout(timeout=30))
for address in self.remote_agent_addresses:
card_resolver = A2ACardResolver(
base_url=address, httpx_client=httpx_client
)
try:
card = await card_resolver.get_agent_card()
remote_connection = RemoteAgentConnections(
agent_card=card, agent_url=card.url
)
self.remote_agent_connections[card.name] = remote_connection
self.cards[card.name] = card
except httpx.ConnectError:
print(f"ERROR: Failed to get agent card from : {address}")
agent_info = []
for ra in self.list_remote_agents():
agent_info.append(json.dumps(ra))
self.agents = "\n".join(agent_info)
...
في هذه الخطوة، نحاول الوصول إلى جميع بطاقات الوكيل المتاحة باستخدام وحدة A2ACardResolver
المضمّنة في عميل A2A، ثم نجمع معلومات الاتصال اللازمة لإرسال رسالة إلى الوكيل، وبعد ذلك نحتاج أيضًا إلى إدراج جميع الوكلاء المتاحين ومواصفاتهم في الطلب حتى يعرف الوكيل أنّه يمكنه التواصل مع هؤلاء الوكلاء.
أداة "الطلب وإرسال المهمة"
هذا هو الطلب والأداة اللذان نقدّمهما إلى وكيل ADK هنا
...
def root_instruction(self, context: ReadonlyContext) -> str:
current_agent = self.check_active_agent(context)
return f"""You are an expert purchasing delegator that can delegate the user product inquiry and purchase request to the
appropriate seller remote agents.
Execution:
- For actionable tasks, you can use `send_task` to assign tasks to remote agents to perform.
- When the remote agent is repeatedly asking for user confirmation, assume that the remote agent doesn't have access to user's conversation context.
So improve the task description to include all the necessary information related to that agent
- Never ask user permission when you want to connect with remote agents. If you need to make connection with multiple remote agents, directly
connect with them without asking user permission or asking user preference
- Always show the detailed response information from the seller agent and propagate it properly to the user.
- If the remote seller is asking for confirmation, rely the confirmation question to the user if the user haven't do so.
- If the user already confirmed the related order in the past conversation history, you can confirm on behalf of the user
- Do not give irrelevant context to remote seller agent. For example, ordered pizza item is not relevant for the burger seller agent
- Never ask order confirmation to the remote seller agent
Please rely on tools to address the request, and don't make up the response. If you are not sure, please ask the user for more details.
Focus on the most recent parts of the conversation primarily.
If there is an active agent, send the request to that agent with the update task tool.
Agents:
{self.agents}
Current active seller agent: {current_agent["active_agent"]}
"""
...
async def send_task(self, agent_name: str, task: str, tool_context: ToolContext):
"""Sends a task to remote seller agent
This will send a message to the remote agent named agent_name.
Args:
agent_name: The name of the agent to send the task to.
task: The comprehensive conversation context summary
and goal to be achieved regarding user inquiry and purchase request.
tool_context: The tool context this method runs in.
Yields:
A dictionary of JSON data.
"""
if agent_name not in self.remote_agent_connections:
raise ValueError(f"Agent {agent_name} not found")
state = tool_context.state
state["active_agent"] = agent_name
client = self.remote_agent_connections[agent_name]
if not client:
raise ValueError(f"Client not available for {agent_name}")
session_id = state["session_id"]
task: Task
message_id = ""
metadata = {}
if "input_message_metadata" in state:
metadata.update(**state["input_message_metadata"])
if "message_id" in state["input_message_metadata"]:
message_id = state["input_message_metadata"]["message_id"]
if not message_id:
message_id = str(uuid.uuid4())
payload = {
"message": {
"role": "user",
"parts": [
{"type": "text", "text": task}
], # Use the 'task' argument here
"messageId": message_id,
"contextId": session_id,
},
}
message_request = SendMessageRequest(
id=message_id, params=MessageSendParams.model_validate(payload)
)
send_response: SendMessageResponse = await client.send_message(
message_request=message_request
)
print(
"send_response",
send_response.model_dump_json(exclude_none=True, indent=2),
)
if not isinstance(send_response.root, SendMessageSuccessResponse):
print("received non-success response. Aborting get task ")
return None
if not isinstance(send_response.root.result, Task):
print("received non-task response. Aborting get task ")
return None
return send_response.root.result
...
في الطلب، نقدّم لموظف خدمة العملاء الخاص بالتسوّق جميع أسماء الموظفين المتاحين عن بُعد وأوصافهم، وفي الأداة self.send_task
، نوفّر آلية لاسترداد العميل المناسب للتواصل مع الموظف وإرسال البيانات الوصفية المطلوبة باستخدام العنصر SendMessageRequest
.
بروتوكولات الاتصال
تعريف المهمة هو نطاق يملكه خادم A2A. ومع ذلك، من منظور عميل A2A، يرى ذلك على أنّه رسالة يتم إرسالها إلى الخادم، ويعود إلى الخادم تحديد كيفية تعريف الرسائل الواردة من العميل على أنّها مهمة وما إذا كان إكمال المهمة يتطلّب تفاعلاً من العميل، ويمكنك الاطّلاع على مزيد من التفاصيل حول دورة حياة المهمة في هذا المستند. يمكنك الاطّلاع أدناه على المفهوم الأوسع نطاقًا لهذا الإجراء:
يتم تنفيذ عملية تبادل الرسائل والمهام هذه باستخدام تنسيق البيانات الأساسية استنادًا إلى معيار JSON-RPC كما هو موضّح في المثال التالي لبروتوكول message/send
:
{ # identifier for this request "id": "abc123", # version of JSON-RPC protocol "jsonrpc": "2.0", # method name "method": "message/send", # parameters/arguments of the method "params": { "message": "hi, what can you help me with?" } }
تتوفّر طرق مختلفة، مثلاً لدعم أنواع مختلفة من الاتصالات (مثل المزامنة والبث والاتصال غير المتزامن) أو لضبط الإشعارات بشأن حالة المهمة. يمكن ضبط خادم A2A بمرونة للتعامل مع معايير تعريف المهام هذه. يمكنك الاطّلاع على تفاصيل هذه الطرق في هذا المستند.
7. اختبار الدمج وفحص الحمولة
لنلقِ نظرة الآن على خدمة المساعدة في الشراء من خلال التفاعل مع الوكيل عن بُعد باستخدام واجهة مستخدم على الويب.
أولاً، علينا تعديل AGENT_ENGINE_RESOURCE_NAME
في .ملف env
تأكَّد من تقديم اسم المورد الصحيح لمحرك الوكيل. يجب أن يظهر ملف .env
على النحو التالي:
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT={your-project-id}
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://purchasing-concierge-{your-project-id}
PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app
BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app
AGENT_ENGINE_RESOURCE_NAME=projects/xxxx/locations/us-central1/reasoningEngines/yyyy
بعد ذلك، شغِّل الأمر التالي لنشر تطبيق Gradio
uv run purchasing_concierge_ui.py
ستظهر النتيجة التالية في حال نجاح العملية
* Running on local URL: http://0.0.0.0:8080 * To create a public link, set `share=True` in `launch()`.
بعد ذلك، انقر مع الضغط على Ctrl على عنوان URL http://0.0.0.0:8080 في الوحدة الطرفية أو انقر على زر معاينة الويب لفتح واجهة مستخدم الويب.
حاوِل إجراء محادثة على النحو التالي :
- عرض قائمة طعام البرغر والبيتزا
- أريد طلب بيتزا دجاج مشوي واحدة وبرجر كاجون حار واحد
ويمكنك مواصلة المحادثة إلى أن تنتهي من الطلب. اطّلِع على سير التفاعل وما هي استدعاءات الأدوات وردودها. الصورة التالية هي مثال على نتيجة التفاعل.
يمكننا أن نرى أنّ التواصل مع وكيلَين مختلفَين يؤدي إلى سلوكَين مختلفَين، ويمكن لـ A2A التعامل مع هذا الأمر بشكل جيد. يقبل وكيل بائع البيتزا طلب وكيل الشراء مباشرةً، بينما يحتاج وكيل البرغر إلى تأكيد منّا قبل المتابعة في تنفيذ طلبنا، وبعد أن نؤكّد له ذلك، يمكنه إرسال التأكيد إلى وكيل البرغر
الآن، انتهينا من المفاهيم الأساسية لعملية الربط بين التطبيقات، وسنرى كيف يتم تنفيذها كبنية قائمة على البرنامج والخادم.
8. التحدي
هل يمكنك الآن إعداد الملف اللازم ونشر تطبيق Gradio على Cloud Run بنفسك؟ حان الوقت لخوض التحدي!
9- تَنظيم
لتجنُّب تحمّل رسوم في حسابك على Google Cloud مقابل الموارد المستخدَمة في هذا الدرس العملي، اتّبِع الخطوات التالية:
- في Google Cloud Console، انتقِل إلى صفحة إدارة الموارد.
- في قائمة المشاريع، اختَر المشروع الذي تريد حذفه، ثم انقر على حذف.
- في مربّع الحوار، اكتب رقم تعريف المشروع، ثم انقر على إيقاف لحذف المشروع.
- بدلاً من ذلك، يمكنك الانتقال إلى Cloud Run في وحدة التحكّم، واختيار الخدمة التي تم نشرها للتو وحذفها.