1. Genel Bakış
Bu codelab'de, tek bir istemi eksiksiz bir Instagram kampanyasına dönüştüren dağıtılmış bir çoklu aracı sistemi olan AI Creative Studio'yu oluşturacaksınız.
Bir cümle yazın. Kitle araştırması, altyazılar, görsel konseptler, kalite kontrolünden geçmiş metinler ve tam proje zaman çizelgesi gibi tüm içerikleri, işbirliği yapan yapay zeka aracı ekibi tarafından üretilmiş şekilde geri alın.
Oluşturacağınız temsilciler
Temsilci | Rol |
Marka Stratejisti | Kitle analizleri, rakip analizi ve 2025 trendleri için web'de arama yapar. |
Metin yazarı (Copywriter) | Platform yönergelerini ve açıklama formüllerini isteğe bağlı olarak yükleyen bir ADK becerisiyle desteklenen, hashtag'ler ve harekete geçirici mesajlar içeren Instagram açıklamaları yazar. |
Tasarımcı | Gemini aracılığıyla görsel konseptler oluşturur ve gerçek görüntüler üretir. Bu görüntüler GCS'de saklanır. |
Eleştirmen | İnceleme metni ve görselleri: Belirli geri bildirimlerle |
Project Manager | Proje takvimi ve görev dökümü oluşturur. İsteğe bağlı olarak MCP aracılığıyla Notion ile senkronize edilebilir. |
Kreatif Direktör | Beş uzmanı sırayla yönetir. Siz bir istem girersiniz, geri kalanını koordine eder. |
5 aracı, bağımsız Cloud Run mikro hizmetleri olarak dağıtılır. A2A protokolü üzerinden iletişim kurarlar. Bu protokol, dilden bağımsız bir açık standarttır. Böylece herhangi bir temsilci, çerçeveden bağımsız olarak başka bir temsilciyi arayabilir. Creative Director, Agent Runtime üzerinde çalışır ve her uzmanla uzaktan bağlantı kurar.
Mimari

Neler öğreneceksiniz?
- Google ADK,
Agent, sistem talimatları ve yerleşik araçlarla LLM temsilcileri oluşturun. - Yeniden kullanılabilir temsilci bilgilerini ADK Becerileri (
SkillToolset) ile modüler dosyalara paketleyin. FunctionToolaracılığıyla bir metin ajanını bir görüntü modeline bağlayarak gerçek görüntüler oluşturun.- Model Context Protocol (MCP) kullanarak harici API'leri özel yapıştırıcı kod olmadan entegre edin.
- HTTPS üzerinden Agent to Agent Protocol (A2A) kullanarak herhangi bir aracıyı ağdan çağrılabilir bir hizmete dönüştürün.
RemoteA2aAgentveAgentToolile dağıtılmış aracıları düzenleyin.- Bağımsız aracıları Cloud Run mikro hizmetleri olarak paketleyip dağıtın.
- Agent Runtime'da durum bilgisi olan bir düzenleyici barındırın.
- Bağlam sıkıştırma özelliğini kullanarak uzun çok agentlı iş akışlarını bağlam sınırları içinde tutun.
- Kalite kontrolü döngüsü oluşturun: Eleştirmenler çıktıyı inceler → gerektiğinde otomatik düzeltme yapılır.
İhtiyacınız olanlar
- Faturalandırmanın etkin olduğu bir Google Cloud projesi
- Sahip veya Düzenleyici IAM rolü
- Temel Python bilgisi
2. Ortamınızı Kurma
Bu codelab'de Cloud Shell'i kullanacağız.
Cloud Shell nedir?
Cloud Shell, her şeyin önceden yüklendiği ücretsiz bir tarayıcı tabanlı Linux ortamıdır: gcloud, git, Python, Docker ve daha fazlası. Yerel olarak herhangi bir şey yüklemeniz gerekmez.
Cloud Shell'i açmak için GCP Console'un sağ üst araç çubuğundaki terminal simgesini tıklayın:

Cloud Shell'i ilk kez açtığınızda hesabınızı doğrulamanız istenir. Doğrula'yı tıklayın:

Ardından, Cloud Shell'in Google Cloud API çağrıları yapmasına izin vermek için Authorize'ı (Yetkilendir) tıklayın:

Cloud Shell artık hazır. Terminalde bir karşılama mesajı görürsünüz: 
Projenizin kimliğini doğrulama ve projeyi yapılandırma
Cloud Shell, Google Hesabınızla zaten kimliği doğrulanmış durumda. Etkin hesabınızı onaylayın ve proje kimliğinizi bulun:
gcloud config list
Proje kimliğinizi GCP Console kontrol panelinin sol tarafındaki panelde de görebilirsiniz. Bu değeri kopyalayın. Bir sonraki komutta bu değere ihtiyacınız olacak:

Şimdi projenizi ayarlayın:
export PROJECT_ID=$(gcloud config get-value project)
export REGION="us-central1" # Cloud Run deployment region
echo "Project: $PROJECT_ID"
Beklenen çıktı:
Project: my-project-123
Gerekli API'leri etkinleştirme
gcloud services enable \
aiplatform.googleapis.com \
apphub.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
generativelanguage.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
storage.googleapis.com \
secretmanager.googleapis.com
Bu işlem yaklaşık 2 dakika sürer. İşlem tamamlandığında Operation finished successfully simgesini görürsünüz.
Uygulama Varsayılan Kimlik Bilgileri'ni (ADC) ayarlama
Temsilciler, gcloud KSA kimlik doğrulamasından ayrı olarak Uygulama Varsayılan Kimlik Bilgileri gerektiren Google Auth kitaplığını kullanarak Gemini Enterprise Agent Platform'u çağırır.
Bu komutu bir kez çalıştırın:
gcloud auth application-default login
Onaylamanızı isteyen bir tarayıcı sekmesi açılır. İzin ver'i tıklayın. Şunları görürsünüz:
Credentials saved to file: ~/.config/gcloud/application_default_credentials.json
Başlangıç deposunu klonlama
Bu codelab'de, tüm altyapının (Dockerfiles, pyproject.toml, dağıtım komut dosyaları) hazır olduğu ancak aracı mantığının sizin yazmanıza bırakıldığı bir iskelet proje olan başlangıç deposu kullanılır.
git clone https://github.com/Saoussen-CH/mas-a2a-gcp.git ~/ai-creative-studio
cd ~/ai-creative-studio/workshop/starter
Her agent.py, temsilci mantığını yazacağınız # TODO yer tutucularını içerir. Dockerfile, pyproject.toml ve dağıtım komut dosyaları zaten tamamlanmış.
Ortam değişkenlerini yapılandırma
Sağlanan örneği kopyalayın ve proje kimliğinizi tek adımda yerleştirin:
cp .env.example .env
sed -i "s|GOOGLE_CLOUD_PROJECT=your-project-id|GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)|" .env
Ardından, Tasarımcı'nın oluşturulan resimleri saklayacağı GCS paketini oluşturun ve .env değerini paket adıyla güncelleyin:
export PROJECT_ID=$(gcloud config get-value project)
export BUCKET_NAME="${PROJECT_ID}-campaign-images"
gcloud storage buckets create gs://${BUCKET_NAME} \
--location=us-central1 \
--project=${PROJECT_ID}
sed -i "s|GCS_IMAGES_BUCKET=your-project-id-campaign-images|GCS_IMAGES_BUCKET=${BUCKET_NAME}|" .env
Ardından, imzalı resim URL'si desteğini ayarlayın. Reklam Öğesi Yöneticisi, nihai kampanya özetindeki her resim için tıklanabilir HTTPS bağlantıları oluşturur. Bunun için URL'leri imzalamak üzere bir hizmet hesabı gerekir. Hizmet hesabını yapılandırmak için aşağıdaki komutları çalıştırın:
export PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
export SA_EMAIL="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
export AGENT_RUNTIME_SA="service-${PROJECT_NUMBER}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
# Allow your user account to sign URLs locally (adk web)
gcloud iam service-accounts add-iam-policy-binding ${SA_EMAIL} \
--member="user:$(gcloud config get-value account)" \
--role="roles/iam.serviceAccountTokenCreator"
# Allow Agent Runtime to sign URLs when deployed
gcloud projects add-iam-policy-binding $(gcloud config get-value project) \
--member="serviceAccount:${AGENT_RUNTIME_SA}" \
--role="roles/iam.serviceAccountTokenCreator"
# Save SA email and project number to .env
grep -q "^SIGNING_SERVICE_ACCOUNT" .env \
&& sed -i "s|^SIGNING_SERVICE_ACCOUNT=.*|SIGNING_SERVICE_ACCOUNT=${SA_EMAIL}|" .env \
|| echo "SIGNING_SERVICE_ACCOUNT=${SA_EMAIL}" >> .env
grep -q "^GOOGLE_CLOUD_PROJECT_NUMBER" .env \
&& sed -i "s|^GOOGLE_CLOUD_PROJECT_NUMBER=.*|GOOGLE_CLOUD_PROJECT_NUMBER=${PROJECT_NUMBER}|" .env \
|| echo "GOOGLE_CLOUD_PROJECT_NUMBER=${PROJECT_NUMBER}" >> .env
Tüm ayarları incelemek için düzenleyicide .env simgesini açın:
cloudshell edit .env
Bu işlem, .env dosyasını Cloud Shell Düzenleyici'de sekme olarak açar. Düzenleyici paneli görünmüyorsa araç çubuğundaki Open Editor (Düzenleyiciyi Aç) düğmesini tıklayın:


Projenin doğru şekilde ayarlandığını onaylayın:
grep GOOGLE_CLOUD_PROJECT .env
Bağımlıları yükleme
Sanal ortamları işleyen ve tek bir araçla yükleme yapan hızlı ve modern bir Python paket yöneticisi olan uv'ı kullanıyoruz. pip'dan yaklaşık 10-100 kat daha hızlıdır ve Python projelerini yönetmek için önerilen yöntemdir.
Cloud Shell'de uv zaten yüklüdür. Tüm aracılar aynı temel bağımlılıkları paylaştığından bir kez yüklediğinizde bu codelab'deki her aracı için çalışır:
uv sync
uv sync komutu pyproject.toml dosyasını okur ve tüm bağımlılıkların bulunduğu bir .venv/ dizini oluşturur. Her uzman, yalnızca Docker derlemeleri tarafından kullanılan kendi pyproject.toml'ına da sahiptir. Yukarıdaki paylaşılan yükleme, yerel test için ihtiyacınız olan her şeyi kapsar.
3. Google ADK'yı anlama
Kod yazmadan önce, bu codelab'deki her ajanı oluşturmak için kullanacağınız çerçeve olan Agent Development Kit (ADK)'i anlayalım.
ADK nedir?
Agent Development Kit (ADK), yapay zeka ajanları geliştirip dağıtmak için kullanılan esnek ve modüler bir çerçevedir. ADK, Gemini ve Google ekosistemi için optimize edilmiş olsa da modelden ve dağıtımdan bağımsızdır ve diğer çerçevelerle uyumlu olacak şekilde geliştirilmiştir. ADK, geliştiricilerin basit görevlerden karmaşık iş akışlarına kadar değişen ajan mimarileri oluşturmasını, dağıtmasını ve düzenlemesini kolaylaştırmak için ajan geliştirmeyi yazılım geliştirmeye daha çok benzeyecek şekilde tasarlanmıştır.
ADK, karmaşık kısımları (araç çağırma, çok turlu sohbet, bağlam yönetimi, akış) ele alır. Böylece siz de aracı mantığına odaklanabilirsiniz.
ADK aracısının yapı taşları
Her aracı dört yapı taşı oluşturur:
Engelle | Rol |
Model | Hedefler üzerinde akıl yürüten, plan belirleyen ve yanıt oluşturan LLM |
Araçlar | API'leri veya hizmetleri çağırarak veri getiren ya da işlem gerçekleştiren işlevler |
Düzenleme | Dönüşler arasında hafızayı ve durumu korur, araç çağrılarını yönlendirir, sonuçları modele geri iletir. |
Çalışma zamanı |
|
Aracı tanımı
Bu codelab'deki 5 aracının her biri aynı şekilde tanımlanır:
from google.adk.agents import Agent
from google.adk.tools.google_search_tool import google_search
root_agent = Agent(
name="brand_strategist", # unique identifier
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"), # the LLM powering this agent
instruction=SYSTEM_INSTRUCTION, # the agent's persona, constraints, and output format
description="Brand strategist for market research, trend analysis, and competitive insights",
tools=[google_search], # functions the LLM can call
)
Alan | Amaç |
| Benzersiz kimlik: Aramaları yönlendirmek için düzenleyiciler tarafından kullanılır. |
| Bu temsilciyi destekleyen Gemini modeli |
| Sistem istemi: Ajanın rolünü, kısıtlamalarını ve çıkış biçimini tanımlar. |
| Tek satırlık özet: Düzenleyici, hangi uzmanı arayacağına karar vermek için bu özeti okur. |
| LLM'nin çağırabileceği işlevler ( |
ADK, aracıları nasıl çalıştırır?
User message
│
▼
Agent (LLM) ← reads instruction + conversation history
│
├─► needs more info? → calls a tool → gets result → continues reasoning
│
└─► done reasoning → returns final text response
LLM, bir aracı çağırmaya, hangi aracı çağırmaya ve hangi argümanlarla çağırmaya karar verir. Talimatı siz yazarsınız, gerisini ADK halleder.
4. Marka Stratejisti aracını oluşturma ve test etme
İlk temsilciyle başlayalım: Marka Stratejisti. Bu, Google Arama'yı kullanarak hedef kitle analizleri, rakip analizi ve trend olan konuları aramak için kullanılan yalnızca araştırma amaçlı bir aracıdır.
İskelet aracı dosyasını Cloud Shell Düzenleyici'de açın:
cloudshell edit agents/brand_strategist/agent.py
Doldurmanız için iki # TODO bölümü görürsünüz.
YAPILACAKLAR 1: Sistem talimatını yazın
İlk olarak, ajan için sistem talimatını yazarsınız. Sistem talimatı, aracının rolünü, kısıtlamalarını ve çıkış biçimini tanımlayan bir dizedir.
SYSTEM_INSTRUCTION = f"""You are a Brand Strategist specializing in market research and trend analysis.
IMPORTANT: Today's date is {datetime.date.today().strftime("%B %d, %Y")}.
When conducting research, focus on current trends from {datetime.date.today().year}.
Use search queries like "[topic] trends {datetime.date.today().year}" for recent insights.
IMPORTANT: Your role is RESEARCH ONLY. You do NOT create campaign content, captions, or designs.
After providing research insights, your work is complete.
Your expertise:
- Identifying target audience insights and behaviors
- Analyzing competitor strategies
- Researching current social media trends
- Understanding platform algorithms and best practices
You have access to:
- google_search: Search the web for competitors, trends, and market insights
When given a campaign brief:
1. Use google_search to research the target audience's current interests
2. Search for and analyze 2-3 competitor brands
3. Identify 3-5 trending topics related to the product category
4. Provide high-level strategic insights - NOT specific campaign content
DO NOT create captions, copy, designs, or any campaign content.
Format your output as:
**Audience Insights:**
[Key behaviors and preferences based on research]
**Competitive Analysis:**
[What 2-3 competitors are doing - strengths and weaknesses]
**Trending Topics:**
[3-5 relevant trends to consider]
**Key Strategic Insights:**
[High-level themes and positioning opportunities]
"""
TODO 2 - Create the root_agent
Ardından, eksik root_agent ifadesini aşağıdakilerle değiştirin:
root_agent = Agent(
name="brand_strategist",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
instruction=SYSTEM_INSTRUCTION,
description="Brand strategist for market research, trend analysis, and competitive insights",
tools=[google_search],
)
ADK web kullanıcı arayüzü ile yerel olarak test etme
Şimdi de ADK web kullanıcı arayüzünü kullanarak temsilciyi test edelim. Bu arayüz, buluta dağıtmadan önce temsilcileri test etmek için kullanılan yerleşik bir sohbet arayüzüdür.
uv run adk web agents --allow_origins='*'
Şunları görürsünüz:
INFO: Started server process
INFO: Uvicorn running on http://localhost:8000
Sunucu artık Cloud Shell'de çalışıyor:
Önizlemeyi tarayıcınızda açmak için Web Önizleme'yi kullanın:
- Sayfanın üst kısmındaki Cloud Shell araç çubuğuna bakın.
- Web Önizlemesi simgesini (Cloud Shell araç çubuğunun sağ üst kısmında yukarı doğru ok olan bir kutu gibi görünür) tıklayın.
- "Bağlantı noktasını değiştir"'i tıklayın ve
8000girin, ardından "Değiştir ve Önizle"'yi tıklayın.
ADK web kullanıcı arayüzünü içeren yeni bir tarayıcı sekmesi açılır. Sol üstteki "Bir temsilci seçin" açılır listesini tıklayın. Tüm temsilcilerinizin listelendiğini görürsünüz:
Teste başlamak için brand_strategist seçeneğini belirleyin:
Aşağıdaki test istemlerini deneyin
ADK web kullanıcı arayüzü sohbet kutusunda şunları deneyin:
Research the eco-friendly water bottle market for health-conscious millennialsWhat are the top Instagram trends in the wellness space in 2025?
Aracı, Google Arama'yı çağırır ve Kitle Analizleri, Rekabet Analizi ve Trend Olan Konular bölümlerini içeren yapılandırılmış bir araştırma döndürür.
5. Build the Copywriter - ADK Skills
Rol: Marka araştırmalarını Instagram altyazılarına dönüştür. Metin yazarı, farklı üslupları (ilham verici, eğitici, topluluk) kapsayan 3 altyazı varyasyonu oluşturur. Her varyasyonda hashtag'ler ve bir harekete geçirici mesaj bulunur.
Kavram: ADK Becerileri
Basit bir yaklaşımda, tüm platform bilgileri (karakter sınırları, hashtag katmanları, altyazı formülleri, marka sesi örnekleri) doğrudan sistem istemine yerleştirilir. Bu yöntem işe yarasa da her isteği, aracının yalnızca ara sıra ihtiyaç duyduğu içeriklerle şişirir.
ADK Becerileri (SkillToolset, ADK 1.25.0'da kullanıma sunuldu) bu bilgileri üç yükleme düzeyine sahip modüler dosyalar halinde paketlemenize olanak tanır:
- L1 - ön kısım (
name+descriptioninSKILL.md): Her zaman kullanılabilir, beceri keşfi için kullanılır. - L2 - talimatlar (
SKILL.mdgövdesi): Temsilci, beceriyi tetiklediğinde yüklenir. - L3 - kaynaklar (
references/veassets/dosyaları): Yalnızca temsilci bunları açıkça okuduğunda yüklenir.
Sistem talimatı, kısa bir rol ifadesi ve "yazmadan önce beceriyi yükle" ifadesine indirgenir. Platform ayrıntıları yalnızca temsilcinin gerçekten ihtiyaç duyduğu durumlarda bağlam penceresine girilir.
Copywriter becerisi agents/copywriter/skills/instagram-copywriting/ içinde yer alır:
skills/
instagram-copywriting/
SKILL.md ← L1 frontmatter (discovery) + L2 instructions (loaded on trigger)
references/
platform-guide.md ← L3: character limits, hashtag tiers, algorithm signals
caption-formulas.md ← L3: hook formulas, CTA patterns, full caption structures
assets/
brand-voice-examples.md ← L3: annotated real-world caption examples
Dosyayı doğrudan Cloud Shell düzenleyicide açın:
cloudshell edit agents/copywriter/agent.py
YAPILACAKLAR 1: load_skill_from_dir ve skill_toolset öğelerini içe aktarın
Yorumu bulun # TODO 1: Import load_skill_from_dir and skill_toolset ve iki içe aktarma işlemini ekleyin:
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
YAPILACAKLAR 2: Beceriyi yükleyin ve SkillToolset oluşturun
İçe aktarma işlemlerinin altındaki iki yorumu bulun:
# TODO 2: Load the instagram-copywriting skill from the skills/ directory
# TODO 2: Create a SkillToolset with the loaded skill
Şunlarla değiştirin:
_instagram_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "instagram-copywriting"
)
_copywriting_skills = skill_toolset.SkillToolset(skills=[_instagram_skill])
load_skill_from_dir, SKILL.md ile references/ ve assets/ klasörlerindeki tüm dosyaları okur. SkillToolset, bunu ADK temsilcilerinin kabul ettiği biçime (ham beceri değil, araç seti) dönüştürür.
YAPILACAKLAR 3: Araç setini temsilciye kaydetme
tools=[], # TODO 3: Add the SkillToolset here simgesini bulun ve aşağıdakilerle değiştirin:
tools=[_copywriting_skills],
Nasıl yapılandırıldığını görmek için beceri dosyasını açın:
cloudshell edit agents/copywriter/skills/instagram-copywriting/SKILL.md
ADK web kullanıcı arayüzünü çalışır durumda tutun. Sunucuyu yeniden başlatmadan copywriter'e geçmek için aracı açılır listesini kullanın.
Çalışmıyorsa tekrar başlatın:
uv run adk web agents --allow_origins='*'
Deneyin: Açılır listeyi copywriter olarak değiştirin ve gönderin:
You are writing captions for EcoFlow Smart Water Bottle targeting health-conscious millennials aged 25-35.
Audience insight: they prioritize sustainability, track health metrics, and share lifestyle content.
Competitor insight: Hydro Flask dominates with lifestyle branding; S'well leads on premium aesthetics.
Write 3 Instagram captions - one inspirational, one educational, one community-focused. Include 5 hashtags each and a CTA.
6. Build the Designer - Multimodal Image Generation
ADK web kullanıcı arayüzünü çalışır durumda tutun. Sunucuyu yeniden başlatmadan temsilciler arasında geçiş yapmak için temsilci açılır listesini kullanın.
Rol: Her altyazı için görsel konseptler oluşturun ve Gemini'ın yerel görüntü üretme özelliğini kullanarak gerçek görüntüleri oluşturun. Tasarımcı, her altyazı için tam olarak 1 görsel konsept oluşturur. Bu konseptte ayrıntılı bir istem, stil, renk paleti, ruh hali ve Instagram biçimi bulunur. Ardından, gerçek görüntüyü oluşturmak ve GCS'ye yüklemek için hemen generate_image aracını çağırır.
Kavram: Bir metin aracısını bir araç aracılığıyla görüntü modeliyle bağlama
Tasarımcı, gemini-3-flash-preview (.env içinde GEMINI_MODEL aracılığıyla ayarlanan metin modeli) üzerinde çalışır ancak görüntü oluşturma için özel bir model (gemini-3.1-flash-image-preview) gerekir. Bu görüntü modeli, işlev çağrısını desteklemediğinden doğrudan ADK aracısı olarak kullanılamaz. Bunun yerine, düz bir Python işlevine sarmalanır ve FunctionTool olarak kaydedilir.
Bu, LLM'nin doğrudan çağıramadığı tüm modeller veya API'ler için geçerli olan bir kalıptır: Modeli veya API'yi bir araçla sarmalayın, aracının ne zaman çağrılacağını düzenlemesine izin verin ve yapılandırılmış bir sonuç alın.
Designer agent (text model)
│
│ decides visual concept, writes image prompt
▼
generate_image tool
│
│ calls gemini-3.1-flash-image-preview
│ uploads result to GCS
▼
{"status": "success", "gcs_uri": "gs://..."}
│
│ returned to agent, included in response
▼
Critic (receives gcs_uri, passes to Vertex AI for multimodal review)
Dosyayı doğrudan Cloud Shell düzenleyicide açın:
cloudshell edit agents/designer/image_gen_tool.py
İşlev imzası, ortam kurulumu ve en boy oranı yerleştirme sağlanır. Üç yapılacak işi sırayla tamamlayın:
YAPILACAKLAR 1: Gemini görüntü modelini çağırma
# TODO 1 yorumunu bulun ve aşağıdakiyle değiştirin:
client = genai.Client(vertexai=True, project=project_id, location=location)
response = client.models.generate_content(
model=image_model,
contents=prompt_with_aspect,
config=types.GenerateContentConfig(
response_modalities=["IMAGE", "TEXT"],
http_options=types.HttpOptions(
retry_options=types.HttpRetryOptions(
attempts=5, exp_base=2, initial_delay=30,
http_status_codes=[429, 500, 503, 504],
),
timeout=180_000,
),
),
)
YAPILACAKLAR 2: Yanıttan görüntü baytlarını ayıklayın
# TODO 2 yorumunu bulun ve aşağıdakiyle değiştirin:
image_bytes = None
mime_type = "image/png"
for part in response.candidates[0].content.parts:
if part.inline_data is not None:
image_bytes = part.inline_data.data
mime_type = part.inline_data.mime_type or "image/png"
break
if not image_bytes:
return {"status": "error", "error": "Gemini returned no image data"}
YAPILACAKLAR 3: GCS'ye yükleyin ve URI'yi döndürün
# TODO 3 yorumunu bulun ve aşağıdakiyle değiştirin:
ext = "jpg" if "jpeg" in mime_type else "png"
from google.cloud import storage
gcs_client = storage.Client(project=project_id)
bucket = gcs_client.bucket(bucket_name)
blob_name = f"campaign-images/{concept_name}-{uuid.uuid4().hex[:8]}.{ext}"
blob = bucket.blob(blob_name)
blob.upload_from_file(io.BytesIO(image_bytes), content_type=mime_type)
gcs_uri = f"gs://{bucket_name}/{blob_name}"
Deneyin: Açılır listeyi designer olarak değiştirin ve gönderin:
Create a visual concept and generate the image for an EcoFlow Smart Water Bottle Instagram post targeting health-conscious millennials.
Style: clean, modern, lifestyle-focused. Include a detailed prompt with color palette, mood, and format (1080x1080 or 1080x1350).
7. Eleştirmen - Yapılandırılmış Çıkış Oluşturma
Rol: Metin ve görselleri proje yöneticisine teslim etmeden önce kalite kontrolünden geçirin. Eleştirmen, her iki çıktıyı da puanlar ve APPROVED veya NEEDS_REVISION ile birlikte belirli önerilerde bulunur. Girişte gcs_uri değerleri varsa puanlama yapmadan önce oluşturulan her resmi görsel olarak incelemek için review_image aracını çağırır.
Kavram: Gemini çıktısı için ne zaman Pydantic modeli kullanılmalı?
Kural, çıktıyı kimin tükettiğiyle ilgilidir:
- Python kodu bunu kullanır →
response_schema+ Pydantic kullanın. Kod, belirsizliği işleyemez. Bu nedenle, alanları güvenilir bir şekilde ayıklamak için garantili bir yapıya ihtiyacınız vardır. - LLM tarafından tüketilir → Metin biçimi + sistem talimatı yeterlidir. LLM'ler biçimlendirme kurallarını anlar ve farklılıklara tolerans gösterir.
review_image içinde Python kodu, yazılan değerler olarak score, approval_status, what_works, issues ve suggestions değerlerini gerektirir. response_schema=_GeminiReview, Gemini'ı API düzeyinde geçerli JSON döndürecek şekilde kısıtlar. model_validate_json() ise bunu, kodunuzun güvenilir bir şekilde kullanabileceği türü belirlenmiş bir nesneye ayrıştırır.
class _GeminiReview(BaseModel):
score: int = Field(ge=1, le=10)
approval_status: Literal["APPROVED", "NEEDS_REVISION"]
what_works: str
issues: str
suggestions: str
Dosyayı doğrudan Cloud Shell düzenleyicide açın:
cloudshell edit agents/critic/image_review_tool.py
Pydantic modelleri ve istemi sağlanır. Üç yapılacak işi sırayla tamamlayın:
YAPILACAKLAR 1: GCS URI'sinden bir resim parçası oluşturun
# TODO 1 yorumunu bulun ve aşağıdakiyle değiştirin:
image_part = types.Part.from_uri(file_uri=gcs_uri, mime_type=mime_type)
YAPILACAKLAR 2: Yapılandırılmış bir yanıt şemasıyla Gemini'ı çağırma
# TODO 2 yorumunu bulun ve aşağıdakiyle değiştirin:
response = client.models.generate_content(
model=model,
contents=[image_part, prompt],
config=types.GenerateContentConfig(
response_schema=_GeminiReview,
response_mime_type="application/json",
),
)
YAPILACAKLAR 3: Yanıtı ayrıştırın ve sonucu döndürün
# TODO 3 yorumunu bulun ve aşağıdakiyle değiştirin:
review = _GeminiReview.model_validate_json(response.text)
return ImageReviewResult(status="success", concept_name=concept_name, **review.model_dump())
Deneyin: Açılır listeyi critic olarak değiştirin ve gönderin:
Review this Instagram caption for an eco-friendly water bottle brand targeting millennials:
"Hydrate smarter, live greener. 💧 Our EcoFlow bottle tracks your intake, keeps your drink cold for 24h, and never touches single-use plastic. Because what you drink from matters as much as what you drink. #EcoFlow #HydrationGoals #SustainableLiving #ZeroWaste #HealthyHabits - Shop link in bio."
Score it and indicate APPROVED or NEEDS_REVISION with specific feedback.
Yanıtta **POSTS REVIEW:**, Status: APPROVED (veya NEEDS_REVISION) ve **OVERALL ASSESSMENT:** bulunduğunu doğrulayın. Bu bölümler varsa Critic, düzenleyiciye bağlanmaya hazırdır.
Üç aracıyı da test etmeyi tamamladığınızda sunucuyu durdurmak için Ctrl+C tuşuna basın.
8. MCP ile proje yöneticisi temsilcisi oluşturma
Proje yöneticisi yeni bir kavram olan MCP (Model Context Protocol)'yi tanıtıyor.
Dosyayı açın:
cloudshell edit agents/project_manager/agent.py
Bu dosya daha karmaşıktır. İki dallı bir create_project_manager_agent() işlevi vardır: biri Notion'ın olmadığı (yalnızca metin içeren zaman çizelgeleri) ve biri Notion MCP araç setinin olduğu dal. İkisini de doldurursunuz.
MCP'nin çözdüğü sorun
Aracınızın harici bir hizmeti (ör. Notion'da sayfa oluşturma) çağırması gerekiyor. Doğrudan Notion REST API'yi çağıran Python kodu yazabilirsiniz. Ancak:
- Her geliştirici farklı bir sarmalayıcı yazar.
- Özel entegrasyon kodunu korumanız gerekir.
- Her uç noktayı manuel olarak açıklamadığınız sürece LLM, API'nin varlığını bilmez.
MCP, bu sorunu harici hizmetlerin özelliklerini, LLM'nin otomatik olarak keşfedip çağırabileceği araçlar olarak sunması için standart bir yöntem tanımlayarak çözer.
MCP nedir?
MCP (Model Context Protocol), yapay zeka ajanlarını harici araçlara ve veri kaynaklarına bağlamak için kullanılan bir açık standarttır (Anthropic tarafından yayınlanmıştır). Evrensel adaptör gibi çalışır.
MCP sunucusu, aşağıdaki işlevleri yerine getiren küçük bir programdır:
- Harici bir API'yi (Notion, GitHub, veritabanları, dosya sistemleri vb.) sarmalar.
- Bu API'yi, türü belirlenmiş ve belgelenmiş araçlar listesi olarak kullanıma sunar.
- Basit bir protokol (stdio veya HTTP) aracılığıyla aracıyla iletişim kurar.
Aracı, MCP sunucusuna bağlanır, kullanılabilir araçları otomatik olarak keşfeder ve bunları diğer araçlar gibi çağırabilir. LLM, API-post-page(...) öğesini çağrılabilir bir işlev olarak görür.
A2A ve MCP arasındaki fark nedir?
Bu, sık karşılaşılan bir kafa karışıklığıdır. Temel fark şudur:
A2A | MCP | |
Bağlantı noktaları | Temsilci ↔ Temsilci | Aracı ↔ Harici araç/hizmet |
Diğer taraf ise | Başka bir LLM aracısı | API sarmalayıcı (LLM yok) |
Örnek | Kreatif direktör, marka stratejistini arıyor | Proje yöneticisi, Notion API'yi çağırır. |
Protokol | HTTPS üzerinden JSON-RPC | stdio veya HTTP akışı |
Tanımlayan | Anthropic |
Şöyle düşünün:
- A2A = Temsilcilerin diğer temsilcilerle konuşma şekli
- MCP = aracıların araçlar ve hizmetlerle nasıl iletişim kurduğu
Bu projede her ikisi de birlikte kullanılır:
Creative Director
│
│ (A2A) Brand Strategist ─── (google_search tool built into ADK)
│ (A2A) Copywriter
│ (A2A) Designer
│ (A2A) Critic
│ (A2A) Project Manager
│
│ (MCP) notion-mcp-server ──► Notion REST API
MCP'nin bu projedeki işleyiş şekli
Aracı çalıştırıldığında ADK, notion-mcp-server alt işlemi olarak başlatılır. Bu işlem, aşağıdaki araçları doğrudan LLM'ye sunar:
Araç | Ne işe yarar? |
| Şemayı (özellik adları, türler, geçerli değerler) getirir. |
| Mevcut sayfalara sorgu gönderme |
| Yeni bir sayfa oluşturur. |
| Mevcut bir sayfayı günceller. |
LLM, bunları diğer işlevler gibi çağırır. Bu işlevlerin arka planda Notion REST API'ye gitmek için MCP'den geçtiğini bilmez.
Neden stdio? Neden sadece HTTP değil?
MCP sunucusu, stdin/stdout üzerinden iletişim kurarak aracının alt süreci olarak çalışır. Bunun anlamı şudur:
- Ek ağ bağlantı noktası gerekmez
- Yaşam döngüsü, temsilci tarafından yönetilir (isteğe bağlı olarak başlatılır, çıkışta durdurulur)
- Her şey tek bir Docker görüntüsünde gönderilir. Dağıtılacak ayrı bir hizmet yoktur.
(İsteğe bağlı) Notion entegrasyonunu etkinleştirme
Bu bölümün tamamını atlayabilirsiniz. Proje yöneticisi aracısı, Notion ile veya Notion olmadan her zaman metin tabanlı eksiksiz bir kampanya takvimi oluşturur. Bu kurulumu atlarsanız aracı, bellek içi moda geri döner ve zaman çizelgesini sohbette düz metin olarak çıkarır. Hiçbir şey bozulmaz. Yalnızca görevler Notion veritabanında görünmez. Atlamak istiyorsanız doğrudan YAPILACAKLAR LİSTESİ 1'e gidin.
Notion hesabınız varsa ve MCP entegrasyonunu kullanmak istiyorsanız aşağıdaki kurulumu hemen tamamlayın. Aşağıdaki YAPILACAKLAR, Notion veritabanı kimliklerine referans verir. Bu kimlikleri buradan alabilirsiniz.
1. adım: Şablondan Notion veritabanı oluşturun
Veritabanımız olarak resmi Notion Projects & Tasks şablonunu kullanıyoruz. Bu şablonu, karmaşık bir gerçek dünya ortamını göstermek için özellikle seçtik. Şablonda, açık olmayan adlara sahip birden fazla özellik türü (durum, tarih aralıkları, ilişkiler, seçimler) var. Bu, MCP'nin dinamik şema keşfi için harika bir testtir: Temsilci, özellik adlarını sabit kodlamak yerine çalışma zamanında tam olarak belirlemelidir.
Şablonu Notion çalışma alanınıza eklemek için aşağıdaki bağlantıyı tıklayın:
→ "Projeler ve Görevler " şablonunu Notion'a ekleme

Eklendikten sonra Projeler ve Görevler olmak üzere iki bağlı veritabanınız olur. Şablonda örnek girişler bulunur. Devam etmeden önce tümünü silin. Böylece aracı temiz bir çalışma alanıyla başlar (Tümünü seç → Sil).
2. adım: Notion entegrasyonu oluşturun
Entegrasyonu oluşturun:
- notion.so/my-integrations adresine gidin.
- New Integration'ı (Yeni Entegrasyon) tıklayın →
AI Creative Studioolarak adlandırın. - Çalışma alanınızla ilişkilendirin.
- Ayarları yapılandır'ı tıklayın → İçerik okuma, İçerik güncelleme ve İçerik ekleme özelliklerinin tümünün işaretli olduğundan emin olun.

- Dahili Entegrasyon Jetonu'nu (
ntn_...) kopyalayıp.envdosyanıza yapıştırın:
NOTION_TOKEN=ntn_your-token-here
Entegrasyonu veritabanlarınıza bağlayın:
- Yeni kopyaladığınız şablon sayfasını açın ve Projeler veritabanını tıklayın.
...menüsü (sağ üst) → Bağlantılar → Bağlantı ekle'yi tıklayın →AI Creative Studiosimgesini seçin.


- Aynı işlemi Görevler veritabanı için de yapın.
Veritabanı kimliklerini alma:
- Projeler veritabanı bağlantısını tıklayarak açın. Veritabanı, şu gibi bir URL ile kendi sayfasında açılır:
https://www.notion.so/9887b6a94f7f83f68f8581e038d1aaa4?v=2c37b6a94f7f838685f1086e312c7278

Veritabanı kimliği, URL'deki ilk UUID'dir (?v= öncesindeki her şey):
https://www.notion.so/{DATABASE_ID}?v=...
^^^^^^^^^^^^^^^^
9887b6a94f7f83f68f8581e038d1aaa4 ← this is your DATABASE_ID
- Veritabanı kimliğini almak için Görevler veritabanı bağlantısı için de aynı işlemi yapın.
- Üç değeri de
.envöğenize ekleyin:
NOTION_TOKEN=ntn_your-token-here
NOTION_PROJECT_DATABASE_ID=9887b6a94f7f83f68f8581e038d1aaa4 # <-- your Projects DB ID
NOTION_TASKS_DATABASE_ID=your-tasks-db-id # <-- your Tasks DB ID
3. adım: Notion MCP sunucusunu yükleyin
Proje yöneticisi, resmi @notionhq/notion-mcp-server Node.js paketi aracılığıyla Notion'a bağlanır. Global olarak yükleyin:
npm install -g @notionhq/notion-mcp-server@1.9.1
Yüklemeyi doğrulayın:
npm list -g @notionhq/notion-mcp-server
Beklenen çıktı:
└── @notionhq/notion-mcp-server@1.9.1
notion-mcp-server: command not found
? Node.js'nin yüklendiğinden (node --version) ve npm global bin'inizin PATH'inizde olduğundan (export PATH=$PATH:$(npm bin -g)) emin olun.
4. adım: .env dosyanızı doğrulayın
.env simgesini açın ve üç Notion değerinin de ayarlandığını onaylayın (2. adımda eklemiştiniz):
cloudshell edit .env
NOTION_TOKEN=ntn_... # integration token
NOTION_PROJECT_DATABASE_ID=... # Projects database ID
NOTION_TASKS_DATABASE_ID=... # Tasks database ID
Proje Yöneticisi aracısı, bu değişkenleri başlangıçta otomatik olarak algılar ve Notion MCP araç setini etkinleştirir.
Şema keşfinin işleyiş şekli
Proje yöneticisi, dinamik şema keşfi kullanır. Notion özellik adlarını asla sabit kodlamaz:
Step 1: Call API-retrieve-a-database to discover exact property names
Step 2: Read the "properties" object in the response
Step 3: Use ONLY discovered property names (case-sensitive) in API calls
Step 4: For select/status fields, use only values from the options array
Bu sayede, ajan herhangi bir Notion veritabanı yapısına otomatik olarak uyum sağlar. Özelliklerinizi Fransızca, Arapça veya başka bir dilde yeniden adlandırsanız bile ajan çalışmaya devam eder.
YAPILACAKLAR 1: Sistem talimatını yazın
Başlatıcı, Notion yapılandırılmadığında boş bir dize olan notion_section değerini, yapılandırıldığında ise veritabanı kimliklerini ve tam araç kılavuzunu içeren bir bloğu önceden hesaplar. Bu sayede Notion talimatları, Notion'ın olmadığı aracı isteminden tamamen çıkarılır. LLM, sahip olmadığı araçlarla ilgili kuralları asla görmez.
Göreviniz, return yer tutucusunu {notion_section} kullanan gerçek bir sistem talimatıyla değiştirmek:
return f"""You are a Project Manager specializing in creative campaign execution.
Today's date is {datetime.date.today().strftime("%B %d, %Y")}.
Use this as the starting point for all timelines.
Your goal: create a complete project plan for the campaign.
{notion_section}
**Project Timeline:**
Phase 1: Strategy & Research | [date] → [date] | [key activities]
Phase 2: Content Creation | [date] → [date] | [key activities]
Phase 3: Review & Revision | [date] → [date] | [key activities]
Phase 4: Launch & Monitoring | [date] → [date] | [key activities]
**Task List:**
| Task | Owner | Deadline | Status |
[list each task with realistic deadlines from today; set Owner to TBD]
**Budget Breakdown:**
[by category with approximate allocations]
**Milestones:**
[3-5 key checkpoints with dates]
**Notion Status:**
[What happened - e.g. "Project created (ID: xxx), 8 tasks linked" or "Notion not configured - text timeline only"]
"""
TODO 2 - Agent without Notion
create_project_manager_agent() içinde, if not notion_token dalında eksik temsilciyi aşağıdakilerle değiştirin:
return Agent(
name="project_manager",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
generate_content_config=GENERATE_CONTENT_CONFIG,
instruction=get_system_instruction(),
description="Project manager that creates campaign timelines and task breakdowns",
)
YAPILACAKLAR 3 - Notion MCP'li Ajan
Not: Başlangıç dosyasında create_project_manager_agent() üzerinde önceden yazılmış bir handle_notion_error geri çağırma işlevi zaten vardır. Notion API hatalarını (400/404) yakalar ve ham hata yüklerini temiz, uygulanabilir mesajlarla değiştirir. Böylece LLM kendi kendini düzeltebilir. after_tool_callback üzerinden bağlamanız yeterlidir.
Öncelikle, create_project_manager_agent() bölümünün en üstündeki her iki veritabanı kimliğini okuyun:
notion_token = os.getenv("NOTION_TOKEN")
notion_project_db_id = os.getenv("NOTION_PROJECT_DATABASE_ID")
notion_tasks_db_id = os.getenv("NOTION_TASKS_DATABASE_ID")
Ardından, else dalında MCP araç setini ve aracıyı oluşturun:
from google.adk.tools.mcp_tool import McpToolset, StdioConnectionParams
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command="notion-mcp-server",
env={
"NOTION_TOKEN": notion_token,
"PATH": os.environ.get("PATH", ""),
}
)
notion_toolset = McpToolset(
connection_params=StdioConnectionParams(
server_params=server_params,
timeout=30.0
)
)
return Agent(
name="project_manager",
model=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"),
generate_content_config=GENERATE_CONTENT_CONFIG,
after_tool_callback=handle_notion_error,
instruction=get_system_instruction(
project_database_id=notion_project_db_id,
tasks_database_id=notion_tasks_db_id,
),
description="Project manager with Notion integration for task tracking",
tools=[notion_toolset],
)
En iyi uygulama: İsteğe bağlı entegrasyonlarda hiçbir zaman kesin olarak başarısız olmayın. Metin zaman çizelgesi her zaman birincil çıktı; Notion ise ek bir çıktıdır.
ADK Web ile Proje Yöneticisi'ni yerel olarak test etme
uv run adk web agents --allow_origins='*'
8000 numaralı bağlantı noktasında web önizlemesini açın. Aracı açılır listesini kullanarak project_manager'ı seçin ve şunları deneyin:
Create a project plan for a GreenBrew organic coffee brand Instagram campaign.
Budget: $2,500. Launch in 3 weeks. Target audience: eco-conscious millennials aged 22-30.
Include phases, tasks with deadlines from today, and milestones.
Aşamalar, görev listesi ve ara hedefler içeren yapılandırılmış bir metin zaman çizelgesi görürsünüz. .env içinde Notion kimlik bilgileri ayarlanmışsa temsilci, Notion çalışma alanınızda da girişler oluşturur.
9. A2A protokolünü anlama
Sistemimizdeki farklı temsilcileri bağlamak için Temsilciden Temsilciye Protokolü'nü (A2A) kullanacağız. Bu özelliğin işleyiş şeklini açıklayalım.
A2A'nın çözdüğü sorun
ADK ile oluşturulmuş bir Marka Stratejisti temsilciniz ve LangGraph ile oluşturulmuş bir Metin Yazarı temsilciniz olduğunu düşünün. Bir kullanıcı diğerini nasıl arar? Farklı iç diller konuşuyorlar. Her seferinde özel yapıştırıcı kodu yazmanız gerekir.
A2A, herhangi bir aracı (çerçeveden bağımsız olarak) tarafından konuşulabilecek evrensel bir dil tanımlayarak bu sorunu çözer. Bu, aracı dünyasının HTTP'sidir: herkesin herkesle konuşabilmesi için herkesin kabul ettiği bir standarttır.
A2A nedir?
Agent-to-Agent (A2A), Google tarafından yayınlanan açık bir aracı iletişimi standardıdır. Bu kayıtta şunlar tanımlanır:
- Bir temsilcinin kendisini nasıl tanımladığı -
/.well-known/agent.jsonadresindeki temsilci kartı - Başka bir aracının bunu nasıl çağırdığı: HTTPS üzerinden JSON-RPC
- Sonuçlar nasıl döndürülür? (Akış veya tek yanıt)
A2A'yı esnek kılan özellikler:
- Dilden bağımsız: Python aracıları, TypeScript aracılarıyla konuşabilir.
- Çerçeveden bağımsız: ADK temsilcileri, LangGraph veya CrewAI temsilcileriyle konuşabilir.
- Altyapıdan bağımsız: Yerel aracıların bulut aracılarıyla iletişim kurabilmesi
Adım adım işleyiş şekli
Creative Director Brand Strategist
│ │
│ 1. GET /.well-known/agent.json │
│ ────────────────────────────────►│
│ ◄──── agent card (name, url, │
│ skills, capabilities) ───│
│ │
│ 2. POST / │
│ {"method": "tasks/send", │
│ "params": {"message": ...}} │
│ ────────────────────────────────►│
│ │ LLM does
│ │ the work...
│ 3. streaming response chunks │
│ ◄───────────────────────────────│
│ ◄───────────────────────────────│
│ ◄───────────────────────────────│
1. adım: Keşif: Düzenleyici, aracının adını, URL'sini ve özelliklerini öğrenmek için aracı kartını bir kez getirir.
2. adım: Çağırma: Düzenleyici, JSON-RPC POST üzerinden bir görev gönderir. Gövde, mesajı (uzman için istem) içerir.
3. adım: Yanıt: Uzman, yanıtını normal bir LLM çağrısında olduğu gibi parçalar halinde yayınlar.
Temsilci kartı
Her ajan, /.well-known/agent.json adresinde kendi açıklamasını yayınlar. Bu, bir kartvizite benzer. Dünyaya temsilcinin neler yapabileceğini ve ona nasıl ulaşılacağını söyler:
{
"name": "brand_strategist",
"description": "Market research and competitive analysis",
"url": "https://brand-strategist-xyz.run.app",
"capabilities": { "streaming": true },
"skills": [
{
"id": "market_research",
"description": "Research target audiences, competitors, and trends"
}
]
}
Düzenleyici, RemoteA2aAgent nesnesini oluşturmak için bu kartı okur. Uzmanın iç işleyişiyle ilgili sabit kodlanmış bilgiye gerek yoktur.
ADK'da A2A aracılığıyla bir aracı kullanıma sunma
to_a2a(), herhangi bir ADK aracısını A2A uyumlu bir FastAPI uygulamasına sarar. Tek satır:
from google.adk.a2a.utils.agent_to_a2a import to_a2a
# root_agent = your normal ADK Agent(...)
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
Bu işlem otomatik olarak şunları oluşturur:
/.well-known/agent.json- temsilci kartı/- JSON-RPC uç noktası (tüm A2A görev istekleri kök yola gider)
10. Aracıları A2A hizmetleri olarak kullanıma sunma
Aracıları A2A hizmetleri olarak kullanıma sunmak için ADK'daki to_a2a() yardımcı işlevini kullanabilirsiniz.
to_a2a() nasıl çalışır?
from google.adk.a2a.utils.agent_to_a2a import to_a2a
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
to_a2a(), ADK aracınızı otomatik olarak aşağıdaki öğeleri kullanıma sunan bir FastAPI uygulamasına sarmalar:
/.well-known/agent.json- the agent card (name, description, capabilities)/a2a/{agent_name}: Görevleri almak için kullanılan JSON-RPC uç noktası
Her aracının iskelet kodu, __main__ bloğunu kullanarak aracı to_a2a() ile A2A sunucusuna sarmalayan bir blok içerir. Bu kodu yazmanız gerekmez. Kod sağlanır.
Çift URL yapılandırmasını anlama
python agent.py komutunu çalıştırdığınızda __main__ bloğu iki ayrı URL yapılandırması kullanır:
# Where the server actually listens (network interface):
HOST = "0.0.0.0"
PORT = 8082 # Brand Strategist (others use 8083–8086 locally)
# What gets advertised in the agent card (the address other agents use to reach it):
PUBLIC_HOST = os.getenv("PUBLIC_HOST", "localhost")
PUBLIC_PORT = int(os.getenv("PUBLIC_PORT", str(PORT)))
PROTOCOL = os.getenv("PROTOCOL", "http")
a2a_app = to_a2a(root_agent, host=PUBLIC_HOST, port=PUBLIC_PORT, protocol=PROTOCOL)
uvicorn.run(a2a_app, host=HOST, port=PORT)
Ortam |
|
|
Yerel |
|
|
Cloud Run |
|
|
Her ikisi de yerel olarak aynı makineye işaret eder. Cloud Run'da kapsayıcı, dahili olarak 8080 üzerinde dinler ancak aracı kartı, herkese açık HTTPS URL'sini yayınlamalıdır. Aksi takdirde, Creative Director, kapsayıcının dışından uzmana ulaşamaz.
5 uzman A2A sunucusunu da başlatın.
5 uzmanı da aynı anda A2A sunucuları olarak çalıştıralım, ardından reklam öğesi yöneticisini yerel olarak bu sunuculara yönlendirerek test edelim.
5 ayrı Cloud Shell terminali açın (terminal sekmesi çubuğundaki + simgesini tıklayın) ve terminal başına bir aracı çalıştırın.
uv run, .venv'ı otomatik olarak etkinleştirir. Her terminalde manuel source gerekmez.
Terminal 1 - Marka Stratejisti (bağlantı noktası 8082):
cd ~/ai-creative-studio/workshop/starter
PORT=8082 uv run agents/brand_strategist/agent.py
Terminal 2 - Copywriter (bağlantı noktası 8083):
cd ~/ai-creative-studio/workshop/starter
PORT=8083 uv run agents/copywriter/agent.py
Terminal 3 - Designer (bağlantı noktası 8084):
cd ~/ai-creative-studio/workshop/starter
PORT=8084 uv run agents/designer/agent.py
Terminal 4 - Critic (bağlantı noktası 8085):
cd ~/ai-creative-studio/workshop/starter
PORT=8085 uv run agents/critic/agent.py
Terminal 5 - Project Manager (bağlantı noktası 8086):
cd ~/ai-creative-studio/workshop/starter
PORT=8086 uv run agents/project_manager/agent.py
.env dosyasında localhost URL'lerini ayarlama
Terminal 6'da, reklam öğesi yöneticisinin bulabilmesi için .env öğesini yerel ajans URL'leriyle güncelleyin:
cd ~/ai-creative-studio/workshop/starter
sed -i \
-e 's|STRATEGIST_AGENT_URL=.*|STRATEGIST_AGENT_URL=http://localhost:8082|' \
-e 's|COPYWRITER_AGENT_URL=.*|COPYWRITER_AGENT_URL=http://localhost:8083|' \
-e 's|DESIGNER_AGENT_URL=.*|DESIGNER_AGENT_URL=http://localhost:8084|' \
-e 's|CRITIC_AGENT_URL=.*|CRITIC_AGENT_URL=http://localhost:8085|' \
-e 's|PM_AGENT_URL=.*|PM_AGENT_URL=http://localhost:8086|' \
.env
A2A inceleyici ile aracıları inceleme
A2A Inspector, A2A protokolünü yerel olarak kullanan açık kaynaklı bir geliştirici aracıdır. Bu araç, çalışan herhangi bir A2A aracısına doğrudan bağlanmanıza, aracı kartını okumanıza ve görev göndermenize olanak tanır. Tüm bunları herhangi bir istemci kodu yazmadan yapabilirsiniz.
Gösterdiği bilgiler:
- Aracı kartı: Aracınızın reklamını yaptığı yapılandırılmış meta veriler (adı, açıklaması, desteklenen giriş/çıkış modları ve uç nokta URL'si). Bu, Kreatif Direktörün bir uzmanı keşfettiğinde okuduğu metindir.
- Sohbet arayüzü: A2A üzerinden temsilciye herhangi bir mesaj gönderin ve ham yanıtı görün. İstemleri, aracıları birbirine bağlamadan önce ayrı ayrı test edebilirsiniz.
- Protokol doğrulama: İnceleyici, aracı kartının A2A spesifikasyonuna uygun olup olmadığını kontrol eder ve eksik alanları veya hatalı biçimlendirilmiş yanıtları erken aşamada gösterir.
Neden önemlidir? Daha sonra Cloud Run'a dağıtım yaptığınızda Creative Director, /.well-known/agent.json'dan aracı kartını getirerek her uzmanı keşfeder. Bu kart yanlışsa (URL hatalı, özellikler eksik) düzenleyici sessizce başarısız olur. İnceleyici, buluta dağıtım yapmadan önce bu sorunları yerel olarak yakalamanıza olanak tanır.

Temsilci kartında, uzmanın kimliği ve yetenekleri diğer temsilcilerin gördüğü şekilde gösterilir.

İnceleyiciyi yükleme ve başlatma
cd ~/ai-creative-studio/workshop
./setup_inspector.sh
.env güncellemesi tek seferlik bir komuttur. İnceleyiciyi başlatmak için Terminal 6'yı kullanın:
cd ~/a2a-inspector
bash scripts/run.sh
Denetleyici kullanıcı arayüzünü açmak için Web önizlemesi → Bağlantı noktasını değiştir'i kullanın → 5001 yazın.
Marka stratejisi uzmanına bağlanma
Denetçinin URL alanına http://localhost:8082 girin ve Bağlan'ı tıklayın. Denetleyici, temsilci kartını getirir ve uzmanın meta verilerini gösterir.

Temsilci kartında yer alan bilgiler
Aracı kartı, meta verilerden daha fazlasıdır. Aracı, ağa reklamını yaptığı tam özellik sözleşmesidir. En kapsamlı örneği görmek için Proje Yöneticisi'ne (http://localhost:8086) bağlanın:
{
"name": "project_manager",
"description": "Project manager with Notion integration for task tracking",
"protocolVersion": "0.3.0",
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "project_manager",
"name": "model",
"tags": ["llm"],
"description": "... full system instruction including today's date and Notion database IDs ..."
},
{
"id": "project_manager-API-post-page",
"name": "API-post-page",
"tags": ["llm", "tools"],
"description": "Notion | Create a page"
},
{
"id": "project_manager-API-retrieve-a-database",
"name": "API-retrieve-a-database",
"tags": ["llm", "tools"],
"description": "Notion | Retrieve a database"
}
]
}
Üç nokta öne çıkıyor:
1. MCP araçları A2A becerileri haline geliyor: Proje yöneticisinin erişebildiği her Notion aracı (API-post-page, API-retrieve-a-database vb.) aracı kartında ayrı bir beceri olarak listelenir. Ağdaki diğer tüm aracılar, bu aracının hangi araçları kullanabileceğini herhangi bir kodu okumadan tam olarak keşfedebilir.
2. Sistem talimatı yerleştirilmiş: İlk becerinin description bölümünde, bugünün tarihi ve Notion veritabanı kimlikleri de dahil olmak üzere sistem talimatının tamamı yer alıyor. Böylece Reklam Öğesi Direktörü, Proje Yöneticisi'ni aradığında neyi ileteceğini bilir.
3. URL, canlı uç noktadır: url alanı, Kreatif Direktör bu uzmanı aradığında RemoteA2aAgent tarafından kullanılan alandır. Karttaki URL yanlışsa düzenleyici, temsilciye ulaşamaz.
Bu nedenle, inceleyici güçlü bir hata ayıklama aracıdır: Aracı kartına bir göz atarak aracın çalışıp çalışmadığını, hangi araçlara sahip olduğunu ve uç noktanın doğru olup olmadığını öğrenebilirsiniz.
Test mesajı gönderme
Bağlandıktan sonra sohbet paneline bir istem yazıp gönderin. İnceleme uzmanı, bunu A2A görevi olarak gönderir ve yanıtı geri aktarır. Bu işlem, Creative Director'ın bu aracı üretimde çağırmasıyla aynı şekilde yapılır.

Her uzmanı ayrı ayrı test etmek için inceleyiciyi herhangi bir yerel bağlantı noktasına (8082-8086) yönlendirin.
11. Kreatif Direktör Orkestratörünü oluşturma
Kreatif direktör, orkestranın şefidir. Ortam değişkenlerindeki uzman URL'lerini okur, her birini RemoteA2aAgent olarak sarmalar ve LLM'nin çağırabileceği AgentTool olarak kullanıma sunar.
5 uzman aracının hâlâ çalıştığından emin olun (10. adımdaki 1-5 numaralı terminaller).
Terminal 6'da (A2A Inspector terminali) denetçiyi Ctrl+C ile durdurun.
Dosyayı açın:
cd ~/ai-creative-studio/workshop/starter
cloudshell edit agents/creative_director/agent.py
Bu dosyada üç yapılacak iş var. Bunları sırayla uygulayın.
YAPILACAKLAR 1: Önceden yazılmış sistem talimatını inceleyin
Sistem talimatı, aynı dizindeki prompt.py içinde yer alır ve otomatik olarak içe aktarılır:
from .prompt import SYSTEM_INSTRUCTION_TEMPLATE
Devam etmeden önce okumak için prompt.py açın:
cloudshell edit agents/creative_director/prompt.py
Orkestrasyon davranışının tamamını kontrol ettiğinden bu parametreyi anlamak önemlidir.
Orkestratör istemi neden her şeyi kontrol eder?
Bu bölümün yanında prompt.py bölümünü açın. Aşağıdaki örneklerde bu bölümün belirli kısımlarına atıfta bulunulmaktadır.
prompt.py içindeki istem yalnızca doküman değildir. Aynı zamanda tüm sistemin kontrol düzlemidir. Kötü yapılandırılmış bir düzenleyici istemi şu sonuçları doğurur: sırası gelmeden çağrılan temsilciler, uzmanlar yerine düzenleyici tarafından oluşturulan içerikler, hatalardan sonra devam eden iş akışları ve temsilciler arasında bağlamın sessizce bırakılması. Bu dokuz öğe, en yaygın hataları önler:
0. öğe: Önce planlayın, sonra uygulayın
Bu en kritik öğedir. Düzenleyici, herhangi bir uzmanı aramadan önce numaralandırılmış bir plan oluşturması için talimat alır:
I'll create your campaign by coordinating the specialist agents in sequence:
1. Brand Strategist - develop positioning and audience insights
2. Copywriter - write captions using those insights
3. Visual Designer - create image prompts aligned with the copy
4. Critic - review and score the full package
5. Project Manager - build the timeline and task breakdown
Bu adım olmadan LLM doğrudan araç çağrılarına geçer ve iş akışında nerede olduğunu takip edemez. Bu durum, özellikle bir uzmandan uzun bir yanıt aldıktan sonra yaşanır. Önce planın ana hatlarını belirlemek, düzenleyiciyi sabitler: Hangi adımda olduğunu, bir sonraki adımın ne olduğunu ve tam bir çalıştırmanın nasıl görüneceğini bilir. Bu adımın atlanması, düzenleyicinin iş akışının ortasında durmasına veya adımları tekrarlamasına neden olur.
1. öğe: Açık rol tanımı
❌ "You are a helpful creative assistant."
✅ "You orchestrate specialists. You do NOT write captions, designs, or timelines yourself."
Açıkça yasaklanmadığı takdirde LLM bazen uzmanlara danışmayı atlayıp doğrudan içerik oluşturur. Bu yöntem daha hızlıdır ve LLM, bunu nasıl yapacağını "bilir". Talimat bunu yanlış yapmalıdır.
2. öğe: Yanlış kalıpların listelendiği araç çağrısı söz dizimi
Yalnızca doğru söz dizimini göstermek yeterli değildir. LLM, makul görünen ancak sessizce başarısız olan çağrılar oluşturabilir. İstemde hem doğru kalıp hem de asla kullanılmaması gereken kalıplar açıkça listeleniyor:
✅ copywriter(request="...") ← correct
❌ print(copywriter(...)) ← breaks silently
❌ default_api.copywriter(...) ← breaks silently
❌ copywriter.run(...) ← breaks silently
❌ agents.copywriter(...) ← breaks silently
Yanlış kalıpların açıkça listelenmesi, üretimde hatalı biçimlendirilmiş araç çağrılarını yaklaşık% 95 oranında azalttı.
3. öğe: Sıralı yürütme adım adım açıklanır
a) Call the tool
b) Wait for tool_output
c) Verify the output is not an error
d) Confirm to the user: "✓ Brand Strategist complete"
e) Then move to the next agent
(b) ve (c) adımları olmadan LLM bazen iki aracı aynı anda çağırır veya yanıtı almadan önce başarıyı varsayarak devam eder.
4. öğe: Hata yönergeleri: DUR, bildir, devam etme
İlk sürümlerde, düzenleyici bir uzmandan hata alır, bu hata için makul bir çıkış oluşturur ve bir sonraki temsilciye geçerdi. Kullanıcı, halüsinasyon temelli bir temel üzerinde oluşturulmuş, eksiksiz görünümlü bir kampanya elde etti. Düzeltme açıkça belirtilmiştir: Hemen DURDURUN. Hatayı tam olarak bildirin. Asla devam etmeyin.
5. öğe: Bağlam geçirme kuralları
Uzak aracıların görüşme geçmişi yoktur. Orkestratör, A2A aracılığıyla Copywriter'ı çağırdığında Copywriter yalnızca tek bir istekteki mesajı görür. Marka stratejistinin ne söylediği hakkında bilgisi yoktur. Düzenleyici, önceki çıkışları açıkça sonraki her çağrıya paketlemelidir:
copywriter(request="Create 3 posts for EcoFlow water bottle targeting millennials.
Use these insights from the Brand Strategist: [paste full strategist output here].
Create engaging captions with hashtags.")
Talimatta bu açıkça belirtilir: "Uzak aracılar, paylaşılan belleğe sahip DEĞİLDİR. Önceki çıkışları açıkça iletmeniz gerekir." Bu olmadan her temsilci körü körüne çalışır.
6. öğe: İstek sınıflandırması: basit ve karmaşık
Her istek için beş aracının tamamı gerekmez. İstem, düzenleyiciye planlamadan önce isteği sınıflandırması talimatını veriyor:
SIMPLE → one agent needed
"Research the eco-friendly water bottle market" → brand_strategist only
"Write 3 Instagram captions" → copywriter only
COMPLEX → all agents sequentially
"Create a complete campaign with timeline" → all 5 agents
Bu sınıflandırma olmadan düzenleyici, "bana 3 gönderi fikri ver" gibi her istek için beş aracının tamamını çalıştırarak gereksiz gecikme ve maliyet oluşturur.
7. öğe: İletişim kuralları: Tam çıktıları göster, filtreleme yok
İstemde, düzenleyicinin uzmanların döndürdüğü bilgileri özetlememesi veya düzenlememesi gerektiği açıkça belirtiliyor:
- DO NOT summarize unless the output exceeds 2000 words
- DO NOT filter or edit agent responses
- Show the user exactly what each specialist produced
- NEVER say results are ready unless you received them in tool_output
Bu olmadan, düzenleyici uzman çıktılarının içeriğini kendi kelimeleriyle yeniden yazarak ayrıntıları kaybeder, hatalara yol açar ve uzmanların var olma amacını boşa çıkarır.
8. öğe: İş akışını tamamlama: asla erken durmayın
İnce ancak kritik bir hata modu: Düzenleyici, 5 adımlık bir plan duyurur, 3 adımı tamamlar ve ardından sonuçları tamamlanmış gibi sunar. İstem, düzenleyicinin tamamlayabilmesi için geçilmesi gereken açık bir yapılacaklar listesiyle bunu önler:
✓ Did I announce a plan with N agents?
✓ Have I called ALL N agents from my plan?
✓ Did each agent respond successfully?
✓ Am I presenting complete results from ALL agents?
If any answer is NO → continue executing the remaining agents.
Bu, düzenleyicinin kısmi bir çalıştırmayı tamamlanmış olarak değerlendirmesini engeller.
Kalite Kontrol Döngüsü
Düzeltme iş akışı, prompt.py'nın en karmaşık kısmıdır. ## REVISION WORKFLOW bölümünü açın ve adımları uygulayın.
İşleyiş şekli
Eleştirmen yanıt verdikten sonra Kreatif Direktör, Proje Yöneticisi'ne körü körüne devam etmez. Eleştirmen çıkışını ve dallarını okur:
Critic output
│
├── "All Approved: YES"
│ └──► proceed to Project Manager
│
└── "Status: NEEDS_REVISION"
│
├── posts fail → call copywriter again with feedback
├── visuals fail → call designer again with feedback
└── both fail → call copywriter, then designer
│
└──► revised output → Project Manager
(1 revision max per deliverable)
Bu özellik, kodla değil LLM ile desteklenir.
Daha önce codelab'de, düzenleyicinin Critic'in yanıtını "ayrıştırdığı" belirtilmişti. Bu ayrıştırma işlemini yapan bir Python kodu yoktur (normal ifade veya dize eşleştirme yoktur). Kreatif Direktör, kendi talimatını okuyan bir LLM'dir. Bu talimatta şunlar belirtilir:
Look for "Status: NEEDS_REVISION" in the critic's response.
Posts need revision → call copywriter
Visuals need revision → call designer
LLM, Eleştirmen'in çıktısındaki bu tam dizeleri okur ve dala uyar. Bu nedenle, eleştiri biçimi üzerinde değişiklik yapılamaz: Eleştirmen NEEDS_REVISION yerine "biraz çalışılması gerekiyor" yazarsa LLM, talimatında eşleşme bulamaz ve düzeltme adımını sessizce atlar.
Bağlam, düzeltme çağrısında nasıl yönlendirilir?
Düzeltme çağrısı, 5. öğedeki bağlam geçirme kuralıyla aynıdır. Kopyalama uzmanı, ilk sürümünü hatırlamadığı için düzenleyici her şeyi açıkça belirtmelidir:
"I need you to revise the Instagram posts based on critic feedback.
ORIGINAL BRIEF:
[the original user request]
YOUR FIRST VERSION:
[the posts the copywriter created]
CRITIC FEEDBACK (Score: 6/10 - NEEDS_REVISION):
[the critic's specific suggestions]
Please revise the posts addressing this feedback while maintaining
the strengths the critic identified."
"İLK VERSİYONUNUZ" bölümü olmadan, metin yazarı daha önce ürettiği içeriği iyileştirmek yerine sıfırdan yazardı.
1 revizyon sınırı ve önemi
Bir düzeltme turundan sonra düzenleyici, puan ne olursa olsun proje yöneticisine geçer. Talimat, bunu zihinsel olarak takip eder:
After calling copywriter for revision once:
→ mark "copywriter_revised = true" in context
→ even if the critic still suggests changes, proceed to PM
Bu sınır olmadan döngü süresiz olarak devam edebilir: Eleştirmen bir sorunu işaretler → Metin yazarı düzeltir → Eleştirmen tekrar işaretler → Metin yazarı tekrar düzeltir. Her tur için jeton ve zaman gerekir. Kontrolsüz bir döngü riski olmadan kaliteyi artırmak için tek bir revizyon yeterlidir.
Proje yöneticisine hangi bilgiler iletilir?
Proje yöneticisi her zaman orijinal sürümleri değil, nihai onaylanmış sürümleri alır. Revizyonlar yapıldıysa düzenleyici, revize edilmiş kopyayı ve görselleri iletir. İlk geçişte her şey onaylandıysa doğrudan bu öğeler geçirilir. PM, reddedilen taslakları asla görmez.
YAPILACAKLAR 2: Her uzmanı RemoteA2aAgent + AgentTool olarak kaydetme
# TODO 2: For each specialist URL... yorumunu bulun ve aşağıdakiyle değiştirin:
if strategist_url:
available_agents_list.append(
"- **brand_strategist**: Market research, competitor analysis, trend identification"
)
strategist_agent = RemoteA2aAgent(
name="brand_strategist",
description="Researches markets, competitors, and trends using Google Search",
agent_card=f"{strategist_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=strategist_agent))
if copywriter_url:
available_agents_list.append(
"- **copywriter**: Instagram captions, hashtags, and CTAs"
)
copywriter_agent = RemoteA2aAgent(
name="copywriter",
description="Creates Instagram captions with hashtags and CTAs",
agent_card=f"{copywriter_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=copywriter_agent))
if designer_url:
available_agents_list.append(
"- **designer**: Visual concepts and real images generated via Gemini (GCS URIs returned)"
)
designer_agent = RemoteA2aAgent(
name="designer",
description="Creates visual concepts and generates real images via Gemini, stored in GCS",
agent_card=f"{designer_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=designer_agent))
if critic_url:
available_agents_list.append(
"- **critic**: Quality review with APPROVED/NEEDS_REVISION scoring"
)
critic_agent = RemoteA2aAgent(
name="critic",
description="Reviews campaign materials and returns structured quality feedback",
agent_card=f"{critic_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=critic_agent))
if pm_url:
available_agents_list.append(
"- **project_manager**: Project timelines, task breakdowns, Notion integration"
)
pm_agent = RemoteA2aAgent(
name="project_manager",
description="Creates project timelines and task breakdowns, optionally in Notion",
agent_card=f"{pm_url}/.well-known/agent.json",
)
agent_tools.append(AgentTool(agent=pm_agent))
YAPILACAKLAR 3 - Bağlam sıkıştırmasıyla bir uygulamaya sarmalama
Sıkıştırma neden gereklidir?
Bir sohbetteki her mesaj (kullanıcının istemi, her araç çağrısı, her araç yanıtı), LLM'nin bir sonraki dönüşte okuduğu bağlam penceresine eklenir. 5 temsilcili bir iş akışında bu durum hızla artar:
Turn 1: user prompt ~200 tokens
Turn 2: orchestrator plan ~300 tokens
Turn 3: brand_strategist tool_call ~150 tokens
Turn 4: brand_strategist tool_output ~1,500 tokens ← full research report
Turn 5: copywriter tool_call ~300 tokens ← must include strategist output
Turn 6: copywriter tool_output ~2,000 tokens ← 3 captions
Turn 7: designer tool_call ~500 tokens
Turn 8: designer tool_output ~1,500 tokens
...
4. Temsilci (Eleştirmen) tarafından bağlam penceresi, önceki üç temsilcinin tüm çıktısını içerir. Bu, genellikle yalnızca araç yanıtlarında 8.000-12.000 jeton anlamına gelir. Gemini 2.5 Pro'nun büyük bağlam penceresiyle bile, düzenleyicinin akıl yürütme kalitesi, sürekli büyüyen bir geçmişe bakması gerektiğinden düşer. Sıkıştırma olmadan uzun iş akışları, 4. Ajan civarında pratik sınırlara ulaşır.
Sıkıştırma ne işe yarar?
ADK, her etkinliği tam olarak tutmak yerine eski etkinlikleri kompakt bir şekilde özetlemek için düzenli olarak bir LLM çağırır. Yalnızca geçmiş etkinliklerin özeti ve en son aracının tam çıktısı bağlamda tutulur.
Without compaction:
[full strategist output] + [full copywriter output] + [full designer output] + → Critic
With compaction (interval=3, overlap=1):
[summary of strategist + copywriter] + [full designer output] + → Critic
Özet, ayrıntılı biçimlendirmeyi, her aracıya iletilen tekrarlanan bağlamı ve ara muhakemeyi atarken temel bilgileri (önemli analizler, onaylanmış altyazılar, görsel konseptler) korur. Eleştirmen, değerlendirme için gereken her şeye sahiptir. Yalnızca üç tam rapor yerine bir özet okur.
Kod
# TODO 3: Wrap the agent in an App... yorumunu bulun ve yer tutucu App(...) yerine aşağıdakileri girin:
from google.adk.apps import App
from google.adk.apps.app import EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
compaction_config = EventsCompactionConfig(
summarizer=LlmEventSummarizer(llm=Gemini(model_id=os.getenv("GEMINI_MODEL", "gemini-2.5-flash"))),
compaction_interval=3, # Summarize after every 3 agent completions
overlap_size=1, # Keep the most recent agent's output in full
)
app = App(
name="creative_director",
root_agent=agent,
events_compaction_config=compaction_config,
plugins=[LoggingPlugin()],
)
return agent, app
compaction_interval=3: Sıkıştırma, her 3 aracı tamamlamasından sonra tetiklenir. 5 aracılık bir ardışık düzende bu, bir kez tetiklendiği (1-3 numaralı aracıların ardından) ve ardından eleştirmen ile proje yöneticisinin 1-3 numaralı aracıların özetini ve önceki aracının tam çıktısını gördüğü anlamına gelir.
overlap_size=1: En son temsilcinin tam yanıtı her zaman kelimesi kelimesine korunur, asla özetlenmez. Eleştirmen'in, gerçek görüntüleri yükleyip incelemek için Tasarımcı'nın gcs_uri değerleri de dahil olmak üzere tam çıktısına ihtiyacı olduğundan bu önemlidir. Özetlerde bu URI'ler kaybolur.
Tam kampanya yayınında nasıl çalışır?
Agent 1 (Strategist) → full context
Agent 2 (Copywriter) → full context
Agent 3 (Designer) → full context
↓ compaction fires: summarizes agents 1-2, keeps 3 in full
Agent 4 (Critic) → sees [summary of 1-2] + [full output of 3]
Agent 5 (PM) → sees [summary of 1-3] + [full output of 4]
RemoteA2aAgent ve AgentTool işaretlemelerini anlama
RemoteA2aAgent("brand_strategist", agent_card=url)
│
│ wraps the remote service so ADK can call it
▼
AgentTool(agent=strategist_agent)
│
│ exposes it as a callable tool to the LLM
▼
Agent(tools=[...])
│
│ LLM calls tool("brand_strategist", message=...) when needed
▼
brand-strategist-xxxx.run.app ← actual HTTP A2A call happens here
LLM, sistem talimatına ve kullanıcının isteğine göre her aracı ne zaman çağıracağına karar verir. Düzenleyici, aracıları kodda hiçbir zaman doğrudan çağırmaz. Her şey LLM'nin muhakemesiyle yönlendirilir.
Kreatif Direktör'ü yerel olarak test etme
uv run adk web agents --allow_origins='*'
8000 numaralı bağlantı noktasında web önizlemesini açın. Aracı açılır listesini kullanarak creative_director'ı seçin ve şunları deneyin:
Research the eco-friendly water bottle market for health-conscious millennials
Reklam Öğesi Yöneticisi'nin bunu yalnızca Marka Stratejisti'ne yönlendirdiğini ve Marka Stratejisti'nden yanıt aldığınızı görürsünüz.
Kampanyanın tamamı için şunları deneyin:
Create a complete Instagram campaign for SolarPack portable solar charger targeting
outdoor enthusiasts and digital nomads aged 22-35.
Budget $2,000, launch in 2 weeks.
Reklam öğesi yöneticisinin, 5 uzmanı sırayla koordine ettiğini ve her bir temsilcinin çıktısının bir sonraki temsilciye aktarıldığını göreceksiniz.

Devam etmeden önce Creative Director'ı (Ctrl+C) durdurun. A2A inceleyici de 8000 numaralı bağlantı noktasını kullanır.
Yerel test tamamlandığında 5 uzman sunucuyu durdurun (her terminalde Ctrl+C).
12. Uzman Ajanları Dağıtma ve Test Etme
Artık aracıları Google Cloud'a dağıtmaya hazırız. Cloud Run, aracı dağıtmak için harika bir hizmettir. Sunucusuz, ölçeklenebilir ve kullanımı kolaydır. Her uzman temsilci bağımsız bir Cloud Run hizmeti olarak dağıtılır.
Dağıtım yapılandırması
Her uzman için Dockerfile şu deseni izler:
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc curl
# Fast dependency install with uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY pyproject.toml .
RUN uv sync --no-install-project --no-dev
COPY . .
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
ENV PYTHONUNBUFFERED=1 PORT=8080 HOST=0.0.0.0
EXPOSE 8080
CMD ["uv", "run", "python", "agent.py"]
5 uzmanı sırayla dağıtın
cd ~/ai-creative-studio/workshop/starter
source .env
uv run deploy/deploy_all_specialists.py
Bu komut dosyası, 5 aracının tümünü tek tek dağıtır (toplamda yaklaşık 10-12 dakika sürer). Sıralı dağıtım, Cloud Build yoklama kotasını (60 istek/dakika) aşmayı önler. İşlem tamamlandığında her aracının Cloud Run URL'sini .env'ye geri yazar.
Tasarımcı dağıtıldıktan sonra, oluşturulan resimleri yükleyebilmesi için komut dosyası, GCS paketinize roles/storage.objectCreator Cloud Run hizmet hesabına otomatik olarak izin verir.
.env içinde Notion kimlik bilgilerini yapılandırdıysanız komut dosyası bunları Secret Manager'da (notion-token, notion-project-db-id, notion-tasks-db-id olarak) güvenli bir şekilde saklar ve düz ortam değişkenleri yerine --set-secrets aracılığıyla Project Manager hizmetine yerleştirir. Bu nedenle, jeton Cloud Run'ın ortam sekmesinde veya gcloud komut geçmişinde görünmez.
Dağıtımları doğrulama
Dağıtım tamamlandığında komut dosyası, Cloud Run URL'lerini otomatik olarak .env dosyasına geri yazar ve önceki adımdaki localhost URL'lerinin yerini alır:
source .env
echo "Deployed URLs:"
echo " Brand Strategist: $STRATEGIST_AGENT_URL"
echo " Copywriter: $COPYWRITER_AGENT_URL"
echo " Designer: $DESIGNER_AGENT_URL"
echo " Critic: $CRITIC_AGENT_URL"
echo " Project Manager: $PM_AGENT_URL"
Reklam öğesi yönetmeni, sonraki adımda Agent Runtime'a dağıtıldığında bu Cloud Run URL'lerini otomatik olarak kullanır.
Temsilci kartlarını doğrulama
Dağıtılan her aracı, /.well-known/agent.json adresinde bir aracı kartı gösterir. Her şeyin yayında olduğunu doğrulamak için bunları getirin:
source .env
for agent_url in $STRATEGIST_AGENT_URL $COPYWRITER_AGENT_URL $DESIGNER_AGENT_URL $CRITIC_AGENT_URL $PM_AGENT_URL; do
echo "=== Agent Card: $agent_url ==="
curl -s "${agent_url}/.well-known/agent.json" | python3 -m json.tool | grep -E '"name"|"url"|"description"'
echo ""
done
Her temsilci için beklenen çıktı:
"name": "brand_strategist",
"url": "https://brand-strategist-xxxx.run.app",
"description": "Brand strategist for market research and competitive insights"
A2A inceleyici (Cloud Run) ile test etme
A2A Inspector, 10. adımda zaten yüklenmiştir. Başlatın:
cd ~/a2a-inspector
bash scripts/run.sh
Web Önizlemesi'ni açın → Bağlantı noktasını değiştir'i → 5001 tıklayın. Bağlantı alanına Cloud Run URL'nizi girin:
https://brand-strategist-xxxx.us-central1.run.app
Bağlan'ı tıklayın. Hizmetler --allow-unauthenticated ile dağıtıldığından kimlik doğrulama jetonu gerekmez.
İnceleme uzmanı bağlanır, temsilci kartını doğrular ve A2A üzerinden etkileşimli olarak sohbet etmenize olanak tanır.
Cloud Run'a dağıtılan aracıları inceleme
Cloud Run'a dağıttıktan sonra, bulut dağıtımının çalıştığını doğrulamak için denetleyiciyi herkese açık HTTPS URL'sine yönlendirin:

İş akışı aynıdır: Cloud Run URL'sini yapıştırın, bağlanın ve bir test mesajı gönderin. Temsilci kartı yüklenir ve sohbet yanıt verirse uzman doğru şekilde dağıtılmış ve ulaşılabilir demektir.
13. Creative Director'ı Agent Runtime'a dağıtma
Orkestratör, yönetilen oturum durumu, otomatik ölçeklendirme ve yerleşik izleme sağlayan Agent Runtime'a dağıtılır.
Orkestratör için neden Agent Runtime?
Beş uzman, Cloud Run'a dağıtılır. Bu uzmanlar hafif, durum bilgisi olmayan ve her biri bir görevi yerine getiren uzmanlardır. Reklam öğesi yöneticisinin farklı gereksinimleri vardır:
Gereksinim | Neden önemli? |
Oturum durumu | Çok adımlı bir iş akışı 45 saniyeden uzun sürüyor. Agent Runtime, orkestratörün araç çağrıları arasındaki sohbet durumunu korur. Böylece, işlem hattının ortasında hiçbir şey kaybolmaz. |
Değişken yük | Bazen saatte bir kampanya, bazen de aynı anda birden fazla kampanya. Aracı çalışma zamanı, boşta kaldığında sıfıra ölçeklenir ve otomatik olarak ölçeklendirilir. Boşta kalan kapasite için ödeme yapmazsınız. |
Gözlemlenebilirlik | Cloud Logging, Cloud Monitoring ve Cloud Trace yerleşik olarak sunulur. Her A2A çağrısını, kullanılan her jetonu ve her gecikme artışını herhangi bir enstrümantasyon eklemeden görebilirsiniz. |
Uzun süren iş akışları | Cloud Run'da istek zaman aşımı 3.600 saniyedir. Temsilci Çalışma Zamanı, yönetilen yeniden denemeler ve durum kalıcılığı ile dakikalar sürebilen iş akışları için tasarlanmıştır. |
Cloud Run, durum bilgisiz uzmanlar için doğru platformdur. Agent Runtime, durum bilgisi olan düzenleyici için doğru platformdur.
Orchestrator'ı dağıtma
cd ~/ai-creative-studio/workshop/starter
source .env
uv run deploy/deploy_orchestrator.py --action deploy
Bu işlem yaklaşık 5-10 dakika sürer. İşlem tamamlandığında AGENT_ENGINE_ID ve AGENT_ENGINE_RESOURCE_NAME, .env'ye kaydedilir.
source .env
echo "Agent Engine ID: $AGENT_ENGINE_ID"
echo "Resource: $AGENT_ENGINE_RESOURCE_NAME"
Dağıtımın işleyiş şekli
client.agent_engines.create(), App nesnenizi paketler, bağımlılarıyla birlikte yükler ve yönetilen altyapıya dağıtır. Her bir parametrenin işlevi aşağıda açıklanmıştır:
import vertexai
from vertexai import Client, agent_engines
vertexai.init(project=PROJECT_ID, location=LOCATION, staging_bucket=STAGING_BUCKET)
# Wrap the App in an AdkApp adapter - enables tracing in Cloud Trace
adk_app = agent_engines.AdkApp(app=root_app, enable_tracing=True)
# Initialize client and deploy
client = Client(project=PROJECT_ID, location=LOCATION)
agent_engine_resource = client.agent_engines.create(
agent=adk_app,
config={
"staging_bucket": STAGING_BUCKET, # GCS bucket for packaging artifacts
"display_name": "Creative Director",
# Python packages installed in the managed runtime - pin for reproducibility
"requirements": [
"google-cloud-aiplatform[agent_engines]>=1.132.0,<2.0.0",
"google-adk[a2a]==1.31.1",
"google-genai>=1.70.0",
"google-cloud-storage>=2.10.0",
"python-dotenv>=1.0.0",
"pydantic>=2.0.0",
"cloudpickle>=3.0.0",
],
# Specialist URLs passed as env vars - the orchestrator reads these at runtime
"env_vars": {
"COPYWRITER_AGENT_URL": COPYWRITER_URL,
"DESIGNER_AGENT_URL": DESIGNER_URL,
"STRATEGIST_AGENT_URL": STRATEGIST_URL,
"CRITIC_AGENT_URL": CRITIC_URL,
"PM_AGENT_URL": PM_URL,
},
},
)
resource_name = agent_engine_resource.api_resource.name
agent_engine_id = resource_name.split("/")[-1]
Arka planda neler olur?
1. Agent Engine packages your App + requirements into a container
2. Uploads it to the staging bucket in your project
3. Deploys to managed compute (you never see or manage the VM)
4. Returns a resource name: projects/.../locations/.../reasoningEngines/<id>
5. That ID is saved to .env as AGENT_ENGINE_ID
Dağıtımdan sonra düzenleyici, ortam değişkenlerindeki URL'ler aracılığıyla beş Cloud Run uzmanına bağlanır.
- Bunlar, dağıtım komut dosyası çalıştırılmadan önce
.envüzerinden iletilir.
14. Uçtan uca kampanya yayınlama
Sistemin tamamı dağıtılır. Agent Runtime playground'da eksiksiz bir kampanya yayınlayın.
Agent Runtime playground'unu açma
- https://console.cloud.google.com/agent-platform/runtimes adresine gidin. Ayrıca Agent Platform > Agents > Deployments'tan (Aracı Platformu > Aracıları > Dağıtımlar) Agent Runtime'a (Aracı Çalışma Zamanı) da gidebilirsiniz.
- Dağıtılan Agent Runtime'ınızı seçin (
creative-director) - Sol kenar çubuğunda Playground'u tıklayın.
- Yeni bir görüşme açmak için Yeni oturum'u tıklayın.
Tam bir kampanya yayınlama
Bu özeti sohbete yapıştırıp gönderin:
Create a complete Instagram campaign for:
- Product: EcoFlow Smart Water Bottle (tracks hydration, keeps drinks cold 24h)
- Target Audience: Health-conscious millennials, 25-35 years old
- Platform: Instagram
- Goal: Brand awareness + drive website traffic
- Brand Voice: Motivational, clean, science-backed
- Budget: $3,000
- Timeline: Launch in 2 weeks
Yaratıcı yönetmen, 5 aracının tamamını sırayla çalıştırır:
- Marka Stratejisti → pazar araştırması, rakip analizi, kitle analizleri
- Metin yazarı → Açıklamalar, hashtag'ler ve harekete geçirici mesajlar içeren 3 Instagram gönderisi
- Designer: Her yayın için Gemini (GCS URI'leri) aracılığıyla oluşturulan görsel konseptler ve gerçek görüntüler
- Eleştirmen → ONAYLANDI / DÜZENLENMESİ_GEREKİYOR puanlarıyla kaliteli inceleme
- (Gerekirse revizyon) → Metin yazarı veya tasarımcı, geri bildirimle tekrar aranır.
- Proje yöneticisi → 2 haftalık zaman çizelgesi, görev dökümü, bütçe ayırma

Tek temsilci yönlendirmeyi test etme
Bu daha kısa isteği yeni bir oturumda gönderin:
Research the luxury skincare market - top brands and trends in 2025
Reklam yöneticisinin bu görevi yalnızca Marka Stratejisti'ne yönlendirdiğine dikkat edin. Başka hiçbir temsilci aranmaz. Bu, sistem talimatından gelen istek sınıflandırma mantığının doğru şekilde çalıştığını gösterir.
Yürütme izlerini inceleme
Hâlâ konsoldayken:
- Sol kenar çubuğunda Traces'i (Playground'un yanında) tıklayın.
- İzleme Görünümü bölümünde, az önce çalıştırdığınız oturumun izlemesini seçin.
- Her aracı çağrısını, girişlerini/çıkışlarını, gecikmesini ve jeton kullanımını görmek için izleme ağacını genişletin.
Uzmanla yapılan her A2A görüşmesi ayrı bir aralık olarak görünür. Yaratıcı yönetmenin her bir aracıya hangi bağlamı ilettiğini ve karşılığında ne aldığını tam olarak görebilirsiniz.
İsteğe bağlı: Terminalden çalıştırma
Ayrıca, kampanyayı başlangıç paketinde yer alan run_campaign.py komut dosyasını kullanarak programatik olarak da çalıştırabilirsiniz.
cd ~/ai-creative-studio/workshop/starter
uv run run_campaign.py
15. Temizleme
Devam eden ücretlerden kaçınmak için Google Cloud kaynaklarını temizleyin.
Sökme komut dosyasını çalıştırın. Bu komut dosyası, .env öğenizi okur ve bu codelab sırasında oluşturulan her şeyi siler:
bash deploy/teardown_gcp.sh
Komut dosyası, tam olarak neyi sileceğini gösterir ve herhangi bir işlem yapmadan önce onay ister:
Kaynak | Neler silinir? |
Cloud Run hizmetleri | marka stratejisti, metin yazarı, tasarımcı, eleştirmen, proje yöneticisi |
Agent Runtime | Kreatif direktör muhakeme motoru + tüm oturumlar |
Artifact Registry |
|
GCS paketleri |
|
Secret Manager |
|
Her şeyin kaldırıldığını doğrulayın
gcloud run services list --region=us-central1
gcloud storage buckets list --project=$GCP_PROJECT_ID
Beklenen çıktı: Boş listeler veya yalnızca önceden var olan kendi kaynaklarınız.
16. Özet
Tebrikler! Google Cloud'da üretim düzeyinde çoklu ajanlı bir yapay zeka sistemi oluşturup dağıttınız.
Oluşturduğunuz öğeler
Temsilci | Kapasite | Dağıtım |
Marka Stratejisi Uzmanı | Google Arama aracılığıyla pazar araştırması | Cloud Run |
Metin Yazarı | Instagram başlığı oluşturma | Cloud Run |
Tasarımcı | Gemini + GCS yükleme ile görüntü üretme | Cloud Run |
Eleştirmen | Puanlama içeren kalite incelemesi | Cloud Run |
Proje Yöneticisi | Timeline + Notion MCP | Cloud Run |
Kreatif Direktör | A2A aracılığıyla tam düzenleme | Agent Runtime |
Öğrendiğiniz önemli kalıplar
- ADK
Agent- bir talimat ve isteğe bağlı araçlarla bir LLM aracısı tanımlayın adk web: Yerleşik bir sohbet kullanıcı arayüzüyle herhangi bir ADK aracısını yerel olarak çalıştırma ve test etmeSkillToolset: Yeniden kullanılabilir bilgileri, isteğe bağlı olarak yüklenen modüler dosyalara paketleyin.FunctionTool: Herhangi bir Python işlevini (veya harici modeli) çağrılabilir bir aracı aracı olarak sarmalamato_a2a(): Herhangi bir ADK aracısını A2A uyumlu bir HTTPS hizmeti olarak kullanıma sunmaRemoteA2aAgent+AgentTool: Uzak aracıları çağrılabilir araçlar olarak düzenleyin.McpToolset: MCP stdio sunucuları üzerinden harici hizmetlere bağlanmaEventsCompactionConfig- Uzun çok aracılı iş akışlarında jeton sınırlarını yönetme- Yapılandırılmış eleştirmen çıktısı: Otomatik düzeltme ile makine tarafından okunabilir kalite kontrolü
- Cloud Run: Container mimarisine alınmış aracıları geniş ölçekte dağıtma
- Agent Runtime: Yönetilen oturumlar ve izleme ile düzenleyicileri barındırma
Sonraki adımlar
gemini-3.1-flash-image-preview'ın düzenleme özelliğini kullanarak Tasarımcı'ya çok dönüşlü görüntü düzenleme ekleyin.- Cloud Run hizmetlerine IAM kimlik doğrulaması ekleme (
--allow-unauthenticatedsimgesini kaldırma) - Bir uzmanı LangGraph veya CrewAI aracısıyla değiştirin. A2A, çerçeveye özel değildir.
- Katılımcıların çıkışları değerlendirip yineleyebilmesi için kullanıcı geri bildirimini araç olarak ekleyin.
- Cloud Console'da Agent Runtime izlemeyi keşfedin