Google Cloud ile Ajan Tabanlı Şarkı Önerisi Oluşturucu Geliştirme: Düzenleme, Değerlendirme ve Analiz

1. Giriş

Acenteler için uzmanlık dersi banner'ı

Ham bir konu özetini alıp son derece ilgi çekici sosyal medya öğelerinin oluşturulmasını düzenleyen çok formatlı ve çok agent'lı bir motor oluşturmayı öğrenin. Google'ın Agent Development Kit (ADK) ve Agent2Agent (A2A) protokolünü kullanarak bağımsız mikro ajanlar oluşturacak, marka kurallarını yeniden kullanılabilir bir ajan becerisi olarak paketleyecek, Cloud Run'a bir ajan hizmeti dağıtacak ve BigQuery AI işlevleriyle marka uyumluluğu için oluşturulan temel görsellere puan vereceksiniz.

Yapacaklarınız

Bu codelab'de aşağıdaki görevleri nasıl gerçekleştireceğinizi öğreneceksiniz:

  • Belirleyici bir grafik iş akışıyla birden fazla ADK aracısını düzenleyin.
  • Marka kurallarını yalnızca gerektiğinde yüklenen bir aracı becerisi olarak paketleyin.
  • Bir ajana, çıktısını eser olarak kaydeden bir görüntü üretme aracıyla donatın.
  • Bir aracı A2A hizmeti olarak kullanıma sunma ve başka bir aracıdan uzaktan düğüm olarak çağırma
  • Görsel Yönetmen'i Cloud Run'a dağıtın ve iş akışını A2A üzerinden çağırın.
  • BigQuery'de yapay zeka işlevlerini kullanarak oluşturulan temel görselleri marka uyumluluğu açısından puanlayın.

İhtiyacınız olanlar

  • Web tarayıcısı (ör. Chrome)
  • Faturalandırmanın etkin olduğu bir Google Cloud hesabı ve Google Cloud projesi.

2. Başlamadan önce

Google Cloud projesi oluşturma

  1. Google Cloud Console'daki proje seçici sayfasında bir Google Cloud projesi seçin veya oluşturun.
  2. Cloud projeniz için faturalandırmanın etkinleştirildiğinden emin olun. Bir projede faturalandırmanın etkin olup olmadığını nasıl kontrol edeceğinizi öğrenin.

Cloud Shell'i Başlatma

Kodu indirmek, kurulum komut dosyalarını çalıştırmak ve uygulamayı dağıtmak için Google Cloud Shell'i kullanacaksınız.

  1. Tarayıcınızda Google Cloud Shell'i açın (veya Google Cloud Console'un üst kısmındaki Cloud Shell'i etkinleştir'i tıklayın):
    https://shell.cloud.google.com/
    
    Ek bildirimler verilirse Devam'ı tıklayın.Hem terminalin hem de düzenleyicinin tamamen yüklenmesini bekleyin. Bu işlem bir iki dakika sürebilir.
  2. Bu kodu terminale yapıştırarak ortamınızda Google Cloud proje kimliğinizi ve bölgenizi (örneğin, us-central1) yapılandırın ( ve değerlerini kendi değerlerinizle değiştirin):
    export PROJECT_ID="<YOUR_PROJECT_ID>"
    export REGION="<YOUR_REGION>"
    gcloud config set project $PROJECT_ID
    
    Terminalde yapıştırmaAşağıdakine benzer bir mesaj görürsünüz:
    Your active configuration is: [cloudshell-####]
    Updated property [core/project]
    
  3. Projeniz için gerekli Google Cloud API'lerini etkinleştirin:
    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
    

Depoyu Klonlama

Codelab'e başlamanıza yardımcı olacak bir kod şablonumuz var. Bu dosya nispeten küçüktür ancak bulunduğu GitHub deposu oldukça büyüktür. Klonlama işlemini hızlandırmak ve disk alanından tasarruf etmek için normalde git clone komutunu --filter=blob:none seçeneği, git sparse-checkout ve başka bazı komutlarla birlikte kullanırız.

Bu çok karmaşık görünüyor ancak Antigravity tüm bunları bizim için yapabilir.

Öncelikle Antigravity CLI'yı yapılandırarak doğrudan sorunumuzu çözmesini sağlayalım ve başlatalım.

Cloud Shell'de şu komutu çalıştırın:

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)

Bu komut, Antigravity CLI'yı yapılandırır ve aynı terminalde başlatır. Antigravity CLI'dan çıktığınızda Cloud Shell isteminize geri dönersiniz.

Antigravity CLI

Depoda yalnızca codelabs/bwg-multi-agent-pitch-generator klasörüne ihtiyacımız var. Antigravity'den yalnızca bu klasörü indirmesini ve ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/ konumunda yerel olarak saklamasını isteyelim.

Antigravity CLI'ya şu görevi verin:

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 CLI istemi

Antigravity görevi yerine getirir. Birkaç komut çalıştırmak için sizden izin isteyecektir. Kod indirildikten sonra /exit komutunu çalıştırarak Antigravity CLI'dan çıkın:

/exit

Antigravity CLI'dan çıkma

Depo çalışma alanını açın.

Şimdi Cloud Shell'de kod çalışma alanını açalım. Cloud Shell terminalinde şu komutu çalıştırın:

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

Kurulum komut dosyasını çalıştırın

Bu deneyimi daha sorunsuz hale getirmek için kurulum komut dosyasını depodan çalıştırın. Ortam değişkenlerini yapılandırır, agents-cli'ı yükler, yapılar için Cloud Storage paketi oluşturur, BigQuery Cloud Resource bağlantısını oluşturur ve otomatik yeniden deneme ile hizmet hesabına gerekli IAM izinlerini verir.

Kurulum komut dosyası, yukarıda dışa aktardığınız PROJECT_ID ve REGION'den her iki aracının da ihtiyaç duyduğu değişkenleri (GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_REGION, GOOGLE_CLOUD_LOCATION ve GOOGLE_GENAI_USE_VERTEXAI) türeten küçük bir yardımcı olan setenv.sh'yı da çağırır. Ayrıca bu iki değeri ana dizininizdeki bir .env dosyasına kaydederek daha sonra kurtarmanızı sağlar.

  1. Cloud Shell'de kurulum komut dosyasını yürütülebilir hale getirin ve çalıştırın:
    chmod +x codelab-setup.sh setenv.sh
    ./codelab-setup.sh
    
  2. Bu işlemin çalışması yaklaşık bir dakika sürer. Başarıyı belirten şu mesajı görmelisiniz: "🎉 🦄 Komut dosyası yürütme tamamlandı."başarılı
  3. Kurulum komut dosyası kendi kabuğunda çalıştığı için değişkenleri terminalinize ulaşmadı. Bu dosyaları oturumunuza yükleyin:
    source ./setenv.sh
    
    Projenizin, bölgenizin ve konumunuzun tekrarlandığını görürsünüz.

3. Grafik iş akışıyla aracıları düzenleme

Bu görevde, şarkı önerisi oluşturucu projesini oluşturacak ve iki aracı çalıştırıp çıkışlarını birleştiren bir grafik iş akışı oluşturacaksınız.

Bir şarkı önerisi için konsept gerekir. Konsept, fikri ve bu fikri destekleyen öğeleri ifade eder. Bu kullanım alanında, iş kapsamı içinde farklı sorumluluklara sahip olan aracıları tasarlayacağız. Böylece, karmaşık görevleri nasıl ayırıp farklı sorumluluklara sahip farklı aracılara atayabileceğinizi ve bu görevleri nasıl daha kolay yönetebileceğinizi göstereceğiz.

Bu tür işlerin uzmanlar arasında paylaştırılması, her temsilcinin ne zaman çalışacağını koordine etmeyi gerektirir. Ajanınızın her alt ajanı ne zaman arayacağına karar vermesine izin verebilir veya daha deterministik bir yaklaşım uygulayabilirsiniz. Bu codelab'de, grafik iş akışıyla deterministik bir yaklaşım kullanacaksınız.

İlk ajan projesini oluşturma

  1. Cloud Shell'de, bu kodu terminale yapıştırarak projeyi oluşturun:
    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
    
    Bu işlem, çalıştırılabilir eksiksiz bir proje oluşturur: bir aracı, bir Dockerfile, testler, daha sonra kullanılmak üzere Terraform ve .env.example şablonuyla birlikte bir .env dosyası. Bu codelab için iki bölüm önemlidir:
    • pitch_generator/agent.py, ajanı ve yeniden yazdığınız dosyayı ifade eder.
    • pitch_generator/, --agent-directory tarafından ayarlanan paket adıdır.
    Aracı, projesini ve bölgesini setenv.sh ile dışa aktardığınız ortamdan okur. Bu nedenle, burada yapılandırılacak bir şey yoktur.
  2. Bağımlılıkları yükleyin:
    cd pitch-generator
    agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
    
    Not: İskele, projeyi bu codelab'de daha sonra kullanılan protokol olan A2A'yı sunacak şekilde de bağlar. Şimdilik bu dosyaları olduğu gibi bırakın.

Grafiği anlama

ADK v2.x, grafik iş akışlarını destekler. Grafikler, iş birimleri olan düğümlerden ve bunları birbirine bağlayan kenarlardan oluşur. Bir düğüm genellikle bir aracıdır ancak düz bir Python işlevi de kullanılabilir. Bir kenar, bir düğüm tamamlandığında bir sonrakinin çalışacağını belirtir.

Kenarlar liste olarak yazılır ve ADK sırayı belirler:

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

İç içe yerleştirme, kenara anlamını verir:

Edge

Anlamı

(a, b, c)

Zincir. Önce a, sonra b, sonra c, birbiri ardına

(a, (b, c))

Ayrıntılı bir şekilde. Önce a, sonra aynı anda b ve c

((a, b), c)

Fan-in. c, hem a hem de b'yi bekler.

Fan-in için JoinNode kullanırsınız. Bu görev, tüm öncüllerin tamamlanmasını bekler ve çıkışlarını birlikte iletir.

Bu görevde aşağıdaki iş akışını oluşturacağız:

ilk iş akışı grafiği

Ardışık düzeni oluşturma

  1. Bu kodu terminale yapıştırarak aracı dosyasını açın:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator
    cloudshell edit pitch_generator/agent.py
    
    Cloud Shell düzenleyicisinde iskeleli agent.py öğesini görürsünüz.💡 İpucu: İstediğiniz zaman kodu seçip ampul simgesini kullanarak Gemini'dan kodu açıklamasını isteyebilirsiniz. Antigravity CLI'ya da sorabilirsiniz.Gemini Code Assist'i kullanma
  2. pitch_generator/agent.py düzenleyicisindeki dosyanın tamamını aşağıdakiyle değiştirin:
    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'ya benzer şekilde inceleme için playground adlı yerleşik bir web geliştirme kullanıcı arayüzü içerir. Playground'u başlatmak için:
    agents-cli playground --port 8080
    
    Telemetriyi etkinleştirmek isteyip istemediğiniz sorulur. n yazıp Enter tuşuna basın.
  4. Terminalin sağ üst kısmındaki göz simgesi olan Web önizlemesi'ni tıklayın ve 8080 bağlantı noktasında önizle'yi seçin.web önizlemesini tıklayın
  5. Temsilciyle sohbet etmek için aşağıdaki arayüzü görürsünüz. "Kediler için uçan kaykaylar" istemini göndermeyi deneyin. Aşağıdaki gibi bir yanıt görürsünüz. Burada iş akışı grafiğinin tamamını da inceleyebilirsiniz.demo iş akışıBu yanıtın nasıl üretildiğini inceleyin. Deneme alanında, grafiğin sırasıyla creative_director, copywriter, assemble ve package adımlarını nasıl attığı gösterilir. Bu sıra, kablolarını bağladığınız grafiktir. Bu şekilde, yeni oluşturduğunuz grafiği hızlıca onaylayabilirsiniz.
  6. Terminale dönün ve Ctrl+C tuşlarına iki kez basarak çalışan agents-cli playground işlemini durdurun.

4. Bir ajana beceri atama

Bu görevde ikinci bir aracı oluşturup ona beceri olarak paketlenmiş bir dizi marka yönergesi vereceksiniz.

Ardışık düzen, kelimeleri yazar. Bir resmin kendine özgü bir stili olmalıdır: palet, ışıklandırma şekli, kullandığınız ve asla kullanmadığınız kompozisyonlar. Bu bir kurallar sayfasıdır ve kurallar sayfasının yönetilmesi için daha iyi bir mekanizma gerekir. Bunu yapmanın bir yolu, "aracı becerisi" olarak paketlemektir.

Beceri, SKILL.md dosyası içeren bir klasördür. Beceri dizininin yapısı, aşağıdaki örnekte (visual_director kullanılarak, oluşturacağınız bir sonraki ajan) gösterildiği gibidir:

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
   ...

Ajan becerisinin giriş noktası, aşağıdaki gibi bir YAML ön bölümü içeren SKILL.md dosyasıdır:

---
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...

Frontmatter etikettir. Ajanın önceden gördüğü tek şey budur. Bu nedenle, becerinin ne zaman yüklenmeye değer olduğunu açıklamada belirtmeniz gerekir. Gövde, içeriktir ve aracı load_skill çağırana kadar bağlamın dışında kalır.

Buradaki amaç, bu ayrımı yapmaktır. İstem kısa kalır, ajan kuralları yalnızca gerektiğinde kullanır ve stil değişikliği, talimat dizesinde arama yapmak yerine tek bir dosyayı düzenlemek anlamına gelir.

Aşağıdaki şemada gösterildiği gibi, ajan becerilerini kullanarak ikinci ajanı (visual-director) oluşturmaya başlayacağız:

İkinci ajanı beceriyle donatma

Görsel yönetmeni yönlendirme

Görsel bileşeni işlemek için uzman bir temsilci (visual-director) oluşturacaksınız. Bu proje, daha sonra A2A protokolünü kullanarak birden fazla aracının birbiriyle nasıl iletişim kurduğunu göstermek için kendi hizmetine dönüştüğünden ayrı bir projedir. Yan yana iki projeniz olur:

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. Bu kodu terminale yapıştırarak projeyi oluşturun ve bağımlılarını yükleyin:
    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
    

Markalama kurallarını yazma

  1. Beceri klasörünü oluşturun ve dosyayı açın:
    mkdir -p visual_director/skills/brand-guidelines
    cloudshell edit visual_director/skills/brand-guidelines/SKILL.md
    
  2. Aşağıdaki içeriği SKILL.md dosyasına Düzenleyici'de yapıştırın ve kaydedin:Beceri
    ---
    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 uygulamasını güncelleme

agent.py dosyasını güncelleyin ve daha önce tanımlanmış beceriyle donatılacak şekilde yapılandırın.

  1. Aracı dosyasını açın:
    cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py
    
  2. visual_director/agent.py dosyasının tüm içeriğini aşağıdaki kodla değiştirin:
    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 aracısı artık bir aracı becerisiyle düzgün şekilde yapılandırıldı. Test etmeden önce bu ajana, temel özelliklerinden biri olarak resim öğeleri oluşturma aracı ekleyeceksiniz.

5. Bir ajana görüntü üretme aracı ekleme

Bu görevde, görsel yönetmene sanat yönetimini görüntü olarak oluşturup yapay ürün olarak kaydeden bir araç veriyorsunuz. Yapay ürün, yapay zeka aracısının bir görev sırasında oluşturduğu, değiştirdiği veya kullandığı, adlandırılmış ve sürümü belirlenmiş bir ikili veri parçası ya da dosya içeriğidir.

aracı ve yazdığı yapıyı

Aracı uygulayın ve temsilciye ekleyin

  1. Aracı dosyasını açın:
    cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py
    
  2. Aşağıdaki generate_key_visual aracını root_agent tanımından önce kopyalayın:
    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. Ajana aracı eklemek için generate_key_visual simgesini SkillToolset simgesinin altına ekleyin:
       tools=[
          SkillToolset(skills=[BRAND_SKILL]),
          ## Supply the `generate_key_visual` tool below this comment
          generate_key_visual,
       ],
    
  4. agents-cli, ADK'ya benzer şekilde inceleme için playground adlı yerleşik bir web geliştirme kullanıcı arayüzü içerir. Playground'u başlatmak için:
    agents-cli playground --port 8080
    
  5. Terminalin sağ üst kısmındaki göz simgesi olan Web önizlemesi'ni tıklayın ve 8080 bağlantı noktasında önizle'yi seçin.web önizlemesini tıklayın
  6. Temsilciyle sohbet etmek için aşağıdaki arayüzü görürsünüz. "Dokuz can. Sıfır yer çekimi."demo iş akışıMarkalama kuralları becerisini okumak için visual_director aracısının nasıl load_skill("brand-guidelines") yürüttüğünü ve ardından görüntüyü oluşturmaya başlamak için nasıl generate_key_visual yürüttüğünü etkileşimlerden inceleyebilirsiniz. Elde edilen resim, kullanıcı arayüzünde de gösterilen ve kolayca incelenebilen bir yapıt olarak saklanır.
  7. Terminale dönün ve Ctrl+C tuşlarına iki kez basarak çalışan agents-cli playground işlemini durdurun.

6. A2A protokolü ile çoklu ajan mimarisi

Bu görevde, Görsel Yönetici'yi diğer aracıların çağırabileceği bir hizmet olarak kullanıma sunacak ve oluşturulan resimle yanıt verecek şekilde yapılandıracaksınız.

Agent2Agent (A2A), bir ajanın ağ üzerinden başka bir ajanı çağırması için kullanılan açık bir protokoldür. Merkezi unsur, temsilcinin kendisi hakkında iyi bilinen bir URL aracılığıyla yayınladığı, adını, açıklamasını ve özelliklerini içeren bir JSON belgesi olan temsilci kartıdır. Arayan kişi kartı getirir ve kaynak kodu, bağımlılıklar veya dil paylaşımı olmadan kartın arkasındaki temsilciyle nasıl konuşacağını bilir.

A2A protokolü

agents-cli bu özelliği varsayılan olarak zaten bağlamıştır. Aracıdan kartı oluşturan ve rotaları bağlayan visual_director/app_utils/a2a.py ile bunları sunan visual_director/fast_api_app.py iskeleleri oluşturulur. Yapay nesneleri istemciye geri göndermesini sağlamak için küçük bir değişiklik yapmanız yeterlidir.

Mimari, aşağıda gösterildiği gibi görünecektir. Temsilcinin henüz ilk iş akışımıza entegre edilmediğini unutmayın:

A2A sunucusunu ayarlama

agents-cli A2A sunucu iskelesi

visual-director aracısını agents-cli kullanarak başlattığımızda aşağıdaki kod ve modül zaten sağlanır. Aşağıdaki komutları terminale yapıştırarak bu dosyaları açın:

cloudshell edit visual_director/fast_api_app.py
cloudshell edit visual_director/app_utils/a2a.py

visual_director/fast_api_app.py, aracıyı başlatır ve A2A rotalarını uygulama adından oluşturulan bir yolun altına yerleştirir:

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, üç hamlede gerisini halleder.

İlk olarak, ajanın kendisinden ajan kartı oluşturur. Ad, açıklama ve her araç, arayan kişinin okuyabileceği girişler haline gelir:

agent_card = await AgentCardBuilder(
    agent=agent,
    rpc_url=f"{resolved_app_url}{rpc_path}",
).build()

İkincisi, protokol ile temsilciniz arasına bir yürütücü yerleştirir. Gelen A2A istekleri ADK çalıştırmalarına çevrilir ve sonuçlar tekrar çevrilir:

request_handler = DefaultRequestHandler(
    agent_executor=A2aAgentExecutor(runner=runner, force_new_version=True),
    task_store=task_store,
    agent_card=agent_card,
)

Üçüncüsü, iki rota oluşturur: biri kartı sunar, diğeri aramaları kabul eder.

Rota

Amaç

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

Kart Arayan kişi, temsilcinin neler yapabileceğini öğrenmek için önce bunu okur.

/a2a/visual_director

JSON-RPC uç noktası. Gerçek isteklerin gittiği yer

Çıktıların sınırı aşmasına izin verme

Varsayılan olarak, A2A yanıtı metin içerir. Resim bir yapay nesnedir ve dahil edilecek şekilde yapılandırmadığınız sürece yayın aracısının deposunda kalır.

  1. Oluşturulan A2A dosyasını açın:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director
    cloudshell edit visual_director/app_utils/a2a.py
    
  2. AgentCardBuilder içe aktarma işlemini bulun ve altına A2aAgentExecutorConfig ile include_artifacts_in_a2a_event_interceptor içe aktarma işlemlerini ekleyin:
    ## ...
    ## 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), satırını bulup aşağıdakiyle değiştirin (A2aAgentExecutorConfig ekleyerek):
             agent_executor=A2aAgentExecutor(
                runner=runner,
                force_new_version=True,
                config=A2aAgentExecutorConfig(
                   execute_interceptors=[include_artifacts_in_a2a_event_interceptor]
                ),
             ),
    

Hizmeti başlatın ve yayınlanan A2A kartını okuyun.

  1. Sunucuyu arka planda başlatın. Kartın kendi adresi olarak bildirdiği adres APP_URL olduğundan bu adresi tanımlamanız gerekir. Bunu terminale yapıştırın:
    APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 &
    
  2. Başlaması için birkaç saniye bekleyin, ardından yayınlandığını doğrulayın:
    sleep 10
    tail -2 /tmp/visual-director.log
    
    Şunları görmeniz gerekir:
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://127.0.0.1:8801 (Press CTRL+C to quit)
    
  3. Ajanın yayınladığı kartı okuyun:
    curl -s http://localhost:8801/a2a/visual_director/.well-known/agent-card.json | python3 -m json.tool
    
    Kartta, generate_key_visual dahil olmak üzere temsilcinin adı, açıklaması, URL'si ve becerileri listelenir. Doğrudan koddaki aracı tanımından oluşturulur.
    {
       "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 aracısını ana pitch-generator iş akışına yerleştirmeye hazırsınız.

7. A2A uzak aracısını iş akışına yerleştirme

Bu görevde, uzak aracıyı grafiğe üçüncü bir dal olarak ekleyeceksiniz.

Uzak aracı, RemoteA2aAgent içine alınır ve grafikte diğer düğümler gibi yerleştirilir. Kenarlar aynı şekli korur ve koordinatör, hangi düğümlerinin yerel olduğunu bilmez.

Koordinatörü hizmete yönlendirin ve grafik iş akışını güncelleyin

  1. Aracı dosyasını açın:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator
    cloudshell edit pitch_generator/agent.py
    
  2. Bu içe aktarma işlemlerini dosyanın en üstüne, mevcut olanların yanına ekleyin:
    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 bildiriminin üzerine aşağıdaki RemoteA2aAgent tanımı ekleyin:
    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. package düğümü Python işlevini aşağıdaki tanımla üzerine yazın veya değiştirin:
    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. Aşağı akış oluşturma işlemi devam etmeden önce İnsan Onayı Aşaması ekleyin. pitch_generator/agent.py bölümünde, root_agent üzerindeki onay düğümlerini tanımlayın:
    @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. Son olarak, üst kısımdaki içe aktarma işlemlerini google.adk.events ve google.adk.workflow'den RequestInput ve node'yi içerecek şekilde güncelleyin:
    from google.adk.events import Event, RequestInput
    from google.adk.workflow import JoinNode, Workflow, node
    
    ve root_agent iş akışını edges user_approval üzerinden yönlendirecek şekilde değiştirin:
        edges=[
            ("START", creative_director),
            (creative_director, user_approval, (copywriter, visual_director)),
            ((creative_director, copywriter, visual_director), assemble),
            (assemble, package),
        ],
    
    Dikkat edilmesi gereken birkaç nokta:
    • Kullanıcı müdahalesi (HITL) onayı: approve_concept, RequestInput sonucunu verir. İş akışı bu düğüme ulaştığında yürütme duraklatılır ve arayana kesinti sinyali gönderilir. Kullanıcı onayı doğrulanana kadar aşağı akış dalları (copywriter ve visual_director) çalışmaz.
    • visual_director, copywriter ile aynı şekilde kenarlarda görünür. Ancak biri işlev çağrısı, diğeri ise ağ üzerinden çalışır.
    • Şu anda yalnızca metin bir düğümün çıkışına yükseltildiğinden, döndürülen resim node_input yerine oturum etkinliklerinden okunur. Resim, A2A önleyici üzerinden sınırı aştı ancak uzak aracının etkinliklerine eklenmiş olarak geldi. Bu nedenle, _key_visual yardımcı işlevi resmi oradan alır.

Entegrasyonu test etme

Şimdi, Görsel Yönetmen (arka planda çalışır) ve Şarkı Önerisi Oluşturucu'nun A2A protokolü üzerinden iletişim kurabildiğini test edeceksiniz.

  1. Görsel Yönetmen'in arka planda çalıştığını onaylayın:
    curl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.json
    
    Burada visual director: 200 sonucu almanız gerekir.Başka bir durumla karşılaşırsanız yeniden başlatmak için aşağıdaki komutu çalıştırın:
    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. Önizlemeyi başlatın:
    cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator/pitch_generator
    agents-cli playground --port 8080
    
  3. Terminalin sağ üst kısmındaki göz simgesi olan Web önizlemesi'ni tıklayın ve 8080 bağlantı noktasında önizle'yi seçin.web önizlemesini tıklayın
  4. Temsilciyle sohbet etme arayüzünü görürsünüz. "Kediler için uçan kaykaylar" istemini göndermeyi deneyin.demo iş akışıdemo iş akışıİş akışının başlatıldığı ve her aracının çalıştığı tam etkileşimi görürsünüz. creative_director konsepti oluşturduktan sonra iş akışı onay adımında duraklatılır ve sizden şunu onaylamanız istenir: "Lütfen kampanya konseptini onaylayın (evet/hayır)." Devam etmek için giriş alanına "yes" (evet) yazın. Onaylandıktan sonra grafik açılır: visual-director aracısının beceriyi yüklemeye ne zaman başladığını ve görüntü oluşturma işleminin ortasında copywriter aracısının sosyal medya başlığını oluşturmayı ne zaman tamamladığını görebilirsiniz. Bu, her iki aracının da birbirini beklemeden paralel olarak çalıştığını gösterir. Her ikisi de tamamlandıktan sonra assemble düğümü, creative_director tarafından oluşturulan onaylı konseptle birlikte sonuçları birleştirerek package işlevinde şarkı önerisi içerik yayınını tamamlar.A2A üzerinden bağlanan iki hizmet

8. Önemli görselleri Cloud Storage'da kalıcı hale getirme

Şimdiye kadar her önemli görsel hafızada kaldı. İşlem durduğu anda görüntü kaybolur. Bu durum, deneme alanı için sorun olmasa da kampanya için kullanışsızdır. Bu görevde, iş akışına yazılacak bir paket verir ve son görevde kullanacağınız bir BigQuery veri kümesi oluşturursunuz.

ADK, başlangıçta yapıtların nereye gideceğine karar verir. Oluşturulan app_utils/services.py, tek bir ortam değişkenini okur:

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 seçeneğini belirlerseniz her save_artifact görüşmesi bunun yerine Cloud Storage'da yer alır.

yapı hizmetini GCS paketiyle entegre etme

BigQuery veri kümesini oluşturma

  1. Cloud Shell'de, BigQuery veri kümesi oluşturmak için aşağıdaki komutu çalıştırın:
    bq mk --dataset --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> bwg
    
  2. Koordinatörün yapay ürün deposunu kovaya yönlendirin:
    export LOGS_BUCKET_NAME="<YOUR_PROJECT_ID>-bwg"
    
    GcsArtifactService, gs:// ön eki olmadan yalnızca paket adını alır. Diğer değişkenler gibi bu değişken de kabuğunuzda bulunur ve dağıtım görevi bunu Cloud Run'a iletir.
  3. Bucket'ınızın içeriğini kontrol edin. Yeni bir tarayıcı sekmesinde şu URL'yi açın:
    https://console.cloud.google.com/storage/browser?project=<YOUR_PROJECT_ID>
    
    Paketi tıklayın. Geçmiş testlerinize bağlı olarak, daha önce oluşturulmuş resimler içerebilir.

9. Visual Director aracısını Cloud Run'a dağıtma

Şimdiye kadar her şey tek bir makinede çalıştı ve Görsel Yönetmen'e localhost:8801 adresinden ulaşılabiliyordu. Bu görevde, Visual Director aracısını kendi Cloud Run hizmeti olarak dağıtacak ve Agent2Agent (A2A) protokolünü kullanarak ağ üzerinden şarkı önerisi oluşturucuyla iletişim kurmasına izin vereceksiniz.

Görsel Yönetmen gerçek bir https:// URL'si alır. Böylece, daha önce yazdığınız _cloud_run_client, None döndürmek yerine istekleri imzalamaya başlar. Ayrıca, Cloud Run dağıtımları varsayılan olarak özeldir.

her iki aracı da Cloud Run hizmeti olarak

Görsel Yönetmen'i dağıtma

  1. Yerel arka plan hizmeti ve oyun alanı hâlâ çalışıyorsa bunları durdurun:
    fuser -k 8801/tcp 2>/dev/null || true
    fuser -k 8000/tcp 2>/dev/null || true
    
  2. Ajanı dağıtın. Bu işlem, bir kapsayıcı oluşturur ve kapsayıcıyı gönderir.⏰ Bu işlem birkaç dakika sürer.
    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"
    

Cloud Run'a dağıtılan Visual Director'ı kullanan Şarkı Önerisi Üretici'yi çalıştırma

  1. Görsel Yönetmen URL'sini okuyun ve bu URL'yi kullanan Şarkı Önerisi Oluşturucu'yu çalıştırın:
    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 &
    

Dağıtılan iş akışını çağırma

Her iki aracı da A2A protokolünü desteklemelidir. Depoda, A2A aracılığıyla Pitch Generator'ı çağırmak için küçük bir istemci bulunur.

PITCH_GENERATOR_URL, yerel olarak çalışan Şarkı Önerisi Oluşturucu URL'sine ayarlanmalıdır. Bu sırada, Görsel Yönetmen Cloud Run'da çalışır ve Şarkı Önerisi Oluşturucu, A2A üzerinden Görsel Yönetmen ile iletişim kurar.

  1. İstemciyi projenize kopyalayın ve uygulayın:
    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
    
    İş akışında insan onayı aşaması olduğu için taslak konsept oluşturulduktan sonra komut dosyası duraklatılır:
    === HUMAN APPROVAL REQUIRED ===
    
    [DRAFT CONCEPT]
    Concept Line: "Gravity is a Suggestion."
    ...
    
    Please approve the campaign concept (yes/no):
    
    İş akışını onaylayıp devam ettirmek için yes yazıp Enter tuşuna basın. (Otomatik olarak onaylamak için -y veya --auto-approve parametrelerini de iletebilirsiniz).
  2. call_agent.py dosyasını açın ve a2a-sdk kullanarak ajanla nasıl etkileşim kurduğunu inceleyin:
    • ClientFactory, resmi bir A2A Client hedefleme https://SERVICE_URL/a2a/pitch_generator oluşturur.
    • generate_pitch_async, ilk SendMessageRequest'ı gönderir. Yanıt TaskState.TASK_STATE_INPUT_REQUIRED ile döndüğünde adk_request_input bölümünü algılar, taslak konsepti gösterir, onayınızı alır ve yanıtınızı içeren bir özgeçmiş isteğini göreve geri gönderir.
    • Ayrıştırma döngüsü, tamamlanan görevin yapıtlarındaki CONCEPT, COPY ve ART DIRECTION bölümlerini okur ve ikili resmi key_visual.png konumuna kaydeder.
    Üç metin bölümünün yazdırıldığını ve resmin key_visual.png konumuna kaydedildiğini görmelisiniz.
  3. BigQuery'nin işaret edebileceği bir ön ek altında, önemli resmi paketinize yükleyin:
    gcloud storage cp ./key_visual.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png
    
  4. Karşılaştırabileceğiniz bir içerik olması için ikinci bir şarkı önerisi oluşturun ve bunu da yükleyin:
    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'de marka uyumu için temel görsellere puan verme

Artık bir pakette resimleriniz ve bu resimlere şekil vermesi gereken marka kurallarınız var. Bu görevde, iki öğeyi bir araya getiriyorsunuz: BigQuery'deki resimlere referans verin, ardından bir Gemini modelinden her birini yönergelere göre derecelendirmesini isteyin. Bu sırada Cloud Storage'dan tek bir bayt bile taşımayın.

Bu işlem için iki BigQuery özelliği kullanılır:

  • ObjectRef, bir Cloud Storage nesnesini işaret eden bir değerdir. OBJ.MAKE_REF, URI'ye ek olarak BigQuery'ye pakete yetki verilmiş erişim izni veren bir bağlantıdan oluşturur. Kurulum komut dosyası tarafından oluşturulan pitch-connection, bu bağlantıdır ve Storage Object Viewer ile Agent Platform User rollerini zaten içerir.
  • AI.SCORE, bir istemi alır ve FLOAT64 döndürür. İstemde, ObjectRef değerleriyle dizeler karıştırılabilir. Böylece model, puan anahtarınızı ve görüntüleri birlikte görür.

BigQuery, paketi okur

Önemli görsellerin tablosunu oluşturma

  1. BigQuery Studio'yu yeni bir tarayıcı sekmesinde açın:
    https://console.cloud.google.com/bigquery?project=<YOUR_PROJECT_ID>
    
  2. Yeni sorgu oluştur'u (+ simgesi) tıklayın, ardından aşağıdakileri yapıştırıp çalıştırın ( ve yerine proje kimliğinizi ve bölgenizi girin). Her bir temel görsel için bir satır oluşturur ve kampanya konseptini resme referansla eşleştirir:
    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'
      )
    ]);
    
    bqOBJ.MAKE_REF, URI ve bağlantıdan referans oluşturur. OBJ.FETCH_METADATA ardından Cloud Storage ile iletişime geçer ve nesnenin boyutunu, içerik türünü ve oluşturma zamanını doldurur. Bu ikinci arama, bağlantınızın çalıştığını kanıtlamanın en hızlı yoludur: İzinler yanlışsa details alanı, meta veriler yerine hatayı tutarak geri döner.
  3. Depoladığınız öğeleri inceleyin. Önceki sorguyu bu sorguyla değiştirin ve çalıştırın:
    SELECT campaign, concept, key_visual.uri, key_visual.details
    FROM bwg.key_visuals;
    
    Tabloda resim değil, bir işaretçi ve meta verileri bulunur. Baytlar hiçbir zaman paketten ayrılmadı.

Her resmi marka kurallarına göre derecelendirin.

Görsel yönetmene bir palete, bir ışık kuralına ve bir kompozisyon kuralına uyması söylendi. Bunun gerçekten yapılıp yapılmadığı bir değerlendirme konusudur ve AI.SCORE bu amaçla kullanılır.

  1. Aşağıdaki sorguyu çalıştırın ( yerine bölgenizi girin). İstem bir demettir: değerlendirme ölçütleriniz, kampanya konsepti ve resim için 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. Puanı, ekibinizin harekete geçebileceği bir karara dönüştürün:
    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 yalnızca FLOAT64 değerini döndürür. Bu nedenle, eşik düz SQL'de bulunur ve isteme dokunmadan ayarlanabilir. Puanlama satır bazında yapılır. Bu nedenle, yalnızca burada oluşturduğunuz iki öğe değil, bir kampanyanın ürettiği her öğeye aynı değerlendirme ölçütü uygulanır.

11. Sonraki adımlar

Değerlendirme oluşturma

Ajan değerlendirmeleri veya "değerlendirmeler", bağımsız yapay zeka ajanlarının akıl yürütme, planlama, araç kullanma ve çok adımlı iş akışını tamamlama becerilerini ölçmek için kullanılan otomatik testlerdir. Bu testler, aracıların birim testine benzer ancak aracıların deterministik olmayan yapısını dikkate alır.

Temsilcilerimizden biri Human in the loop içerir. Bu, giriş beklediği anlamına gelir. Bu davranışın otomatik değerlendirmelerin önüne geçmemesi için Antigravity'nin mevcut kodda değişiklik yapmasına izin vermeniz gerekir.

Başlamanın en iyi yollarından biri Antigravity CLI'ya soru sormaktır.

KSA'yı başlatmak için Cloud Shell'e aşağıdakileri yazın:

cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
agy

Başlangıç istemi:

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.

Değerlendirme örneğini ve bunları çalıştırma talimatlarını klonlanmış depoda da bulabilirsiniz.

12. Temizleme

Bu codelab'de kullanılan kaynaklar için Google Cloud hesabınızdan ücret alınmasını önlemek üzere projeyi (önerilir) veya codelab sırasında oluşturulan tek tek kaynakları silin:

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. Tebrikler!

Bu codelab'de, Agent Development Kit ile çoklu ajan içeren bir kampanya önerisi oluşturucu geliştirdiniz. Üç ajanı, deterministik bir grafik iş akışına bağladınız, marka kurallarını isteğe bağlı olarak yüklenen bir ajan becerisi olarak paketlediniz ve bir ajana, çıktısını bir çıktı olarak kaydeden bir görüntü üretme aracı verdiniz. Ardından, Görsel Yönetmen'i kendi A2A hizmetine böldünüz, uzaktan düğüm olarak grafiğe geri yerleştirdiniz, Cloud Run'a dağıttınız ve tüm iş akışını yerel olarak çalışan bir koordinatörden A2A üzerinden çağırdınız. Son olarak, BigQuery'den oluşturulan temel görsellere ObjectRef ile referans verdiniz ve bunları kendi marka kurallarınıza göre değerlendirmek için AI.SCORE kullandınız.