1. Giriş
Aracılar arası (A2A) protokolü, özellikle harici sistemlerde dağıtılanlar için yapay zeka aracıları arasındaki iletişimi standartlaştırmak üzere tasarlanmıştır. Daha önce, bu tür protokoller Model Context Protocol (MCP) adı verilen Araçlar için oluşturulmuştu. MCP, LLM'leri veriler ve kaynaklarla bağlamak için geliştirilen bir standarttır. A2A, farklı bir soruna odaklanırken MCP'yi tamamlamaya çalışır. MCP, aracıları araçlara ve verilere bağlamak için karmaşıklığı azaltmaya odaklanırken A2A, aracıların doğal yöntemleriyle işbirliği yapmasını nasıl sağlayacağına odaklanır. Bu sayede temsilciler, araç olarak değil temsilci (veya kullanıcı) olarak iletişim kurabilir. Örneğin, bir şey sipariş etmek istediğinizde karşılıklı iletişime olanak tanır.
A2A, MCP'yi tamamlayacak şekilde konumlandırılmıştır. Resmi belgelerde, uygulamaların araçlar için MCP'yi, AgentCard ile temsil edilen aracılar için ise A2A'yı kullanması önerilir ( Bunu daha sonra ele alacağız). Ardından, çerçeveler kullanıcıları, uzak aracıları ve diğer aracılarla iletişim kurmak için A2A'yı kullanabilir.
Bu demoda, Python SDK'sını kullanarak A2A'nın uygulanmasıyla başlayacağız. Siparişimizle ilgilenmek için hamburger ve pizza satıcısı temsilcileriyle iletişim kurmamıza yardımcı olabilecek kişisel bir satın alma danışmanımız olduğunda nasıl bir kullanım durumuyla karşılaşacağımızı inceleyeceğiz.
A2A, istemci-sunucu ilkesini kullanır. Bu demoda bekleyeceğimiz tipik A2A akışı aşağıda verilmiştir.
- A2A istemcisi, önce erişilebilen tüm A2A sunucu aracı kartlarında keşif yapar ve bağlantı istemcisi oluşturmak için bu kartlardaki bilgileri kullanır.
- Gerektiğinde A2A İstemcisi, A2A Sunucusu'na bir mesaj gönderir. Sunucu bu mesajı tamamlanacak bir Görev olarak değerlendirir. A2A istemcisinde anlık bildirim alıcı URL'si yapılandırılmışsa ve A2A sunucusu tarafından destekleniyorsa sunucu, görev ilerleme durumunu istemcideki alıcı uç noktaya da yayınlayabilir.
- Görev tamamlandıktan sonra A2A sunucusu, yanıt yapısını A2A istemcisine gönderir.
Bu codelab'de aşağıdaki gibi adım adım bir yaklaşım kullanacaksınız:
- Google Cloud projenizi hazırlayın ve gerekli tüm API'leri etkinleştirin.
- Kodlama ortamınız için çalışma alanı oluşturma
- Burger ve pizza aracısı hizmetleri için ortam değişkenlerini hazırlayın ve yerel olarak deneyin.
- Hamburger ve pizza aracısını Cloud Run'a dağıtma
- A2A sunucusunun nasıl oluşturulduğuyla ilgili ayrıntıları inceleyin.
- Satın alma asistanı için ortam değişkenlerini hazırlama ve yerel olarak deneme
- Satın alma danışmanını Agent Engine'e dağıtma
- Yerel arayüz üzerinden aracı motoruna bağlanma
- A2A istemcisinin nasıl oluşturulduğu ve veri modellemesiyle ilgili ayrıntıları inceleyin.
- A2A istemcisi ile sunucu arasındaki yükü ve etkileşimi inceleme
Mimariye Genel Bakış
Aşağıdaki hizmet mimarisini dağıtacağız
A2A sunucusu olarak işlev görecek 2 hizmet dağıtacağız: Burger aracısı ( CrewAI aracı çerçevesi tarafından desteklenir) ve Pizza aracısı ( Langgraph aracı çerçevesi tarafından desteklenir). Kullanıcı yalnızca A2A istemcisi olarak işlev görecek Aracı Geliştirme Kiti (ADK) çerçevesi kullanılarak çalıştırılacak olan Satın Alma danışmanı ile doğrudan etkileşim kuracak.
Bu aracıların her biri kendi ortamına ve kendi dağıtımına sahip olur.
Ön koşullar
- Python ile rahatça çalışabilme
- HTTP hizmetini kullanan temel tam yığın mimarisi hakkında bilgi sahibi olma
Neler öğreneceksiniz?
- A2A sunucusunun temel yapısı
- A2A istemcisinin temel yapısı
- Aracı hizmetini Cloud Run'a dağıtma
- Aracı hizmetini Agent Engine'e dağıtma
- A2A istemcisi, A2A sunucusuna nasıl bağlanır?
- Akışkan olmayan bağlantıda istek ve yanıt yapısı
Gerekenler
- Chrome web tarayıcısı
- Gmail hesabı
- Faturalandırmanın etkin olduğu bir Cloud projesi
Her seviyeden geliştirici (yeni başlayanlar dahil) için tasarlanan bu codelab'de örnek uygulamada Python kullanılmaktadır. Ancak sunulan kavramları anlamak için Python bilgisi gerekmez.
2. Başlamadan önce
Cloud Console'da Etkin Projeyi Seçme
Bu codelab'de, faturalandırmanın etkin olduğu bir Google Cloud projenizin olduğu varsayılmaktadır. Henüz kullanmıyorsanız başlamak için aşağıdaki talimatları uygulayabilirsiniz.
- Google Cloud Console'daki proje seçici sayfasında bir Google Cloud projesi seçin veya oluşturun.
- Cloud projeniz için faturalandırmanın etkinleştirildiğinden emin olun. Faturalandırmanın bir projede etkin olup olmadığını kontrol etmeyi öğrenin.
Cloud Shell Terminal'de Cloud projesi oluşturma
- bq'nun önceden yüklendiği, Google Cloud'da çalışan bir komut satırı ortamı olan Cloud Shell'i kullanacaksınız. Google Cloud Console'un üst kısmından Cloud Shell'i etkinleştir'i tıklayın. Yetkilendirmeniz istenirse Yetkilendir'i tıklayın.
- Cloud Shell'e bağlandıktan sonra aşağıdaki komutu kullanarak kimliğinizin doğrulanmış olduğunu ve projenin proje kimliğinize ayarlandığını kontrol edin:
gcloud auth list
- gcloud komutunun projeniz hakkında bilgi sahibi olduğunu doğrulamak için Cloud Shell'de aşağıdaki komutu çalıştırın.
gcloud config list project
- Projeniz ayarlanmamışsa ayarlamak için aşağıdaki komutu kullanın:
gcloud config set project <YOUR_PROJECT_ID>
Alternatif olarak, PROJECT_ID
kimliğini konsolda da görebilirsiniz.
Bu seçeneği tıkladığınızda sağ tarafta tüm projenizi ve proje kimliğini görürsünüz.
- Aşağıda gösterilen komutu kullanarak gerekli API'leri etkinleştirin. Bu işlem birkaç dakika sürebilir. Lütfen bekleyin.
gcloud services enable aiplatform.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
cloudresourcemanager.googleapis.com
Komut başarıyla yürütüldüğünde aşağıda gösterilene benzer bir mesaj görürsünüz:
Operation "operations/..." finished successfully.
Gcloud komutuna alternatif olarak, her ürünü arayarak veya bu bağlantıyı kullanarak konsolu kullanabilirsiniz.
Herhangi bir API atlanırsa uygulama sırasında istediğiniz zaman etkinleştirebilirsiniz.
gcloud komutları ve kullanımı için belgelere bakın.
Cloud Shell Düzenleyici'ye gidin ve uygulama çalışma dizinini ayarlayın
Şimdi kod düzenleyicimizi bazı kodlama işlemleri yapacak şekilde ayarlayabiliriz. Bu işlem için Cloud Shell Düzenleyici'yi kullanacağız.
- Düzenleyiciyi aç düğmesini tıklayın. Bu işlemle Cloud Shell Düzenleyici açılır. Kodumuzu buraya yazabiliriz.
- Cloud Code projesinin, aşağıdaki resimde vurgulandığı gibi Cloud Shell düzenleyicisinin sol alt köşesinde (durum çubuğu) ayarlandığından ve faturalandırmanın etkin olduğu etkin Google Cloud projesine ayarlandığından emin olun. İstenirse Yetkilendir'i seçin. Önceki komutu zaten uyguladıysanız düğme, oturum açma düğmesi yerine doğrudan etkinleştirilmiş projenize de yönlendirebilir.
- Ardından, bu codelab için şablon çalışma dizinini GitHub'dan klonlayalım. Bunun için aşağıdaki komutu çalıştırın. Çalışma dizini, purchasing-concierge-a2a dizininde oluşturulur.
git clone https://github.com/alphinside/purchasing-concierge-intro-a2a-codelab-starter.git purchasing-concierge-a2a
- Ardından Cloud Shell Düzenleyici'nin üst bölümüne gidip File->Open Folder'ı (Dosya->Klasörü Aç) tıklayın, username (kullanıcı adı) dizininizi ve purchasing-concierge-a2a dizinini bulup Tamam düğmesini tıklayın. Bu işlem, seçilen dizini ana çalışma dizini yapar. Bu örnekte, kullanıcı adı alvinprayuda olduğundan dizin yolu aşağıda gösterilmiştir.
Cloud Shell Düzenleyiciniz artık aşağıdaki gibi görünmelidir.
Ortam Kurulumu
Bir sonraki adım, geliştirme ortamını hazırlamaktır. Mevcut etkin terminaliniz purchasing-concierge-a2a çalışma dizininde olmalıdır. Bu codelab'de Python 3.12'yi kullanacağız. Python sürümü ve sanal ortam oluşturma ve yönetme ihtiyacını basitleştirmek için uv python proje yöneticisini kullanacağız.
- Terminali henüz açmadıysanız Terminal -> Yeni Terminal'i tıklayarak açın veya Ctrl + Üst Karakter + C tuşlarını kullanın. Bu tuşlar, tarayıcının alt kısmında bir terminal penceresi açar.
- Şimdi
uv
kullanarak satın alma danışmanının sanal ortamını başlatalım (Cloud Terminal'de önceden yüklenmiştir). Bu komutu çalıştırın:
uv sync --frozen
Bu işlem, .venv dizinini oluşturur ve bağımlılıkları yükler. pyproject.toml dosyasına hızlıca göz atarak, bağımlılıklar hakkında aşağıdaki gibi bilgiler edinebilirsiniz.
dependencies = [ "a2a-sdk>=0.2.16", "google-adk>=1.8.0", "gradio>=5.38.2", ]
- Sanal ortamı test etmek için main.py adlı yeni bir dosya oluşturun ve aşağıdaki kodu kopyalayın.
def main():
print("Hello from purchasing-concierge-a2a!")
if __name__ == "__main__":
main()
- Ardından aşağıdaki komutu çalıştırın.
uv run main.py
Aşağıdaki gibi bir çıkış alırsınız.
Using CPython 3.12 Creating virtual environment at: .venv Hello from purchasing-concierge-a2a!
Bu, Python projesinin düzgün şekilde ayarlandığını gösterir.
Şimdi bir sonraki adıma geçebiliriz: Uzak satıcı aracımızı yapılandırma ve dağıtma
3. Remote Seller Agent - A2A Server'ı Cloud Run'a dağıtma
Bu adımda, kırmızı kutuyla işaretlenmiş bu iki uzaktan satıcı aracısını dağıtacağız. Hamburger temsilcisi CrewAI temsilci çerçevesi, pizza temsilcisi ise Langgraph temsilcisi tarafından desteklenir. Her ikisi de Gemini Flash 2.0 modeliyle çalışır.
Uzak Burger Aracısı'nı dağıtma
Burger aracısı kaynak kodu, remote_seller_agents/burger_agent dizinindedir. Temsilci başlatma işlemi, agent.py komut dosyasında incelenebilir. Başlatılan aracının kod snippet'i aşağıda verilmiştir.
from crewai import Agent, Crew, LLM, Task, Process
from crewai.tools import tool
...
model = LLM(
model="vertex_ai/gemini-2.5-flash-lite", # Use base model name without provider prefix
)
burger_agent = Agent(
role="Burger Seller Agent",
goal=(
"Help user to understand what is available on burger menu and price also handle order creation."
),
backstory=("You are an expert and helpful burger seller agent."),
verbose=False,
allow_delegation=False,
tools=[create_burger_order],
llm=model,
)
agent_task = Task(
description=self.TaskInstruction,
agent=burger_agent,
expected_output="Response to the user in friendly and helpful manner",
)
crew = Crew(
tasks=[agent_task],
agents=[burger_agent],
verbose=False,
process=Process.sequential,
)
inputs = {"user_prompt": query, "session_id": sessionId}
response = crew.kickoff(inputs)
return response
...
remote_seller_agents/burger_agent dizininde bulunan tüm dosyalar, aracımızı Cloud Run'a dağıtmak için yeterlidir. Böylece aracımıza hizmet olarak erişilebilir. Bu konuyu daha sonra ele alacağız. Dağıtmak için aşağıdaki komutu çalıştırın:
gcloud run deploy burger-agent \
--source remote_seller_agents/burger_agent \
--port=8080 \
--allow-unauthenticated \
--min 1 \
--region us-central1 \
--update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
--update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}
Kaynak koddan dağıtım için bir container deposu oluşturulacağı sorulursa Y yanıtını verin. Bu durum yalnızca daha önce hiç kaynaktan Cloud Run'a dağıtım yapmadıysanız meydana geliyordu. Başarılı dağıtımın ardından aşağıdaki gibi bir günlük gösterilir.
Service [burger-agent] revision [burger-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic. Service URL: https://burger-agent-xxxxxxxxx.us-central1.run.app
Buradaki xxxx
kısmı, hizmeti kullanıma sunduğumuzda benzersiz bir tanımlayıcı olacaktır. Şimdi, tarayıcı üzerinden dağıtılan bu burger temsilcisi hizmetlerinin https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
yolunu izlemeyi deneyelim. Bu, dağıtılan A2A sunucu aracısı kartına erişmek için kullanılan URL'dir.
Başarıyla dağıtılırsa https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
adresine erişirken tarayıcınızda aşağıdaki gibi bir yanıt görürsünüz :
Bu, keşif amacıyla erişilebilir olması gereken burger temsilcisi kartı bilgileridir. Bu konuyu daha sonra ele alacağız. url
değerinin burada hâlâ http://0.0.0.0:8080/
olarak ayarlandığını unutmayın. Bu url
değeri, A2A istemcisinin dış dünyadan mesaj göndermesi için gereken temel bilgidir ve düzgün şekilde yapılandırılmamıştır. Bu demo için ek bir ortam değişkeni HOST_OVERRIDE
ekleyerek bu değeri burger aracısı hizmetimizin URL'siyle güncellememiz gerekir.
Ortam değişkeni aracılığıyla temsilci kartındaki Burger Agent URL değerini güncelleme
Burger aracısı hizmetine HOST_OVERRIDE
eklemek için aşağıdaki adımları uygulayın.
- Cloud Console'unuzun üst kısmındaki arama çubuğunda Cloud Run'ı arayın.
- Daha önce dağıtılan burger-agent Cloud Run hizmetini tıklayın.
- Burger hizmeti URL'sini kopyalayın, ardından Yeni düzeltmeyi düzenle ve dağıt'ı tıklayın.
- Ardından Değişkenler ve Gizli Anahtarlar bölümünü tıklayın.
- Ardından Değişken ekle'yi tıklayın ve
HOST_OVERRIDE
değerini hizmet URL'si (https://burger-agent-xxxxxxxxx.us-central1.run.app
kalıbına sahip olan) olarak ayarlayın.
- Son olarak, hizmetinizi yeniden dağıtmak için dağıt düğmesini tıklayın.
Artık tarayıcıda burger-agent aracı kartına tekrar eriştiğinizde https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
, url
değeri doğru şekilde yapılandırılmış olacak.
Uzak Pizza Aracısını Dağıtma
Benzer şekilde, pizza aracısı kaynak kodu remote_seller_agents/pizza_agent dizinindedir. Temsilci başlatma işlemi, agent.py komut dosyasında incelenebilir. Başlatılan aracının kod snippet'i aşağıda verilmiştir.
from langchain_google_vertexai import ChatVertexAI
from langgraph.prebuilt import create_react_agent
...
self.model = ChatVertexAI(
model="gemini-2.5-flash-lite",
location=os.getenv("GOOGLE_CLOUD_LOCATION"),
project=os.getenv("GOOGLE_CLOUD_PROJECT"),
)
self.tools = [create_pizza_order]
self.graph = create_react_agent(
self.model,
tools=self.tools,
checkpointer=memory,
prompt=self.SYSTEM_INSTRUCTION,
)
...
Önceki burger-agent dağıtım adımına benzer şekilde, remote_seller_agents/pizza_agent dizininde bulunan tüm dosyalar, aracımızı Cloud Run'a dağıtmak için yeterlidir. Böylece aracımıza hizmet olarak erişilebilir. Dağıtmak için aşağıdaki komutu çalıştırın:
gcloud run deploy pizza-agent \
--source remote_seller_agents/pizza_agent \
--port=8080 \
--allow-unauthenticated \
--min 1 \
--region us-central1 \
--update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
--update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}
Başarılı dağıtımın ardından aşağıdaki gibi bir günlük gösterilir.
Service [pizza-agent] revision [pizza-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic. Service URL: https://pizza-agent-xxxxxxxxx.us-central1.run.app
Buradaki xxxx
kısmı, hizmeti kullanıma sunduğumuzda benzersiz bir tanımlayıcı olacaktır. A2A sunucu aracısı kartına erişmek için tarayıcı üzerinden dağıtılan pizza aracısı hizmetlerinin https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
rotasına gitmeye çalıştığınızda burger aracısında da aynı durum söz konusudur. Pizza aracısının, aracısı kartındaki url
değeri henüz düzgün şekilde yapılandırılmamıştır. Ayrıca, ortam değişkenine HOST_OVERRIDE
eklememiz gerekiyor.
Ortam değişkeni aracılığıyla aracı kartındaki Pizza Aracısı URL değerini güncelleme
Pizza aracısı hizmetine HOST_OVERRIDE
eklemek için aşağıdaki adımları uygulayın.
- Cloud Console'unuzun üst kısmındaki arama çubuğunda Cloud Run'ı arayın.
- Daha önce dağıtılan pizza-agent Cloud Run hizmetini tıklayın.
- Yeni düzeltmeyi düzenle ve dağıt'ı tıklayın.
- Pizza servisi URL'sini kopyalayın, ardından Variable & Secrets (Değişken ve Gizli Dizeler) bölümünü tıklayın.
- Ardından Değişken ekle'yi tıklayın ve
HOST_OVERRIDE
değerini hizmet URL'si (https://pizza-agent-xxxxxxxxx.us-central1.run.app
kalıbına sahip olan) olarak ayarlayın.
- Son olarak, hizmetinizi yeniden dağıtmak için dağıt düğmesini tıklayın.
Artık tarayıcıda pizza-agent aracı kartına tekrar eriştiğinizde https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json
değeri doğru şekilde yapılandırılmış olacak.url
Bu noktada, hem hamburger hem de pizza hizmetlerini Cloud Run'a başarıyla dağıtmış oluyoruz. Şimdi A2A sunucusunun temel bileşenlerini ele alalım.
4. A2A sunucusunun temel bileşenleri
Şimdi de A2A sunucusunun temel kavramını ve bileşenlerini ele alalım.
Aracı kartı
Her A2A sunucusunda, /.well-known/agent.json
kaynağında erişilebilen bir aracı kartı olmalıdır. Bu, A2A istemcisindeki keşif aşamasını desteklemek için yapılır. Bu aşamada, aracıya nasıl erişileceği ve tüm özelliklerinin nasıl kullanılacağı hakkında eksiksiz bilgi ve bağlamlar sağlanır. Swagger veya Postman kullanılarak iyi belgelenmiş API belgelerine benzer.
Bu, dağıtılan burger agent agent kartımızın içeriğidir.
{
"capabilities": {
"streaming": true
},
"defaultInputModes": [
"text",
"text/plain"
],
"defaultOutputModes": [
"text",
"text/plain"
],
"description": "Helps with creating burger orders",
"name": "burger_seller_agent",
"protocolVersion": "0.2.6",
"skills": [
{
"description": "Helps with creating burger orders",
"examples": [
"I want to order 2 classic cheeseburgers"
],
"id": "create_burger_order",
"name": "Burger Order Creation Tool",
"tags": [
"burger order creation"
]
}
],
"url": "https://burger-agent-109790610330.us-central1.run.app",
"version": "1.0.0"
}
Bu aracı kartlarında; aracı becerileri, yayın özellikleri, desteklenen yöntemler ve protokol sürümü gibi birçok önemli bileşen öne çıkarılır.
Tüm bu bilgiler, A2A istemcisinin düzgün iletişim kurabilmesi için uygun bir iletişim mekanizması geliştirmek amacıyla kullanılabilir. Desteklenen yöntem ve kimlik doğrulama mekanizması, iletişimin düzgün şekilde kurulabilmesini sağlar. Ayrıca, istemcinin temsilcisine çağrılacak uzak temsilci özellikleri ve becerileri hakkında bağlam bilgisi vermek için temsilci skills
bilgileri A2A istemci sistemi istemine yerleştirilebilir. Bu temsilci kartıyla ilgili daha ayrıntılı alanları bu dokümanda bulabilirsiniz.
Kodumuzda, aracı kartının uygulanması A2A Python SDK'sı kullanılarak gerçekleştirilir. Uygulama için aşağıdaki remote_seller_agents/burger_agent/main.py snippet'ini inceleyin.
...
capabilities = AgentCapabilities(streaming=True)
skill = AgentSkill(
id="create_burger_order",
name="Burger Order Creation Tool",
description="Helps with creating burger orders",
tags=["burger order creation"],
examples=["I want to order 2 classic cheeseburgers"],
)
agent_host_url = (
os.getenv("HOST_OVERRIDE")
if os.getenv("HOST_OVERRIDE")
else f"http://{host}:{port}/"
)
agent_card = AgentCard(
name="burger_seller_agent",
description="Helps with creating burger orders",
url=agent_host_url,
version="1.0.0",
defaultInputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
defaultOutputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
capabilities=capabilities,
skills=[skill],
)
...
Burada şu gibi çeşitli alanlar görebiliriz:
AgentCapabilities
: Temsilci hizmeti tarafından desteklenen ek isteğe bağlı işlevlerin (ör. akış özelliği ve/veya push bildirimi desteği) beyanıAgentSkill
: Temsilci tarafından desteklenen araçlar veya işlevlerInput/OutputModes
: Desteklenen giriş/çıkış türü modalitesiUrl
: Temsilciyle iletişim kurulacak adres
Bu yapılandırmada, yerel test ile bulut dağıtımı arasında geçişi kolaylaştırmak için dinamik aracı ana makine URL'si oluşturma özelliği sunuyoruz. Bu nedenle, önceki adımda HOST_OVERRIDE
değişkenini eklememiz gerekiyor.
Görev Sırası ve Temsilci Yürütücü
A2A sunucusu, farklı aracıların veya kullanıcıların isteklerini işleyebilir ve her görevi mükemmel bir şekilde izole edebilir. Bunların bağlamlarını daha iyi görselleştirmek için aşağıdaki resmi inceleyebilirsiniz.
Bu nedenle, her A2A sunucusu gelen görevleri izleyebilmeli ve görevlerle ilgili uygun bilgileri saklayabilmelidir. A2A SDK, A2A sunucusunda bu zorluğun üstesinden gelmek için modüller sağlar. İlk olarak, gelen isteği nasıl işlemek istediğimize dair mantık oluşturabiliriz. AgentExecutor soyut sınıfını devralarak görev yürütme ve iptal işlemlerini nasıl yönetmek istediğimizi kontrol edebiliriz. Bu örnek uygulama, remote_seller_agents/burger_agent/agent_executor.py
modülünde ( pizza satıcısı örneğinde benzer bir yol izlenir) incelenebilir.
...
class BurgerSellerAgentExecutor(AgentExecutor):
"""Burger Seller AgentExecutor."""
def __init__(self):
self.agent = BurgerSellerAgent()
async def execute(
self,
context: RequestContext,
event_queue: EventQueue,
) -> None:
query = context.get_user_input()
try:
result = self.agent.invoke(query, context.context_id)
print(f"Final Result ===> {result}")
parts = [Part(root=TextPart(text=str(result)))]
await event_queue.enqueue_event(
completed_task(
context.task_id,
context.context_id,
[new_artifact(parts, f"burger_{context.task_id}")],
[context.message],
)
)
except Exception as e:
print("Error invoking agent: %s", e)
raise ServerError(error=ValueError(f"Error invoking agent: {e}")) from e
async def cancel(
self, request: RequestContext, event_queue: EventQueue
) -> Task | None:
raise ServerError(error=UnsupportedOperationError())
...
Yukarıdaki kodda, istek geldiğinde aracının doğrudan çağrılacağı ve çağrıyı tamamladıktan sonra tamamlanan görev etkinliklerini göndereceği temel bir işleme şeması uyguluyoruz. Ancak kısa süreli bir işlem olarak değerlendirildiği için burada iptal yöntemi uygulanmadı.
Yürütücüyü oluşturduktan sonra, HTTP sunucusunu başlatmak için yerleşik DefaultRequestHandler, InMemoryTaskStore ve A2AStarletteApplication'ı doğrudan kullanabiliriz. Bu uygulama remote_seller_agents/burger_agent/__main__.py
içinde incelenebilir.
...
request_handler = DefaultRequestHandler(
agent_executor=BurgerSellerAgentExecutor(),
task_store=InMemoryTaskStore(),
)
server = A2AStarletteApplication(
agent_card=agent_card, http_handler=request_handler
)
uvicorn.run(server.build(), host=host, port=port)
...
Bu modül, /.well-known/agent.json
rota aracılığıyla aracı kartına erişmenizi ve A2A protokolünü desteklemek için POST uç noktasını kullanmanızı sağlar.
Özet
Kısacası, şu ana kadar aşağıdaki 2 işlevi destekleyebilen Python SDK'sını kullanarak bir A2A sunucusu dağıttık:
- Temsilci kartını
/.well-known/agent.json
rotasında yayınlama - JSON-RPC isteğini bellek içi görev sırasına alma ile işleme
Bu işlevlerin başlatılmasındaki giriş noktası, __main__.py
komut dosyasında ( remote_seller_agents/burger_agent
veya remote_seller_agents/pizza_agent
üzerinde) incelenebilir.
5. Satın Alma Concierge'ini A2A istemcisinden Agent Engine'e dağıtma
Bu adımda, satın alma danışmanı aracısını dağıtacağız. Etkileşim kuracağımız temsilci budur.
Satın alma concierge aracımızın kaynak kodu, purchasing_concierge dizinindedir. Aracı başlatma işlemi, purchasing_agent.py komut dosyasında incelenebilir. Başlatılan aracının kod snippet'i aşağıda verilmiştir.
from google.adk import Agent
...
def create_agent(self) -> Agent:
return Agent(
model="gemini-2.5-flash-lite",
name="purchasing_agent",
instruction=self.root_instruction,
before_model_callback=self.before_model_callback,
before_agent_callback=self.before_agent_callback,
description=(
"This purchasing agent orchestrates the decomposition of the user purchase request into"
" tasks that can be performed by the seller agents."
),
tools=[
self.send_task,
],
)
...
Bu temsilciyi temsilci motoruna dağıtacağız. Vertex AI Agent Engine, geliştiricilerin üretimde yapay zeka aracılarını dağıtmasına, yönetmesine ve ölçeklendirmesine olanak tanıyan bir hizmetler kümesidir. Üretimde aracıları ölçeklendirmek için altyapıyı yönetir. Böylece biz de uygulama oluşturmaya odaklanabiliriz. Bu konu hakkında daha fazla bilgiyi bu belgede bulabilirsiniz. Daha önce aracı hizmetimizi dağıtmak için gereken dosyaları (ör. ana sunucu komut dosyası ve Dockerfile) hazırlamamız gerekiyordu. Bu durumda, ADK ve Agent Engine'i birlikte kullanarak kendi arka uç hizmetimizi geliştirmemize gerek kalmadan aracımızı doğrudan Python komut dosyasından dağıtabiliriz. Dağıtmak için aşağıdaki adımları uygulayın :
- Öncelikle Cloud Storage'da hazırlama depolama alanımızı oluşturmamız gerekiyor.
gcloud storage buckets create gs://purchasing-concierge-{your-project-id} --location=us-central1
- Şimdi önce .env değişkenini hazırlamamız gerekiyor. .env.example dosyasını .env dosyasına kopyalayalım.
cp .env.example .env
- Şimdi .env dosyasını açtığınızda aşağıdaki içeriği görürsünüz.
GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT={your-project-id} GOOGLE_CLOUD_LOCATION=us-central1 STAGING_BUCKET=gs://purchasing-concierge-{your-project-id} PIZZA_SELLER_AGENT_URL={your-pizza-agent-url} BURGER_SELLER_AGENT_URL={your-burger-agent-url} AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}
Bu temsilci, hamburger ve pizza temsilcisiyle iletişim kuracağından her ikisi için de uygun kimlik bilgilerini sağlamamız gerekir. PIZZA_SELLER_AGENT_URL ve BURGER_SELLER_AGENT_URL parametrelerini önceki adımlardaki Cloud Run URL'siyle güncellememiz gerekir.
Bunu unutursanız Cloud Run konsolunu ziyaret edelim. Konsolunuzun üst kısmındaki arama çubuğuna "Cloud Run" yazın ve Cloud Run simgesini sağ tıklayarak yeni bir sekmede açın.
Daha önce dağıtılan uzaktan satıcı temsilcisi hizmetlerimizi aşağıda gösterildiği gibi görmelisiniz.
Bu hizmetlerin herkese açık URL'sini görmek için hizmetlerden birini tıkladığınızda Hizmet ayrıntıları sayfasına yönlendirilirsiniz. URL'yi, bölge bilgilerinin hemen yanındaki üst alanda görebilirsiniz.
Son ortam değişkeni aşağıdaki gibi görünmelidir.
GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT={your-project-id} GOOGLE_CLOUD_LOCATION=us-central1 STAGING_BUCKET=gs://purchasing-concierge-{your-project-id} PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}
- Artık satın alma danışmanı aracımızı dağıtmaya hazırız. Bu demoda, içeriğin aşağıda gösterildiği
deploy_to_agent_engine.py
komut dosyasını kullanarak dağıtım yapacağız.
"""
Copyright 2025 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import vertexai
from vertexai.preview import reasoning_engines
from vertexai import agent_engines
from dotenv import load_dotenv
import os
from purchasing_concierge.agent import root_agent
load_dotenv()
PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT")
LOCATION = os.getenv("GOOGLE_CLOUD_LOCATION")
STAGING_BUCKET = os.getenv("STAGING_BUCKET")
vertexai.init(
project=PROJECT_ID,
location=LOCATION,
staging_bucket=STAGING_BUCKET,
)
adk_app = reasoning_engines.AdkApp(
agent=root_agent,
)
remote_app = agent_engines.create(
agent_engine=adk_app,
display_name="purchasing-concierge",
requirements=[
"google-cloud-aiplatform[adk,agent_engines]",
"a2a-sdk==0.2.16",
],
extra_packages=[
"./purchasing_concierge",
],
env_vars={
"GOOGLE_GENAI_USE_VERTEXAI": os.environ["GOOGLE_GENAI_USE_VERTEXAI"],
"PIZZA_SELLER_AGENT_URL": os.environ["PIZZA_SELLER_AGENT_URL"],
"BURGER_SELLER_AGENT_URL": os.environ["BURGER_SELLER_AGENT_URL"],
},
)
print(f"Deployed remote app resource: {remote_app.resource_name}")
Bu, ADK aracımızı aracı motoruna dağıtmak için gereken adımlardır. Öncelikle ADK'mızdan AdkApp
nesnesi oluşturmamız gerekir root_agent
. Ardından, agent_engines.create
yöntemini adk_app
nesnesini sağlayarak, requirements
alanında gereksinimleri belirterek, extra_packages
alanında aracı dizini yolunu belirterek ve gerekli ortam değişkenlerini sağlayarak çalıştırabiliriz.
Komut dosyasını çalıştırarak dağıtabiliriz:
uv run deploy_to_agent_engine.py
Başarılı dağıtımın ardından aşağıdaki gibi bir günlük gösterilir. xxxx proje kimliğiniz, yyyy ise aracı motoru kaynak kimliğinizdir.
AgentEngine created. Resource name: projects/xxxx/locations/us-central1/reasoningEngines/yyyy To use this AgentEngine in another session: agent_engine = vertexai.agent_engines.get('projects/xxxx/locations/us-central1/reasoningEngines/yyyy) Deployed remote app resource: projects/xxxx/locations/us-central1/reasoningEngines/xxxx
Ayrıca, arama motoru kontrol panelinde incelediğimizde (arama çubuğunda "arama motoru" ifadesini arayın) önceki dağıtımımız gösterilir.
Dağıtılan Aracıyı Agent Engine'de Test Etme
Aracı motoruyla etkileşim, curl
komutu ve SDK aracılığıyla yapılabilir. Örneğin, dağıtılan temsilciyle etkileşim kurmayı denemek için aşağıdaki komutu çalıştırın.
Temsilcinin başarıyla dağıtılıp dağıtılmadığını kontrol etmek için bu sorguyu göndermeyi deneyebilirsiniz.
curl \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://us-central1-aiplatform.googleapis.com/v1/projects/{YOUR_PROJECT_ID}/locations/us-central1/reasoningEngines/{YOUR_AGENT_ENGINE_RESOURCE_ID}:streamQuery?alt=sse -d '{
"class_method": "stream_query",
"input": {
"user_id": "user_123",
"message": "List available burger menu please",
}
}'
Başarılı olursa konsolunuzda aşağıdaki gibi birkaç yanıt etkinliği yayınlanır.
{ "content": { "parts": [ { "text": "Here is our burger menu:\n- Classic Cheeseburger: IDR 85K\n- Double Cheeseburger: IDR 110K\n- Spicy Chicken Burger: IDR 80K\n- Spicy Cajun Burger: IDR 85K" } ], "role": "model" }, "usage_metadata": { "candidates_token_count": 51, "candidates_tokens_details": [ { "modality": "TEXT", "token_count": 51 } ], "prompt_token_count": 907, "prompt_tokens_details": [ { "modality": "TEXT", "token_count": 907 } ], "total_token_count": 958, "traffic_type": "ON_DEMAND" }, "invocation_id": "e-14679918-af68-45f1-b942-cf014368a733", "author": "purchasing_agent", "actions": { "state_delta": {}, "artifact_delta": {}, "requested_auth_configs": {} }, "id": "dbe7fc43-b82a-4f3e-82aa-dd97afa8f15b", "timestamp": 1754287348.941454 }
Bir sonraki adımda kullanıcı arayüzünü kullanmayı deneyeceğiz ancak öncelikle A2A istemcilerinin temel bileşenleri ve tipik akışı hakkında konuşalım.
6. A2A istemcisinin temel bileşenleri
Yukarıda gösterilen resim, A2A etkileşimlerinin tipik akışını göstermektedir:
- İstemci, rotadaki sağlanan uzak aracı URL'sinde yayınlanmış bir aracı kartı bulmaya çalışır
/.well-known/agent.json
- Ardından, gerektiğinde bu aracıya ileti ve gerekli meta veri parametreleriyle ( ör. oturum kimliği, geçmiş bağlam vb.) bir mesaj gönderir. Sunucu bu mesajı tamamlanması gereken bir görev olarak algılar.
- A2A sunucusu isteği işler. Sunucu anlık bildirimleri destekliyorsa görev işleme sırasında bazı bildirimleri de yayınlayabilir ( Bu işlev, bu codelab'in kapsamı dışındadır).
- İşlem tamamlandıktan sonra A2A sunucusu yanıt yapısını istemciye geri gönderir.
Yukarıdaki etkileşimlerle ilgili temel nesnelerden bazıları şunlardır (daha fazla bilgiyi burada bulabilirsiniz) :
- Mesaj: İstemci ile uzak aracı arasındaki iletişim dönüşü
- Görev: A2A tarafından yönetilen ve benzersiz bir kimlikle tanımlanan temel iş birimi
- Öğe: Aracının bir görev sonucunda oluşturduğu ve Bölümlerden oluşan çıktı (ör. belge, resim, yapılandırılmış veri)
- Bölüm: İleti veya Yapılandırma İçinde yer alan en küçük içerik birimi. Bölüm; metin, resim, video, dosya vb. olabilir.
Kart Keşfi
A2A Client hizmeti başlatıldığında, genellikle aracı kartı bilgilerini almaya ve gerektiğinde kolayca erişmek için depolamaya çalışılır. Bu codelab'de before_agent_callback
üzerinde uyguluyoruz. Uygulamayı purchasing_concierge/purchasing_agent.py
adresinde görebilirsiniz. Aşağıdaki kod snippet'ine bakın.
...
async def before_agent_callback(self, callback_context: CallbackContext):
if not self.a2a_client_init_status:
httpx_client = httpx.AsyncClient(timeout=httpx.Timeout(timeout=30))
for address in self.remote_agent_addresses:
card_resolver = A2ACardResolver(
base_url=address, httpx_client=httpx_client
)
try:
card = await card_resolver.get_agent_card()
remote_connection = RemoteAgentConnections(
agent_card=card, agent_url=card.url
)
self.remote_agent_connections[card.name] = remote_connection
self.cards[card.name] = card
except httpx.ConnectError:
print(f"ERROR: Failed to get agent card from : {address}")
agent_info = []
for ra in self.list_remote_agents():
agent_info.append(json.dumps(ra))
self.agents = "\n".join(agent_info)
...
Burada, yerleşik A2A istemci A2ACardResolver
modülünü kullanarak mevcut tüm temsilci kartlarına erişmeye çalışırız. Ardından, temsilciye mesaj göndermek için gereken bağlantıyı toplarız. Bundan sonra, mevcut tüm temsilcileri ve özelliklerini isteme listelememiz gerekir. Böylece temsilcimiz, bu temsilcilerle iletişim kurabileceğini bilir.
İstem ve Görev Gönderme Aracı
Bu, ADK temsilcimize sağladığımız istem ve araçtır.
...
def root_instruction(self, context: ReadonlyContext) -> str:
current_agent = self.check_active_agent(context)
return f"""You are an expert purchasing delegator that can delegate the user product inquiry and purchase request to the
appropriate seller remote agents.
Execution:
- For actionable tasks, you can use `send_task` to assign tasks to remote agents to perform.
- When the remote agent is repeatedly asking for user confirmation, assume that the remote agent doesn't have access to user's conversation context.
So improve the task description to include all the necessary information related to that agent
- Never ask user permission when you want to connect with remote agents. If you need to make connection with multiple remote agents, directly
connect with them without asking user permission or asking user preference
- Always show the detailed response information from the seller agent and propagate it properly to the user.
- If the remote seller is asking for confirmation, rely the confirmation question to the user if the user haven't do so.
- If the user already confirmed the related order in the past conversation history, you can confirm on behalf of the user
- Do not give irrelevant context to remote seller agent. For example, ordered pizza item is not relevant for the burger seller agent
- Never ask order confirmation to the remote seller agent
Please rely on tools to address the request, and don't make up the response. If you are not sure, please ask the user for more details.
Focus on the most recent parts of the conversation primarily.
If there is an active agent, send the request to that agent with the update task tool.
Agents:
{self.agents}
Current active seller agent: {current_agent["active_agent"]}
"""
...
async def send_task(self, agent_name: str, task: str, tool_context: ToolContext):
"""Sends a task to remote seller agent
This will send a message to the remote agent named agent_name.
Args:
agent_name: The name of the agent to send the task to.
task: The comprehensive conversation context summary
and goal to be achieved regarding user inquiry and purchase request.
tool_context: The tool context this method runs in.
Yields:
A dictionary of JSON data.
"""
if agent_name not in self.remote_agent_connections:
raise ValueError(f"Agent {agent_name} not found")
state = tool_context.state
state["active_agent"] = agent_name
client = self.remote_agent_connections[agent_name]
if not client:
raise ValueError(f"Client not available for {agent_name}")
session_id = state["session_id"]
task: Task
message_id = ""
metadata = {}
if "input_message_metadata" in state:
metadata.update(**state["input_message_metadata"])
if "message_id" in state["input_message_metadata"]:
message_id = state["input_message_metadata"]["message_id"]
if not message_id:
message_id = str(uuid.uuid4())
payload = {
"message": {
"role": "user",
"parts": [
{"type": "text", "text": task}
], # Use the 'task' argument here
"messageId": message_id,
"contextId": session_id,
},
}
message_request = SendMessageRequest(
id=message_id, params=MessageSendParams.model_validate(payload)
)
send_response: SendMessageResponse = await client.send_message(
message_request=message_request
)
print(
"send_response",
send_response.model_dump_json(exclude_none=True, indent=2),
)
if not isinstance(send_response.root, SendMessageSuccessResponse):
print("received non-success response. Aborting get task ")
return None
if not isinstance(send_response.root.result, Task):
print("received non-task response. Aborting get task ")
return None
return send_response.root.result
...
İstemde, satın alma danışmanı aracımıza mevcut tüm uzak aracıların adını ve açıklamasını veriyoruz. Araçta self.send_task
ise aracıya bağlanılacak uygun istemciyi almak ve SendMessageRequest
nesnesini kullanarak gerekli meta verileri göndermek için bir mekanizma sağlıyoruz.
İletişim Protokolleri
Görev tanımı, A2A sunucusuna ait bir alandır. Ancak A2A istemcisi açısından bu, sunucuya gönderilen bir Mesaj olarak görülür. İstemciden gelen mesajların hangi görev olarak tanımlanacağı ve görevin tamamlanması için istemciyle etkileşim gerekip gerekmediği sunucuya bağlıdır. Görev yaşam döngüsü hakkında daha fazla bilgiyi bu dokümanda bulabilirsiniz. Bu kavramın daha üst düzey bir görünümü aşağıda gösterilmiştir:
Bu mesaj -> görev değişimi, message/send
protokolünün aşağıdaki örneğinde gösterildiği gibi JSON-RPC standardının üzerinde yük biçimi kullanılarak uygulanır :
{ # identifier for this request "id": "abc123", # version of JSON-RPC protocol "jsonrpc": "2.0", # method name "method": "message/send", # parameters/arguments of the method "params": { "message": "hi, what can you help me with?" } }
Örneğin, farklı iletişim türlerini (ör. senkronizasyon, yayın, asenkron) desteklemek veya görev durumuyla ilgili bildirimleri yapılandırmak için çeşitli yöntemler kullanılabilir. A2A sunucusu, bu görev tanımı standartlarını işleyecek şekilde esnek bir şekilde yapılandırılabilir. Bu yöntemlerin ayrıntılarını bu belgede bulabilirsiniz.
7. Entegrasyon testi ve yük incelemesi
Şimdi de web kullanıcı arayüzünü kullanarak uzaktan temsilci etkileşimiyle satın alma asistanımızı inceleyelim.
Öncelikle, AGENT_ENGINE_RESOURCE_NAME
uygulamasını .env
dosyası. Doğru aracı motoru kaynak adını sağladığınızdan emin olun. .env
dosyanız şu şekilde görünmelidir:
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT={your-project-id}
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://purchasing-concierge-{your-project-id}
PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app
BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app
AGENT_ENGINE_RESOURCE_NAME=projects/xxxx/locations/us-central1/reasoningEngines/yyyy
Ardından, Gradio uygulamasını dağıtmak için aşağıdaki komutu çalıştırın.
uv run purchasing_concierge_ui.py
İşlem başarılı olursa aşağıdaki çıkış gösterilir.
* Running on local URL: http://0.0.0.0:8080 * To create a public link, set `share=True` in `launch()`.
Ardından, web kullanıcı arayüzünü açmak için terminalde http://0.0.0.0:8080 URL'sini Ctrl + tıklayın veya web önizleme düğmesini tıklayın.
Şu şekilde bir görüşme yapmayı deneyin :
- Bana burger ve pizza menüsünü göster
- 1 adet barbekü soslu tavuklu pizza ve 1 adet acı baharatlı Cajun burger sipariş etmek istiyorum.
Siparişi tamamlayana kadar sohbete devam edin. Etkileşimin nasıl ilerlediğini, araç çağrısının ve yanıtının ne olduğunu inceleyin. Aşağıdaki resimde, etkileşim sonucuna dair bir örnek verilmiştir.
2 farklı temsilciyle iletişim kurmanın 2 farklı davranışa yol açtığını ve A2A'nın bunu iyi bir şekilde ele alabildiğini görüyoruz. Pizza satıcısı temsilcisi, satın alma temsilcisi isteğimizi doğrudan kabul ederken burger temsilcisinin isteğimizle devam etmeden önce onayımızı alması gerekir. Onayımızı aldıktan sonra temsilci, burger temsilcisine onayımızı iletebilir.
Şimdi A2A'nın temel kavramlarını tamamladık ve bunun istemci ve sunucu mimarisi olarak nasıl uygulandığını görüyoruz.
8. Zorluk
Şimdi gerekli dosyayı hazırlayıp Gradio uygulamasını kendiniz Cloud Run'a dağıtabilir misiniz? Meydan okumaya katılma zamanı!
9. Temizleme
Bu codelab'de kullanılan kaynaklar için Google Cloud hesabınızın ücretlendirilmesini istemiyorsanız şu adımları uygulayın:
- Google Cloud Console'da Kaynakları yönetin sayfasına gidin.
- Proje listesinde silmek istediğiniz projeyi seçin ve Sil'i tıklayın.
- İletişim kutusunda proje kimliğini yazın ve projeyi silmek için Kapat'ı tıklayın.
- Alternatif olarak, konsolda Cloud Run'a gidebilir, yeni dağıttığınız hizmeti seçip silebilirsiniz.