একটি এজেন্টিক পিচ জেনারেটর তৈরি করুন: গুগল ক্লাউডের সাহায্যে অর্কেস্ট্রেশন, মূল্যায়ন এবং অ্যানালিটিক্স

১. ভূমিকা

এজেন্ট মাস্টারক্লাস ব্যানার

শিখুন কীভাবে একটি মাল্টিমোডাল মাল্টি-এজেন্ট ইঞ্জিন তৈরি করতে হয়, যা একটি প্রাথমিক টপিক ব্রিফ গ্রহণ করে অত্যন্ত আকর্ষক সোশ্যাল অ্যাসেট তৈরির কাজটি পরিচালনা করে। গুগলের এজেন্ট ডেভেলপমেন্ট কিট (ADK) এবং এজেন্টটুএজেন্ট (A2A) প্রোটোকল ব্যবহার করে, আপনি স্বয়ংক্রিয় মাইক্রো-এজেন্ট তৈরি করবেন, ব্র্যান্ডের নিয়মগুলোকে একটি পুনঃব্যবহারযোগ্য এজেন্ট স্কিল হিসেবে প্যাকেজ করবেন, ক্লাউড রানে একটি এজেন্ট সার্ভিস ডেপ্লয় করবেন এবং বিগকোয়েরি এআই ফাংশনের মাধ্যমে ব্র্যান্ডের সাথে সামঞ্জস্যতা যাচাই করার জন্য তৈরি হওয়া মূল ভিজ্যুয়ালগুলোকে স্কোর করবেন।

আপনি যা করবেন

এই কোডল্যাবে, আপনি নিম্নলিখিত কাজগুলো কীভাবে সম্পাদন করতে হয় তা শিখবেন:

  • একটি ডিটারমিনিস্টিক গ্রাফ ওয়ার্কফ্লো ব্যবহার করে একাধিক ADK এজেন্টকে সমন্বিত করুন।
  • ব্র্যান্ড নির্দেশিকাগুলোকে এমন একটি এজেন্ট দক্ষতা হিসেবে প্যাকেজ করুন যা শুধুমাত্র প্রয়োজনের সময় লোড হয়।
  • এজেন্টকে এমন একটি ইমেজ জেনারেশন টুল দিয়ে সজ্জিত করুন যা এর আউটপুটকে একটি আর্টিফ্যাক্ট হিসেবে সংরক্ষণ করে।
  • একটি এজেন্টকে A2A পরিষেবা হিসাবে প্রকাশ করুন এবং অন্য একটি এজেন্ট থেকে এটিকে একটি রিমোট নোড হিসাবে কল করুন।
  • ক্লাউড রান-এ ভিজ্যুয়াল ডিরেক্টরটি ডেপ্লয় করুন এবং A2A-এর মাধ্যমে ওয়ার্কফ্লোটি কল করুন।
  • BigQuery-তে AI ফাংশন ব্যবহার করে ব্র্যান্ড ফিটের জন্য তৈরি করা মূল ভিজ্যুয়ালগুলোকে স্কোর করুন।

আপনার যা যা লাগবে

  • একটি ওয়েব ব্রাউজার (যেমন ক্রোম)।
  • একটি গুগল ক্লাউড অ্যাকাউন্ট এবং বিলিং চালু থাকা একটি গুগল ক্লাউড প্রজেক্ট।

২. শুরু করার আগে

একটি গুগল ক্লাউড প্রজেক্ট তৈরি করুন

  1. গুগল ক্লাউড কনসোলের প্রজেক্ট সিলেক্টর পেজে, একটি গুগল ক্লাউড প্রজেক্ট নির্বাচন করুন বা তৈরি করুন।
  2. আপনার ক্লাউড প্রোজেক্টের জন্য বিলিং চালু আছে কিনা তা নিশ্চিত করুন। কোনো প্রোজেক্টে বিলিং চালু আছে কিনা তা কীভাবে পরীক্ষা করবেন, তা জেনে নিন।

ক্লাউড শেল শুরু করুন

আপনি গুগল ক্লাউড শেল ব্যবহার করে কোড ডাউনলোড করবেন, সেটআপ স্ক্রিপ্ট চালাবেন এবং অ্যাপ্লিকেশনটি ডেপ্লয় করবেন।

  1. আপনার ব্রাউজারে গুগল ক্লাউড শেল খুলুন (অথবা গুগল ক্লাউড কনসোলের উপরে থাকা ‘অ্যাক্টিভেট ক্লাউড শেল’- এ ক্লিক করুন):
    https://shell.cloud.google.com/
    
    অতিরিক্ত কোনো বিজ্ঞপ্তি দেওয়া হলে ' চালিয়ে যান'-এ ক্লিক করুন। টার্মিনাল এবং এডিটর উভয়ই সম্পূর্ণরূপে লোড হওয়া পর্যন্ত অপেক্ষা করুন। এতে এক বা দুই মিনিট সময় লাগতে পারে।
  2. আপনার পরিবেশে আপনার Google Cloud Project ID এবং অঞ্চল (উদাহরণস্বরূপ, 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]
    
  3. আপনার প্রোজেক্টের জন্য প্রয়োজনীয় গুগল ক্লাউড এপিআইগুলো সক্রিয় করুন:
    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
    

রিপোজিটরি ক্লোন করুন

কোডল্যাব শুরু করার জন্য আমাদের কাছে একটি কোড টেমপ্লেট আছে। এটি তুলনামূলকভাবে ছোট, কিন্তু যে গিটহাব রিপোজিটরিতে এটি রয়েছে, সেটি বেশ বড়। ক্লোন প্রক্রিয়া দ্রুত করতে এবং ডিস্কের জায়গা বাঁচাতে, আমরা সাধারণত --filter=blob:none অপশনসহ git clone , git sparse-checkout এবং আরও কিছু কমান্ড ব্যবহার করে থাকি।

এটা শুনতে খুব জটিল মনে হতে পারে, কিন্তু অ্যান্টিগ্র্যাভিটি আমাদের জন্য এই সবকিছুই করতে পারে!

প্রথমে, আমাদের সমস্যা সমাধানে সরাসরি কাজ শুরু করার জন্য Antigravity CLI কনফিগার করে এটিকে চালু করা যাক।

ক্লাউড শেলে, এই কমান্ডটি চালান:

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)

এই কমান্ডটি অ্যান্টিগ্র্যাভিটি সিএলআই কনফিগার করে এবং একই টার্মিনালে এটি চালু করে। আপনি যখন অ্যান্টিগ্র্যাভিটি সিএলআই থেকে বেরিয়ে যাবেন, তখন আপনার ক্লাউড শেল প্রম্পটে ফিরে আসবেন।

অ্যান্টিগ্র্যাভিটি সিএলআই

রিপোজিটরিতে আমাদের শুধু 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.

অ্যান্টিগ্র্যাভিটি সিএলআই প্রম্পট

অ্যান্টিগ্র্যাভিটি কাজটি সম্পাদন করবে। এটি কয়েকটি কমান্ড চালানোর জন্য আপনার অনুমতি চাইবে। কোডটি ডাউনলোড হয়ে গেলে, /exit কমান্ডটি চালিয়ে অ্যান্টিগ্র্যাভিটি CLI থেকে বেরিয়ে যান:

/exit

অ্যান্টিগ্র্যাভিটি CLI থেকে প্রস্থান করুন

রিপোজিটরি ওয়ার্কস্পেস খুলুন

এখন, ক্লাউড শেলে কোড ওয়ার্কস্পেসটি খুলুন। ক্লাউড শেল টার্মিনালে এই কমান্ডটি চালান:

cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
cloudshell workspace .

সেটআপ স্ক্রিপ্টটি চালান

এই অভিজ্ঞতাটিকে আরও মসৃণ করতে, রিপোজিটরি থেকে সেটআপ স্ক্রিপ্টটি চালান। এটি এনভায়রনমেন্ট ভেরিয়েবল কনফিগার করে, agents-cli ইনস্টল করে, আর্টিফ্যাক্টসের জন্য ক্লাউড স্টোরেজ বাকেট তৈরি করে, BigQuery ক্লাউড রিসোর্স কানেকশন তৈরি করে এবং অটো-রিট্রাই সহ এর সার্ভিস অ্যাকাউন্টে প্রয়োজনীয় IAM পারমিশন প্রদান করে।

সেটআপ স্ক্রিপ্টটি setenv.sh নামক একটি ছোট হেল্পারকেও কল করে, যা আপনার উপরে এক্সপোর্ট করা PROJECT_ID এবং REGION থেকে উভয় এজেন্টের প্রয়োজনীয় ভ্যারিয়েবলগুলো— GOOGLE_CLOUD_PROJECT , GOOGLE_CLOUD_REGION , GOOGLE_CLOUD_LOCATION , এবং GOOGLE_GENAI_USE_VERTEXAI নির্ণয় করে। এটি সেই দুটি মান আপনার হোম ডিরেক্টরিতে একটি .env ফাইলে সংরক্ষণও করে, যাতে আপনি পরে সেগুলো পুনরুদ্ধার করতে পারেন।

  1. ক্লাউড শেলে, সেটআপ স্ক্রিপ্টটিকে এক্সিকিউটেবল করুন এবং এটি চালান:
    chmod +x codelab-setup.sh setenv.sh
    ./codelab-setup.sh
    
  2. এটি চলতে প্রায় এক মিনিট সময় লাগবে। সফলতার চিহ্ন হিসেবে আপনি এই বার্তাটি দেখতে পাবেন: "🎉 🦄 স্ক্রিপ্ট নির্বাহ সম্পন্ন।" সাফল্য
  3. সেটআপ স্ক্রিপ্টটি নিজস্ব একটি শেলে চলেছিল, তাই এর ভেরিয়েবলগুলো আপনার টার্মিনালে পৌঁছায়নি। সেগুলোকে আপনার সেশনে লোড করুন:
    source ./setenv.sh
    
    আপনার প্রজেক্ট, অঞ্চল এবং অবস্থানের তথ্যগুলো প্রদর্শিত হবে।

৩. গ্রাফ ওয়ার্কফ্লো ব্যবহার করে এজেন্টদের সমন্বয় করুন

এই টাস্কে, আপনাকে পিচ জেনারেটর প্রজেক্ট তৈরি করতে হবে এবং একটি গ্রাফ ওয়ার্কফ্লো নির্মাণ করতে হবে যা দুটি এজেন্টকে চালনা করে ও তাদের আউটপুট একত্রিত করে।

একটি পিচের জন্য একটি কনসেপ্ট বা ধারণা প্রয়োজন, অর্থাৎ সেই ধারণা এবং সেই ধারণাটিকে গ্রহণযোগ্য করে তোলার মতো উপাদানসমূহ। এই ব্যবহারিক ক্ষেত্রে, আমরা এমন এজেন্ট ডিজাইন করব যাদের কাজের পরিধির মধ্যে বিভিন্ন দায়িত্ব থাকবে। এর মাধ্যমে দেখানো হবে কীভাবে জটিল কাজগুলোকে পৃথক করে স্বতন্ত্র দায়িত্বসম্পন্ন বিভিন্ন এজেন্টের কাছে অর্পণ করা যায়, যা সেগুলোকে পরিচালনা করা আরও সহজ করে তোলে।

বিশেষজ্ঞদের মধ্যে এই ধরনের কাজ ভাগ করে দেওয়ার জন্য এমন কিছুর প্রয়োজন হয় যা প্রতিটি এজেন্ট কখন চলবে তা সমন্বয় করবে। আপনি চাইলে আপনার এজেন্টকে প্রতিটি সাব-এজেন্টকে কখন কল করতে হবে সেই সিদ্ধান্ত নিতে দিতে পারেন, অথবা আরও একটি সুনির্দিষ্ট পদ্ধতি প্রয়োগ করতে পারেন। এই কোডল্যাবে, আপনি একটি গ্রাফ ওয়ার্কফ্লো সহ একটি সুনির্দিষ্ট পদ্ধতি ব্যবহার করবেন।

প্রথম এজেন্ট প্রকল্পের কাঠামো তৈরি করুন

  1. ক্লাউড শেলে , টার্মিনালে এটি পেস্ট করে প্রজেক্টটি তৈরি করুন:
    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-approve
    
    এটি একটি সম্পূর্ণ, চালনাযোগ্য প্রজেক্ট তৈরি করে: একটি এজেন্ট, একটি Dockerfile , টেস্ট, পরবর্তী ব্যবহারের জন্য টেরাফর্ম, এবং এর .env.example টেমপ্লেট সহ একটি .env ফাইল। এই কোডল্যাবের জন্য দুটি অংশ গুরুত্বপূর্ণ:
    • pitch_generator/agent.py হলো এজেন্ট, এবং এটিই সেই ফাইল যা আপনাকে নতুন করে লিখতে হবে।
    • pitch_generator/ হলো প্যাকেজের নাম, যা --agent-directory দ্বারা সেট করা হয়।
    এজেন্টটি আপনার setenv.sh দিয়ে এক্সপোর্ট করা এনভায়রনমেন্ট থেকে তার প্রজেক্ট এবং রিজিয়ন পড়ে নেয়, তাই এখানে কনফিগার করার মতো কিছু নেই।
  2. নির্ভরতা ইনস্টল করুন:
    cd pitch-generator
    agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
    
    দ্রষ্টব্য: এই স্কাফোল্ডটি প্রজেক্টটিকে A2A প্রোটোকল পরিবেশন করার জন্যও প্রস্তুত করে, যা এই কোডল্যাবে পরে ব্যবহৃত হবে। আপাতত ওই ফাইলগুলো অপরিবর্তিত রাখুন।

গ্রাফটি বুঝুন

ADK v2.x গ্রাফ ওয়ার্কফ্লো সমর্থন করে। একটি গ্রাফ নোড (যারা কাজের একক) এবং এজ (যারা সেগুলোকে সংযুক্ত করে) দিয়ে গঠিত হয়। একটি নোড সাধারণত একজন এজেন্ট হয়, যদিও একটি সাধারণ পাইথন ফাংশনও কাজ করে। একটি এজ নির্দেশ করে যে, যখন একটি নোডের কাজ শেষ হয়, তখন পরবর্তী নোডটি চলবে।

এজগুলোকে একটি তালিকা হিসেবে লেখা হয়, এবং ADK এদের ক্রম নির্ধারণ করে:

edges=[
    ("START", creative_director),        ## the graph begins here
    (creative_director, copywriter),     ## then this
]

এই স্তরবিন্যাসই একটি প্রান্তকে তার অর্থ প্রদান করে:

প্রান্ত

অর্থ

(a, b, c)

একটি শৃঙ্খল। প্রথমে a, তারপর b, তারপর c, একের পর এক।

(a, (b, c))

একটি ফ্যান-আউট। প্রথমে a, তারপর b এবং c একই সাথে।

((a, b), c)

একটি ফ্যান-ইন। c, a এবং b উভয়ের জন্য অপেক্ষা করে।

ফ্যান-ইন এর জন্য একটি JoinNode ব্যবহার করা হয়, যা প্রতিটি পূর্বসূরীর জন্য অপেক্ষা করে এবং তাদের আউটপুটগুলো একসাথে পাঠিয়ে দেয়।

এই টাস্কে, আমরা নিম্নলিখিত ওয়ার্কফ্লোটি তৈরি করব:

প্রাথমিক ওয়ার্কফ্লো গ্রাফ

পাইপলাইন তৈরি করুন

  1. টার্মিনালে এটি পেস্ট করে এজেন্ট ফাইলটি খুলুন:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator
    cloudshell edit pitch_generator/agent.py
    
    আপনি ক্লাউড শেল এডিটরে স্কাফোল্ড করা agent.py ফাইলটি দেখতে পাবেন।💡 ইঙ্গিত : যেকোনো মুহূর্তে, আপনি কোডটি সিলেক্ট করে লাইটবাল্ব আইকনটি ব্যবহার করে জেমিনিকে এটি ব্যাখ্যা করতে বলতে পারেন। এছাড়াও আপনি অ্যান্টিগ্র্যাভিটি সিএলআই-কেও জিজ্ঞাসা করতে পারেন। জেমিনি কোড অ্যাসিস্ট ব্যবহার করুন
  2. এডিটরে থাকা 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",
    )
    
  3. agents-cli ADK-এর মতো পরিদর্শনের জন্য playground নামক একটি অন্তর্নির্মিত ওয়েব ডেভেলপমেন্ট UI রয়েছে। প্লেগ্রাউন্ড শুরু করতে:
    agents-cli playground --port 8080
    
    আপনাকে জিজ্ঞাসা করা হবে আপনি টেলিমেট্রি চালু করতে চান কিনা। n টাইপ করে এন্টার চাপুন।
  4. টার্মিনালের উপরের ডানদিকে থাকা চোখের আইকন, অর্থাৎ ওয়েব প্রিভিউ-তে ক্লিক করুন এবং পোর্ট ৮০৮০-তে প্রিভিউ নির্বাচন করুন। ওয়েব প্রিভিউতে ক্লিক করুন
  5. এজেন্টের সাথে চ্যাট করার জন্য আপনি নিম্নলিখিত ইন্টারফেসটি দেখতে পাবেন। "Flying skateboards for cats" প্রম্পটটি পাঠানোর চেষ্টা করুন। আপনি নীচে দেখানো ছবির মতো একটি প্রতিক্রিয়া দেখতে পাবেন, যেখানে আপনি সম্পূর্ণ ওয়ার্কফ্লো গ্রাফটিও দেখতে পারবেন। ডেমো ওয়ার্কফ্লো ওই উত্তরটি কীভাবে তৈরি হয়েছে তা খতিয়ে দেখুন। প্লেগ্রাউন্ডটি গ্রাফটির প্রতিটি ধাপ ক্রমানুসারে দেখায়: প্রথমে creative_director , তারপর copywriter , তারপর assemble , এবং সবশেষে package । এই ক্রমটিই হলো আপনার তৈরি করা গ্রাফ, এবং এর মাধ্যমে আপনি এইমাত্র তৈরি করা গ্রাফটি দ্রুত যাচাই করে নিতে পারবেন।
  6. টার্মিনালে ফিরে যান এবং দুইবার Ctrl+C চেপে চলমান agents-cli playground প্রসেসটি বন্ধ করুন।

৪. একজন এজেন্টকে একটি দক্ষতা দিন

এই টাস্কে, আপনি একটি দ্বিতীয় এজেন্ট তৈরি করবেন এবং তাকে একটি স্কিল হিসেবে কিছু ব্র্যান্ড নির্দেশিকা দেবেন।

পাইপলাইন শব্দ লেখে। একটি ছবির নিজস্ব একটি শৈলী থাকা প্রয়োজন: একটি রঙের বিন্যাস, আলো ফেলার একটি পদ্ধতি, ব্যবহৃত এবং কখনও ব্যবহার না করা কম্পোজিশন। এটি হলো কিছু নিয়মের একটি তালিকা, এবং এই নিয়মের তালিকাটি পরিচালনা করার জন্য একটি উন্নততর পদ্ধতির প্রয়োজন। এটি করার একটি উপায় হলো এটিকে একটি 'এজেন্ট স্কিল' হিসেবে প্যাকেজ করা।

স্কিল হলো এমন একটি ফোল্ডার যার মধ্যে একটি 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 ফাইল, যেটিতে নিচে দেখানোটির মতো একটি 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 , পরিচালনা করার জন্য একটি বিশেষায়িত এজেন্ট তৈরি করবেন। এটি একটি আলাদা প্রজেক্ট, কারণ পরবর্তীতে এটি একটি স্বতন্ত্র সার্ভিসে পরিণত হয়, যা 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
  1. টার্মিনালে এটি পেস্ট করে প্রজেক্টটি তৈরি করুন এবং এর ডিপেন্ডেন্সিগুলো ইনস্টল করুন:
    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
    

ব্র্যান্ড নির্দেশিকা লিখুন

  1. স্কিল ফোল্ডারটি তৈরি করুন এবং ফাইলটি খুলুন:
    mkdir -p visual_director/skills/brand-guidelines
    cloudshell edit visual_director/skills/brand-guidelines/SKILL.md
    
  2. এডিটরে খোলা 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 ফাইলটি আপডেট করুন এবং এটিকে এমনভাবে কনফিগার করুন যাতে এটি পূর্বে সংজ্ঞায়িত দক্ষতা দ্বারা সজ্জিত হয়।

  1. এজেন্ট ফাইলটি খুলুন:
    cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py
    
  2. 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 এজেন্টটি এখন একটি এজেন্ট স্কিল দিয়ে সঠিকভাবে কনফিগার করা হয়েছে। এটি পরীক্ষা করার আগে, আপনি এই এজেন্টটিকে এর অন্যতম প্রধান সক্ষমতা হিসেবে ইমেজ অ্যাসেট তৈরি করার একটি টুল দিয়ে সজ্জিত করবেন।

৫. একজন এজেন্টকে একটি চিত্র তৈরির সরঞ্জাম দিয়ে সজ্জিত করুন।

এই টাস্কে, আপনাকে ভিজ্যুয়াল ডিরেক্টরকে এমন একটি টুল দিতে হবে যা আর্ট ডিরেকশনকে একটি ইমেজ হিসেবে রেন্ডার করে এবং সেটিকে একটি আর্টিফ্যাক্ট হিসেবে সংরক্ষণ করে। আর্টিফ্যাক্ট হলো নামযুক্ত ও ভার্সনযুক্ত বাইনারি ডেটা বা ফাইলের বিষয়বস্তু, যা একটি এআই এজেন্ট কোনো টাস্ক চলাকালীন তৈরি, পরিবর্তন বা ব্যবহার করে।

টুলটি এবং এটি যে আর্টিফ্যাক্টটি লেখে

টুলটি বাস্তবায়ন করুন এবং এজেন্টের সাথে যুক্ত করুন।

  1. এজেন্ট ফাইলটি খুলুন:
    cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py
    
  2. root_agent সংজ্ঞার আগে নিম্নলিখিত generate_key_visual টুলটি কপি করুন:
    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,
       }
    
  3. এজেন্টকে টুলটি দিয়ে সজ্জিত করতে SkillToolset নিচে generate_key_visual যোগ করুন:
       tools=[
          SkillToolset(skills=[BRAND_SKILL]),
          ## Supply the `generate_key_visual` tool below this comment
          generate_key_visual,
       ],
    
  4. agents-cli ADK-এর মতো পরিদর্শনের জন্য playground নামক একটি অন্তর্নির্মিত ওয়েব ডেভেলপমেন্ট UI রয়েছে। প্লেগ্রাউন্ড শুরু করতে:
    agents-cli playground --port 8080
    
  5. টার্মিনালের উপরের ডানদিকে থাকা চোখের আইকন, অর্থাৎ ওয়েব প্রিভিউ-তে ক্লিক করুন এবং পোর্ট ৮০৮০-তে প্রিভিউ নির্বাচন করুন। ওয়েব প্রিভিউতে ক্লিক করুন
  6. এজেন্টের সাথে চ্যাট করার জন্য আপনি নিম্নলিখিত ইন্টারফেসটি দেখতে পাবেন। 'Nine lives. Zero gravity.' এই প্রম্পটটি পাঠানোর চেষ্টা করুন। ডেমো ওয়ার্কফ্লো ইন্টারঅ্যাকশনগুলো থেকে আপনি দেখতে পারেন, কীভাবে visual_director এজেন্ট ব্র্যান্ড গাইডলাইন স্কিলটি পড়ার জন্য load_skill("brand-guidelines") কমান্ডটি চালায় এবং তারপর ইমেজ তৈরি করা শুরু করার জন্য generate_key_visual এক্সিকিউট করে। ফলাফলস্বরূপ প্রাপ্ত ইমেজটি একটি আর্টিফ্যাক্ট হিসেবে সংরক্ষিত হয়, যা UI-তেও প্রদর্শিত হয় এবং সহজেই পর্যবেক্ষণ করা যায়।
  7. টার্মিনালে ফিরে যান এবং দুইবার Ctrl+C চেপে চলমান agents-cli playground প্রসেসটি বন্ধ করুন।

৬. এ২এ প্রোটোকল সহ মাল্টি-এজেন্ট আর্কিটেকচার

এই টাস্কে, আপনি ভিজ্যুয়াল ডিরেক্টরকে এমন একটি সার্ভিস হিসেবে উন্মুক্ত করবেন যাকে অন্যান্য এজেন্টরা কল করতে পারবে, এবং এটিকে জেনারেট করা ইমেজ দিয়ে রেসপন্স করার জন্য কনফিগার করবেন।

এজেন্টটুএজেন্ট (A2A) হলো একটি উন্মুক্ত প্রোটোকল, যার মাধ্যমে একটি এজেন্ট নেটওয়ার্কের মাধ্যমে অন্য এজেন্টকে কল করতে পারে। এর মূল অংশ হলো এজেন্ট কার্ড , যা একটি JSON ডকুমেন্ট। এজেন্ট একটি সুপরিচিত URL-এর মাধ্যমে এই ডকুমেন্টটি প্রকাশ করে, যেখানে তার নাম, বিবরণ এবং সক্ষমতা উল্লেখ থাকে। একজন কলার এই কার্ডটি সংগ্রহ করে এবং এর পেছনের এজেন্টের সাথে কীভাবে কথা বলতে হবে তা জেনে যায়; এক্ষেত্রে কোনো শেয়ার করা সোর্স কোড, নির্ভরতা বা ভাষার প্রয়োজন হয় না।

A2A প্রোটোকল

agents-cli ডিফল্টভাবেই এটি সংযুক্ত করে রেখেছে। স্কাফোল্ডটি visual_director/app_utils/a2a.py তৈরি করেছে, যা আপনার এজেন্ট থেকে কার্ডটি বিল্ড করে ও রাউটগুলো মাউন্ট করে, এবং visual_director/fast_api_app.py তৈরি করেছে, যা সেগুলোকে সার্ভ করে। আর্টিফ্যাক্টগুলো ক্লায়েন্টের কাছেও ফেরত পাঠানোর জন্য আপনাকে শুধু একটি ছোট পরিবর্তন করতে হবে।

আর্কিটেকচারটি নিচে দেখানো ছবির মতো হবে। উল্লেখ্য যে, এজেন্টটি এখনও আমাদের প্রাথমিক ওয়ার্কফ্লোতে সমন্বিত করা হয়নি:

A2A সার্ভার সেটআপ করুন

agents-cli এ২এ সার্ভার স্ক্যাফোল্ড

agents-cli ব্যবহার করে visual-director এজেন্ট ইনিশিয়ালাইজ করার সময় নিম্নলিখিত কোড এবং মডিউলটি আগে থেকেই সরবরাহ করা থাকে। টার্মিনালে নিম্নলিখিত কমান্ডগুলো পেস্ট করে এই ফাইলগুলো খুলুন:

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,
)

তৃতীয়ত, এটি দুটি রুট স্থাপন করে: একটি কার্ডের জন্য, অন্যটি কল গ্রহণ করার জন্য।

রুট

উদ্দেশ্য

/a2a/visual_director/.well-known/agent-card.json

কার্ডটি। একজন কলার এজেন্ট কী করতে পারেন তা জানতে প্রথমে এটি পড়েন।

/a2a/visual_director

JSON-RPC এন্ডপয়েন্ট। যেখানে প্রকৃত অনুরোধগুলো যায়।

শিল্পকর্মগুলোকে সীমানা অতিক্রম করতে দিন

ডিফল্টরূপে, একটি A2A উত্তরে টেক্সট থাকে। ছবিটি একটি আর্টিফ্যাক্ট, এবং আপনি এটিকে অন্তর্ভুক্ত করার জন্য কনফিগার না করা পর্যন্ত এটি সার্ভিং এজেন্টের স্টোরে থেকে যায়।

  1. তৈরি হওয়া A2A ফাইলটি খুলুন:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director
    cloudshell edit visual_director/app_utils/a2a.py
    
  2. 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,
    )
    
  3. 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 কার্ডটি পড়ুন।

  1. সার্ভারটি ব্যাকগ্রাউন্ডে চালু করুন। আপনাকে 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 &
    
  2. শুরু হতে কয়েক সেকেন্ড সময় দিন, তারপর এটি পরিবেশন করছে কিনা তা নিশ্চিত করুন:
    sleep 10
    tail -2 /tmp/visual-director.log
    
    আপনার দেখা উচিত:
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://127.0.0.1:8801 (Press CTRL+C to quit)
    
  3. এজেন্ট এখন যে কার্ডটি প্রকাশ করবে তা পড়ুন:
    curl -s http://localhost:8801/a2a/visual_director/.well-known/agent-card.json | python3 -m json.tool
    
    কার্ডটিতে এজেন্টের নাম, বিবরণ, ইউআরএল এবং generate_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"
    }
    
    আপনি মূল pitch-generator ওয়ার্কফ্লোতে visual-director এজেন্টকে এম্বেড করার জন্য প্রস্তুত।

৭. ওয়ার্কফ্লোতে A2A রিমোট এজেন্টকে অন্তর্ভুক্ত করুন।

এই টাস্কে, আপনি রিমোট এজেন্টটিকে গ্রাফে তৃতীয় শাখা হিসেবে যুক্ত করবেন।

একটি রিমোট এজেন্টকে RemoteA2aAgent মধ্যে মোড়ানো হয় এবং অন্য যেকোনো নোডের মতোই গ্রাফে স্থাপন করা হয়। এজগুলোর আকৃতি একই থাকে এবং কোঅর্ডিনেটর জানে না যে এর কোন নোডগুলো লোকাল।

কোঅর্ডিনেটরকে সার্ভিসটির দিকে নির্দেশ করুন এবং গ্রাফ ওয়ার্কফ্লো আপডেট করুন।

  1. এজেন্ট ফাইলটি খুলুন:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator
    cloudshell edit pitch_generator/agent.py
    
  2. ফাইলের শীর্ষে, বিদ্যমান ইম্পোর্টগুলোর পাশে এই ইম্পোর্টগুলো যোগ করুন:
    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
    
  3. creative_director ডিক্লারেশনের উপরে নিম্নলিখিত RemoteA2aAgent ডেফিনিশনটি যোগ করুন:
    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,
    )
    
  4. `node` 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)
    
  5. ডাউনস্ট্রিম জেনারেশন শুরু হওয়ার আগে একটি হিউম্যান অ্যাপ্রুভাল গেট যোগ করুন। 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")
    
  6. অবশেষে, উপরের ইম্পোর্টগুলো আপডেট করে google.adk.events এবং google.adk.workflow থেকে RequestInput এবং node অন্তর্ভুক্ত করুন:
    from google.adk.events import Event, RequestInput
    from google.adk.workflow import JoinNode, Workflow, node
    
    এবং user_approval মাধ্যমে রাউট করার জন্য root_agent ওয়ার্কফ্লো edges পরিবর্তন করুন:
        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 হেল্পার ফাংশনটি সেখান থেকে এটি পুনরুদ্ধার করে।

ইন্টিগ্রেশন পরীক্ষা করুন

এখন আপনি পরীক্ষা করে দেখবেন যে ব্যাকগ্রাউন্ডে চলমান ভিজ্যুয়াল ডিরেক্টর এবং পিচ জেনারেটর A2A প্রোটোকলের মাধ্যমে যোগাযোগ করতে পারে কি না।

  1. ভিজ্যুয়াল ডিরেক্টর এখনও ব্যাকগ্রাউন্ডে চলছে কিনা তা নিশ্চিত করুন:
    curl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.json
    
    এখানে আপনার visual 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
    
  2. প্রিভিউ শুরু করুন:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator/pitch_generator
    agents-cli playground --port 8080
    
  3. টার্মিনালের উপরের ডানদিকে থাকা চোখের আইকন, অর্থাৎ ওয়েব প্রিভিউ-তে ক্লিক করুন এবং পোর্ট ৮০৮০-তে প্রিভিউ নির্বাচন করুন। ওয়েব প্রিভিউতে ক্লিক করুন
  4. আপনি এজেন্টের সাথে চ্যাট করার ইন্টারফেসটি দেখতে পাবেন। 'Flying skateboards for cats' প্রম্পটটি পাঠানোর চেষ্টা করুন। ডেমো ওয়ার্কফ্লোডেমো ওয়ার্কফ্লো আপনি সম্পূর্ণ ইন্টারঅ্যাকশনটি দেখতে পাবেন, যেখানে ওয়ার্কফ্লো শুরু হয় এবং প্রতিটি এজেন্ট কাজ শুরু করে। creative_director কনসেপ্টের খসড়া তৈরি করার পর, ওয়ার্কফ্লোটি অ্যাপ্রুভাল গেটে থেমে যায় এবং আপনাকে নিশ্চিত করতে বলে: "অনুগ্রহ করে ক্যাম্পেইন কনসেপ্টটি অনুমোদন করুন (হ্যাঁ/না)।" এগিয়ে যাওয়ার জন্য ইনপুট ফিল্ডে "হ্যাঁ" লিখুন। একবার অনুমোদন হয়ে গেলে, গ্রাফটি ছড়িয়ে পড়ে: আপনি দেখতে পাবেন কখন visual-director এজেন্ট স্কিল লোড করা শুরু করে, এবং ইমেজ তৈরির মাঝামাঝি সময়ে copywriter এজেন্ট সোশ্যাল মিডিয়া ক্যাপশন তৈরি করা শেষ করে—যা দেখায় যে উভয় এজেন্ট একে অপরের জন্য অপেক্ষা না করে সমান্তরালভাবে কাজ করে। উভয়ের কাজ শেষ হয়ে গেলে, assemble নোডটি creative_director তৈরি করা অনুমোদিত কনসেপ্টের সাথে ফলাফলগুলোকে একত্রিত করে, এবং package ফাংশনে পিচ কন্টেন্ট ডেলিভারি চূড়ান্ত করে। A2A এর মাধ্যমে সংযুক্ত দুটি পরিষেবা

৮. ক্লাউড স্টোরেজে মূল ভিজ্যুয়ালগুলো সংরক্ষণ করুন।

এখন পর্যন্ত প্রতিটি মূল ভিজ্যুয়াল মেমরিতে সংরক্ষিত ছিল। প্রসেসটি বন্ধ হওয়ার সাথে সাথেই ছবিটি মুছে যায়, যা একটি প্লেগ্রাউন্ডের জন্য ঠিক আছে কিন্তু কোনো ক্যাম্পেইনের জন্য অকেজো। এই টাস্কে, আপনি ওয়ার্কফ্লোকে লেখার জন্য একটি বাকেট দেবেন এবং একটি 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 কল ক্লাউড স্টোরেজে জমা হবে।

আর্টিফ্যাক্ট পরিষেবা GCS বালতির সাথে একীভূত করুন

BigQuery ডেটাসেট তৈরি করুন

  1. ক্লাউড শেলে, একটি BigQuery ডেটাসেট তৈরি করতে নিম্নলিখিত কমান্ডটি চালান:
    bq mk --dataset --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> bwg
    
  2. কোঅর্ডিনেটরের আর্টিফ্যাক্ট স্টোরটিকে বাকেটটির দিকে নির্দেশ করুন:
    export LOGS_BUCKET_NAME="<YOUR_PROJECT_ID>-bwg"
    
    GcsArtifactService gs:// প্রিফিক্স ছাড়া শুধুমাত্র বাকেটের নাম গ্রহণ করে। অন্যান্য ভেরিয়েবলের মতো এটিও আপনার শেল-এ থাকে এবং ডিপ্লয় টাস্ক এটিকে ক্লাউড রান-এ পাঠিয়ে দেয়।
  3. আপনার বাকেটের বিষয়বস্তু পরীক্ষা করুন। একটি নতুন ব্রাউজার ট্যাবে, নিম্নলিখিত URL-টি খুলুন:
    https://console.cloud.google.com/storage/browser?project=<YOUR_PROJECT_ID>
    
    বালতিটিতে ক্লিক করুন। আপনার পূর্ববর্তী পরীক্ষার উপর নির্ভর করে, এতে আগে তৈরি করা ছবি থাকতে পারে।

৯. ক্লাউড রান-এ ভিজ্যুয়াল ডিরেক্টর এজেন্ট স্থাপন করুন

এখন পর্যন্ত সবকিছু একটি মেশিনে চলছিল, যেখানে ভিজ্যুয়াল ডিরেক্টর localhost:8801 এ অ্যাক্সেসযোগ্য ছিল। এই টাস্কে আপনি ভিজ্যুয়াল ডিরেক্টর এজেন্টকে তার নিজস্ব ক্লাউড রান সার্ভিস হিসেবে ডেপ্লয় করবেন এবং পিচ জেনারেটরকে এজেন্টটুএজেন্ট (A2A) প্রোটোকল ব্যবহার করে নেটওয়ার্কের মাধ্যমে এর সাথে যোগাযোগ করতে দেবেন।

ভিজ্যুয়াল ডিরেক্টর একটি আসল https:// ইউআরএল পায়, তাই আপনার আগে লেখা _cloud_run_client টি None রিটার্ন করার পরিবর্তে রিকোয়েস্ট সাইন করা শুরু করে। এছাড়াও, ক্লাউড রান ডিফল্টরূপে প্রাইভেট ডিপ্লয়মেন্ট করে।

ক্লাউড রান পরিষেবা হিসাবে উভয় এজেন্ট

ভিজ্যুয়াল ডিরেক্টর স্থাপন করুন

  1. স্থানীয় ব্যাকগ্রাউন্ড সার্ভিস এবং প্লেগ্রাউন্ড যদি এখনও চালু থাকে, তবে সেগুলি বন্ধ করুন:
    fuser -k 8801/tcp 2>/dev/null || true
    fuser -k 8000/tcp 2>/dev/null || true
    
  2. এজেন্টটি ডেপ্লয় করুন। এটি একটি কন্টেইনার তৈরি করে এবং পুশ করে।⏰ এতে কয়েক মিনিট সময় লাগবে।
    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"
    

ক্লাউড রানে ডেপ্লয় করা ভিজ্যুয়াল ডিরেক্টর ব্যবহার করে পিচ জেনারেটরটি চালান।

  1. ভিজ্যুয়াল ডিরেক্টরের 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 প্রোটোকল সমর্থন করে। রিপোজিটরিটির সাথে A2A-এর মাধ্যমে পিচ জেনারেটরকে কল করার জন্য একটি ছোট ক্লায়েন্ট অন্তর্ভুক্ত রয়েছে।

স্থানীয়ভাবে চলমান পিচ জেনারেটরের URL-এ PITCH_GENERATOR_URL সেট করা প্রয়োজন। অন্যদিকে, ভিজ্যুয়াল ডিরেক্টর ক্লাউড রান-এ চলে এবং পিচ জেনারেটর A2A-এর মাধ্যমে এটির সাথে যোগাযোগ করে।

  1. ক্লায়েন্ট ফাইলটি আপনার প্রজেক্টে কপি করে রান করুন:
    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 ব্যবহার করতে পারেন)।
  2. call_agent.py খুলুন এবং a2a-sdk ব্যবহার করে এটি এজেন্টের সাথে কীভাবে কাজ করে তা পরীক্ষা করুন:
    • ClientFactory https://SERVICE_URL/a2a/pitch_generator লক্ষ্য করে একটি আনুষ্ঠানিক A2A Client তৈরি করে।
    • generate_pitch_async একটি প্রাথমিক SendMessageRequest পাঠায়। যখন TaskState.TASK_STATE_INPUT_REQUIRED সহ প্রতিক্রিয়াটি ফিরে আসে, তখন এটি adk_request_input অংশটি শনাক্ত করে, খসড়া ধারণাটি প্রদর্শন করে, আপনার অনুমোদন সংগ্রহ করে এবং আপনার প্রতিক্রিয়াটি টাস্কে ফেরত পাঠিয়ে একটি রিজুম রিকোয়েস্ট পাঠায়।
    • পার্সিং লুপটি সম্পন্ন হওয়া টাস্কের আর্টিফ্যাক্টগুলো থেকে CONCEPT , COPY , এবং ART DIRECTION সেকশনগুলো পড়ে এবং বাইনারি ইমেজটি key_visual.png নামে সংরক্ষণ করে।
    আপনি তিনটি টেক্সট সেকশন প্রিন্ট হতে দেখবেন এবং ছবিটি key_visual.png ফাইলে সেভ হতে দেখবেন।
  3. আপনার বাকেটে মূল ভিজ্যুয়ালটি আপলোড করুন, এমন একটি প্রিফিক্সের অধীনে যা আপনি BigQuery-কে নির্দেশ করতে পারেন:
    gcloud storage cp ./key_visual.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png
    
  4. তুলনা করার জন্য দ্বিতীয় একটি পিচ তৈরি করুন এবং সেটিও আপলোড করুন:
    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
    

১০. BigQuery-তে ব্র্যান্ড ফিটের জন্য মূল ভিজ্যুয়ালগুলোকে স্কোর করুন।

এখন আপনার কাছে একটি বাকেটে ছবি এবং সেগুলোকে রূপ দেওয়ার জন্য তৈরি ব্র্যান্ড নির্দেশিকাগুলো রয়েছে। এই টাস্কে, আপনি এই দুটিকে একত্রিত করবেন: BigQuery থেকে ছবিগুলোকে রেফারেন্স করবেন, তারপর ক্লাউড স্টোরেজ থেকে এক বাইটও না সরিয়ে একটি Gemini মডেলকে নির্দেশিকাগুলোর সাপেক্ষে প্রত্যেকটি ছবির মান নির্ণয় করতে বলবেন।

BigQuery-এর দুটি বৈশিষ্ট্য এই কাজটি করে:

  • ObjectRef হলো এমন একটি ভ্যালু যা একটি ক্লাউড স্টোরেজ অবজেক্টকে নির্দেশ করে। OBJ.MAKE_REF একটি URI এবং এমন একটি কানেকশন ব্যবহার করে এটি তৈরি করে, যা BigQuery-কে বাকেটটিতে ডেলিগেটেড অ্যাক্সেস প্রদান করে। সেটআপ স্ক্রিপ্ট দ্বারা তৈরি pitch-connection হলো সেই কানেকশন, এবং এতে আগে থেকেই Storage Object Viewer ও Agent Platform User সংরক্ষিত থাকে।
  • AI.SCORE একটি প্রম্পট গ্রহণ করে এবং একটি FLOAT64 রিটার্ন করে। প্রম্পটটিতে স্ট্রিং এবং ObjectRef ভ্যালু মিশ্রিত থাকতে পারে, ফলে মডেলটি আপনার রুব্রিক এবং ছবিটি একসাথে দেখতে পায়।

BigQuery বাকেটটি পড়ে।

মূল ভিজ্যুয়ালগুলির একটি সারণী তৈরি করুন

  1. BigQuery Studio একটি নতুন ব্রাউজার ট্যাবে খুলুন:
    https://console.cloud.google.com/bigquery?project=<YOUR_PROJECT_ID>
    
  2. নতুন কোয়েরি তৈরি করুন ( প্লাস আইকন)-এ ক্লিক করুন, তারপর নিম্নলিখিতটি পেস্ট করে চালান (প্রতিস্থাপন করে) এবং আপনার প্রজেক্ট আইডি এবং অঞ্চল সহ)। এটি প্রতিটি মূল ভিজ্যুয়ালের জন্য একটি করে সারি তৈরি করে, যেখানে ক্যাম্পেইনের ধারণার সাথে ছবিটির একটি রেফারেন্স যুক্ত থাকে:
    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'
      )
    ]);
    
    bq OBJ.MAKE_REF ইউআরআই এবং কানেকশন থেকে রেফারেন্সটি তৈরি করে। এরপর OBJ.FETCH_METADATA ক্লাউড স্টোরেজের সাথে যোগাযোগ করে এবং অবজেক্টের সাইজ, কন্টেন্ট টাইপ ও জেনারেশন পূরণ করে। এই দ্বিতীয় কলটিই আপনার কানেকশন কাজ করছে কিনা তা প্রমাণ করার দ্রুততম উপায়: যদি পারমিশন ভুল থাকে, তাহলে details ফিল্ডে মেটাডেটার পরিবর্তে এররটি চলে আসে।
  3. আপনি যা সংরক্ষণ করেছেন তা পরীক্ষা করুন। পূর্ববর্তী কোয়েরিটি এটি দিয়ে প্রতিস্থাপন করুন এবং চালান :
    SELECT campaign, concept, key_visual.uri, key_visual.details
    FROM bwg.key_visuals;
    
    টেবিলটি একটি পয়েন্টার এবং তার মেটাডেটা ধারণ করে, ছবিটি নয়। বাইটগুলো কখনোই বাকেট থেকে বের হয়নি।

ব্র্যান্ড নির্দেশিকা অনুসারে প্রতিটি ছবির মান নির্ধারণ করুন।

ভিজ্যুয়াল ডিরেক্টরকে একটি প্যালেট, একটি লাইটিং নিয়ম এবং একটি কম্পোজিশন নিয়ম মেনে চলতে বলা হয়েছিল। তিনি আসলে তা করেছিলেন কিনা, সেটা বিবেচনার বিষয়, এবং AI.SCORE কাজই হলো সেটি।

  1. নিম্নলিখিত কোয়েরিটি চালান (প্রতিস্থাপন করে) আপনার অঞ্চল সহ)। প্রম্পটটি একটি টাপল: আপনার রুব্রিক, ক্যাম্পেইনের ধারণা, এবং ছবিটির জন্য 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;
    
  2. স্কোরটিকে এমন একটি সিদ্ধান্তে পরিণত করুন যার ওপর ভিত্তি করে আপনার দল পদক্ষেপ নিতে পারে:
    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.SCORE শুধুমাত্র একটি FLOAT64 রিটার্ন করে, তাই থ্রেশহোল্ডটি সাধারণ SQL-এ থাকে, যেখানে আপনি প্রম্পট স্পর্শ না করেই এটি টিউন করতে পারেন। স্কোরিং প্রতি সারি অনুযায়ী চলে, যার মানে হলো একটি ক্যাম্পেইন দ্বারা উৎপাদিত প্রতিটি অ্যাসেটের জন্য একই নিয়ম প্রযোজ্য হয়, শুধু আপনার তৈরি করা দুটি অ্যাসেটের জন্য নয়।

১১. পরবর্তী পদক্ষেপ

মূল্যায়ন তৈরি করুন

এজেন্টিক ইভ্যালুয়েশন বা ‘ইভ্যালস’ হলো স্বয়ংক্রিয় পরীক্ষা, যা দিয়ে পরিমাপ করা হয় স্বায়ত্তশাসিত এআই এজেন্টরা কতটা ভালোভাবে যুক্তি দিতে, পরিকল্পনা করতে, টুল ব্যবহার করতে এবং একাধিক ধাপের কর্মপ্রবাহ সম্পন্ন করতে পারে। এগুলো এজেন্টদের জন্য ইউনিট টেস্টিং-এর মতোই, তবে এতে তাদের অনির্দিষ্ট প্রকৃতিকে বিবেচনায় রাখা হয়।

আমাদের একটি এজেন্ট ‘ Human in the loop অন্তর্ভুক্ত করে, যার মানে এটি ইনপুটের জন্য অপেক্ষা করে। আপনাকে অ্যান্টিগ্র্যাভিটিকে বর্তমান কোডে পরিবর্তন করার অনুমতি দিতে হবে, যাতে এই আচরণটি স্বয়ংক্রিয় মূল্যায়নের পথে বাধা সৃষ্টি না করে।

শুরু করার অন্যতম সেরা উপায় হলো অ্যান্টিগ্র্যাভিটি সিএলআই-কে জিজ্ঞাসা করা।

CLI শুরু করতে ক্লাউড শেলে নিম্নলিখিতটি টাইপ করুন:

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.

আপনি ক্লোন করা রিপোজিটরিতে মূল্যায়নগুলির একটি উদাহরণ এবং সেগুলি চালানোর নির্দেশাবলীও খুঁজে পেতে পারেন।

১২. পরিষ্কার করুন

এই কোডল্যাবে ব্যবহৃত রিসোর্সগুলির জন্য আপনার গুগল ক্লাউড অ্যাকাউন্টে চার্জ হওয়া এড়াতে, হয় প্রজেক্টটি ডিলিট করুন (এটিই সুপারিশ করা হচ্ছে) অথবা কোডল্যাব চলাকালীন তৈরি করা স্বতন্ত্র রিসোর্সগুলি ডিলিট করুন:

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

১৩. অভিনন্দন!

এই কোডল্যাবে, আপনি এজেন্ট ডেভেলপমেন্ট কিট ব্যবহার করে একটি মাল্টি-এজেন্ট ক্যাম্পেইন পিচ জেনারেটর তৈরি করেছেন। আপনি তিনটি এজেন্টকে একটি ডিটারমিনিস্টিক গ্রাফ ওয়ার্কফ্লোতে সংযুক্ত করেছেন, ব্র্যান্ড গাইডলাইনগুলোকে একটি এজেন্ট স্কিল হিসেবে প্যাকেজ করেছেন যা চাহিদা অনুযায়ী লোড হয়, এবং একটি এজেন্টকে এমন একটি ইমেজ জেনারেশন টুল দিয়েছেন যা তার আউটপুটকে একটি আর্টিফ্যাক্ট হিসেবে সংরক্ষণ করে। এরপর আপনি ভিজ্যুয়াল ডিরেক্টরকে তার নিজস্ব A2A সার্ভিসে বিভক্ত করেছেন, এটিকে একটি রিমোট নোড হিসেবে গ্রাফে পুনরায় এমবেড করেছেন, ক্লাউড রানে ডেপ্লয় করেছেন, এবং স্থানীয়ভাবে চলমান একটি কোঅর্ডিনেটর থেকে A2A-এর মাধ্যমে সম্পূর্ণ ওয়ার্কফ্লোটি কল করেছেন। সবশেষে, আপনি ObjectRef ব্যবহার করে BigQuery থেকে জেনারেট করা মূল ভিজ্যুয়ালগুলোকে রেফারেন্স করেছেন এবং আপনার নিজস্ব ব্র্যান্ড গাইডলাইনের সাথে সেগুলোর তুলনা করার জন্য AI.SCORE ব্যবহার করেছেন।