Erste Schritte mit dem Agent2Agent-Protokoll (A2A): Interaktionen zwischen einem Einkaufs-Concierge und einem Remote-Verkäufer-Agent auf Cloud Run und Agent Engine

1. 📖 Einführung

983be32cd5f6b65d.png

Das Agent2Agent-Protokoll (A2A) wurde entwickelt, um die Kommunikation zwischen KI-Agenten zu standardisieren, insbesondere für Agenten, die in externen Systemen bereitgestellt werden. Bisher wurden solche Protokolle für Tools mit dem Namen Model Context Protocol (MCP) eingerichtet. MCP ist ein aufstrebender Standard zum Verbinden von LLMs mit Daten und Ressourcen. A2A soll MCP ergänzen. Während sich MCP darauf konzentriert, die Komplexität zu verringern, um KI-Agenten mit Tools und Daten zu verbinden, geht es bei A2A darum, wie KI-Agenten in ihren natürlichen Modalitäten zusammenarbeiten können. So können Agents als Agents (oder als Nutzer) und nicht als Tools kommunizieren. Das ist z. B. nützlich, wenn Sie etwas bestellen möchten.

A2A soll MCP ergänzen. In der offiziellen Dokumentation wird empfohlen, MCP für Tools und A2A für Agenten zu verwenden, die durch AgentCard dargestellt werden ( wir werden dies später noch genauer erläutern). Die Frameworks können dann A2A verwenden, um mit ihren Nutzern, den Remote-Agenten und anderen Agenten zu kommunizieren.

cb49a578e47636e1.png

In dieser Demo beginnen wir mit der Implementierung von A2A mit dem Python SDK. Wir sehen uns einen Anwendungsfall an, in dem wir einen persönlichen Einkaufsassistenten haben, der uns helfen kann, mit Burger- und Pizzaverkäufern zu kommunizieren, um unsere Bestellung aufzugeben.

A2A basiert auf dem Client-Server-Prinzip. Hier sehen Sie den typischen A2A-Ablauf, den Sie in dieser Anleitung erwarten können.

e7e3224d05b725f0.jpeg

  1. Der A2A-Client führt zuerst die Ermittlung für alle zugänglichen A2A-Server-Agentenkarten durch und verwendet die Informationen, um einen Verbindungsclient zu erstellen.
  2. Bei Bedarf sendet der A2A-Client eine Nachricht an den A2A-Server. Der Server wertet diese als Aufgabe aus, die erledigt werden muss. Wenn die URL des Push-Benachrichtigungsempfängers auf dem A2A-Client konfiguriert ist und vom A2A-Server unterstützt wird, kann der Server den Status des Aufgabenfortschritts auch am Empfangsendpunkt auf dem Client veröffentlichen.
  3. Nach Abschluss der Aufgabe sendet der A2A-Server das Antwortartefakt an den A2A-Client.

In diesem Codelab gehen Sie schrittweise so vor:

  1. Google Cloud-Projekt vorbereiten
  2. Arbeitsverzeichnis für die Programmierumgebung einrichten
  3. Burger-Agent in Cloud Run bereitstellen
  4. Pizza-Agent in Cloud Run bereitstellen
  5. Einkaufs-Concierge in Agent Engine bereitstellen
  6. Über die lokale Schnittstelle mit dem Kauf-Concierge interagieren

Architekturübersicht

Sie stellen die folgende Dienstarchitektur bereit:

a485135c8f7b97bd.jpeg

Sie stellen zwei Dienste bereit, die als A2A-Server fungieren: den Burger-Agent ( basierend auf dem CrewAI-Agent-Framework) und den Pizza-Agent ( basierend auf dem Langgraph-Agent-Framework). Der Nutzer interagiert nur direkt mit dem Einkaufs-Concierge, der mit dem Agent Development Kit (ADK) Framework als A2A-Client ausgeführt wird.

Jeder dieser Agents hat eine eigene Umgebung und wird separat bereitgestellt.

Voraussetzungen

  • Vertrautheit mit Python
  • Grundkenntnisse der Full-Stack-Architektur mit HTTP-Dienst

Lerninhalte

  • Grundstruktur des A2A-Servers
  • Kernstruktur des A2A-Clients
  • Agent-Dienst in Cloud Run bereitstellen
  • Agent-Dienst in Agent Engine bereitstellen
  • So stellt ein A2A-Client eine Verbindung zu einem A2A-Server her
  • Struktur von Anfragen und Antworten bei Nicht-Streaming-Verbindungen

Voraussetzungen

  • Chrome-Webbrowser
  • Ein Gmail-Konto
  • Ein Cloud-Projekt mit aktiviertem Abrechnungskonto

In diesem Codelab, das sich an Entwickler aller Erfahrungsstufen (auch Anfänger) richtet, wird Python in der Beispielanwendung verwendet. Python-Kenntnisse sind jedoch nicht erforderlich, um die vorgestellten Konzepte zu verstehen.

2. 🚀 Vorbereitung der Workshop-Entwicklung

Schritt 1: Aktives Projekt in der Cloud Console auswählen

Wählen Sie in der Google Cloud Console auf der Seite zur Projektauswahl ein Google Cloud-Projekt aus oder erstellen Sie eines (siehe oben links in der Console).

7758dd17c20c3094.png

Klicken Sie darauf, um eine Liste aller Ihrer Projekte aufzurufen, wie in diesem Beispiel:

8c93fa37e7a7b856.png

Der Wert, der durch das rote Kästchen angegeben wird, ist die PROJEKT-ID. Dieser Wert wird im gesamten Tutorial verwendet.

Die Abrechnung für das Cloud-Projekt muss aktiviert sein. Klicken Sie dazu links oben in der Leiste auf das Dreistrich-Menü ☰, um das Navigationsmenü aufzurufen, und suchen Sie nach dem Abrechnungsmenü.

db07810b26fc61d6.png

Wenn Sie „Google Cloud Platform-Testabrechnungskonto“ ist verknüpft sehen, kann Ihr Projekt für diese Anleitung verwendet werden. Wenn nicht, kehren Sie zum Anfang dieses Tutorials zurück und lösen Sie das Abrechnungskonto ein.

4f592f31aef0c40.png

Schritt 2: Mit Cloud Shell vertraut machen

Für den Großteil der Anleitungen verwenden Sie Cloud Shell. Klicken Sie dazu oben in der Google Cloud Console auf „Cloud Shell aktivieren“. Wenn Sie zur Autorisierung aufgefordert werden, klicken Sie auf Autorisieren.

26f20e837ff06119.png

79b06cc89a99f840.png

Nachdem Sie eine Verbindung zu Cloud Shell hergestellt haben, müssen wir prüfen, ob die Shell ( oder das Terminal) bereits mit Ihrem Konto authentifiziert ist.

gcloud auth list

Wenn Sie Ihr privates Gmail-Konto wie im Beispiel unten sehen, ist alles in Ordnung.

Credentialed Accounts

ACTIVE: *
ACCOUNT: alvinprayuda@gmail.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

Falls nicht, aktualisieren Sie Ihren Browser und klicken Sie auf Autorisieren, wenn Sie dazu aufgefordert werden. Möglicherweise wurde die Verbindung unterbrochen.

Als Nächstes müssen wir prüfen, ob die Shell bereits für die richtige PROJECT ID konfiguriert ist. Wenn im Terminal vor dem Symbol „$“ ein Wert in Klammern angezeigt wird (im Screenshot unten ist der Wert a2a-agent-engine), gibt dieser Wert das konfigurierte Projekt für Ihre aktive Shell-Sitzung an.

8365518c832055f.png

Wenn der angezeigte Wert bereits korrekt ist, können Sie den nächsten Befehl überspringen. Wenn sie nicht korrekt ist oder fehlt, führen Sie den folgenden Befehl aus:

gcloud config set project <YOUR_PROJECT_ID>

Klonen Sie dann das Arbeitsverzeichnis der Vorlage für dieses Codelab von GitHub, indem Sie den folgenden Befehl ausführen. Das Arbeitsverzeichnis wird im Verzeichnis purchasing-concierge-a2a erstellt.

git clone https://github.com/alphinside/purchasing-concierge-intro-a2a-codelab-starter.git purchasing-concierge-a2a

Schritt 3: Cloud Shell-Editor kennenlernen und Arbeitsverzeichnis der Anwendung einrichten

Jetzt können wir unseren Code-Editor für einige Programmieraufgaben einrichten. Dazu verwenden wir den Cloud Shell-Editor.

Klicken Sie auf die Schaltfläche Editor öffnen, um den Cloud Shell-Editor 168eacea651b086c.png zu öffnen.

Klicken Sie dann oben im Cloud Shell-Editor auf Datei > Ordner öffnen, suchen Sie nach dem Verzeichnis username und dann nach dem Verzeichnis purchasing-concierge-a2a. Klicken Sie auf die Schaltfläche „OK“. Dadurch wird das ausgewählte Verzeichnis zum Hauptarbeitsverzeichnis. In diesem Beispiel ist der Nutzername alvinprayuda. Der Verzeichnispfad wird unten angezeigt.

c87d2b76896d0c59.png

d5d829a1c43d7451.png

Der Cloud Shell Editor sollte jetzt so aussehen:

9b4793fa38e35af2.png

Öffnen Sie nun das Terminal für den Editor. Klicken Sie dazu in der Menüleiste auf Terminal -> Neues Terminal oder verwenden Sie die Tastenkombination Strg + Umschalt + C. Dadurch wird unten im Browser ein Terminalfenster geöffnet.

8635b60ae2f45bbc.jpeg

Ihr aktuelles aktives Terminal sollte sich im Arbeitsverzeichnis purchasing-concierge-a2a befinden. In diesem Codelab verwenden wir Python 3.12 und den uv-Python-Projektmanager, um das Erstellen und Verwalten von Python-Versionen und virtuellen Umgebungen zu vereinfachen. Das uv-Paket ist bereits in Cloud Shell vorinstalliert.

Führen Sie diesen Befehl aus, um die erforderlichen Abhängigkeiten in der virtuellen Umgebung im Verzeichnis .venv zu installieren.

uv sync --frozen

Sehen Sie sich die deklarierten Abhängigkeiten für diese Anleitung in der Datei pyproject.toml an. Sie lauten a2a-sdk, google-adk, and gradio.

Jetzt müssen wir die erforderlichen APIs über den unten gezeigten Befehl aktivieren. Das kann etwas dauern.

gcloud services enable aiplatform.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudresourcemanager.googleapis.com

Bei erfolgreicher Ausführung des Befehls sollte eine Meldung wie die unten gezeigte angezeigt werden:

Operation "operations/..." finished successfully.

3. 🚀 A2A-Server-Remote-Seller-Agents in Cloud Run bereitstellen

In diesem Schritt stellen wir die beiden Remote-Verkäufer-Agents bereit, die durch das rote Feld gekennzeichnet sind. Der Burger-Agent basiert auf dem CrewAI-Agent-Framework und der Pizza-Agent auf dem Langgraph-Agent.

87dbae9eff7781f9.png

4. 🚀 Burger Seller-Agent als A2A-Server bereitstellen

Der Quellcode des Burger-Agents befindet sich im Verzeichnis remote_seller_agents/burger_agent.

Alle Dateien im Verzeichnis remote_seller_agents/burger_agent reichen bereits aus, um unseren Agent in Cloud Run bereitzustellen, sodass er als Dienst zugänglich ist. Führen Sie den folgenden Befehl aus, um sie bereitzustellen:

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}

Wenn Sie aufgefordert werden, ein Container-Repository für die Bereitstellung aus der Quelle zu erstellen, antworten Sie mit Y. Nach erfolgreicher Bereitstellung wird ein Log wie dieses angezeigt.

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

Der Teil xxxx ist eine eindeutige Kennung, wenn wir den Dienst bereitstellen.

Öffnen Sie einen neuen Browsertab und rufen Sie die https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json-Route der bereitgestellten Burger-Agent-Dienste über den Browser auf. Dies ist die URL für den Zugriff auf die bereitgestellte Agentenkarte des A2A-Servers.

Wenn die Bereitstellung erfolgreich war, sehen Sie beim Zugriff auf die Agent-Karte eine Antwort wie unten im Browser.

3d353be0e82ff46c.png

Dies sind die Informationen auf der Burger-Agent-Karte, die zu Erkennungszwecken zugänglich sein sollten.

Der Wert url ist hier weiterhin auf http://0.0.0.0:8080/ festgelegt. Dieser url-Wert sollte die Hauptinformation für den A2A-Client sein, um Nachrichten von außerhalb zu senden. Er ist jedoch nicht richtig konfiguriert.

Wir müssen diesen Wert auf die URL unseres Burger-Agent-Dienstes aktualisieren, indem wir eine zusätzliche Umgebungsvariable HOST_OVERRIDE hinzufügen.

Aktualisieren des Burger Agent-URL-Werts auf der Agent-Karte über die Umgebungsvariable

So fügen Sie HOST_OVERRIDE dem Burger-Agent-Dienst hinzu:

  1. Suchen Sie in der Suchleiste oben in der Cloud Console nach Cloud Run.

f56ec00607eafb6f.png

  1. Klicken Sie auf den zuvor bereitgestellten Cloud Run-Dienst burger-agent.

9bf379c89e7fe625.png

  1. Kopieren Sie die URL des Burger-Dienstes und klicken Sie dann auf Neue Überarbeitung bearbeiten und bereitstellen.

75a4a1a3b7fa3cd6.png

  1. Klicken Sie dann auf den Bereich Variablen und Secrets.

4fcaa1176de7038d.png

  1. Klicken Sie dann auf Variable hinzufügen und legen Sie für HOST_OVERRIDE die Dienst-URL fest ( die mit dem https://burger-agent-xxxxxxxxx.us-central1.run.app-Muster).

c160f7d90d219129.png

  1. Klicken Sie abschließend auf die Schaltfläche Bereitstellen, um Ihren Dienst noch einmal bereitzustellen.

763bbc02ceac0e28.png

Wenn Sie im Browser https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json wieder auf die Agent-Karte „burger-agent“ zugreifen , ist der Wert url bereits richtig konfiguriert.

9acf6c51329d6e91.png

5. 🚀 Bereitstellung des Pizza Seller-Agenten – A2A-Server

Der Quellcode des Pizza-Agents befindet sich im Verzeichnis remote_seller_agents/pizza_agent.

Ähnlich wie beim vorherigen Schritt zur Bereitstellung des Burger-Agents reichen alle Dateien im Verzeichnis remote_seller_agents/pizza_agent bereits aus, um unseren Agent in Cloud Run bereitzustellen, sodass er als Dienst zugänglich ist. Führen Sie den folgenden Befehl aus, um sie bereitzustellen:

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}

Nach erfolgreicher Bereitstellung wird ein Log wie dieses angezeigt.

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

Der Teil xxxx ist eine eindeutige Kennung, wenn wir den Dienst bereitstellen.

Das ist auch beim Burger-Agenten der Fall. Wenn Sie versuchen, über den Browser auf die https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json-Route der bereitgestellten Pizza-Agenten-Dienste zuzugreifen, um die A2A-Server-Agentenkarte aufzurufen, ist der url-Wert des Pizza-Agenten auf seiner Agentenkarte noch nicht richtig konfiguriert. Außerdem müssen wir HOST_OVERRIDE in die Umgebungsvariable einfügen.

Aktualisieren des URL-Werts des Pizza-Agents auf der Agent-Karte über die Umgebungsvariable

So fügen Sie HOST_OVERRIDE dem Pizza-Agent-Dienst hinzu:

  1. Suchen Sie in der Suchleiste oben in der Cloud Console nach Cloud Run.

f56ec00607eafb6f.png

  1. Klicken Sie auf den zuvor bereitgestellten Cloud Run-Dienst pizza-agent.

d9840497ae8afa2c.png

  1. Klicken Sie auf Neue Überarbeitung bearbeiten und bereitstellen.

e45d52012bef34c6.png

  1. Kopieren Sie die URL des Pizzadienstes und klicken Sie dann auf den Bereich Variablen und Secrets.

19265c4edc2be7ae.png

  1. Klicken Sie dann auf Variable hinzufügen und legen Sie für HOST_OVERRIDE die Dienst-URL fest ( die mit dem https://pizza-agent-xxxxxxxxx.us-central1.run.app-Muster).

7a6bd93cb6f11b64.png

  1. Klicken Sie abschließend auf die Schaltfläche Bereitstellen, um Ihren Dienst noch einmal bereitzustellen.

763bbc02ceac0e28.png

Wenn Sie jetzt im Browser https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json wieder auf die Agent-Karte „pizza-agent“ zugreifen, ist der Wert url bereits richtig konfiguriert.

f682caa1d89c6b5d.png

An diesem Punkt haben wir bereits sowohl den Burger- als auch den Pizza-Dienst erfolgreich in Cloud Run bereitgestellt.

6. 🚀 Einkaufs-Concierge – A2A-Client in der Agent Engine bereitstellen

In diesem Schritt stellen wir den Einkaufs-Concierge-Agent bereit. Mit diesem Agenten interagieren wir.

d62d062dd6959e8.png

Der Quellcode unseres Einkaufsservice-Agents befindet sich im Verzeichnis purchasing_concierge. Die Initialisierung des Agents kann im Script purchasing_concierge/purchasing_agent.py eingesehen werden.

So stellen Sie die App bereit :

  1. Zuerst müssen wir den Staging-Speicher in Cloud Storage erstellen.
gcloud storage buckets create gs://purchasing-concierge-{your-project-id} --location=us-central1
  1. Jetzt müssen wir zuerst die .env-Variable vorbereiten. Kopieren wir die Datei .env.example in die Datei .env.
cp .env.example .env
  1. Öffnen Sie nun die Datei .env. Sie sehen den folgenden Inhalt:
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}

Dieser Agent kommuniziert mit dem Burger- und Pizza-Agenten. Daher müssen wir die entsprechenden Anmeldedaten für beide angeben. Wir müssen die PIZZA_SELLER_AGENT_URL und BURGER_SELLER_AGENT_URL mit der Cloud Run-URL aus den vorherigen Schritten aktualisieren.

Wenn Sie das vergessen, rufen Sie die Cloud Run-Konsole auf. Geben Sie in der Suchleiste oben in der Konsole „Cloud Run“ ein und klicken Sie mit der rechten Maustaste auf das Cloud Run-Symbol, um es in einem neuen Tab zu öffnen.

f56ec00607eafb6f.png

Sie sollten die zuvor bereitgestellten Dienste für den Agenten des Remote-Händlers wie unten dargestellt sehen.

561e3d125ae54e35.png

Wenn Sie die öffentliche URL dieser Dienste aufrufen möchten, klicken Sie auf einen der Dienste. Sie werden dann zur Seite „Dienstdetails“ weitergeleitet. Die URL wird oben direkt neben den Regionsinformationen angezeigt.

382c2094967718ae.png

Die endgültige Umgebungsvariable sollte ungefähr so aussehen:

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. Jetzt können wir unseren Einkaufs-Concierge-Agent bereitstellen. Wir stellen sie in der Agent Engine bereit. Der Bereitstellungscode befindet sich im deploy_to_agent_engine.py-Skript.

Wir können es bereitstellen, indem wir das Skript ausführen:

uv run deploy_to_agent_engine.py

Nach erfolgreicher Bereitstellung wird ein Log wie dieses angezeigt. Der Ressourcenname der Agent Engine wird als "projects/xxxx/locations/us-central1/reasoningEngines/yyyy" angezeigt.

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

Wenn wir es im Agent Engine-Dashboard prüfen (suchen Sie in der Suchleiste nach „Agent Engine“), wird unsere vorherige Bereitstellung angezeigt.

765cdbdbbc3a94bc.png

Sie können auch prüfen, ob der Ressourcenname der Agent Engine dort angezeigt wird. Anschließend können wir diesen Ressourcennamen zum Testen verwenden.

Aktualisieren Sie dann AGENT_ENGINE_RESOURCE_NAME in der Datei .env mit diesem Wert. Achten Sie darauf, dass Sie den richtigen Ressourcennamen für die Agent-Engine angeben. Ihre .env-Datei sollte so aussehen:

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

Bereitgestellten Agent in der Agent Engine testen

Die Interaktion mit der Agent Engine kann über den curl-Befehl und das SDK erfolgen. Führen Sie beispielsweise den folgenden Befehl aus, um mit dem bereitgestellten Agenten zu interagieren.

Sie können diese Anfrage senden, um zu prüfen, ob der Agent erfolgreich bereitgestellt wurde. Führen Sie das folgende test_agent_engine.sh-Skript aus:

bash test_agent_engine.sh

Wenn Sie sich das Script ansehen, sehen Sie, dass wir den Agenten fragen: List available burger menu please (Bitte liste das verfügbare Burgermenü auf).

Bei Erfolg werden in der Konsole mehrere Antwortereignisse gestreamt, z. B.

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

Im nächsten Schritt werden wir die Benutzeroberfläche verwenden. Zuerst möchten wir jedoch die Kernkomponenten und den typischen Ablauf von A2A-Clients besprechen.

7. 🚀 Integrationstests und Nutzlastprüfung

Sehen wir uns nun unseren Kauf-Concierge mit der Remote-Agent-Interaktion über eine Weboberfläche an. Führen Sie den folgenden Befehl aus, um eine Gradio-App bereitzustellen. Dazu müssen Sie die .env-Datei bereits korrekt ausgefüllt haben.

uv run purchasing_concierge_ui.py

Bei Erfolg wird die folgende Ausgabe angezeigt:

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

Strg+Klick auf die URL „http://0.0.0.0:8080“ im Terminal oder auf die Schaltfläche „Webvorschau“, um die Weboberfläche zu öffnen

bf615f875b1d870.png

So könnte eine Unterhaltung aussehen :

  • Zeig mir die Speisekarte für Burger und Pizza
  • Ich möchte eine BBQ-Chicken-Pizza und einen Spicy Cajun Burger bestellen.

Setzen Sie die Unterhaltung fort, bis Sie die Bestellung abgeschlossen haben. Sehen Sie sich an, wie die Interaktion verläuft und was der Toolaufruf und die Antwort sind. Das folgende Bild zeigt ein Beispiel für das Interaktionsergebnis.

e3ada3143680efff.png

f661b0721ec6fbb0.png

789782458635578e.png

5d66b087aed1743e.png

Die Kommunikation mit zwei verschiedenen Agenten führt zu zwei unterschiedlichen Verhaltensweisen, was A2A gut bewältigen kann. Der Pizzaverkäufer-Agent akzeptiert unsere Anfrage direkt, während der Burger-Agent unsere Bestätigung benötigt, bevor er mit unserer Anfrage fortfährt. Nachdem wir die Bestätigung gesendet haben, kann er sich darauf verlassen.

Nachdem wir nun die grundlegenden Konzepte von A2A kennengelernt haben, sehen wir uns an, wie sie als Client- und Serverarchitektur implementiert werden.

8. 💡 [Codeerläuterung] A2A-Serverkonzept und -Implementierung

Die Initialisierung des Remote-Verkäufer-Agents kann im Script remote_seller_agents/*/agent.py geprüft werden. Hier ist das Code-Snippet der Verkäufer-Agents.

Burger Agent

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

...

Pizza Agent

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

...

Wie Sie sehen, werden diese beiden Agenten mit völlig unterschiedlichen Frameworks ( CrewAI und Langgraph) im Vergleich zum Client-Agent ( ADK) erstellt. Mit A2A ist das kein Problem. Die Agenten müssen ihren internen Code nicht teilen, um miteinander zu kommunizieren. Es spielt keine Rolle, welche Frameworks verwendet werden, welche Sprache genutzt wird oder wo sie bereitgestellt werden.

Kernkomponenten des A2A-Servers

Sehen wir uns nun das Kernkonzept und die Komponenten des A2A-Servers an.

Agent-Karte

Jeder A2A-Server muss eine Agentenkarte haben, auf die über die /.well-known/agent.json-Ressource zugegriffen werden kann. Dies soll die Ermittlungsphase im A2A-Client unterstützen, die vollständige Informationen und Kontexte zum Zugriff auf den Agenten und alle seine Funktionen liefern soll. Das ist ähnlich wie bei gut dokumentierter API-Dokumentation mit Swagger oder Postman.

Das ist der Inhalt der bereitgestellten Burger-Agent-Karte.

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

Auf diesen Agentenkarten werden viele wichtige Komponenten wie Agentenfähigkeiten, Streamingfunktionen, unterstützte Modalitäten, Protokollversion und andere Dinge hervorgehoben.

Alle diese Informationen können verwendet werden, um einen geeigneten Kommunikationsmechanismus zu entwickeln, damit der A2A-Client ordnungsgemäß kommunizieren kann. Die unterstützte Modalität und der Authentifizierungsmechanismus sorgen dafür, dass die Kommunikation ordnungsgemäß hergestellt werden kann. Die skills-Informationen des Agents können in den Systemprompt des A2A-Clients eingebettet werden, um dem Agent des Clients Kontext zu den Fähigkeiten und Fertigkeiten des Remote-Agents zu geben, die aufgerufen werden sollen. Weitere Informationen zu den Feldern

In unserem Code wird die Implementierung der Agentenkarte mit dem A2A Python SDK eingerichtet. Die Implementierung finden Sie im folgenden Snippet remote_seller_agents/burger_agent/main.py.

...

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

...

Dort sind mehrere Felder zu sehen, z. B.:

  1. AgentCapabilities :Deklaration zusätzlicher optionaler Funktionen, die vom Agent-Dienst unterstützt werden, z. B. Streaming- und/oder Push-Benachrichtigungsunterstützung
  2. AgentSkill :Tools oder Funktionen, die vom Agent unterstützt werden
  3. Input/OutputModes :Unterstützte Modalität des Ein-/Ausgabetyps
  4. Url :Adresse für die Kommunikation mit dem Agent

In dieser Konfiguration wird eine dynamische Agent-Host-URL erstellt, sodass es einfacher ist, zwischen lokalen Tests und der Cloud-Bereitstellung zu wechseln. Aus diesem Grund müssen wir im vorherigen Schritt die Variable HOST_OVERRIDE hinzufügen.

Task Queue und Agent Executor

Ein A2A-Server kann Anfragen von verschiedenen Agents oder Nutzern verarbeiten und jede Aufgabe perfekt isolieren. Die Kontexte sind auf dem Bild unten dargestellt.

10c75db36741da90.jpeg

Daher sollte jeder A2A-Server eingehende Aufgaben verfolgen und entsprechende Informationen dazu speichern können. Das A2A SDK bietet Module, um diese Herausforderung auf dem A2A-Server zu bewältigen. Zuerst können wir die Logik dafür instanziieren, wie wir die eingehende Anfrage verarbeiten möchten. Durch die Übernahme der abstrakten Klasse „AgentExecutor“ können wir steuern, wie die Ausführung und das Abbrechen von Aufgaben verwaltet werden sollen. Diese Beispielimplementierung kann im remote_seller_agents/burger_agent/agent_executor.py-Modul eingesehen werden ( ähnlicher Pfad für den Fall des Pizzaverkäufers).

...

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

...

Im obigen Code implementieren wir ein einfaches Verarbeitungsschema, bei dem der Agent direkt aufgerufen wird, wenn eine Anfrage eingeht, und Ereignisse für abgeschlossene Aufgaben gesendet werden, nachdem der Aufruf beendet wurde. Die Methode zum Abbrechen wurde hier jedoch nicht implementiert, da es sich um einen kurz laufenden Vorgang handelt.

Nachdem wir den Executor erstellt haben, können wir direkt die integrierten DefaultRequestHandler, InMemoryTaskStore und A2AStarletteApplication verwenden,um den HTTP-Server zu starten. Diese Implementierung kann in remote_seller_agents/burger_agent/__main__.py eingesehen werden.

...

        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)

...

In diesem Modul wird die Implementierung der /.well-known/agent.json-Route für den Zugriff auf die Agentenkarte sowie des POST-Endpunkts zur Unterstützung des A2A-Protokolls beschrieben.

Zusammenfassung

Kurz gesagt: Bisher haben wir einen A2A-Server mit dem Python SDK bereitgestellt, der die beiden folgenden Funktionen unterstützt:

  1. Veröffentlichen der Agent-Karte auf der /.well-known/agent.json-Route
  2. JSON-RPC-Anfrage mit In-Memory-Aufgabenwarteschlange verarbeiten

Der Einstiegspunkt beim Start dieser Funktionen kann im __main__.py-Skript ( auf der remote_seller_agents/burger_agent oder remote_seller_agents/pizza_agent) eingesehen werden.

9. 💡 [Code Explanation] Agent Engine Deployment

Hier ist das Code-Snippet des Einkaufskonkurrenten-Agents in purchasing_concierge/purchasing_agent.py::

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

...

Dieser Agent wurde mit dem ADK erstellt und in der Agent Engine bereitgestellt.

Vertex AI Agent Engine ist eine Reihe von Diensten, mit denen Entwickler KI-Agenten in der Produktion bereitstellen, verwalten und skalieren können. Die Infrastruktur zum Skalieren von KI-Agenten in der Produktion wird verwaltet, sodass wir uns auf die Entwicklung von Anwendungen konzentrieren können. Weitere Informationen Bisher mussten wir Dateien vorbereiten, die für die Bereitstellung unseres Agent-Dienstes erforderlich sind, z. B. das main-Serverskript und die Dockerfile. In diesem Fall können wir unseren Agent direkt über das Python-Skript bereitstellen, ohne einen eigenen Back-End-Dienst entwickeln zu müssen. Dazu verwenden wir eine Kombination aus ADK und Agent Engine.

In dieser Anleitung stellen wir die Anwendung mit dem Script deploy_to_agent_engine.py bereit, dessen Inhalt unten zu sehen ist.

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

Das sind die Schritte, die erforderlich sind, um unseren ADK-Agenten in der Agent Engine bereitzustellen. Zuerst müssen wir ein AdkApp-Objekt aus unserem ADK root_agent erstellen. Anschließend können wir die Methode agent_engines.create ausführen, indem wir das adk_app-Objekt, die Anforderungen im Feld requirements, den Pfad zum Agentenverzeichnis in extra_packages ( bei Bedarf können Sie hier auch andere Verzeichnisse und Dateien angeben) und die erforderlichen Umgebungsvariablen angeben.

10. 💡 [Code Explanation] A2A Client Concept and Implementation

e7e3224d05b725f0.jpeg

Das Bild oben zeigt den typischen Ablauf von A2A-Interaktionen:

  1. Der Client versucht, in der bereitgestellten Remote-Agent-URL im Pfad /.well-known/agent.json eine veröffentlichte Agentenkarte zu finden.
  2. Bei Bedarf wird dann eine Nachricht mit der Nachricht und den erforderlichen Metadatenparametern ( z. B. Sitzungs-ID, historischer Kontext usw.) an diesen Agenten gesendet. Der Server betrachtet diese Nachricht als zu erledigende Aufgabe.
  3. Der A2A-Server verarbeitet die Anfrage. Wenn der Server Push-Benachrichtigungen unterstützt, kann er auch während der Aufgabenverarbeitung Benachrichtigungen veröffentlichen. Diese Funktion ist jedoch nicht Teil dieses Codelabs.
  4. Nach Abschluss sendet der A2A-Server das Antwortartefakt zurück an den Client.

Einige der wichtigsten Objekte für die oben genannten Interaktionen sind die folgenden (weitere Informationen) :

  • Nachricht:Eine Kommunikationsrunde zwischen einem Kunden und einem Remote-Kundenservicemitarbeiter
  • Aufgabe: Die von A2A verwaltete Grundeinheit der Arbeit, die durch eine eindeutige ID identifiziert wird.
  • Artefakt:Eine Ausgabe (z. B. ein Dokument, ein Bild oder strukturierte Daten), die vom Agent als Ergebnis einer Aufgabe generiert wird und aus Teilen besteht.
  • Teil:Die kleinste Inhaltseinheit in einer Nachricht oder einem Artefakt. Ein Teil kann Text, ein Bild, ein Video, eine Datei usw. sein.

Karten-Erkennung

Wenn der A2A-Clientdienst eingerichtet wird, wird in der Regel versucht, die Informationen der Agent-Karte abzurufen und zu speichern, damit bei Bedarf leicht darauf zugegriffen werden kann. In diesem Codelab implementieren wir sie auf before_agent_callback. Die Implementierung finden Sie in purchasing_concierge/purchasing_agent.py (siehe Code-Snippet unten).

...

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)

...

Hier versuchen wir, mit dem integrierten A2A-Clientmodul A2ACardResolver auf alle verfügbaren Agentenkarten zuzugreifen. Dann erfassen wir die Verbindung, die zum Senden von Nachrichten an den Agenten erforderlich ist. Außerdem müssen wir alle verfügbaren Agenten und ihre Spezifikationen im Prompt auflisten, damit unser Agent weiß, dass er mit diesen Agenten kommunizieren kann.

Tool „Prompt and Send Task“

Das ist der Prompt und das Tool, das wir unserem ADK-Agenten hier zur Verfügung stellen.

...

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

...

Im Prompt geben wir unserem Purchasing Concierge-Agenten alle verfügbaren Namen und Beschreibungen von Remote-Agents. Im Tool self.send_task stellen wir einen Mechanismus zum Abrufen des entsprechenden Clients bereit, um eine Verbindung zum Agenten herzustellen und die erforderlichen Metadaten mit dem SendMessageRequest-Objekt zu senden.

Die Kommunikationsprotokolle

Die Task-Definition ist eine Domain, die dem A2A-Server gehört. Aus Sicht des A2A-Clients wird die Nachricht jedoch als Nachricht betrachtet, die an den Server gesendet wird. Es liegt am Server, wie eingehende Nachrichten vom Client als welche Aufgabe definiert werden und ob für die Ausführung der Aufgabe eine Interaktion des Clients erforderlich ist. Weitere Informationen zum Aufgabenlebenszyklus finden Sie in dieser Dokumentation. Das übergeordnete Konzept lässt sich so veranschaulichen:

4f2a4c908e0fc75.jpeg

1810d38d264cb6a.jpeg

Dieser Austausch von Nachricht -> Aufgabe wird mithilfe des Nutzlastformats auf Grundlage des JSON-RPC-Standards implementiert, wie im folgenden Beispiel des message/send-Protokolls gezeigt :

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

Es gibt verschiedene Methoden, z. B. zur Unterstützung verschiedener Arten der Kommunikation (z. B. synchron, Streaming, asynchron) oder zum Konfigurieren von Benachrichtigungen für den Aufgabenstatus. Ein A2A-Server kann flexibel konfiguriert werden, um diese Standards für die Aufgabendefinition zu verarbeiten. Details zu diesen Methoden finden Sie in diesem Dokument.

11. 🎯 Herausforderung

Können Sie jetzt die erforderliche Datei vorbereiten und die Gradio-App selbst in Cloud Run bereitstellen? Zeit, die Herausforderung anzunehmen!

12. 🧹 Bereinigen

So vermeiden Sie, dass Ihrem Google Cloud-Konto die in diesem Codelab verwendeten Ressourcen in Rechnung gestellt werden:

  1. Wechseln Sie in der Google Cloud Console zur Seite Ressourcen verwalten.
  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Beenden, um das Projekt zu löschen.
  4. Alternativ können Sie in der Console zu Cloud Run und Agent Engine wechseln, den gerade bereitgestellten Dienst auswählen und löschen.