Memulai Protokol Agent-to-Agent (A2A): Interaksi Agen Penjual Jarak Jauh dan Concierge Pembelian dengan Gemini di Cloud Run dan Agent Engine

1. Pengantar

b013ad6b246401eb.png

Protokol agent-to-agent (A2A) dirancang untuk menstandardisasi komunikasi antar-agen AI, terutama untuk agen yang di-deploy dalam sistem eksternal. Sebelumnya, protokol tersebut ditetapkan untuk Alat yang disebut Model Context Protocol (MCP) yang merupakan standar baru untuk menghubungkan LLM dengan data dan resource. A2A mencoba melengkapi MCP. Jika MCP berfokus pada pengurangan kompleksitas untuk menghubungkan agen dengan alat dan data, A2A berfokus pada cara memungkinkan agen berkolaborasi dalam modalitas alami mereka. Fitur ini memungkinkan agen berkomunikasi sebagai agen (atau sebagai pengguna), bukan sebagai alat; misalnya, memungkinkan komunikasi dua arah saat Anda ingin memesan sesuatu.

A2A diposisikan untuk melengkapi MCP, dalam dokumentasi resmi, aplikasi disarankan untuk menggunakan MCP untuk alat dan A2A untuk agen - yang diwakili oleh AgentCard ( Kita akan membahasnya nanti). Framework kemudian dapat menggunakan A2A untuk berkomunikasi dengan pengguna, agen jarak jauh, dan agen lainnya.

83b1a03588b90b68.png

Dalam demo ini, kita akan memulai dengan penerapan A2A menggunakan Python SDK. Kita akan mempelajari kasus penggunaan saat kita memiliki petugas pembelian pribadi yang dapat membantu kita berkomunikasi dengan agen penjual burger dan pizza untuk menangani pesanan kita.

A2A menggunakan prinsip klien-server. Berikut adalah alur A2A umum yang akan kita harapkan dalam demo ini

aa6c8bc5b5df73f1.jpeg

  1. Klien A2A akan terlebih dahulu melakukan penemuan pada semua kartu agen Server A2A yang dapat diakses dan menggunakan informasinya untuk membangun klien koneksi
  2. Jika diperlukan, Klien A2A akan mengirim pesan ke Server A2A, dan server akan mengevaluasi pesan ini sebagai Tugas yang harus diselesaikan. Jika URL penerima notifikasi push dikonfigurasi di klien A2A dan didukung oleh Server A2A, server juga akan dapat memublikasikan status progres tugas ke endpoint penerima di klien
  3. Setelah tugas selesai, server A2A akan mengirimkan artefak respons ke Klien A2A

Selama mengikuti codelab, Anda akan menggunakan pendekatan langkah demi langkah sebagai berikut:

  1. Siapkan project Google Cloud Anda dan Aktifkan semua API yang diperlukan di project tersebut
  2. Menyiapkan ruang kerja untuk lingkungan coding Anda
  3. Siapkan variabel env untuk layanan agen burger dan pizza, lalu coba secara lokal
  4. Men-deploy agen burger dan pizza ke Cloud Run
  5. Periksa detail tentang cara server A2A dibuat
  6. Siapkan variabel env untuk concierge pembelian dan coba secara lokal
  7. Men-deploy concierge pembelian ke Agent Engine
  8. Menghubungkan ke mesin agen melalui antarmuka lokal
  9. Periksa detail tentang cara klien A2A dibuat dan pemodelan datanya
  10. Memeriksa payload dan interaksi antara klien dan server A2A

Ringkasan Arsitektur

Kita akan men-deploy arsitektur layanan berikut

9cfc4582f2d8b6f3.jpeg

Kita akan men-deploy 2 layanan yang akan bertindak sebagai server A2A, agen Burger ( didukung oleh framework agen CrewAI) dan agen Pizza ( didukung oleh framework agen Langgraph). Pengguna hanya akan berinteraksi langsung dengan Purchasing concierge yang akan dijalankan menggunakan framework Agent Development Kit (ADK) yang akan bertindak sebagai klien A2A.

Setiap agen ini akan memiliki lingkungan dan deploymentnya sendiri.

Prasyarat

  • Nyaman bekerja dengan Python
  • Pemahaman tentang arsitektur full-stack dasar menggunakan layanan HTTP

Yang akan Anda pelajari

  • Struktur inti Server A2A
  • Struktur inti Klien A2A
  • Men-deploy layanan agen ke Cloud Run
  • Men-deploy layanan agen ke Agent Engine
  • Cara Klien A2A terhubung ke Server A2A
  • Struktur Permintaan dan Respons pada koneksi non-streaming

Yang Anda butuhkan

  • Browser web Chrome
  • Akun Gmail
  • Project Cloud dengan penagihan diaktifkan

Codelab ini, yang dirancang untuk developer dari semua level (termasuk pemula), menggunakan Python dalam aplikasi contohnya. Namun, pengetahuan Python tidak diperlukan untuk memahami konsep yang disajikan.

2. Sebelum memulai

Pilih Project Aktif di Konsol Cloud

Codelab ini mengasumsikan bahwa Anda sudah memiliki project Google Cloud dengan penagihan yang diaktifkan. Jika belum memilikinya, Anda dapat mengikuti petunjuk di bawah untuk memulai.

  1. Di Konsol Google Cloud, di halaman pemilih project, pilih atau buat project Google Cloud.
  2. Pastikan penagihan diaktifkan untuk project Cloud Anda. Pelajari cara memeriksa apakah penagihan telah diaktifkan pada suatu project.

bc8d176ea42fbb7.png

Menyiapkan Project Cloud di Terminal Cloud Shell

  1. Anda akan menggunakan Cloud Shell, lingkungan command line yang berjalan di Google Cloud yang telah dilengkapi dengan bq. Klik Activate Cloud Shell di bagian atas konsol Google Cloud. Jika Anda diminta untuk memberikan otorisasi, klik Authorize.

1829c3759227c19b.png

  1. Setelah terhubung ke Cloud Shell, Anda dapat memeriksa bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda menggunakan perintah berikut:
gcloud auth list
  1. Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda.
gcloud config list project
  1. Jika project Anda belum ditetapkan, gunakan perintah berikut untuk menetapkannya:
gcloud config set project <YOUR_PROJECT_ID>

Atau, Anda juga dapat melihat ID PROJECT_ID di konsol

4032c45803813f30.jpeg

Klik project tersebut dan Anda akan melihat semua project Anda dan project ID di sisi kanan

8dc17eb4271de6b5.jpeg

  1. Aktifkan API yang diperlukan melalui perintah yang ditampilkan di bawah. Proses ini mungkin memerlukan waktu beberapa menit, jadi harap bersabar.
gcloud services enable aiplatform.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudresourcemanager.googleapis.com

Jika perintah berhasil dieksekusi, Anda akan melihat pesan yang mirip dengan yang ditampilkan di bawah:

Operation "operations/..." finished successfully.

Alternatif untuk perintah gcloud adalah melalui konsol dengan menelusuri setiap produk atau menggunakan link ini.

Jika ada API yang terlewat, Anda dapat mengaktifkannya kapan saja selama pelaksanaan.

Baca dokumentasi untuk mempelajari perintah gcloud dan penggunaannya.

Buka Cloud Shell Editor dan Siapkan Direktori Kerja Aplikasi

Sekarang, kita dapat menyiapkan editor kode untuk melakukan beberapa hal terkait coding. Kita akan menggunakan Cloud Shell Editor untuk melakukannya

  1. Klik tombol Open Editor, yang akan membuka Cloud Shell Editor, kita dapat menulis kode di sini b16d56e4979ec951.png
  2. Pastikan project Cloud Code ditetapkan di pojok kiri bawah (status bar) editor Cloud Shell, seperti yang ditandai dalam gambar di bawah dan ditetapkan ke project Google Cloud aktif tempat Anda mengaktifkan penagihan. Authorize jika diminta. Jika Anda sudah mengikuti perintah sebelumnya, tombol juga dapat mengarah langsung ke project yang diaktifkan, bukan tombol login

f5003b9c38b43262.png

  1. Selanjutnya, clone direktori kerja template untuk codelab ini dari GitHub dengan menjalankan perintah berikut. Perintah ini akan membuat direktori kerja di direktori purchasing-concierge-a2a
git clone https://github.com/alphinside/purchasing-concierge-intro-a2a-codelab-starter.git purchasing-concierge-a2a
  1. Setelah itu, buka bagian atas Editor Cloud Shell, klik File->Open Folder, temukan direktori username Anda, lalu temukan direktori purchasing-concierge-a2a, lalu klik tombol OK. Tindakan ini akan menjadikan direktori yang dipilih sebagai direktori kerja utama. Dalam contoh ini, nama penggunanya adalah alvinprayuda, sehingga jalur direktori ditampilkan di bawah

2c53696f81d805cc.png

253b472fa1bd752e.png

Sekarang, Editor Cloud Shell Anda akan terlihat seperti ini

aedd0725db87717e.png

Penyiapan Lingkungan

Langkah selanjutnya adalah menyiapkan lingkungan pengembangan. Terminal aktif Anda saat ini harus berada di dalam direktori kerja purchasing-concierge-a2a. Kita akan menggunakan Python 3.12 dalam codelab ini dan kita akan menggunakan pengelola project python uv untuk menyederhanakan kebutuhan pembuatan dan pengelolaan versi python serta lingkungan virtual

  1. Jika Anda belum membuka terminal, buka dengan mengklik Terminal -> New Terminal , atau gunakan Ctrl + Shift + C , yang akan membuka jendela terminal di bagian bawah browser

f8457daf0bed059e.jpeg

  1. Sekarang, mari kita lakukan inisialisasi lingkungan virtual concierge pembelian menggunakan uv (sudah diinstal sebelumnya di terminal cloud). Jalankan perintah ini
uv sync --frozen

Tindakan ini akan membuat direktori .venv dan menginstal dependensi. Pratinjau cepat di pyproject.toml akan memberi Anda informasi tentang dependensi yang ditampilkan seperti ini

dependencies = [
    "a2a-sdk>=0.2.16",
    "google-adk>=1.8.0",
    "gradio>=5.38.2",
]
  1. Untuk menguji lingkungan virtual, buat file main.py baru dan salin kode berikut
def main():
   print("Hello from purchasing-concierge-a2a!")

if __name__ == "__main__":
   main()
  1. Kemudian, jalankan perintah berikut
uv run main.py

Anda akan mendapatkan output seperti yang ditunjukkan di bawah

Using CPython 3.12
Creating virtual environment at: .venv
Hello from purchasing-concierge-a2a!

Ini menunjukkan bahwa project python sedang disiapkan dengan benar.

Sekarang kita dapat melanjutkan ke langkah berikutnya, yaitu mengonfigurasi dan men-deploy agen penjual jarak jauh

3. Men-deploy Agen Penjual Jarak Jauh - Server A2A ke Cloud Run

Pada langkah ini, kita akan men-deploy dua agen penjual jarak jauh yang ditandai dengan kotak merah. Agen burger akan didukung oleh framework agen CrewAI dan agen pizza akan didukung oleh agen Langgraph, keduanya didukung oleh model Gemini Flash 2.0

e91777eecfbae4f7.png

Men-deploy Agen Burger Jarak Jauh

Kode sumber agen burger ada di direktori remote_seller_agents/burger_agent. Inisialisasi agen dapat diperiksa pada skrip agent.py. Berikut adalah cuplikan kode agen yang diinisialisasi

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

...

Semua file yang ada di direktori remote_seller_agents/burger_agent sudah cukup untuk men-deploy agen kita ke Cloud Run sehingga dapat diakses sebagai layanan. Kita akan membahasnya nanti. Jalankan perintah berikut untuk men-deploy-nya

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}

Jika Anda diminta untuk membuat repositori penampung untuk men-deploy dari sumber, jawab Y. Hal ini hanya terjadi jika Anda belum pernah men-deploy ke Cloud Run dari sumber sebelumnya. Setelah deployment berhasil, log seperti ini akan ditampilkan.

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

Bagian xxxx di sini akan menjadi ID unik saat kita men-deploy layanan. Sekarang, mari kita coba membuka rute https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json layanan agen burger yang di-deploy tersebut melalui browser. Ini adalah URL untuk mengakses kartu agen server A2A yang di-deploy.

Jika berhasil di-deploy, Anda akan melihat respons seperti yang ditunjukkan di bawah ini di browser saat mengakses https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json :

72fdf3f52b5e8313.png

Ini adalah informasi kartu agen burger yang harus dapat diakses untuk tujuan penemuan. Kita akan membahasnya nanti. Perhatikan bahwa nilai url masih ditetapkan pada http://0.0.0.0:8080/ di sini. Nilai url ini harus berupa informasi utama bagi Klien A2A untuk mengirim pesan dari luar dan tidak dikonfigurasi dengan benar. Untuk demo ini, kita perlu memperbarui nilai ini ke URL layanan agen burger dengan menambahkan variabel lingkungan tambahan HOST_OVERRIDE.

Memperbarui Nilai URL Agen Burger di Kartu Agen melalui Variabel Lingkungan

Untuk menambahkan HOST_OVERRIDE ke layanan agen burger, lakukan langkah-langkah berikut

  1. Telusuri Cloud Run di kotak penelusuran di bagian atas konsol cloud Anda

1adde569bb345b48.png

  1. Klik layanan Cloud Run burger-agent yang di-deploy sebelumnya

9091c12526fb7f41.png

  1. Salin URL burger-service, lalu klik Edit dan deploy revisi baru

2701da8b124793b9.png

  1. Kemudian, klik bagian Variable & Secrets

31ea00e12134d74d.png

  1. Setelah itu, klik Tambahkan variabel dan tetapkan nilai HOST_OVERRIDE ke URL layanan ( yang memiliki pola https://burger-agent-xxxxxxxxx.us-central1.run.app)

52b382da7cf33cd5.png

  1. Terakhir, klik tombol deploy untuk men-deploy ulang layanan Anda

11464f4a51ffe54.png

Sekarang, saat Anda mengakses kartu agen burger-agent lagi di https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json browser , nilai url akan dikonfigurasi dengan benar

2ed7ebcb530f070a.png

Men-deploy Agen Pizza Jarak Jauh

Demikian pula, kode sumber agen pizza berada di direktori remote_seller_agents/pizza_agent. Inisialisasi agen dapat diperiksa pada skrip agent.py. Berikut adalah cuplikan kode agen yang diinisialisasi

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

...

Mirip dengan langkah deployment burger-agent sebelumnya, semua file yang ada di direktori remote_seller_agents/pizza_agent sudah cukup untuk men-deploy agen kita ke Cloud Run sehingga dapat diakses sebagai layanan. Jalankan perintah berikut untuk men-deploy-nya

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}

Setelah deployment berhasil, log seperti ini akan ditampilkan.

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

Bagian xxxx di sini akan menjadi ID unik saat kita men-deploy layanan. Hal yang sama terjadi pada agen burger, saat Anda mencoba membuka rute https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json dari layanan agen pizza yang di-deploy tersebut melalui browser untuk mengakses kartu agen server A2A, nilai url agen pizza di kartu agennya belum dikonfigurasi dengan benar. Kita juga perlu menambahkan HOST_OVERRIDE ke variabel lingkungannya

Memperbarui Nilai URL Agen Pizza di Kartu Agen melalui Variabel Lingkungan

Untuk menambahkan HOST_OVERRIDE ke layanan agen pizza, lakukan langkah-langkah berikut

  1. Telusuri Cloud Run di kotak penelusuran di bagian atas konsol cloud Anda

1adde569bb345b48.png

  1. Klik layanan Cloud Run pizza-agent yang di-deploy sebelumnya

5743b0aa0555741f.png

  1. Klik Edit dan deploy revisi baru.

d60ba267410183be.png

  1. Salin URL pizza-service, lalu klik bagian Variable & Secrets

618e9da2f94ed415.png

  1. Setelah itu, klik Tambahkan variabel dan tetapkan nilai HOST_OVERRIDE ke URL layanan ( yang memiliki pola https://pizza-agent-xxxxxxxxx.us-central1.run.app)

214a6eb98f877e65.png

  1. Terakhir, klik tombol deploy untuk men-deploy ulang layanan Anda

11464f4a51ffe54.png

Sekarang, saat Anda mengakses kartu agen pizza-agent lagi di browser https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json, nilai url akan dikonfigurasi dengan benar

c37b26ec80c821b6.png

Pada tahap ini, kita telah berhasil men-deploy layanan burger dan pizza ke Cloud Run. Sekarang mari kita bahas komponen inti Server A2A

4. Komponen Inti Server A2A

Sekarang, mari kita bahas konsep dan komponen inti server A2A

Kartu Agen

Setiap Server A2A harus memiliki kartu agen yang dapat diakses di resource /.well-known/agent.json. Hal ini untuk mendukung fase penemuan di Klien A2A, yang akan memberikan informasi dan konteks lengkap tentang cara mengakses agen dan mengetahui semua kemampuannya. Hal ini agak mirip dengan dokumentasi API yang terdokumentasi dengan baik menggunakan Swagger atau Postman.

Ini adalah konten kartu agen burger yang di-deploy

{
  "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"
}

Kartu agen ini menyoroti banyak komponen penting, seperti keterampilan agen, kemampuan streaming, modalitas yang didukung, versi protokol, dan hal lainnya.

Semua informasi ini dapat digunakan untuk mengembangkan mekanisme komunikasi yang tepat sehingga klien A2A dapat berkomunikasi dengan benar. Mekanisme autentikasi dan modalitas yang didukung memastikan komunikasi dapat dilakukan dengan benar, dan informasi agen skills dapat disematkan ke dalam perintah sistem klien A2A untuk memberikan konteks agen klien tentang kemampuan dan keterampilan agen jarak jauh yang akan dipanggil. Kolom yang lebih mendetail untuk kartu agen ini dapat ditemukan di dokumentasi ini.

Dalam kode kami, penerapan kartu agen dilakukan menggunakan A2A python SDK. Lihat cuplikan remote_seller_agents/burger_agent/main.py di bawah untuk mengetahui penerapannya

...

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

...

Kita dapat melihat beberapa kolom di sana seperti:

  1. AgentCapabilities : Deklarasi fungsi opsional tambahan yang didukung oleh layanan agen,seperti kemampuan untuk streaming dan/atau dukungan notifikasi push
  2. AgentSkill : Alat atau fungsi yang didukung oleh agen
  3. Input/OutputModes : Modalitas jenis Input/Output yang didukung
  4. Url : Alamat untuk berkomunikasi dengan agen

Dalam konfigurasi ini, kami menyediakan pembuatan URL host agen dinamis, sehingga lebih mudah untuk beralih antara pengujian lokal dan deployment cloud. Oleh karena itu, kami perlu menambahkan variabel HOST_OVERRIDE pada langkah sebelumnya.

Task Queue dan Agent Executor

Server A2A dapat menangani permintaan dari berbagai agen atau pengguna dan dapat mengisolasi setiap tugas dengan sempurna. Untuk memvisualisasikan konteks ini dengan lebih baik, Anda dapat memeriksa gambar di bawah

b9eb6b4025db4642.jpeg

Oleh karena itu, setiap server A2A harus dapat melacak tugas yang masuk dan menyimpan informasi yang tepat tentang tugas tersebut. SDK A2A menyediakan modul untuk mengatasi tantangan ini di server A2A. Pertama, kita dapat membuat instance logika tentang cara menangani permintaan masuk. Dengan mewarisi class abstrak AgentExecutor, kita dapat mengontrol cara kita ingin mengelola eksekusi dan pembatalan tugas. Penerapan contoh ini dapat diperiksa di modul remote_seller_agents/burger_agent/agent_executor.py ( jalur serupa untuk kasus penjual pizza)

...

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

...

Dalam kode di atas, kita mengimplementasikan skema pemrosesan dasar yang mana agen akan dipanggil secara langsung saat permintaan masuk dan mengirimkan peristiwa tugas selesai setelah menyelesaikan pemanggilan. Namun, kita tidak menerapkan metode pembatalan di sini karena dianggap sebagai operasi yang berjalan singkat.

Setelah membuat executor, kita dapat langsung menggunakan DefaultRequestHandler, InMemoryTaskStore, dan A2AStarletteApplication bawaan untuk menjalankan Server HTTP. Penerapan ini dapat diperiksa di remote_seller_agents/burger_agent/__main__.py

...

        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)

...

Modul ini akan memberi Anda implementasi rute /.well-known/agent.json untuk mengakses kartu agen dan juga endpoint POST untuk mendukung protokol A2A

Ringkasan

Singkatnya, sejauh ini Server A2A yang di-deploy menggunakan Python SDK dapat mendukung 2 fungsi di bawah ini:

  1. Memublikasikan kartu agen di rute /.well-known/agent.json
  2. Menangani permintaan JSON-RPC dengan antrean tugas dalam memori

Titik entri saat memulai fungsi ini dapat diperiksa pada skrip __main__.py ( di remote_seller_agents/burger_agent atau remote_seller_agents/pizza_agent) .

5. Men-deploy Purchasing Concierge - A2A Client ke Agent Engine

Pada langkah ini, kita akan men-deploy agen concierge pembelian. Agen inilah yang akan kita ajak berinteraksi.

c4a8e7a3d18b1ef.png

Kode sumber agen pemandu pembelian kami ada di direktori purchasing_concierge. Inisialisasi agen dapat diperiksa pada skrip purchasing_agent.py. Berikut adalah cuplikan kode agen yang diinisialisasi.

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

...

Kita akan men-deploy agen ini ke agent engine. Vertex AI Agent Engine adalah serangkaian layanan yang memungkinkan developer men-deploy, mengelola, dan menskalakan agen AI dalam produksi. Layanan ini menangani infrastruktur untuk menskalakan agen dalam produksi sehingga kita dapat berfokus pada pembuatan aplikasi. Anda dapat membaca selengkapnya tentang hal ini di dokumen ini . Jika sebelumnya kita perlu menyiapkan file yang diperlukan untuk men-deploy layanan agen (seperti skrip server main dan Dockerfile), dalam hal ini kita dapat men-deploy agen langsung dari skrip python tanpa perlu mengembangkan layanan backend sendiri dengan menggunakan kombinasi ADK dan Agent Engine. Ikuti langkah-langkah berikut untuk men-deploy-nya :

  1. Pertama, kita perlu membuat penyimpanan staging di Cloud Storage
gcloud storage buckets create gs://purchasing-concierge-{your-project-id} --location=us-central1
  1. Sekarang, kita perlu menyiapkan variabel .env terlebih dahulu. Mari salin .env.example ke file .env
cp .env.example .env
  1. Sekarang, buka file .env dan Anda akan melihat konten berikut
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}

Agen ini akan berkomunikasi dengan agen burger dan pizza, sehingga kita perlu memberikan kredensial yang tepat untuk keduanya. Kita perlu memperbarui PIZZA_SELLER_AGENT_URL dan BURGER_SELLER_AGENT_URL dengan URL Cloud Run dari langkah-langkah sebelumnya.

Jika Anda lupa tentang hal ini, buka konsol Cloud Run. Ketik "Cloud Run" di kotak penelusuran di bagian atas konsol Anda, lalu klik kanan ikon Cloud Run untuk membukanya di tab baru

1adde569bb345b48.png

Anda akan melihat layanan agen penjual jarak jauh yang sebelumnya di-deploy seperti yang ditunjukkan di bawah

179e55cc095723a8.png

Sekarang, untuk melihat URL publik layanan tersebut, klik salah satu layanan dan Anda akan dialihkan ke halaman Detail layanan. Anda dapat melihat URL di area atas tepat di samping informasi Wilayah

64c01403a92b1107.png

Variabel lingkungan akhir akan terlihat seperti ini

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}
  1. Sekarang, kita siap men-deploy agen concierge pembelian. Dalam demo ini, kita akan men-deploy menggunakan skrip deploy_to_agent_engine.py yang kontennya ditampilkan di bawah
"""
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}")

Berikut adalah langkah-langkah yang diperlukan untuk men-deploy agen ADK ke agent engine. Pertama, kita perlu membuat objek AdkApp dari root_agent ADK kita. Kemudian, kita dapat menjalankan metode agent_engines.create dengan memberikan objek adk_app, menentukan persyaratan di kolom requirements, menentukan jalur direktori agen di extra_packages, dan memberikan variabel lingkungan yang diperlukan.

Kita dapat men-deploy-nya dengan menjalankan skrip:

uv run deploy_to_agent_engine.py

Setelah deployment berhasil, log seperti ini akan ditampilkan. Perhatikan bahwa xxxx adalah project ID Anda dan yyyy adalah ID resource mesin agen Anda

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

Saat kita memeriksanya di dasbor agent engine (telusuri "agent engine" di kotak penelusuran), deployment sebelumnya akan ditampilkan

29738fbf7e5f5ecc.png

Menguji Agen yang Di-deploy di Agent Engine

Interaksi dengan mesin agen dapat dilakukan melalui perintah curl dan SDK. Misalnya, jalankan perintah berikut untuk mencoba berinteraksi dengan agen yang di-deploy.

Anda dapat mencoba mengirim kueri ini untuk memeriksa apakah agen berhasil di-deploy

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",
  }
}'

Jika berhasil, beberapa peristiwa respons yang di-streaming di konsol Anda akan ditampilkan seperti ini

{
  "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
}

Kita akan mencoba menggunakan UI pada langkah berikutnya, tetapi mari kita bahas terlebih dahulu komponen inti dan alur umum klien A2A

6. Komponen Inti Klien A2A

aa6c8bc5b5df73f1.jpeg

Gambar di atas menunjukkan alur umum interaksi A2A:

  1. Klien akan mencoba menemukan kartu agen yang dipublikasikan di URL agen jarak jauh yang diberikan di rute /.well-known/agent.json
  2. Kemudian, jika perlu, server akan mengirimkan Pesan ke agen tersebut dengan pesan dan parameter metadata yang diperlukan ( misalnya, ID sesi, konteks historis, dll.). Server akan menganggap Pesan ini sebagai Tugas yang harus diselesaikan
  3. Server A2A memproses permintaan, jika server mendukung notifikasi push, server juga akan dapat memublikasikan beberapa notifikasi selama pemrosesan tugas ( Fungsi ini berada di luar cakupan codelab ini)
  4. Setelah selesai, server A2A akan mengirimkan artefak respons kembali ke klien

Beberapa objek inti untuk interaksi di atas adalah item ini (detail selengkapnya dapat dibaca di sini) :

  • Pesan: Giliran komunikasi antara klien dan agen jarak jauh
  • Tugas: Unit kerja dasar yang dikelola oleh A2A, diidentifikasi oleh ID unik
  • Artefak: Output (misalnya, dokumen, gambar, data terstruktur) yang dihasilkan oleh agen sebagai hasil dari tugas, yang terdiri dari Bagian
  • Bagian: Unit konten terkecil dalam Pesan atau Artefak. Bagian dapat berupa teks, gambar, video, file, dll.

Penemuan Kartu

Saat layanan Klien A2A diluncurkan, proses umumnya adalah mencoba mendapatkan informasi kartu agen dan menyimpannya agar mudah diakses saat diperlukan. Dalam codelab ini, kita akan menerapkannya di before_agent_callback. Anda dapat melihat penerapannya di purchasing_concierge/purchasing_agent.py. Lihat cuplikan kode di bawah

...

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)

...

Di sini, kita mencoba mengakses semua kartu agen yang tersedia menggunakan modul klien A2A bawaan A2ACardResolver, lalu kita mengumpulkan koneksi yang diperlukan untuk mengirim pesan ke agen, setelah itu kita juga perlu mencantumkan semua agen yang tersedia dan spesifikasinya ke dalam perintah sehingga agen kita mengetahui bahwa ia dapat berkomunikasi dengan agen-agen ini

Alat Prompt dan Kirim Tugas

Ini adalah perintah dan alat yang kami berikan kepada agen ADK kami di sini

...

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

...

Dalam perintah, kita memberikan semua nama dan deskripsi agen jarak jauh yang tersedia kepada agen concierge pembelian, dan di alat self.send_task kita menyediakan mekanisme untuk mengambil klien yang sesuai untuk terhubung ke agen dan mengirim metadata yang diperlukan menggunakan objek SendMessageRequest.

Protokol Komunikasi

Definisi Task adalah domain yang dimiliki oleh server A2A. Namun, dari perspektif klien A2A, mereka melihatnya sebagai Pesan yang dikirim ke server. Serverlah yang menentukan cara mendefinisikan pesan masuk dari klien sebagai tugas yang mana dan apakah penyelesaian tugas memerlukan interaksi dari klien. Anda dapat membaca detail selengkapnya tentang siklus proses tugas dalam dokumentasi ini. Konsep tingkat yang lebih tinggi dari hal ini dapat divisualisasikan di bawah:

65b8878a4854fd93.jpeg

9ddfae690d40cbbf.jpeg

Pertukaran pesan -> tugas ini diimplementasikan menggunakan format payload di atas standar JSON-RPC seperti yang ditunjukkan dalam contoh protokol message/send di bawah :

{
  # 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?"
  }  
}

Ada berbagai metode yang tersedia, misalnya untuk mendukung berbagai jenis komunikasi (misalnya sinkron, streaming, asinkron) atau untuk mengonfigurasi notifikasi untuk status tugas. Server A2A dapat dikonfigurasi secara fleksibel untuk menangani standar definisi tugas ini. Detail metode ini dapat dibaca di dokumen ini.

7. Pengujian Integrasi dan Inspeksi Payload

Sekarang, mari kita periksa concierge pembelian dengan interaksi agen jarak jauh menggunakan UI web.

Pertama, kita perlu memperbarui AGENT_ENGINE_RESOURCE_NAME di .File env. Pastikan Anda memberikan nama resource mesin agen yang benar. File .env Anda seharusnya terlihat seperti ini:

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

Setelah itu, jalankan perintah berikut untuk men-deploy aplikasi Gradio

uv run purchasing_concierge_ui.py

Output berikut akan ditampilkan jika berhasil

* Running on local URL:  http://0.0.0.0:8080
* To create a public link, set `share=True` in `launch()`.

Kemudian, Ctrl + klik URL http://0.0.0.0:8080 di terminal atau klik tombol pratinjau web untuk membuka UI web

b38b428d9e4582bc.png

Coba lakukan percakapan seperti ini :

  • Tampilkan menu burger dan pizza
  • Saya ingin memesan 1 pizza ayam BBQ dan 1 burger cajun pedas

Kemudian, lanjutkan percakapan hingga Anda menyelesaikan pesanan. Periksa bagaimana interaksi berlangsung dan apa panggilan serta respons alatnya? Gambar berikut adalah contoh hasil interaksi.

ff5f752965816b2b.png

6f65155c7a289964.png

b390f4b15f1c5a8c.png

ff44c54b50c36e1a.png

Kita dapat melihat bahwa berkomunikasi dengan 2 agen yang berbeda menghasilkan 2 perilaku yang berbeda dan A2A dapat menanganinya dengan baik. Agen penjual pizza langsung menerima permintaan agen pembelian kami, sedangkan agen burger memerlukan konfirmasi kami sebelum melanjutkan permintaan kami dan setelah kami mengonfirmasi, agen dapat mengandalkan konfirmasi tersebut untuk agen burger

Sekarang, kita telah menyelesaikan konsep dasar A2A dan melihat cara penerapannya sebagai arsitektur klien dan server

8. Tantangan

Sekarang, dapatkah Anda menyiapkan file yang diperlukan dan men-deploy aplikasi Gradio ke Cloud Run sendiri? Saatnya menerima tantangan!

9. Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam codelab ini, ikuti langkah-langkah berikut:

  1. Di konsol Google Cloud, buka halaman Manage resources.
  2. Dalam daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.
  4. Atau, Anda dapat membuka Cloud Run di konsol, memilih layanan yang baru saja Anda deploy, lalu menghapusnya.