1. Giriş
Yapay zeka temsilcileri daha fazla sorumluluk üstlendikçe her şeyi yapan tek bir temsilciyi yönetmek, ölçeklendirmek ve geliştirmek zorlaşır. Farklı özellikler genellikle farklı dağıtım stratejileri, güncelleme döngüleri veya hatta farklı ekipler gerektirir.
- A2A (Agent2Agent) Protokolü, iletişimi çözerek ajanların birbirlerinin özelliklerini keşfetme ve çerçeveler ile kuruluşlar arasında işbirliği yapma şeklini standartlaştırır.
- Gemini Enterprise Agent Platform Runtime, dağıtım tarafını çözer. Bu, yerleşik A2A desteği, otomatik ölçeklendirme, güvenli uç noktalar, kalıcı oturumlar ve sıfır altyapı yönetimi ile temsilcilerinizi barındıran, tümüyle yönetilen bir sunucusuz platformdur.
Bu araçlar, uzmanlaşmış temsilciler oluşturmanıza, bunları bulunabilir A2A hizmetleri olarak dağıtmanıza ve çok temsilcili sistemlerde birleştirmenize olanak tanır.
Ne oluşturacaksınız?
Gemini Enterprise Agent Platform Sessions tarafından yönetilen ADK oturum durumunu kullanarak restoran masa rezervasyonlarını (oluşturma, kontrol etme ve iptal etme) yöneten bir Rezervasyon Aracısı. Bu ajanı Gemini Enterprise Agent Platform Runtime'a dağıtırsınız. Burada A2A protokolünün ajan kartı aracılığıyla bulunabilir hale gelir. Ardından, Foodie Finds restoran Concierge ajanını (ön koşul codelab'inden) yükselterek Rezervasyon Ajanını uzaktan A2A alt ajanı olarak kullanırsınız (Codelab'i ziyaret etmediyseniz endişelenmeyin, sizin için bir başlangıç deposu hazırladık). Sonuç: Düzenleyicinin menü sorgularını MCP Toolbox'a, rezervasyon isteklerini ise uzak A2A ajanına yönlendirdiği çok ajanlı bir sistem.

Neler öğreneceksiniz?
- Rezervasyon verilerini yönetmek için yönetilen oturum hizmetini kullanan bir ADK aracısı oluşturma
- ADK aracısını, aracı kartları ve becerileriyle A2A sunucusu olarak kullanıma sunma
- Gemini Enterprise Agent Runtime'a A2A ajanı dağıtma
RemoteA2aAgentkullanarak başka bir ADK ajanından uzak bir A2A ajanı kullanma ve kimliği doğrulanmış isteği işleme- Çoklu temsilci sistemlerini artımlı olarak test etme: yerel A2A, dağıtılmış A2A, kısmi entegrasyon, tam dağıtım
Ön koşullar
- (Önerilir) Aşağıdaki codelab'leri tamamlamış olmanız gerekir :
- ADK ve Cloud SQL ile kalıcı yapay zeka ajanları oluşturma -> ADK oturumu ve durumu hakkında daha fazla bilgi
- ADK, MCP Toolbox ve Cloud SQL ile Ajan Tabanlı RAG -> Bu codelab'den aracınızı oluşturmaya devam edebilirsiniz. Sağlanan başlangıç kodu aynıdır.
- Etkin bir faturalandırma hesabına sahip Google Cloud hesabı
- Python ve ADK kavramlarına dair temel bilgi
2. Ortam Kurulumu - Önceki Codelab'den devam etme
Bu codelab'de sağladığımız anlatılar, ön koşul codelab'inin (ADK, MCP Toolbox ve Cloud SQL ile Ajan Tabanlı RAG) devamıdır . Önceki codelab'deki çalışmanıza devam edebilirsiniz.
Önceki codelab'in çalışma dizininde ( çalışma dizini build-agent-adk-toolbox-cloudsql olmalıdır) oluşturmaya başlayabiliriz. Karışıklığı önlemek için dizini, sıfırdan başladığımızda kullandığımız dizin adıyla yeniden adlandıralım.
mv ~/build-agent-adk-toolbox-cloudsql ~/adk-a2a-agent-runtime-starter
cloudshell workspace ~/adk-a2a-agent-runtime-starter && cd ~/adk-a2a-agent-runtime-starter
source .env
Önceki codelab'deki anahtar dosyalarının yerinde olduğunu doğrulayın:
echo "--- Restaurant Agent ---"
cat restaurant_agent/agent.py | head -5
echo ""
echo "--- Toolbox Config ---"
cat tools.yaml | head -5
restaurant_agent/agent.py dosyasını LlmAgent içe aktarma işlemiyle, tools.yaml dosyasını ise araç kutusu yapılandırmanızla birlikte görmeniz gerekir.
Şimdi Python ortamımızı yeniden başlatalım.
rm -rf .venv
uv sync
Ayrıca, veritabanının doldurulmuş ve hazır olduğunu doğrulayın:
uv run python scripts/verify_seed.py
Önceki codelab'deki her test ayrıntısını uygularsanız aşağıdaki gibi bir çıktı görebilirsiniz.
Menu Items: 16/15 Embeddings: 16/15 ✗ Database not ready
Sorun değil. Veritabanı kontrolünde, veri kullanımı kontrolünden girdiğiniz ek veriler dikkate alınmaz. 15 veya daha fazla veriniz olduğu sürece sorun yok.
Gerekli API'yi Etkinleştirme
Ardından, Gemini Enterprise Ajan Platformu ile etkileşim kurmak için gerekli API'yi etkinleştirdiğimizden emin olmamız gerekir.
gcloud services enable \
cloudresourcemanager.googleapis.com
Bir sonraki bölüme geçmek için gerekli dosya ve altyapıya sahip olmanız gerekir: A2A Protocol and Gemini Enterprise Agent Runtime.
3. Ortam Kurulumu - Başlangıç deposuyla yeni bir başlangıç yapma
Bu adımda Cloud Shell ortamınız hazırlanır, Google Cloud projeniz yapılandırılır ve başlangıç deposu klonlanır.
Cloud Shell'i açma
Tarayıcınızda Cloud Shell'i açın. Cloud Shell, bu codelab için ihtiyacınız olan tüm araçların bulunduğu önceden yapılandırılmış bir ortam sağlar. İstendiğinde Yetkilendir'i tıklayın.
Ardından, terminali açmak için "Görünüm" -> "Terminal"i tıklayın. Arayüzünüz aşağıdaki gibi görünmelidir.

Bu, ana arayüzümüz olacak. Üstte IDE, altta terminal yer alacak.
Çalışma dizininizi ayarlama
Başlangıç deposunu klonlayın. Bu codelab'de yazdığınız tüm kodlar burada yer alır:
rm -rf ~/adk-a2a-agent-runtime-starter
git clone https://github.com/alphinside/adk-a2a-agent-runtime-starter.git
cloudshell workspace ~/adk-a2a-agent-runtime-starter && cd ~/adk-a2a-agent-runtime-starter
Sağlanan şablondan .env dosyasını oluşturun:
cp .env.example .env
Terminalinizde proje kurulumunu basitleştirmek için bu proje kurulum komut dosyasını çalışma dizininize indirin:
curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh
Komut dosyasını çalıştırın. Deneme faturalandırma hesabınızı doğrular, yeni bir proje oluşturur (veya mevcut bir projeyi doğrular), proje kimliğinizi geçerli dizindeki bir .env dosyasına kaydeder ve gcloud'de etkin projeyi ayarlar.
bash setup_verify_trial_project.sh && source .env
Komut dosyası:
- Etkin bir deneme faturalandırma hesabınız olduğunu doğrulayın.
.env'da mevcut bir proje olup olmadığını kontrol edin (varsa)- Yeni bir proje oluşturun veya mevcut projeyi yeniden kullanın
- Deneme faturalandırma hesabını projenize bağlama
- Proje kimliğini
.envdosyasına kaydedin. - Projeyi etkin
gcloudprojesi olarak ayarlayın
Cloud Shell terminal isteminde çalışma dizininizin yanındaki sarı metni kontrol ederek projenin doğru şekilde ayarlandığını doğrulayın. Proje kimliğiniz gösterilmelidir.

Gerekli API'yi Etkinleştirme
Ardından, Gemini Enterprise Ajan Platformu ile etkileşim kurmak için gerekli API'yi etkinleştirdiğimizden emin olmamız gerekir.
gcloud services enable \
aiplatform.googleapis.com \
cloudresourcemanager.googleapis.com
Başlangıç Altyapı Kurulumu
Öncelikle, Rust ile yazılmış hızlı bir Python paketi ve proje yöneticisi olan uv kullanarak Python bağımlılıklarını yüklememiz gerekir ( uv belgeleri). Bu codelab, Python projesini korumada hız ve basitlik için bu aracı kullanır.
uv sync
Ardından, Cloud SQL örneğini oluşturan, verileri yerleştiren ve restoran aracımızın ilk durumu olarak işlev görecek Toolbox hizmetini dağıtan tam kurulum komut dosyasını çalıştırın.
bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &
4. Kavram: Agent2Agent (A2A) Protokolü ve Gemini Enterprise Ajan Çalışma Zamanı
Geliştirmeye başlamadan önce, temsilci tabanlı uygulamamızı ölçeklendirmek için bu codelab'de sunulan iki temel teknolojiyi kısaca inceleyelim.
Agent2Agent (A2A) Protokolü
Agent2Agent (A2A) protokolü, yapay zeka aracıları arasında sorunsuz iletişim ve işbirliği sağlamak için tasarlanmış açık bir standarttır. MCP (Model Context Protocol) , aracıları araçlara ve verilere bağlarken A2A, aracıları diğer aracılara bağlar. Böylece, aracıların birbirlerinin özelliklerini keşfetmelerine, görevleri devretmelerine ve çerçeveler ile kuruluşlar arasında işbirliği yapmalarına olanak tanır.

Bir aracıyı araç olarak sarmalama (MCP aracılığıyla) ile A2A aracılığıyla kullanıma sunma arasındaki temel fark: Araçlar durum bilgisiz olup tek işlevleri yerine getirirken A2A aracıları akıl yürütebilir, durumu koruyabilir ve pazarlık veya açıklama gibi çok turlu etkileşimleri yönetebilir. A2A aracılığıyla kullanıma sunulan bir aracı, işlev çağrısına indirgenmek yerine tüm özelliklerini korur.
A2A üç temel kavramı tanımlar:
- Agent Card: Bir aracının ne yaptığını, becerilerini ve uç noktasını açıklayan bir JSON belgesi. Diğer temsilciler, özellikleri keşfetmek için bu kartı getirir.
- Mesaj: Bir görevi tetikleyen, A2A uç noktasına gönderilen kullanıcı veya temsilci isteği.
- Görev: Yaşam döngüsü (gönderildi → çalışıyor → tamamlandı/başarısız oldu) olan bir iş birimi ve sonuçları içeren yapılar.

Daha ayrıntılı bilgi için A2A nedir? başlıklı makaleyi inceleyin.
Gemini Enterprise Ajan Platformu Çalışma Zamanı
Agent Runtime, Google Cloud'da üretimde yapay zeka aracı dağıtmak, ölçeklendirmek ve yönetmek için kullanılan, kurumsal güvenlik özelliklerine (ör. VPC Hizmet Kontrolleri, CMEK) sahip, tümüyle yönetilen bir hizmettir. Altyapıyı yönettiği için aracı mantığına odaklanabilirsiniz.

Agent Runtime'ın sağladıkları:
- Yönetilen dağıtım: ADK, LangGraph veya herhangi bir Python çerçevesiyle oluşturulan aracıları tek bir SDK çağrısıyla dağıtın.
- A2A barındırma: Temsilcileri, otomatik temsilci kartı yayını ve kimliği doğrulanmış erişimle A2A uyumlu uç noktalar olarak dağıtın.
- Kalıcı oturumlar:
VertexAiSessionServiceİstekler arasında sohbet geçmişini ve durumunu saklar. - Otomatik ölçeklendirme: Altyapı yönetimi olmadan trafiği işlemek için sıfırdan ölçeklendirme
- Gözlemlenebilirlik: Google Cloud'un gözlemlenebilirlik yığını aracılığıyla yerleşik izleme, günlük kaydı ve izleme
- ve daha birçok özellik için ayrıntılı bilgiyi bu belgede bulabilirsiniz.
Bu codelab'de rezervasyon aracısını Agent Runtime'a dağıtıyorsunuz. Dağıtım sürecinde aracı kodunuz serileştirilir (pickle) ve yüklenir. Agent Runtime, A2A protokolüne hizmet veren sunucusuz bir uç nokta sağlar. Diğer aracıların (veya istemcilerin) bu uç noktayla etkileşimi, Google Cloud kimlik bilgileriyle kimliği doğrulanmış standart HTTP çağrıları üzerinden gerçekleşir.
5. Rezervasyon aracısını oluşturma
Bu adımda, oturum durumunu kullanarak restoran rezervasyonlarını işleyen yeni bir ADK aracısı oluşturulur. Temsilci, arama anahtarı olarak telefon numarasıyla üç işlemi (oluşturma, kontrol etme ve iptal etme) destekler. Tüm rezervasyon verileri ADK'nın oturum durumunda bulunur.
Temsilciyi yapılandırma
Doğru model ve proje yapılandırmasıyla aracı dizin yapısını oluşturmak için adk create aracını kullanın:
source .env
uv run adk create reservation_agent \
--model gemini-2.5-flash \
--project ${GOOGLE_CLOUD_PROJECT} \
--region ${GOOGLE_CLOUD_LOCATION}
Bu işlem, Ajan Platformu'ndaki Gemini modeli için önceden yapılandırılmış reservation_agent/ dizini oluşturur.__init__.pyagent.py.env
adk-a2a-agent-runtime-starter/ ├── reservation_agent/ │ ├── __init__.py │ ├── agent.py │ └── .env ├── logs ├── scripts └── ...
Ardından, aracı kodunu güncelleyelim.
Aracı kodunu yazma
Oluşturulan temsilci dosyasını açın:
cloudshell edit reservation_agent/agent.py
Ardından içeriği aşağıdakiyle değiştirin:
# reservation_agent/agent.py
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
# App-scoped state prefix ensures reservations persist across all sessions.
# See https://adk.dev/sessions/state/ for state scope details.
STATE_PREFIX = "app:reservation:"
def create_reservation(
phone_number: str,
name: str,
party_size: int,
date: str,
time: str,
tool_context: ToolContext,
) -> dict:
"""Create a new restaurant reservation.
Args:
phone_number: Customer's phone number, used as the reservation ID.
name: Name for the reservation.
party_size: Number of guests.
date: Reservation date (e.g., '2025-07-15' or 'this Friday').
time: Reservation time (e.g., '7:00 PM').
Returns:
Confirmation of the reservation.
"""
reservation = {
"name": name,
"party_size": party_size,
"date": date,
"time": time,
"status": "confirmed",
}
tool_context.state[f"{STATE_PREFIX}{phone_number}"] = reservation
return {
"status": "confirmed",
"message": f"Reservation created for {name}, party of {party_size} on {date} at {time}. Phone: {phone_number}.",
}
def check_reservation(phone_number: str, tool_context: ToolContext) -> dict:
"""Look up an existing reservation by phone number.
Args:
phone_number: The phone number used when the reservation was created.
tool_context: ADK tool context for state access.
Returns:
The reservation details, or a message if not found.
"""
reservation = tool_context.state.get(f"{STATE_PREFIX}{phone_number}")
if reservation:
return {"found": True, "reservation": reservation}
return {"found": False, "message": f"No reservation found for {phone_number}."}
def cancel_reservation(phone_number: str, tool_context: ToolContext) -> dict:
"""Cancel an existing reservation by phone number.
Args:
phone_number: The phone number used when the reservation was created.
tool_context: ADK tool context for state access.
Returns:
Confirmation of cancellation, or a message if not found.
"""
key = f"{STATE_PREFIX}{phone_number}"
reservation = tool_context.state.get(key)
if not reservation:
return {"success": False, "message": f"No reservation found for {phone_number}."}
if reservation.get("status") == "cancelled":
return {"success": False, "message": f"Reservation for {phone_number} is already cancelled."}
reservation["status"] = "cancelled"
tool_context.state[key] = reservation
return {"success": True, "message": f"Reservation for {reservation['name']} ({phone_number}) has been cancelled."}
root_agent = LlmAgent(
name="reservation_agent",
model="gemini-2.5-flash",
instruction="""You are a friendly reservation assistant for "Foodie Finds" restaurant.
You help diners create, check, and cancel table reservations.
When a diner wants to make a reservation, collect these details:
- Name for the reservation
- Phone number (used as the reservation ID)
- Party size (number of guests)
- Date
- Time
Always confirm the details before creating the reservation.
When checking or cancelling, ask for the phone number if not provided.
Be concise and professional.""",
tools=[create_reservation, check_reservation, cancel_reservation],
)
6. A2A sunucu yapılandırmasını hazırlama
A2A temsilci kartını tanımlama
Temsilci kartı, temsilcinizin özelliklerinin yapılandırılmış bir açıklamasıdır. Diğer temsilciler ve istemciler, temsilcinizin ne yaptığını öğrenmek için bu kartı kullanır. Kart yapılandırmasını oluşturun:
cloudshell edit reservation_agent/a2a_config.py
Aşağıdakileri reservation_agent/a2a_config.py içine kopyalayın:
# reservation_agent/a2a_config.py
from a2a.types import AgentSkill
from vertexai.preview.reasoning_engines.templates.a2a import create_agent_card
reservation_skill = AgentSkill(
id="manage_reservations",
name="Restaurant Reservations",
description="Create, check, and cancel table reservations at Foodie Finds restaurant",
tags=["reservations", "restaurant", "booking"],
examples=[
"Book a table for 4 on Friday at 7pm",
"Check reservation for 555-0101",
"Cancel my reservation, phone number 555-0101",
],
input_modes=["text/plain"],
output_modes=["text/plain"],
)
agent_card = create_agent_card(
agent_name="Reservation Agent",
description="Handles restaurant table reservations — create, check, and cancel bookings for Foodie Finds restaurant.",
skills=[reservation_skill],
)
A2A yürütücüsünü oluşturma
Yürütücü, A2A protokolü ile ADK aracısı arasında köprü görevi görür. A2A isteklerini alır, bunları ADK aracısı üzerinden çalıştırır ve sonuçları A2A görevleri olarak döndürür:
cloudshell edit reservation_agent/executor.py
Aşağıdakileri reservation_agent/executor.py içine kopyalayın:
# reservation_agent/executor.py
import os
from typing import NoReturn
import vertexai
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.tasks import TaskUpdater
from a2a.types import TaskState, TextPart, UnsupportedOperationError
from a2a.utils import new_agent_text_message
from a2a.utils.errors import ServerError
from google.adk.artifacts import InMemoryArtifactService
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService, VertexAiSessionService
from google.genai import types
from reservation_agent.agent import root_agent as reservation_agent
class ReservationAgentExecutor(AgentExecutor):
"""Bridge between the A2A protocol and the ADK reservation agent.
Uses InMemorySessionService for local testing, VertexAiSessionService
when deployed to Agent Runtime (detected via GOOGLE_CLOUD_AGENT_ENGINE_ID).
"""
def __init__(self) -> None:
self.agent = None
self.runner = None
def _init_agent(self) -> None:
if self.agent is not None:
return
self.agent = reservation_agent
engine_id = os.environ.get("GOOGLE_CLOUD_AGENT_ENGINE_ID")
if engine_id:
project = os.environ.get("GOOGLE_CLOUD_PROJECT")
location = os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1")
vertexai.init(project=project, location=location)
session_service = VertexAiSessionService(
project=project, location=location, agent_engine_id=engine_id,
)
app_name = engine_id
else:
session_service = InMemorySessionService()
app_name = self.agent.name
self.runner = Runner(
app_name=app_name,
agent=self.agent,
artifact_service=InMemoryArtifactService(),
session_service=session_service,
memory_service=InMemoryMemoryService(),
)
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
if self.agent is None:
self._init_agent()
query = context.get_user_input()
updater = TaskUpdater(event_queue, context.task_id, context.context_id)
user_id = context.message.metadata.get("user_id", "a2a-user") if context.message.metadata else "a2a-user"
if not context.current_task:
await updater.submit()
await updater.start_work()
try:
session = await self._get_or_create_session(context.context_id, user_id)
content = types.Content(role="user", parts=[types.Part(text=query)])
async for event in self.runner.run_async(
session_id=session.id, user_id=user_id, new_message=content,
):
if event.is_final_response():
parts = event.content.parts
answer = " ".join(p.text for p in parts if p.text) or "No response."
await updater.add_artifact([TextPart(text=answer)], name="answer")
await updater.complete()
break
except Exception as e:
await updater.update_status(
TaskState.failed, message=new_agent_text_message(f"Error: {e!s}"),
)
raise
async def _get_or_create_session(self, context_id: str, user_id: str):
app_name = self.runner.app_name
if context_id:
session = await self.runner.session_service.get_session(
app_name=app_name, session_id=context_id, user_id=user_id,
)
if session:
return session
session = await self.runner.session_service.create_session(
app_name=app_name, user_id=user_id, session_id=context_id,
)
return session
async def cancel(self, context: RequestContext, event_queue: EventQueue) -> NoReturn:
raise ServerError(error=UnsupportedOperationError())
Yürütücü, ortamını otomatik olarak algılar: GOOGLE_CLOUD_AGENT_ENGINE_ID ayarlandığında (Agent Runtime bunu dağıtım sırasında ekler) kalıcı oturumlar için VertexAiSessionService kullanılır. Yerel olarak InMemorySessionService'ya geri döner.
reservation_agent dizininizde artık şunlar olmalıdır:
reservation_agent/ ├── __init__.py ├── agent.py ├── a2a_config.py ├── executor.py └── .env
7. Agent Platform SDK'yı kullanarak A2A aracısı hazırlama ve yerel olarak test etme
Bu adımda, rezervasyon aracısı, Agent Platform SDK'sının (SDK adı, geriye dönük uyumluluk için hâlâ vertex terimini kullanmaktadır) A2aAgent sınıfı kullanılarak A2A uyumlu bir aracı olarak sarmalanır. Ardından, tam A2A protokol akışı (aracı kartı alma, mesaj gönderme ve görev alma) yerel olarak test edilir. Bu, bir sonraki adımda Agent Runtime'a dağıtacağınız A2aAgent nesnesiyle aynıdır.
Bağımlılık ekleme
Agent Platform SDK'yı Agent Runtime ve ADK desteğiyle birlikte A2A SDK'yı da yükleyin:
uv add "google-cloud-aiplatform[agent_engines,adk]==1.149.0" "a2a-sdk==0.3.26"
A2A bileşenlerini anlama
A2A için bir ADK aracısını sarmak üç bileşen gerektirir:
- Aracı kartı: Aracının yeteneklerini, becerilerini ve uç nokta URL'sini açıklayan bir"kartvizit". Diğer temsilciler, temsilcinizin ne yaptığını öğrenmek için bu bilgiyi kullanır.
- Agent Executor: A2A protokolü ile ADK temsilcinizin mantığı arasındaki köprü. A2A isteklerini alır, bunları ADK aracısı üzerinden çalıştırır ve sonuçları A2A görevleri olarak döndürür.
- A2aAgent: Kartı ve yürütücüyü dağıtılabilir bir birimde birleştiren Agent Platform SDK sınıfı.
Test komut dosyasını oluşturma
Yerel olarak test etmek için aşağıdaki komut dosyasını oluşturun
cloudshell edit scripts/test_a2a_agent_local.py
Aşağıdakileri scripts/test_a2a_agent_local.py içine kopyalayın:
# scripts/test_a2a_agent_local.py
import asyncio
import json
import os
from pprint import pprint
from dotenv import load_dotenv
from starlette.requests import Request
from vertexai.preview.reasoning_engines import A2aAgent
from reservation_agent.a2a_config import agent_card
from reservation_agent.executor import ReservationAgentExecutor
load_dotenv()
# --- Helper functions for building mock requests ---
def receive_wrapper(data: dict):
async def receive():
byte_data = json.dumps(data).encode("utf-8")
return {"type": "http.request", "body": byte_data, "more_body": False}
return receive
def build_post_request(data: dict = None, path_params: dict = None) -> Request:
scope = {"type": "http", "http_version": "1.1", "headers": [(b"content-type", b"application/json")], "app": None}
if path_params:
scope["path_params"] = path_params
return Request(scope, receive_wrapper(data))
def build_get_request(path_params: dict) -> Request:
scope = {"type": "http", "http_version": "1.1", "query_string": b"", "app": None}
if path_params:
scope["path_params"] = path_params
async def receive():
return {"type": "http.disconnect"}
return Request(scope, receive)
# --- Helper: poll for task completion ---
async def wait_for_task(a2a_agent, task_id, max_retries=30):
"""Poll on_get_task until the task reaches a terminal state."""
for _ in range(max_retries):
request = build_get_request({"id": task_id})
result = await a2a_agent.on_get_task(request=request, context=None)
state = result.get("status", {}).get("state", "")
if state in ["completed", "failed"]:
return result
await asyncio.sleep(1)
return result
def print_task_answer(result):
"""Extract and print the answer from task artifacts."""
print(f"Status: {result.get('status', {}).get('state')}")
for artifact in result.get("artifacts", []):
if artifact.get("parts") and "text" in artifact["parts"][0]:
print(f"Answer: {artifact['parts'][0]['text']}")
# --- Local test ---
async def main():
# Create and set up the A2A agent locally
a2a_agent = A2aAgent(agent_card=agent_card, agent_executor_builder=ReservationAgentExecutor)
a2a_agent.set_up()
# 1. Get agent card
print("=" * 50)
print("1. Retrieving agent card...")
print("=" * 50)
request = build_get_request(None)
card_response = await a2a_agent.handle_authenticated_agent_card(request=request, context=None)
print(f"Agent: {card_response.get('name')}")
print(f"Skills: {[s.get('name') for s in card_response.get('skills', [])]}")
# 2. Create a reservation
print("\n" + "=" * 50)
print("2. Creating a reservation...")
print("=" * 50)
message_data = {
"message": {
"messageId": f"msg-{os.urandom(4).hex()}",
"content": [{"text": "Book a table for 2 on Saturday at 6pm. Name: Bob, Phone: 555-0202"}],
"role": "ROLE_USER",
},
}
request = build_post_request(message_data)
response = await a2a_agent.on_message_send(request=request, context=None)
task_id = response["task"]["id"]
context_id = response["task"].get("contextId")
print(f"Task ID: {task_id}")
# 3. Wait for result
print("\n" + "=" * 50)
print("3. Waiting for task result...")
print("=" * 50)
result = await wait_for_task(a2a_agent, task_id)
print_task_answer(result)
# 4. Check the reservation (same context for session continuity)
print("\n" + "=" * 50)
print("4. Checking the reservation...")
print("=" * 50)
check_data = {
"message": {
"messageId": f"msg-{os.urandom(4).hex()}",
"content": [{"text": "Check the reservation for 555-0202"}],
"role": "ROLE_USER",
"contextId": context_id,
},
}
request = build_post_request(check_data)
check_response = await a2a_agent.on_message_send(request=request, context=None)
check_result = await wait_for_task(a2a_agent, check_response["task"]["id"])
print_task_answer(check_result)
# 5. Cancel the reservation
print("\n" + "=" * 50)
print("5. Cancelling the reservation...")
print("=" * 50)
cancel_data = {
"message": {
"messageId": f"msg-{os.urandom(4).hex()}",
"content": [{"text": "Cancel the reservation for 555-0202"}],
"role": "ROLE_USER",
"contextId": context_id,
},
}
request = build_post_request(cancel_data)
cancel_response = await a2a_agent.on_message_send(request=request, context=None)
cancel_result = await wait_for_task(a2a_agent, cancel_response["task"]["id"])
print_task_answer(cancel_result)
print("\n" + "=" * 50)
print("All tests passed!")
print("=" * 50)
if __name__ == "__main__":
asyncio.run(main())
Test komut dosyası, önceki adımda oluşturduğunuz aracı kartını ve yürütücüyü içe aktarır. Bu nedenle, herhangi bir kopya oluşturulmaz. Bu işlem, yerel bir A2aAgent oluşturur, sahte HTTP istekleri aracılığıyla A2A protokolü çağrılarını simüle eder ve üç rezervasyon işleminin tümünü doğrular.
Yerel olarak GOOGLE_CLOUD_AGENT_ENGINE_ID ayarlanmadığından yürütücü InMemorySessionService kullanır. Agent Runtime'a dağıtıldığında aynı yürütücü, kalıcı oturumlar için otomatik olarak VertexAiSessionService'a geçer.
Testi çalıştırın
PYTHONPATH=. uv run python scripts/test_a2a_agent_local.py
Çıkış beş aşamadan geçer:
- Ajan kartı: Ajanın yeteneklerini ve becerilerini alır.
- Rezervasyon oluştur: Masa ayırtır ve onay içeren bir görev döndürür.
- Get task result: Tamamlanan görevi yanıtla birlikte alır.
- Rezervasyonu kontrol et: Telefon numarasına göre rezervasyonu arar.
- Rezervasyonu iptal et: Rezervasyonu iptal eder ve onaylar.
Aşağıdaki gibi bir çıktı örneği
================================================== 1. Retrieving agent card... ================================================== Agent: Reservation Agent Skills: ['Restaurant Reservations'] ================================================== 2. Creating a reservation... ================================================== Task ID: f7f7004d-cfea-49c2-b57d-5bca9959e193 ================================================== 3. Waiting for task result... ================================================== Status: TASK_STATE_COMPLETED Answer: Your reservation for Bob, party of 2, on Saturday at 6:00 PM has been confirmed. The phone number associated is 555-0202. ================================================== 4. Checking the reservation... ================================================== Status: TASK_STATE_COMPLETED Answer: I found a reservation for Bob, party of 2, on Saturday at 6:00 PM. The reservation status is confirmed. ================================================== 5. Cancelling the reservation... ================================================== Status: TASK_STATE_COMPLETED Answer: Your reservation for Bob (555-0202) has been cancelled. ================================================== All tests passed! ==================================================
Bu noktada şunları doğrulamış olursunuz: A2A aracı kartı doğru becerileri açıklıyor, üç rezervasyon işlemi de A2A protokolünün mesaj/görev akışı üzerinden çalışıyor ve durum aynı bağlamdaki mesajlarda kalıcı oluyor.
8. Rezervasyon aracısını Agent Runtime'a dağıtma
Bu adımda, rezervasyon temsilcisi Gemini Enterprise Agent Platform Runtime'a dağıtılır. Bu platform, temsilcinizi barındıran ve güvenli bir A2A uç noktası olarak kullanıma sunan, tümüyle yönetilen bir sunucusuz platformdur. Dağıtımdan sonra, yetkili tüm istemciler standart A2A HTTP uç noktaları aracılığıyla aracıyı keşfedebilir ve onunla etkileşimde bulunabilir.
Hazırlama paketi oluşturma
Agent Runtime hazırlığı için bir Cloud Storage paketi oluşturun. Agent Runtime, dağıtım sırasında aracınızın kodunu ve bağımlılarını yüklemek için bu paketi kullanır:
STAGING_BUCKET="${GOOGLE_CLOUD_PROJECT}-adk-a2a-agent-runtime"
gsutil mb -l $REGION -p $GOOGLE_CLOUD_PROJECT gs://$STAGING_BUCKET 2>/dev/null || echo "Bucket already exists"
echo "STAGING_BUCKET=$STAGING_BUCKET" >> .env
source .env
Dağıtım komut dosyasını oluşturma
Ardından, dağıtım komut dosyasını hazırlamamız gerekir.
cloudshell edit scripts/deploy_a2a_agent_runtime.py
Aşağıdakileri scripts/deploy_a2a_agent_runtime.py içine kopyalayın:
# scripts/deploy_a2a_agent_runtime.py
import os
from pathlib import Path
import vertexai
from dotenv import load_dotenv
from google.genai import types
from vertexai.preview.reasoning_engines import A2aAgent
from reservation_agent.a2a_config import agent_card
from reservation_agent.executor import ReservationAgentExecutor
load_dotenv()
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
REGION = os.environ["REGION"]
STAGING_BUCKET = os.environ.get("STAGING_BUCKET", f"{PROJECT_ID}-adk-a2a-agent-runtime")
BUCKET_URI = f"gs://{STAGING_BUCKET}"
a2a_agent = A2aAgent(
agent_card=agent_card,
agent_executor_builder=ReservationAgentExecutor,
)
def main():
vertexai.init(project=PROJECT_ID, location=REGION, staging_bucket=BUCKET_URI)
client = vertexai.Client(
project=PROJECT_ID,
location=REGION,
http_options=types.HttpOptions(api_version="v1beta1"),
)
print("Deploying Reservation Agent to Agent Runtime...")
print("This may take 3-5 minutes.")
remote_agent = client.agent_engines.create(
agent=a2a_agent,
config={
"display_name": agent_card.name,
"description": agent_card.description,
"requirements": [
"google-cloud-aiplatform[agent_engines,adk]==1.149.0",
"a2a-sdk==0.3.26",
"google-adk==1.29.0",
"cloudpickle",
"pydantic"
],
"extra_packages": [
"./reservation_agent",
],
"http_options": {
"api_version": "v1beta1",
},
"staging_bucket": BUCKET_URI,
},
)
resource_name = remote_agent.api_resource.name
print(f"\nDeployment complete!")
print(f"Resource name: {resource_name}")
env_path = Path(".env")
lines = env_path.read_text().splitlines() if env_path.exists() else []
lines = [l for l in lines if not l.startswith("RESERVATION_AGENT_RESOURCE_NAME=")]
lines.append(f"RESERVATION_AGENT_RESOURCE_NAME={resource_name}")
env_path.write_text("\n".join(lines) + "\n")
print("Written RESERVATION_AGENT_RESOURCE_NAME to .env")
if __name__ == "__main__":
main()
Dağıtım komut dosyası, yerel testte kullanılan aynı agent_card ve ReservationAgentExecutor öğelerini içe aktarır. Bu sayede kod tekrarı olmaz. Agent Runtime, dağıtım için A2aAgent nesnesini bağımlılıklarıyla birlikte serileştirir (pickle). Dağıtım komut dosyasının sonunda, RESERVATION_AGENT_RESOURCE_NAME değerini .env dosyasına yazar.
Agent Runtime'a dağıtma
Dağıtım komut dosyasını çalıştırın:
PYTHONPATH=. uv run python scripts/deploy_a2a_agent_runtime.py
Dağıtım işlemi 3-5 dakika sürer. Komut dosyası, rezervasyon aracısını barındıran Agent Runtime üzerinde sunucusuz bir uç nokta sağlar. Başarılı dağıtımın ardından aşağıdakine benzer bir çıkış görürsünüz.
Deploying Reservation Agent to Agent Runtime... This may take 3-5 minutes. Deployment complete! Resource name: projects/your-project-number/locations/us-central1/reasoningEngines/your-agent-deployment-unique-id Written RESERVATION_AGENT_RESOURCE_NAME to .env
Dağıtılan aracı Cloud Console'da görüntüleyebilirsiniz. Konsol arama çubuğunda Agent Platform araması yapın.

Ardından, soldaki sekmede Agents simgesinin üzerine gelin ve Deployments simgesini seçin.

Reservation Agent öğesini, aşağıdaki örnekte gösterildiği gibi dağıtım listesinde görürsünüz.

Dağıtılan temsilciyi test etme
Şimdi de dağıtılan aracı test etmeye ve dağıtılan aracı için bir test komut dosyası oluşturmaya hazırız:
cloudshell edit scripts/test_a2a_agent_runtime.py
Aşağıdakileri scripts/test_a2a_agent_runtime.py içine kopyalayın:
# scripts/test_a2a_agent_runtime.py
import asyncio
import os
import time
import vertexai
from a2a.types import TaskState
from dotenv import load_dotenv
from google.genai import types
load_dotenv()
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
REGION = os.environ["REGION"]
RESOURCE_NAME = os.environ["RESERVATION_AGENT_RESOURCE_NAME"]
async def main():
vertexai.init(project=PROJECT_ID, location=REGION)
client = vertexai.Client(
project=PROJECT_ID, location=REGION,
http_options=types.HttpOptions(api_version="v1beta1"),
)
agent = client.agent_engines.get(name=RESOURCE_NAME)
# 1. Get agent card
print("=" * 50)
print("1. Retrieving agent card...")
print("=" * 50)
card = await agent.handle_authenticated_agent_card()
print(f"Agent: {card.name}")
print(f"URL: {card.url}")
print(f"Skills: {[s.name for s in card.skills]}")
# 2. Send a reservation request
print("\n" + "=" * 50)
print("2. Sending reservation request...")
print("=" * 50)
message_data = {
"messageId": "msg-remote-001",
"role": "user",
"parts": [{"kind": "text", "text": "Book a table for 3 on Sunday at noon. Name: Carol, Phone: 555-0303"}],
}
response = await agent.on_message_send(**message_data)
task_object = None
for chunk in response:
if isinstance(chunk, tuple) and len(chunk) > 0 and hasattr(chunk[0], "id"):
task_object = chunk[0]
break
task_id = task_object.id
print(f"Task ID: {task_id}")
print(f"Status: {task_object.status.state}")
# 3. Poll for result
print("\n" + "=" * 50)
print("3. Waiting for result...")
print("=" * 50)
result = None
for _ in range(30):
try:
result = await agent.on_get_task(id=task_id)
if result.status.state in [TaskState.completed, TaskState.failed]:
break
except Exception:
pass
time.sleep(1)
print(f"Final status: {result.status.state}")
if result.artifacts:
for artifact in result.artifacts:
if artifact.parts and hasattr(artifact.parts[0], "root") and hasattr(artifact.parts[0].root, "text"):
print(f"Answer: {artifact.parts[0].root.text}")
print("\n" + "=" * 50)
print("Remote agent test passed!")
print("=" * 50)
if __name__ == "__main__":
asyncio.run(main())
Ardından testi çalıştıralım.
source .env
uv run python scripts/test_a2a_agent_runtime.py
Çıkışta, "Restoran Rezervasyonları" becerisine sahip temsilci kartı ve ardından rezervasyon onayıyla tamamlanan görev gösteriliyor.
================================================== 1. Retrieving agent card... ================================================== Agent: Reservation Agent URL: https://us-central1-aiplatform.googleapis.com/v1beta1/projects/your-project-id/locations/us-central1/reasoningEngines/your-agent-unique-id/a2a Skills: ['Restaurant Reservations'] ================================================== 2. Sending reservation request... ================================================== Task ID: b34585d0-5f03-4cb0-85a3-40710a0d224d Status: TaskState.completed ================================================== 3. Waiting for result... ================================================== Final status: TaskState.completed Answer: Your reservation for Carol, party of 3 on Sunday at noon with phone number 555-0303 is confirmed. ================================================== Remote agent test passed! ==================================================
Rezervasyon aracısı artık Agent Runtime'da yönetilen bir A2A uç noktası olarak başarıyla çalışıyor.
9. A2A Reservation Agent'ı Root Restaurant Agent ile entegre etme
Bu adım, restoran ajanını yükselterek dağıtılan rezervasyon ajanını uzaktan A2A alt ajanı olarak kullanmasını sağlar. Orkestratör yerel olarak çalışırken rezervasyon aracısı, tam dağıtımdan önce A2A bağlantısını doğrulayan kısmi bir entegrasyon olan Agent Runtime'da çalışır.
A2A temsilci kartı URL'sini çözme
RemoteA2aAgent, yeteneklerini keşfetmek için dağıtılan rezervasyon aracısının kart URL'sine ihtiyaç duyar. Bu URL'yi Agent Runtime'dan getiren ve restoran aracısının .env alanına yazan bir komut dosyası oluşturun:
cloudshell edit scripts/resolve_agent_card_url.py
Aşağıdakileri scripts/resolve_agent_card_url.py içine kopyalayın:
# scripts/resolve_agent_card_url.py
import asyncio
import os
from pathlib import Path
import vertexai
from dotenv import load_dotenv
from google.genai import types
load_dotenv()
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
REGION = os.environ["REGION"]
RESOURCE_NAME = os.environ["RESERVATION_AGENT_RESOURCE_NAME"]
async def main():
vertexai.init(project=PROJECT_ID, location=REGION)
client = vertexai.Client(
project=PROJECT_ID, location=REGION,
http_options=types.HttpOptions(api_version="v1beta1"),
)
agent = client.agent_engines.get(name=RESOURCE_NAME)
card = await agent.handle_authenticated_agent_card()
card_url = f"{card.url}/v1/card"
print(f"Agent: {card.name}")
print(f"Card URL: {card_url}")
# Write to restaurant_agent/.env
# Write to both restaurant_agent/.env (for adk web) and root .env (for Cloud Run deploy)
for env_path in [Path("restaurant_agent/.env"), Path(".env")]:
lines = env_path.read_text().splitlines() if env_path.exists() else []
lines = [l for l in lines if not l.startswith("RESERVATION_AGENT_CARD_URL=")]
lines.append(f"RESERVATION_AGENT_CARD_URL={card_url}")
env_path.write_text("\n".join(lines) + "\n")
print(f"Written RESERVATION_AGENT_CARD_URL to {env_path}")
if __name__ == "__main__":
asyncio.run(main())
.env dosyasını aracı kartı URL'siyle doldurmak için komut dosyasını çalıştırın.
uv run python scripts/resolve_agent_card_url.py
source .env
Restoran temsilcisini güncelleme
Restoran temsilcisi dosyasını açın:
cloudshell edit restaurant_agent/agent.py
Ardından, içeriği, alt ajan olarak uzaktan rezervasyon ajanını içeren güncellenmiş sürümle değiştirin:
# restaurant_agent/agent.py
import os
import httpx
from google.adk.agents import LlmAgent
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.auth import default
from google.auth.transport.requests import Request as AuthRequest
from toolbox_adk import ToolboxToolset
TOOLBOX_URL = os.environ.get("TOOLBOX_URL", "http://127.0.0.1:5000")
RESERVATION_AGENT_CARD_URL = os.environ.get("RESERVATION_AGENT_CARD_URL", "")
toolbox = ToolboxToolset(TOOLBOX_URL)
class GoogleCloudAuth(httpx.Auth):
"""Auto-refreshing Google Cloud authentication for httpx.
Refreshes the access token before each request if expired,
so long-running agents never hit 401 errors.
"""
def __init__(self):
self.credentials, _ = default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
def auth_flow(self, request):
# Refresh the token if it is expired or missing
if not self.credentials.valid:
self.credentials.refresh(AuthRequest())
request.headers["Authorization"] = f"Bearer {self.credentials.token}"
yield request
reservation_remote_agent = RemoteA2aAgent(
name="reservation_agent",
description="Handles restaurant table reservations — create, check, and cancel bookings. Delegate to this agent when the user wants to book a table, check a reservation, or cancel a reservation.",
agent_card=RESERVATION_AGENT_CARD_URL,
httpx_client=httpx.AsyncClient(auth=GoogleCloudAuth(), timeout=60),
)
root_agent = LlmAgent(
name="restaurant_agent",
model="gemini-2.5-flash",
instruction="""You are a friendly and knowledgeable concierge at "Foodie Finds," a restaurant. Your job:
- Help diners browse the menu by category or cuisine type.
- Provide full details about specific dishes, including ingredients, price, and dietary information.
- Recommend dishes based on natural language descriptions of what the diner is craving.
- Add new menu items when asked.
- For reservation requests (booking, checking, or cancelling tables), delegate to the reservation_agent.
When a diner asks about a specific dish by name or cuisine, use the get-item-details tool.
When a diner asks for a specific category or cuisine type, use the search-menu tool.
When a diner describes what kind of food they want — by flavor, texture, dietary needs, or cravings — use the search-menu-by-description tool for semantic search.
When in doubt between search-menu and search-menu-by-description, prefer search-menu-by-description — it searches dish descriptions and finds more relevant matches.
If a dish is not available (available is false), let the diner know and suggest similar alternatives from the search results.
Be conversational, knowledgeable, and concise.""",
tools=[toolbox],
sub_agents=[reservation_remote_agent],
)
Önceki sürüme kıyasla öne çıkan değişiklikler:
GoogleCloudAuth: Her istekten önce Google Cloud erişim jetonunu yenileyen özel birhttpx.Authişleyicisi. Agent Runtime, kimliği doğrulanmış A2A çağrıları gerektirir ve jetonların süresi belirli bir süre sonra dolar.RemoteA2aAgent,.env'den (çözümleme komut dosyası tarafından yazılır)RESERVATION_AGENT_CARD_URLdeğerini okur ve kimliği doğrulanmışhttpx_clientdeğerini kullanır.- Alt acente olarak kaydedilmişse: ADK'nin düzenleyicisi, rezervasyon isteklerini otomatik olarak bu acenteye devreder.
- Rezervasyon yetkisinden bahsetmek için talimat güncellendi
Entegre temsilciyi yerel olarak test etme
Başlangıç aracısı için MCP Toolbox ile entegrasyon gerekiyordu. Gerekli dosya, önceki codelab'den veya başlangıç deposundan sağlanmış olmalıdır. Yalnızca araç kutusu sürecinin düzgün şekilde çalıştığından emin olmamız gerekir.
.env içindeki TOOLBOX_URL, halihazırda bir Cloud Run hizmetine (önceki codelab'den veya başlangıç deposunun full_setup.sh'sından) işaret ediyorsa bu adımı atlayabilirsiniz. Aracı, dağıtılan araç kutusuna bağlanır.
Bunun yerine yerel bir Toolbox'a ihtiyacınız varsa yeni bir örnek başlatmadan önce Toolbox'ın çalışıp çalışmadığını kontrol edin:
if curl -s http://127.0.0.1:5000/api/toolsets > /dev/null 2>&1; then
echo "Toolbox already running on port 5000"
else
set -a; source .env; set +a
./toolbox --config=tools.yaml > logs/toolbox.log 2>&1 &
echo "Toolbox started"
fi
Ardından, ADK web geliştirme kullanıcı arayüzü üzerinden restoran temsilcisiyle etkileşim kurmayı deneyebiliriz.
uv run adk web --allow_origins "regex:https://.*\.cloudshell\.dev" --port 8080
Cloud Shell Web Önizlemesi'ni kullanarak ADK web kullanıcı arayüzünü açın (Web Önizlemesi düğmesini tıklayın, bağlantı noktasını 8080 olarak değiştirin) ve ardından restaurant_agent seçeneğini belirleyin.

Karışık bir görüşmeyi test etme:
Menü Sorgusu
What Italian dishes do you have?
Rezervasyon isteği
I want to create reservation under name Bob, phone number 123456
Rezervasyonu kontrol etme
Yeni oturum oluşturma ( yeni bir görüşme başlatma):
Check the reservation for 123456



adk web işlemini Ctrl+C tuşlarına iki kez basarak durdurun. Ardından, sistemi tamamlamak için aracı tamamen dağıtalım.
10. Güncellenen restoran aracısını Cloud Run'a dağıtma
Bu adımda, restoran temsilcisi A2A entegrasyonuyla Cloud Run'a yeniden dağıtılır ve tamamen dağıtılmış çok temsilcili sistem tamamlanır.
Agent Runtime'a erişim izni verme
Cloud Run hizmet hesabının Agent Runtime'ı çağırma izni olması gerekir. Varsayılan Compute Engine hizmet hesabına roles/aiplatform.user rolünü verin:
PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format='value(projectNumber)')
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/aiplatform.user"
Cloud Run'a dağıtma
Bu kurulumda, restoran temsilcisi hizmetinin önceki codelab'den veya sıfırdan başlıyorsanız scripts/full_setup.sh komutunu çalıştırarak zaten mevcut olduğunu varsayıyoruz. Bu, güncellenmiş kodla (yeni RemoteA2aAgent entegrasyonu) yeniden dağıtılır ve rezervasyon aracısı kartı URL'sini yeni bir ortam değişkeni olarak ekler. Mevcut ortam değişkenleri (TOOLBOX_URL, GOOGLE_CLOUD_PROJECT vb.) korunur:
gcloud run deploy restaurant-agent \
--source . \
--region=$REGION \
--allow-unauthenticated \
--update-env-vars="RESERVATION_AGENT_CARD_URL=$RESERVATION_AGENT_CARD_URL" \
--min-instances=0 \
--max-instances=1 \
--memory=1Gi \
--port=8080
Tamamen dağıtılmış sistemi test etme
Dağıtılan hizmet URL'sini alma:
AGENT_URL=$(gcloud run services describe restaurant-agent --region=$REGION --format='value(status.url)')
echo "Agent URL: $AGENT_URL"
URL'yi tarayıcınızda açın. ADK web kullanıcı arayüzü yüklenir. Bu, yerel olarak kullandığınız ve artık Cloud Run'da çalışan arayüzdür.
Temsilciyle sohbet edebilirsiniz.
Menü Sorgusu
What spicy dishes do you have?
Rezervasyon isteği
Book a table for 4 on Friday at 7pm. Name: Eve, Phone: 555-0505
Rezervasyonu kontrol etme
Yeni oturum oluşturma ( yeni bir görüşme başlatma):
Check reservation for 555-0505


Çoklu ajan sistemi tamamen dağıtılır. Cloud Run'daki restoran aracısı, iki arka uç hizmeti arasında düzenleme yapar: menü işlemleri için MCP Toolbox ve Agent Runtime'da A2A rezervasyon aracısı.
11. Tebrikler!
Google Cloud'da A2A protokolünü kullanarak çoklu ajan sistemi oluşturup dağıttınız.
Öğrendikleriniz
- Veritabanı olmadan rezervasyon verilerini yönetmek için oturum durumunu (
ToolContext) kullanan bir ADK aracısı oluşturdu. - Agent Platform SDK'yı kullanarak Agent Runtime'a A2A aracısı dağıtma
RemoteA2aAgent'yı alt ajan olarak kullanarak başka bir ADK ajanından uzaktan A2A ajanı tüketme- Sistemi kademeli olarak test ettik: yerel A2A → dağıtılan A2A → kısmi entegrasyon → tam dağıtım
Temizleme
Google Cloud hesabınızın ücretlendirilmesini önlemek için bu codelab'de oluşturulan kaynakları silin.
1. seçenek: Projeyi silme (önerilir)
gcloud projects delete $GOOGLE_CLOUD_PROJECT
2. seçenek: Kaynakları tek tek silme
# Delete the Agent Runtime deployment
uv run python -c "
import vertexai
from google.genai import types
vertexai.init(project='$GOOGLE_CLOUD_PROJECT', location='$REGION')
client = vertexai.Client(
project='$GOOGLE_CLOUD_PROJECT', location='$REGION',
http_options=types.HttpOptions(api_version='v1beta1'),
)
agent = client.agent_engines.get(name='$RESERVATION_AGENT_RESOURCE_NAME')
agent.delete(force=True)
print('Agent Runtime deployment deleted.')
"
# Delete Cloud Run services
gcloud run services delete restaurant-agent --region=$REGION --quiet
gcloud run services delete toolbox-service --region=$REGION --quiet
# Delete Cloud SQL instance
gcloud sql instances delete $DB_INSTANCE --quiet
# Delete GCS staging bucket
gsutil rm -r gs://$STAGING_BUCKET