1. مقدمة

تعرَّف على كيفية إنشاء محرّك متعدد الوسائط ومتعدد الوكلاء يأخذ موجزًا أوليًا للموضوع وينسّق عملية إنشاء مواد عرض جذابة للغاية على وسائل التواصل الاجتماعي. باستخدام "حزمة تطوير الوكلاء" (ADK) من Google وبروتوكول Agent2Agent (A2A)، ستنشئ وكلاء مصغّرين مستقلين، وتضمّن قواعد العلامة التجارية كمهارة وكيل قابلة لإعادة الاستخدام، وتنشئ خدمة وكيل على Cloud Run، وتقيِّم المرئيات الرئيسية التي تم إنشاؤها للتأكّد من امتثالها للعلامة التجارية باستخدام وظائف الذكاء الاصطناعي في BigQuery.
الإجراءات التي ستنفذّها
في هذا الدرس التطبيقي، ستتعرّف على كيفية تنفيذ المهام التالية:
- يمكنك تنسيق عدة وكلاء ADK باستخدام سير عمل رسم بياني قطعي.
- تضمين إرشادات العلامة التجارية للحزمة كمهارة وكيل يتم تحميلها فقط عند الحاجة
- تزويد وكيل بأداة إنشاء صور تحفظ نتائجها كعنصر.
- عرض وكيل كخدمة A2A واستدعاؤه من وكيل آخر كعقدة بعيدة
- انشر Visual Director على Cloud Run واستدعِ سير العمل عبر A2A.
- تقييم المرئيات الرئيسية التي تم إنشاؤها من حيث مدى ملاءمتها للعلامة التجارية في BigQuery باستخدام دوال الذكاء الاصطناعي
المتطلبات
- متصفّح ويب (مثل Chrome)
- حساب Google Cloud ومشروع Google Cloud تم تفعيل الفوترة فيه
2. قبل البدء
إنشاء مشروع على Google Cloud
- في Google Cloud Console، اختَر مشروعًا على Google Cloud أو أنشِئ مشروعًا جديدًا في صفحة اختيار المشاريع.
- تأكَّد من تفعيل الفوترة لمشروعك على السحابة الإلكترونية. كيفية التحقّق مما إذا كانت الفوترة مفعَّلة في مشروع
بدء Cloud Shell
ستستخدم Google Cloud Shell لتنزيل الرمز البرمجي وتشغيل نصوص الإعداد ونشر التطبيق.
- افتح Google Cloud Shell في المتصفّح (أو انقر على تفعيل Cloud Shell في أعلى Google Cloud Console):
انقر على متابعة إذا تلقّيت إشعارات إضافية.انتظِر إلى أن يتم تحميل كلّ من نافذة الأوامر والمحرّر بالكامل. قد يستغرق ذلك دقيقة أو دقيقتين.https://shell.cloud.google.com/ - اضبط رقم تعريف مشروعك ومنطقتك على Google Cloud (مثلاً،
us-central1) في بيئتك من خلال لصق هذا الرمز في نافذة الأوامر (استبدِلوبقيمك):export PROJECT_ID="<YOUR_PROJECT_ID>" export REGION="<YOUR_REGION>" gcloud config set project $PROJECT_ID
ستظهر لك رسالة مشابهة لما يلي:Your active configuration is: [cloudshell-####] Updated property [core/project] - فعِّل واجهات Google Cloud APIs المطلوبة لمشروعك:
gcloud services enable \ compute.googleapis.com \ cloudresourcemanager.googleapis.com \ aiplatform.googleapis.com \ storage.googleapis.com \ storage-component.googleapis.com \ bigqueryconnection.googleapis.com \ bigquery.googleapis.com \ run.googleapis.com \ secretmanager.googleapis.com \ cloudbuild.googleapis.com \ artifactregistry.googleapis.com \ iap.googleapis.com \ iam.googleapis.com
إنشاء نسخة طبق الأصل من المستودع
لدينا نموذج للرمز البرمجي لمساعدتك في البدء في درس تطبيقي حول الترميز. وهو صغير نسبيًا، ولكن مستودع GitHub الذي يتضمّنه كبير جدًا. لتسريع عملية الاستنساخ وحفظ مساحة القرص، نستخدم عادةً git clone مع الخيار --filter=blob:none وgit sparse-checkout وبعض الأوامر الأخرى.
يبدو هذا الأمر معقّدًا للغاية، ولكن يمكن لـ Antigravity أن ينفّذ كل ذلك نيابةً عنّا.
أولاً، لنضبط إعدادات Antigravity CLI حتى تتمكّن من حلّ مشكلتنا مباشرةً، ثم لنشغّلها.
في Cloud Shell، شغِّل الأمر التالي:
source <(curl -fsSL https://github.com/GoogleCloudPlatform/devrel-demos/raw/refs/heads/vladkol/cloud-shell-configure-agy/codelabs/labs-scripts/bwg-multi-agent-pitch-generator/cloud_shell_configure_agy.sh)
يضبط الأمر Antigravity CLI ويشغّله في الوحدة الطرفية نفسها. عند الخروج من Antigravity CLI، ستعود إلى طلب Cloud Shell.

نحتاج فقط إلى المجلد codelabs/bwg-multi-agent-pitch-generator في المستودع. لنطلب من Antigravity تنزيل هذا المجلد فقط، وسيكون متاحًا على جهازك في ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/.
أعطِ Antigravity CLI هذه المهمة:
Download files from under `https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/codelabs/bwg-multi-agent-pitch-generator`
to folder `~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/`.
If `devrel-demos` folder already exists, rename it with a `.backup` suffix.

سينفّذ Antigravity المهمة. سيطلب منك منح أذونات لتنفيذ بعض الأوامر. بعد تنزيل الرمز، اخرج من واجهة سطر الأوامر Antigravity CLI من خلال تنفيذ الأمر /exit:
/exit

فتح مساحة عمل المستودع
لنفتح الآن مساحة عمل الرمز في Cloud Shell. نفِّذ الأمر التالي في وحدة Cloud Shell الطرفية:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
cloudshell workspace .
تشغيل نص التهيئة البرمجي
لتسهيل هذه التجربة، شغِّل نص التهيئة البرمجي من المستودع. تضبط هذه السمة متغيرات البيئة، وتثبّت agents-cli، وتنشئ حزمة Cloud Storage للعناصر، وتنشئ عملية ربط "مورد السحابة الإلكترونية" في BigQuery، وتمنح أذونات "إدارة الهوية وإمكانية الوصول" المطلوبة لحساب الخدمة مع إعادة المحاولة تلقائيًا.
يستدعي نص التهيئة البرمجي أيضًا setenv.sh، وهو برنامج مساعد صغير يستمد المتغيرات التي يحتاجها كلا الوكيلين، أي GOOGLE_CLOUD_PROJECT وGOOGLE_CLOUD_REGION وGOOGLE_CLOUD_LOCATION وGOOGLE_GENAI_USE_VERTEXAI، من PROJECT_ID وREGION اللذين تم تصديرهما أعلاه. يحفظ أيضًا هاتين القيمتين في ملف .env في الدليل الرئيسي حتى تتمكّن من استعادتهما لاحقًا.
- في Cloud Shell، اجعل نص التهيئة البرمجي قابلاً للتنفيذ وشغِّله:
chmod +x codelab-setup.sh setenv.sh ./codelab-setup.sh - سيستغرق تنفيذ هذا الأمر حوالي دقيقة واحدة. من المفترض أن تظهر لك الرسالة التالية التي تشير إلى النجاح: "🎉 🦄 اكتمل تنفيذ البرنامج النصي."

- تم تشغيل نص التهيئة البرمجي في غلاف خاص به، لذا لم تصل متغيراته إلى جهازك. حمِّل هذه الملفات في جلستك:
من المفترض أن يظهر لك مشروعك ومنطقتك وموقعك الجغرافي.source ./setenv.sh
3- تنظيم الوكلاء باستخدام سير عمل رسومي
في هذه المهمة، ستنشئ مشروعًا لإنشاء عروض تقديمية وتصمّم سير عمل بيانيًا يشغّل وكيلَين ويجمع ناتجَيهما.
يجب أن تتضمّن الأغنية المقترَحة فكرة، أي الفكرة والأصول التي تبيع تلك الفكرة. في حالة الاستخدام هذه، سنصمّم وكلاء يتحمّلون مسؤوليات مختلفة في نطاق العمل، ما يوضّح كيف يمكنك فصل المهام المعقّدة وتفويضها إلى وكلاء مختلفين يتحمّلون مسؤوليات متميّزة، ما يسهّل إدارتها.
يتطلّب تقسيم هذا النوع من العمل بين المتخصّصين شيئًا لتنسيق وقت تشغيل كل وكيل. يمكنك اختيار السماح للوكيل بتحديد وقت الاتصال بكل وكيل فرعي أو تطبيق نهج أكثر حتمية. في هذا الدرس التطبيقي حول الترميز، ستستخدم أسلوبًا حتميًا مع سير عمل بياني.
إنشاء بنية مشروع الوكيل الأول
- في Cloud Shell، أنشئ المشروع من خلال لصق ما يلي في الوحدة الطرفية:
يكتب هذا الأمر مشروعًا كاملاً وقابلاً للتنفيذ: وكيل وcd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create pitch-generator \ --agent adk \ --agent-directory pitch_generator \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approveDockerfileواختبارات وTerraform لاستخدامه لاحقًا وملف.envمع نموذج.env.exampleالخاص به. يتضمّن هذا الدرس التطبيقي حول الترميز جزأين مهمّين:pitch_generator/agent.pyهو الوكيل، والملف الذي تعيد كتابته.-
pitch_generator/هو اسم الحزمة الذي تم ضبطه بواسطة--agent-directory.
setenv.sh، لذلك ليس هناك ما يجب ضبطه هنا. - ثبِّت التبعيّات:
ملاحظة: يربط النموذج أيضًا المشروع بعرض A2A، وهو البروتوكول المستخدَم لاحقًا في هذا الدرس العملي. اترك هذه الملفات كما هي في الوقت الحالي.cd pitch-generator agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
فهم الرسم البياني
يتوافق الإصدار 2.x من "حزمة تطوير التطبيقات" مع سير عمل الرسومات البيانية. يتم إنشاء الرسم البياني من عُقد، وهي وحدات العمل، وحواف، وهي التي تربط بينها. عادةً ما تكون العُقدة عبارة عن وكيل، على الرغم من أنّ دالة Python العادية تعمل أيضًا. تشير الحافة إلى أنّه عند انتهاء إحدى العُقد، يتم تشغيل عقدة أخرى بعدها.
تتم كتابة الحواف على شكل قائمة، ويحدّد "مجموعة تطوير التطبيقات" الترتيب:
edges=[
("START", creative_director), ## the graph begins here
(creative_director, copywriter), ## then this
]
يمنح التداخل الحافة معناها:
Edge | المعنى |
| سلسلة: أ، ثم ب، ثم ج، واحدًا تلو الآخر |
| توزيع موسَّع: أ، ثم ب وج في الوقت نفسه |
| يجب أن ينتظر c كلاً من a وb |
بالنسبة إلى عملية الدمج، يمكنك استخدام JoinNode، التي تنتظر كل عملية سابقة وتمرّر مخرجاتها معًا.
في هذه المهمة، سننشئ سير العمل التالي:

إنشاء مسار المعالجة
- افتح ملف الوكيل من خلال لصق ما يلي في الوحدة الطرفية:
سيظهر لك الرمز البرمجي الذي تم إنشاؤهcd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.pyagent.pyفي محرّر Cloud Shell.💡 ملاحظة: في أي وقت، يمكنك اختيار الرمز البرمجي واستخدام رمز المصباح لطلب شرحه من Gemini. يمكنك أيضًا طرح السؤال على واجهة سطر الأوامر Antigravity.
- استبدِل الملف بأكمله في
pitch_generator/agent.pyفي المحرّر بما يلي:import mimetypes import os from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.agents.context import Context from google.adk.agents.remote_a2a_agent import ( AGENT_CARD_WELL_KNOWN_PATH, RemoteA2aAgent, ) from google.adk.apps import App from google.adk.events.event import Event from google.adk.models import Gemini from google.adk.workflow import JoinNode, Workflow from google.genai import types load_dotenv() MODEL = "gemini-3.8-flash" def _model() -> Gemini: return Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ) """ ⬇️ Configure visual-director RemoteA2aAgent agent below this comment """ creative_director = Agent( name="creative_director", model=_model(), description="Turns a raw idea into a campaign concept.", instruction=( "You are the Creative Director. Turn the idea you are given into ONE " "punchy campaign concept line with the rationale explanation behind it." ), output_key="creative_director", ) copywriter = Agent( name="copywriter", model=Gemini(model=MODEL, retry_options=types.HttpRetryOptions(attempts=3)), description="Writes social copy for a campaign concept.", instruction=( "You are the Copywriter. Write ONE short social caption for the " "campaign concept you are given. Under 25 words." ), ) """ Waits for every node wired into it, then hands their outputs on together.""" assemble = JoinNode(name="assemble") def package(node_input: dict): """Render the joined branches as the finished pitch. """ pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", ] ) """ The first event is what the user sees. The second is the node's output, which any downstream node would receive.""" yield Event(content=types.Content(role="model", parts=[types.Part(text=pitch)])) yield Event(output=pitch) """ we put creative_director before `assemble` so that we can gather the `Concept` output at assemble""" root_agent = Workflow( name="pitch_generator", edges=[ ("START", creative_director), (creative_director, copywriter), ((creative_director, copywriter), assemble), (assemble, package), ], ) app = App( root_agent=root_agent, name="pitch_generator", ) - تتضمّن
agents-cliواجهة مستخدم مدمجة لتطوير الويب تُسمىplayground، وهي تتيح إجراء عمليات فحص مشابهة لتلك التي تتيحها حزمة تطوير التطبيقات (ADK). لبدء استخدام "مساحة المرح"، اتّبِع الخطوات التالية: سيُطلب منك تحديد ما إذا كنت تريد تفعيل القياس عن بُعد. اكتبagents-cli playground --port 8080nواضغط على Enter. - انقر على معاينة الويب، أي رمز العين في أعلى يسار النافذة الطرفية، ثم اختَر المعاينة على المنفذ 8080.

- ستظهر لك الواجهة التالية للدردشة مع موظّف الدعم. جرِّب إرسال الطلب "ألواح تزلّج طائرة للقطط". سيظهر لك ردّ كما هو موضّح أدناه، حيث يمكنك أيضًا فحص الرسم البياني الكامل لسير العمل.
فحص طريقة إنشاء هذه الإجابة تعرض ساحة اللعب كل خطوة اتّخذها الرسم البياني، بالترتيب: creative_director، ثمcopywriter، ثمassemble، ثمpackage. هذا التسلسل هو الرسم البياني الذي ربطته، وبهذه الطريقة يمكنك التأكّد بسرعة من الرسم البياني الذي أنشأته للتو. - ارجع إلى النافذة الطرفية وأوقِف عملية
agents-cli playgroundالجارية بالضغط على Ctrl+C مرّتين.
4. منح الوكيل مهارة
في هذه المهمة، ستنشئ وكيلاً ثانيًا وتزوّده بمجموعة من إرشادات العلامة التجارية المجمّعة كمهارة.
تكتب سلسلة المعالجة الكلمات. تحتاج الصورة إلى أسلوب مميّز: لوحة ألوان وطريقة إضاءة الأشياء والتصاميم التي تستخدمها وتلك التي لا تستخدمها أبدًا. هذه صفحة قواعد، وصفحة القواعد تحتاج إلى آلية أفضل لإدارتها. إحدى طرق إجراء ذلك هي تجميعها كـ "مهارة وكيل".
المهارة هي مجلد يحتوي على ملف SKILL.md. تبدو بنية دليل المهارات مثل المثال التالي (باستخدام visual_director، وهو الوكيل التالي الذي ستنشئه):
visual_director/
...
agent.py
skills/
brand-guidelines/
SKILL.md ## required: frontmatter + instructions
references/ ## optional: longer supporting documents
assets/ ## optional: templates, images, data
scripts/ ## optional: executable helpers
...
نقطة دخول مهارة الوكيل هي الملف SKILL.md، الذي يتضمّن قسم frontmatter بتنسيق YAML مثل القسم الموضّح أدناه:
---
name: brand-guidelines
description: The house brand rules for a key visual. Load this before writing art direction, so the visual looks like it came from this brand.
---
## Brand guidelines
Deep indigo and slate as the ground. One warm accent, amber or terracotta...
المادة التمهيدية هي التصنيف. وهي كل ما يراه الوكيل في البداية، ولهذا السبب يجب أن يوضّح الوصف متى يكون تحميل المهارة مفيدًا. النص هو المحتوى، ويبقى خارج السياق إلى أن يستدعي الوكيل load_skill.
هذا التقسيم هو النقطة الأساسية. يبقى الطلب قصيرًا، ولا يستعين الوكيل بالقواعد إلا عند الحاجة إليها، كما أنّ تغيير النمط يعني تعديل ملف واحد بدلاً من البحث في سلسلة تعليمات.
سنبدأ في إنشاء الوكيل الثاني، visual-director، باستخدام مهارات الوكيل كما هو موضّح في الرسم البياني أدناه:

إنشاء بنية Visual Director
ستنشئ وكيلًا متخصصًا للتعامل مع المكوّن المرئي، visual-director. وهو مشروع منفصل لأنّه سيصبح لاحقًا خدمة مستقلة لتوضيح كيفية تواصل عدة نماذج وكيلة مع بعضها البعض باستخدام بروتوكول A2A. سينتهي بك الأمر بمشروعَين جنبًا إلى جنب:
bwg-multi-agent-pitch-generator/
├── pitch-generator/ ## built in the last task
│ ├── pitch_generator/
│ │ ├── agent.py ## the graph you wrote
│ │ ├── app_utils/ ## generated, A2A wiring
│ │ └── fast_api_app.py ## generated, serves the agent
│ └── pyproject.toml
└── visual-director/ ## created below
└── ... ## the same shape again
- أنشئ المشروع وثبِّت التبعيات من خلال لصق ما يلي في الوحدة الطرفية:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create visual-director \ --agent adk \ --agent-directory visual_director \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approve cd visual-director agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
كتابة إرشادات بناء هوية العلامة التجارية
- أنشئ مجلد المهارة وافتح الملف:
mkdir -p visual_director/skills/brand-guidelines cloudshell edit visual_director/skills/brand-guidelines/SKILL.md - ألصِق المحتوى التالي في ملف
SKILL.mdالمفتوح في "المحرّر" واحفظه:
--- name: brand-guidelines description: The house brand rules for a key visual — palette, light, composition, subject treatment, and what never appears. Load this before writing art direction or rendering an image, so the visual looks like it came from this brand rather than from a generic image model. --- ## Brand guidelines House style for campaign key visuals. Every rule here beats a preference in the brief. If the brief asks for something forbidden below, follow the brief for the subject and the guidelines for the treatment. ## Palette Deep indigo and slate as the ground. One warm accent — amber or terracotta — carrying the eye to the subject. Nothing neon, nothing fluorescent. At most three colors with any weight. A fourth reads as clutter. ## Light One dominant source, low and raking. Long shadows are wanted. Golden hour or a single hard studio key, never flat overhead light and never a ring light. Rim light is allowed on the subject only, and only to separate it from the ground. ## Composition Subject off-center, roughly a third in. Generous negative space on the opposite side — copy lands there later, so leave it genuinely empty. Eye level or slightly below. No top-down flat lays. No fisheye, no Dutch tilt. ## Subject One subject. If the idea implies a crowd, pick the one that carries it. Photographic realism with a shallow depth of field. Not illustration, not 3D render, not clay, not pixel art. ## Never - Text, logos, watermarks, or signage anywhere in the frame - Collage or split-screen layouts - Chrome, lens flare, bokeh sparkle - Cool-toned neon cyan or magenta ## Rendering the prompt When you turn art direction into an image prompt, state the palette, the light, and the composition explicitly. An image model will not infer them from the subject alone. Put the "Never" items in as plain description of what the frame does contain, not as negatives — image models handle a positive description far better than a list of prohibitions.
تعديل visual_director/agent.py
عدِّل ملف agent.py واضبطه ليتضمّن المهارة المحدّدة سابقًا.
- افتح ملف الوكيل:
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - استبدِل محتوى ملف
visual_director/agent.pyبالكامل بالرمز التالي: تمّ الآن إعداد وكيلimport mimetypes from pathlib import Path from google import genai from google.adk.agents import Agent from google.adk.apps import App from google.adk.models import Gemini from google.adk.skills import load_skill_from_dir from google.adk.tools import ToolContext from google.adk.tools.skill_toolset import SkillToolset from google.genai import types MODEL = "gemini-3.8-flash" ## Configure the `brand-guidelines` skill for the agent BRAND_SKILL = load_skill_from_dir(Path(__file__).parent / "skills" / "brand-guidelines") ## Add definition of `generate_key_visual` tool below this comment root_agent = Agent( name="visual_director", model=Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ), description="Turns a campaign concept into art direction and a key visual.", instruction="""You are the Visual Director on a campaign pitch team. Call `load_skill` for `brand-guidelines` before you write anything. The house style is not optional and it is not in this prompt. You are given a campaign concept. Then, in order: 1. Write art direction for ONE key visual that sells it, obeying the brand guidelines: subject, composition, lighting, color, mood. Three or four sentences. 2. Call `generate_key_visual` with exactly that art direction. Your final reply is the art direction itself and nothing else. No preamble, no alternatives, no questions back. Do not mention the skill, the tool, or the image file — the image travels on its own.""", tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment ], ) app = App( root_agent=root_agent, name="visual_director", )visual-directorبشكل صحيح باستخدام مهارة وكيل. قبل اختبارها، عليك تزويد هذا الوكيل بأداة لإنشاء مواد عرض صورية كإحدى قدراته الأساسية.
5- تزويد وكيل بأداة إنشاء صور
في هذه المهمة، ستزوّد "مدير التصميم المرئي" بأداة تعرض التصميم الفني كصورة وتحفظه كعنصر. الناتج هو جزء من بيانات ثنائية أو محتوى ملف يحمل اسمًا ورقم إصدار، وينشئه وكيل الذكاء الاصطناعي أو يعدّله أو يستخدمه أثناء تنفيذ مهمة.

تنفيذ الأداة وإضافتها إلى الوكيل
- افتح ملف الوكيل:
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - انسخ أداة
generate_key_visualالتالية قبل تعريفroot_agent:async def generate_key_visual(art_direction: str, tool_context: ToolContext) -> dict: """Render the art direction as the campaign's key visual. Args: art_direction: The art direction to render, in full. Returns: The saved artifact's filename, version, size and media type. """ IMAGE_MODEL = "gemini-3.1-flash-lite-image" response = await genai.Client(location="global").aio.models.generate_content( model=IMAGE_MODEL, contents=art_direction ) ## The image arrives as inline bytes on one of the response parts. image = next( ( part.inline_data for part in response.candidates[0].content.parts or [] if part.inline_data ), None, ) if image is None: raise ValueError(f"{IMAGE_MODEL} returned no image for: {art_direction[:120]}") filename = "key_visual" + ( mimetypes.guess_extension(image.mime_type or "") or ".bin" ) version = await tool_context.save_artifact(filename, types.Part(inline_data=image)) ## Return the artifact filename and version return { "filename": filename, "version": version, "bytes": len(image.data), "mime_type": image.mime_type, } - أضِف
generate_key_visualأسفلSkillToolsetلتزويد الوكيل بالأداة:tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment generate_key_visual, ], - تتضمّن
agents-cliواجهة مستخدم مدمجة لتطوير الويب تُسمىplayground، وهي تتيح إجراء عمليات فحص مشابهة لتلك التي تتيحها حزمة تطوير التطبيقات (ADK). لبدء استخدام "مساحة المرح"، اتّبِع الخطوات التالية:agents-cli playground --port 8080 - انقر على معاينة الويب، أي رمز العين في أعلى يسار النافذة الطرفية، ثم اختَر المعاينة على المنفذ 8080.

- ستظهر لك الواجهة التالية للدردشة مع موظّف الدعم. جرِّب إرسال الطلب "تسع أرواح. انعدام الجاذبية".
يمكنك الاطّلاع من التفاعلات على كيفية تنفيذ الوكيل visual_directorلـload_skill("brand-guidelines")لقراءة مهارة إرشادات العلامة التجارية، ثم تنفيذgenerate_key_visualلبدء إنشاء الصورة. يتم تخزين الصورة الناتجة كعنصر، ويتم عرضها أيضًا في واجهة المستخدم ويمكن فحصها بسهولة. - ارجع إلى النافذة الطرفية وأوقِف عملية
agents-cli playgroundالجارية بالضغط على Ctrl+C مرّتين.
6. بنية متعددة الوكلاء باستخدام بروتوكول A2A
في هذه المهمة، ستعرض "المخرج المرئي" كخدمة يمكن للوكلاء الآخرين طلبها، وستضبطها للرد بالصورة التي تم إنشاؤها.
Agent2Agent (A2A) هو بروتوكول مفتوح يتيح لوكيل واحد استدعاء وكيل آخر عبر شبكة. العنصر الأساسي هو بطاقة الوكيل، وهي مستند JSON ينشره الوكيل عن نفسه من خلال عنوان URL معروف، ويقدّم اسمه ووصفه وإمكاناته. يسترد المتصل البطاقة ويعرف كيفية التحدث إلى الوكيل الذي يقف وراءها، بدون رمز مصدر أو تبعيات أو لغة مشتركة.

لقد أعدّت agents-cli هذا الإعداد تلقائيًا. يتم إنشاء visual_director/app_utils/a2a.py، وهو العنصر الذي ينشئ البطاقة من وكيلك ويحمّل المسارات، وvisual_director/fast_api_app.py، وهو العنصر الذي يعرضها. ما عليك سوى إجراء تعديل بسيط للسماح له أيضًا بإعادة العناصر إلى العميل.
ستبدو البنية كما هو موضّح أدناه. يُرجى العِلم أنّ الوكيل لم يتم دمجه بعد في سير العمل الأوّلي:

بنية خادم agents-cli A2A
يتم توفير الرمز والوحدة النمطية التاليَين عند إعداد وكيل visual-director باستخدام agents-cli. افتح هذه الملفات من خلال لصق الأوامر التالية في الوحدة الطرفية:
cloudshell edit visual_director/fast_api_app.py
cloudshell edit visual_director/app_utils/a2a.py
يبدأ visual_director/fast_api_app.py الوكيل ويحمّل مسارات A2A ضمن مسار تم إنشاؤه من اسم التطبيق:
await attach_a2a_routes(
app,
agent=root_agent,
runner=runner,
rpc_path=f"/a2a/{adk_app.name}", ## becomes /a2a/visual_director
)
وستنجز أداة visual_director/app_utils/a2a.py باقي الخطوات في ثلاث حركات.
أولاً، ينشئ بطاقة الوكيل من الوكيل نفسه. يصبح الاسم والوصف وكل أداة إدخالات يمكن للمتصل قراءتها:
agent_card = await AgentCardBuilder(
agent=agent,
rpc_url=f"{resolved_app_url}{rpc_path}",
).build()
ثانيًا، يضع منفِّذًا بين البروتوكول والوكيل. تتم ترجمة طلبات A2A الواردة إلى عمليات تشغيل ADK، وتتم ترجمة النتائج مرة أخرى:
request_handler = DefaultRequestHandler(
agent_executor=A2aAgentExecutor(runner=runner, force_new_version=True),
task_store=task_store,
agent_card=agent_card,
)
ثانيًا، يتم إنشاء مسارَين: أحدهما لعرض البطاقة، والآخر لتلقّي المكالمات.
مسار | الغرض |
| البطاقة يقرأ المتصل هذا النص أولاً للتعرّف على ما يمكن أن يفعله الوكيل |
| نقطة نهاية JSON-RPC المكان الذي يتم إرسال الطلبات الفعلية إليه |
السماح للعناصر بتجاوز الحدود
تحتوي استجابة A2A تلقائيًا على نص. الصورة هي عنصر، ويظل العنصر في متجر وكيل العرض ما لم يتم ضبطه ليتم تضمينه.
- افتح ملف A2A الذي تم إنشاؤه:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director cloudshell edit visual_director/app_utils/a2a.py - ابحث عن عملية الاستيراد
AgentCardBuilderوأضِف عمليات الاستيرادA2aAgentExecutorConfigوinclude_artifacts_in_a2a_event_interceptorأدناه:## ... ## from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder ## Add the following two below `AgentCardBuilder` import from google.adk.a2a.executor.config import A2aAgentExecutorConfig from google.adk.a2a.executor.interceptors.include_artifacts_in_a2a_event import ( include_artifacts_in_a2a_event_interceptor, ) - ابحث عن السطر
agent_executor=A2aAgentExecutor(runner=runner),واستبدله بما يلي (مع إضافةA2aAgentExecutorConfig):agent_executor=A2aAgentExecutor( runner=runner, force_new_version=True, config=A2aAgentExecutorConfig( execute_interceptors=[include_artifacts_in_a2a_event_interceptor] ), ),
بدء الخدمة وقراءة بطاقة A2A المنشورة
- ابدأ تشغيل الخادم في الخلفية. عليك تقديم بيان
APP_URL، لأنّ هذا هو العنوان الذي تعلن عنه البطاقة على أنّه عنوانها. ألصِق ما يلي في الوحدة الطرفية:APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & - انتظِر بضع ثوانٍ حتى يبدأ، ثم تأكَّد من أنّه يعرض المحتوى:
يجب أن يظهر لك ما يلي:sleep 10 tail -2 /tmp/visual-director.logINFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8801 (Press CTRL+C to quit) - اقرأ البطاقة التي ينشرها الوكيل الآن:
تعرض البطاقة اسم الوكيل ووصفه وعنوان URL الخاص به ومهاراته، بما في ذلكcurl -s http://localhost:8801/a2a/visual_director/.well-known/agent-card.json | python3 -m json.toolgenerate_key_visual. يتم إنشاؤه مباشرةً من تعريف الوكيل في الرمز. أنت الآن جاهز لتضمين وكيل{ "name": "visual_director", "description": "Turns a campaign concept into art direction and a key visual.", "skills": [ { "id": "visual_director", "name": "model", "tags": [ "llm" ] }, { "id": "visual_director-generate_key_visual", "name": "generate_key_visual", "description": "Render the art direction as the campaign's key visual.\n\nArgs:\n art_direction: The art direction to render, in full.\n\nReturns:\n The saved artifact's filename, version, size and media type.", "tags": [ "llm", "tools" ] } ], "preferredTransport": "JSONRPC", "protocolVersion": "0.3", "url": "http://localhost:8801/a2a/visual_director" }visual-directorفي سير عملpitch-generatorالرئيسي.
7. تضمين الوكيل البعيد A2A في سير العمل
في هذه المهمة، ستضيف الوكيل البعيد إلى الرسم البياني كفرع ثالث.
يتم تضمين وكيل بعيد في RemoteA2aAgent ووضعه في الرسم البياني مثل أي عقدة أخرى. تحتفظ الحواف بالشكل نفسه، ولا يعرف المنسّق أيّ من عُقده محلية.
توجيه المنسّق إلى الخدمة وتعديل سير عمل الرسم البياني
- افتح ملف الوكيل:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.py - أضِف عمليات الاستيراد هذه في أعلى الملف، إلى جانب عمليات الاستيراد الحالية:
import asyncio import subprocess import google.auth.transport.requests import google.oauth2.id_token import httpx from google.adk.a2a.converters.part_converter import convert_genai_part_to_a2a_part - أضِف تعريف
RemoteA2aAgentالتالي فوق تعريفcreative_director:VISUAL_DIRECTOR_URL = os.getenv("VISUAL_DIRECTOR_URL", "http://localhost:8801") ## For deployment on Cloud Run def _cloud_run_client() -> httpx.AsyncClient | None: """An httpx client that signs each request with a Cloud Run ID token. Cloud Run deploys private, so both the agent-card fetch and the A2A calls need one. """ if not VISUAL_DIRECTOR_URL.startswith("https://"): return None async def sign(request: httpx.Request) -> None: token = None try: token = await asyncio.to_thread( google.oauth2.id_token.fetch_id_token, google.auth.transport.requests.Request(), VISUAL_DIRECTOR_URL, ) except Exception: token = subprocess.check_output( ["gcloud", "auth", "print-identity-token", "-q"], stderr=subprocess.PIPE ).decode().strip() if not token: raise Exception("Failed to fetch ID token") request.headers["Authorization"] = f"Bearer {token}" return httpx.AsyncClient(event_hooks={"request": [sign]}, timeout=600) ## Keep the approval's tool traffic out of the A2A request def _pitch_parts_only(part: types.Part): """Sends the Visual Director text and media only. RemoteA2aAgent replays the session on every call, and the Visual Director runs downstream of the human approval, so the approval's function_response would travel alongside the concept text. An ADK server reads a function response as "resume the paused invocation" and rejects a message that also carries text, so drop the tool parts here. """ if part.function_call or part.function_response: return None return convert_genai_part_to_a2a_part(part) visual_director = RemoteA2aAgent( name="visual_director", description="Turns a campaign concept into art direction for one key visual.", agent_card=( f"{VISUAL_DIRECTOR_URL}/a2a/visual_director{AGENT_CARD_WELL_KNOWN_PATH}" ), httpx_client=_cloud_run_client(), genai_part_converter=_pitch_parts_only, ) - استبدِل دالة Python لعقدة
packageأو أعد كتابتها باستخدام التعريف التالي:async def package(ctx: Context, node_input: dict): """Render the joined branches as the finished pitch.""" empty = [name for name, value in node_input.items() if not value] if empty: raise ValueError(f"nothing reached the join from: {', '.join(empty)}") def _key_visual(ctx: Context) -> types.Blob | None: """The image the Visual Director sent back, or None if it sent none.""" for event in reversed(ctx.session.events): if event.author != "visual_director" or not event.content: continue for part in event.content.parts or []: if part.inline_data and part.inline_data.data: return part.inline_data return None image = _key_visual(ctx) if image is None: raise ValueError("the Visual Director returned art direction but no image") suffix = mimetypes.guess_extension(image.mime_type or "") or ".bin" filename = f"key_visual{suffix}" await ctx.save_artifact(filename, types.Part(inline_data=image)) pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", f"ART DIRECTION\n{node_input['visual_director']}", f"KEY VISUAL\n{filename}, {len(image.data)} bytes, {image.mime_type}", ] ) yield Event( content=types.Content( role="model", parts=[types.Part(text=pitch), types.Part(inline_data=image)], ) ) yield Event(output=pitch) - أضِف بوابة موافقة بشرية قبل المتابعة إلى عملية الإنشاء اللاحقة. في
pitch_generator/agent.py، حدِّد عُقد الموافقة فوقroot_agent:@node(rerun_on_resume=False) async def approve_concept(ctx: Context): yield RequestInput( message="Please approve the campaign concept (yes/no).", response_schema=str ) @node(rerun_on_resume=True) async def user_approval(ctx: Context): user_response = await ctx.run_node(approve_concept) if str(user_response).lower() in ("yes", "y"): approved_concept = f"## Approved Concept\n\n{ctx.session.state['creative_director']}" yield Event( content=types.Content( role="model", parts=[types.Part(text=approved_concept)] ) ) else: raise ValueError("User rejected the concept") - أخيرًا، عدِّل عمليات الاستيراد في أعلى الصفحة لتضمين
RequestInputوnodeمنgoogle.adk.eventsوgoogle.adk.workflow: وعدِّل سير عملfrom google.adk.events import Event, RequestInput from google.adk.workflow import JoinNode, Workflow, noderoot_agentedgesللتوجيه من خلالuser_approval: في ما يلي بعض التفاصيل الجديرة بالملاحظة:edges=[ ("START", creative_director), (creative_director, user_approval, (copywriter, visual_director)), ((creative_director, copywriter, visual_director), assemble), (assemble, package), ],- الموافقة على المشاركة البشرية (HITL): يؤدي
approve_conceptإلىRequestInput. عندما يصل سير العمل إلى هذه العقدة، يتوقف التنفيذ مؤقتًا ويصدر مقاطعة للمتصل. لن يتم تشغيل الفروع اللاحقة (copywriterوvisual_director) إلى أن يتم تأكيد موافقة المستخدم. - يظهر
visual_directorفي الحواف تمامًا مثلcopywriter، على الرغم من أنّ أحدهما لا يتطلّب سوى استدعاء دالة، بينما يتطلّب الآخر الاتصال بشبكة. - تتم قراءة الصورة المعروضة من أحداث الجلسة بدلاً من
node_input، لأنّه في الوقت الحالي يتم الترويج للنص فقط إلى ناتج العقدة. عبرت الصورة الحدّ من خلال أداة اعتراض A2A، ولكن تم إرفاقها بأحداث الوكيل البعيد، لذا تسترجعها الدالة المساعدة_key_visualمن هناك.
- الموافقة على المشاركة البشرية (HITL): يؤدي
اختبار عملية الدمج
ستختبر الآن إمكانية التواصل بين Visual Director (الذي يعمل في الخلفية) وPitch Generator من خلال بروتوكول A2A.
- تأكَّد من أنّ تطبيق Visual Director لا يزال يعمل في الخلفية:
من المفترض أن تظهر لك النتيجةcurl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.jsonvisual director: 200هنا.في حال ظهور أي حالة أخرى، نفِّذ الأمر التالي لإعادة تشغيلها:fuser -k 8801/tcp 2>/dev/null || true cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator sleep 10 curl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.json - لبدء المعاينة، اتّبِع الخطوات التالية:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator/pitch_generator agents-cli playground --port 8080 - انقر على معاينة الويب، أي رمز العين في أعلى يسار النافذة الطرفية، ثم اختَر المعاينة على المنفذ 8080.

- ستظهر لك واجهة للدردشة مع الوكيل. جرِّب إرسال الطلب "ألواح تزلج طائرة للقطط".

سيظهر لك التفاعل الكامل حيث يبدأ سير العمل ويتم تشغيل كل وكيل. بعد أن creative_directorيضع مسودة للمفهوم، يتوقف سير العمل عند بوابة الموافقة ويطلب منك تأكيد ما يلي: "يُرجى الموافقة على مفهوم الحملة (نعم/لا)." أدخِل yes في حقل الإدخال للمتابعة.بعد الموافقة، يتوسّع الرسم البياني: يمكنك الاطّلاع على الوقت الذي يبدأ فيه الوكيلvisual-directorبتحميل المهارة، وفي منتصف عملية إنشاء الصورة، ينهي الوكيلcopywriterإنشاء التعليق على وسائل التواصل الاجتماعي، ما يوضّح أنّ كلا الوكيلين يعملان بالتوازي بدون انتظار أحدهما الآخر. بعد انتهاء كلتا العمليتين، تربط العقدةassembleالنتائج معًا بالمفهوم الموافق عليه الذي تم إنشاؤه بواسطةcreative_director، ما يؤدي إلى إكمال عملية تسليم محتوى الأغنية المقترَحة في الدالةpackage.
8. تخزين العناصر المرئية الرئيسية بشكل دائم في Cloud Storage
حتى الآن، تم تخزين كل العناصر المرئية الرئيسية في الذاكرة. وعندما تتوقف العملية، تختفي الصورة، وهو أمر مقبول في ساحة اللعب وغير مفيد في الحملة. في هذه المهمة، ستمنح سير العمل حزمة للكتابة إليها، وستنشئ مجموعة بيانات BigQuery ستستخدمها في المهمة الأخيرة.
يحدّد ADK مكان عرض العناصر عند بدء التشغيل. يقرأ ملف app_utils/services.py الذي تم إنشاؤه متغيّر بيئة واحدًا:
def get_artifact_service():
"""Process-wide artifact service: GCS when a bucket is set, else in-memory."""
if bucket := os.environ.get("LOGS_BUCKET_NAME"):
return GcsArtifactService(bucket_name=bucket)
return InMemoryArtifactService()
إذا ضبطت القيمة على LOGS_BUCKET_NAME، سيتم تخزين كل مكالمة save_artifact في Cloud Storage بدلاً من ذلك.

إنشاء مجموعة بيانات BigQuery
- في Cloud Shell، نفِّذ الأمر التالي لإنشاء مجموعة بيانات BigQuery:
bq mk --dataset --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> bwg - وجِّه متجر عناصر المنسّق إلى الحزمة:تأخذ
export LOGS_BUCKET_NAME="<YOUR_PROJECT_ID>-bwg"GcsArtifactServiceاسم حزمة مجرّدًا، بدون البادئةgs://. وكما هو الحال مع المتغيرات الأخرى، يكون هذا المتغير متاحًا في shell، وتمرّره مهمة النشر إلى Cloud Run. - تحقَّق من محتوى الحزمة. في علامة تبويب جديدة في المتصفّح، افتح عنوان URL التالي:
انقر على الحزمة. واستنادًا إلى اختباراتك السابقة، قد يحتوي على صور تم إنشاؤها سابقًا.https://console.cloud.google.com/storage/browser?project=<YOUR_PROJECT_ID>
9. نشر وكيل Visual Director على Cloud Run
تم تشغيل كل شيء حتى الآن على جهاز واحد، ويمكن الوصول إلى Visual Director على localhost:8801. في هذه المهمة، ستفعّل وكيل Visual Director كخدمة Cloud Run مستقلة وتسمح لمولّد الأغاني بالتواصل معه عبر الشبكة باستخدام بروتوكول Agent2Agent (A2A).
يحصل Visual Director على عنوان URL حقيقي https://، لذا يبدأ _cloud_run_client الذي كتبته سابقًا في توقيع الطلبات بدلاً من عرض None. بالإضافة إلى ذلك، تنشر Cloud Run المحتوى بشكل خاص تلقائيًا.

تفعيل Director المرئي
- أوقِف خدمة تُشغَّل في الخلفية المحلية والملعب إذا كانا لا يزالان يعملان:
fuser -k 8801/tcp 2>/dev/null || true fuser -k 8000/tcp 2>/dev/null || true - نشر الوكيل يؤدي هذا الإجراء إلى إنشاء حاوية وتحميلها.⏰ سيستغرق ذلك بضع دقائق.
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director source .env agents-cli deploy \ --service-name visual-director \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --no-confirm-project \ --labels dev-tutorial=bwg001-devlab-1 \ --update-env-vars "LOGS_BUCKET_NAME=$LOGS_BUCKET_NAME,GOOGLE_GENAI_USE_VERTEXAI=true,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GOOGLE_CLOUD_REGION=$GOOGLE_CLOUD_REGION"
تشغيل أداة Pitch Generator التي تستخدم Visual Director التي تم نشرها على Cloud Run
- اقرأ عنوان URL الخاص بـ "المخرج المرئي"، وشغِّل "أداة إنشاء الأغاني المقترَحة" التي تستخدمه:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator source .env export VISUAL_DIRECTOR_URL=$(gcloud run services list \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --flatten='spec.template.spec.containers[0].env' \ --filter='metadata.name=visual-director AND spec.template.spec.containers[0].env.name=APP_URL' \ --format='value(spec.template.spec.containers[0].env.value)') echo "Visual Director is at $VISUAL_DIRECTOR_URL" APP_URL=http://localhost:8000 nohup uv run uvicorn pitch_generator.fast_api_app:app --port 8000 > /tmp/visual-pitch_generator.log 2>&1 &
استدعاء سير العمل الذي تم نشره
يتوافق كلا الوكيلين مع بروتوكول A2A. يتضمّن المستودع برنامجًا صغيرًا من جهة العميل لإرسال طلبات إلى Pitch Generator من خلال A2A.
يجب ضبط PITCH_GENERATOR_URL على عنوان URL الخاص بأداة إنشاء الأغاني الذي يتم تشغيله محليًا. في الوقت نفسه، يعمل "المخرج المرئي" في Cloud Run، وتتواصل معه "أداة إنشاء الأغاني المقترَحة" عبر A2A.
- انسخ العميل إلى مشروعك وشغِّله:
بما أنّ سير العمل يتضمّن بوابة موافقة بشرية، يتم إيقاف النص البرمجي مؤقتًا بعد إنشاء مسودة التصميم:cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cp ../solution/pitch-generator/call_agent.py . PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "Flying skateboards for cats" --save-image ./key_visual.png اكتب=== HUMAN APPROVAL REQUIRED === [DRAFT CONCEPT] Concept Line: "Gravity is a Suggestion." ... Please approve the campaign concept (yes/no):yesواضغط على Enter للموافقة على سير العمل ومتابعته. (يمكنك أيضًا تمرير-yأو--auto-approveللموافقة تلقائيًا). - افتح
call_agent.pyوافحص كيفية تفاعله مع الوكيل باستخدامa2a-sdk:- تنشئ
ClientFactoryاستهدافًا رسميًاClientفي A2Ahttps://SERVICE_URL/a2a/pitch_generator. - يرسل
generate_pitch_asyncمبلغًا أوليًا بقيمةSendMessageRequest. عندما يعود الردّ معTaskState.TASK_STATE_INPUT_REQUIRED، يتم رصد الجزءadk_request_input، وعرض مسودّة المفهوم، وجمع موافقتك، وإرسال طلب استئناف يحمل ردّك إلى المهمة. - تقرأ حلقة التحليل الأقسام
CONCEPTوCOPYوART DIRECTIONمن عناصر المهمة المكتملة، وتحفظ الصورة الثنائية فيkey_visual.png.
key_visual.png. - تنشئ
- حمِّل الصورة الرئيسية إلى الحزمة ضمن بادئة يمكنك توجيه BigQuery إليها:
gcloud storage cp ./key_visual.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png - أنشئ أغنية مقترَحة ثانية لتتمكّن من المقارنة بينهما، ثم حمِّلها أيضًا:
PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "A commuter bike built for rainy cities" --save-image ./bike.png gcloud storage cp ./bike.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png
10. تسجيل النتائج المرئية الرئيسية من حيث مدى ملاءمتها للعلامة التجارية في BigQuery
أصبحت لديك الآن صور في حزمة وإرشادات العلامة التجارية التي من المفترض أن تشكّلها. في هذه المهمة، يمكنك الجمع بين الطريقتين: الإشارة إلى الصور من BigQuery، ثم الطلب من أحد نماذج Gemini تقييم كل صورة وفقًا للإرشادات، بدون نقل أي بايت من Cloud Storage.
تتولّى ميزتان من ميزات BigQuery تنفيذ هذه المهمة:
-
ObjectRefهي قيمة تشير إلى عنصر Cloud Storage. تنشئOBJ.MAKE_REFواحدًا من معرّف موارد موحّد بالإضافة إلى عملية ربط تمنح BigQuery إذن وصول مفوَّضًا إلى الحزمة. إنّpitch-connectionالذي تم إنشاؤه بواسطة نص التهيئة البرمجي هو هذا الاتصال، ويتضمّن حاليًا Storage Object Viewer وAgent Platform User. - تتلقّى
AI.SCOREطلبًا وتعرضFLOAT64. يمكن أن يجمع الطلب بين السلاسل وقيمObjectRef، وبالتالي يرى النموذج قواعد التقييم والصورة معًا.

إنشاء جدول للعناصر المرئية الرئيسية
- افتح BigQuery Studio في علامة تبويب متصفّح جديدة:
https://console.cloud.google.com/bigquery?project=<YOUR_PROJECT_ID> - انقر على إنشاء طلب بحث جديد (رمز +)، ثم الصِق ما يلي ونفِّذه (مع استبدال
وبرقم تعريف مشروعك ومنطقتك). ينشئ هذا الجدول صفًا واحدًا لكل صورة رئيسية، ويربط مفهوم الحملة بمرجع إلى الصورة: تنشئSET @@location = '<YOUR_REGION>'; CREATE OR REPLACE TABLE bwg.key_visuals AS SELECT campaign, concept, OBJ.FETCH_METADATA( OBJ.MAKE_REF(uri, '<YOUR_REGION>.pitch-connection') ) AS key_visual FROM UNNEST([ STRUCT( 'cats' AS campaign, 'Flying skateboards for cats' AS concept, 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png' AS uri ), STRUCT( 'bike', 'A commuter bike built for rainy cities', 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png' ) ]);
OBJ.MAKE_REFالمرجع من معرّف الموارد المنتظم والاتصال.OBJ.FETCH_METADATAثم تتواصل مع خدمة Cloud Storage وتملأ حجم العنصر ونوع المحتوى والجيل. تُعدّ المكالمة الثانية أيضًا أسرع طريقة لإثبات أنّ الاتصال يعمل: إذا كانت الأذونات غير صحيحة، يعود الحقلdetailsويتضمّن الخطأ بدلاً من البيانات الوصفية. - فحص المحتوى الذي خزّنته استبدِل طلب البحث السابق بهذا الطلب ونفِّذه:
يحتوي الجدول على مؤشر وبياناته الوصفية، وليس على الصورة. لم تغادر وحدات البايت الحزمة مطلقًا.SELECT campaign, concept, key_visual.uri, key_visual.details FROM bwg.key_visuals;
تقييم كل صورة وفقًا لإرشادات العلامة التجارية
تم توجيه "المخرج المرئي" باتّباع لوحة ألوان وقاعدة إضاءة وقاعدة تركيب. ويعود تحديد ما إذا كان قد تم ذلك إلى تقديرك، وهذا هو الغرض من AI.SCORE.
- نفِّذ الطلب التالي (استبدِل
بمنطقتك). الطلب هو مجموعة من ثلاثة عناصر: معايير التقييم وفكرة الحملة وObjectRefللصورة:SELECT campaign, concept, AI.SCORE( ('''You are the brand guardian reviewing a campaign key visual. Score the attached image from 1 to 10 on how closely it follows these house rules: - Palette: deep indigo and slate, with one warm accent of amber or terracotta. Nothing neon. - Light: one dominant low, raking source with long shadows. No flat overhead light. - Composition: subject off-center with generous empty negative space on the opposite side. - Subject: one subject only, photographic realism, shallow depth of field. - Never: text, logos, or watermarks anywhere in the frame. A 10 obeys every rule. A 1 ignores them. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ORDER BY brand_fit DESC; - تحويل النتيجة إلى حكم يمكن لفريقك اتّخاذ إجراء بشأنه:تعرض الدالة
CREATE OR REPLACE TABLE bwg.brand_review AS SELECT campaign, concept, brand_fit, IF(brand_fit >= 7, 'on brand', 'needs another pass') AS verdict FROM ( SELECT campaign, concept, AI.SCORE( ('''Score this campaign key visual from 1 to 10 on how closely it follows the house brand rules: deep indigo and slate palette with a single warm accent and nothing neon; one low raking light source with long shadows; the subject off-center with empty negative space opposite; a single photographic subject; and no text, logos, or watermarks in the frame. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ); SELECT * FROM bwg.brand_review ORDER BY brand_fit DESC;AI.SCOREFLOAT64فقط، لذا يمكن ضبط الحدّ في SQL العادي بدون تعديل الطلب. يتم احتساب النتائج لكل صف، ما يعني تطبيق معايير التقييم نفسها على كل مادة عرض تنتجها الحملة، وليس فقط على مادتَي العرض اللتين أنشأتهما هنا.
11. الخطوات التالية
إنشاء تقييمات
التقييمات المستندة إلى الوكلاء أو "التقييمات" هي اختبارات مبرمَجة تُستخدم لقياس مدى جودة أداء وكلاء الذكاء الاصطناعي المستقلين في الاستدلال والتخطيط واستخدام الأدوات وإكمال مهام سير العمل المتعدّدة الخطوات. وهي تشبه اختبارات الوحدة للوكلاء، ولكنّها تأخذ في الاعتبار طبيعتها غير الحتمية.
يتضمّن أحد الوكلاء Human in the loop، ما يعني أنّه ينتظر إدخال المعلومات. عليك السماح لـ Antigravity بإجراء تعديلات على الرمز الحالي حتى لا يعيق هذا السلوك عمليات التقييم التلقائية.
إحدى أفضل الطرق للبدء هي طرح سؤال على Antigravity CLI.
اكتب ما يلي في Cloud Shell لبدء واجهة سطر الأوامر:
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
agy
إليك طلبًا أوّليًا:
Explore this repository (`pitch-generator` and `visual-director`), including their agent instructions, tools, and `SKILL.md` files. Design and implement a creative `agents-cli eval` evaluation suite under `tests/eval/` that stress-tests the agent's behavior.
يمكنك أيضًا العثور على مثال للتقييمات وتعليمات لتنفيذها في المستودع المستنسخ.
12. تَنظيم
لتجنُّب تحمّل رسوم في حسابك على Google Cloud مقابل الموارد المستخدَمة في هذا الدرس التطبيقي حول الترميز، يمكنك حذف المشروع (ننصحك بذلك) أو حذف الموارد الفردية التي تم إنشاؤها أثناء الدرس التطبيقي حول الترميز:
gcloud run services delete visual-director --region=<YOUR_REGION> --project=<YOUR_PROJECT_ID> --quiet
bq rm -r -f -d <YOUR_PROJECT_ID>:bwg
bq rm --connection --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> pitch-connection
gcloud storage rm -r gs://<YOUR_PROJECT_ID>-bwg
13. تهانينا!
في هذا الدرس التطبيقي حول الترميز، أنشأت أداة لإنشاء عروض ترويجية متعددة الوكلاء باستخدام "حزمة تطوير الوكلاء". ربطت ثلاثة وكلاء بسير عمل رسم بياني حتمي، وحزّمت إرشادات العلامة التجارية كمهارة وكيل يتم تحميلها عند الطلب، وقدّمت للوكيل أداة إنشاء صور تحفظ ناتجها كعنصر. بعد ذلك، قسّمت أداة Visual Director إلى خدمة A2A منفصلة، وأعدت تضمينها في الرسم البياني كعقدة بعيدة، ونشرتها على Cloud Run، واستدعيت سير العمل بالكامل عبر A2A من أداة تنسيق تعمل على جهازك. أخيرًا، أشرت إلى المرئيات الرئيسية التي تم إنشاؤها من BigQuery باستخدام ObjectRef واستخدمت AI.SCORE لتقييمها مقارنةً بإرشادات علامتك التجارية.