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

b013ad6b246401eb.png

Das Agent2Agent-Protokoll (A2A) wurde entwickelt, um die Kommunikation zwischen KI-Agents zu standardisieren, insbesondere für Agents, die in externen Systemen bereitgestellt werden. Bisher wurden solche Protokolle für Tools eingerichtet, die als Model Context Protocol (MCP) bezeichnet werden. Das MCP ist ein aufstrebender Standard, um LLMs mit Daten und Ressourcen zu verbinden. A2A soll MCP ergänzen. Während sich MCP darauf konzentriert, die Komplexität zu verringern, um Agenten mit Tools und Daten zu verbinden, konzentriert sich A2A darauf, wie 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, dass Anwendungen MCP für Tools und A2A für Agents 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-Agents und anderen Agents zu kommunizieren.

83b1a03588b90b68.png

In dieser Demo beginnen wir mit der Implementierung von A2A mithilfe des 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.

aa6c8bc5b5df73f1.jpeg

  1. Der A2A-Client führt zuerst die Suche auf allen zugänglichen A2A-Server-Agent-Karten 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 zu erledigende Aufgabe aus. 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:

9cfc4582f2d8b6f3.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 ausgeführt wird und als A2A-Client fungiert.

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

Voraussetzungen

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

Lerninhalte

  • Kernstruktur des A2A-Servers
  • Kernstruktur des A2A-Clients
  • Agent-Dienst in Cloud Run bereitstellen
  • Agent-Dienst in Agent Engine bereitstellen
  • So stellt der A2A-Client eine Verbindung zum 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).

78c981437f90248.png

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

2f5247dd825b808c.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ü.

db49b5267c00cc33.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.

e44b767990aa6aab.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.

1829c3759227c19b.png

b8fe7df5c3c2b919.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.

fadd80f0da3b906.png

Wenn der angezeigte Wert bereits korrekt ist, können Sie den nächsten Befehl überspringen. Wenn sie jedoch 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 b16d56e4979ec951.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.

2c53696f81d805cc.png

253b472fa1bd752e.png

Ihr Cloud Shell Editor sollte jetzt so aussehen:

aedd0725db87717e.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.

f8457daf0bed059e.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 Agenten für Remote-Verkäufer bereit, die durch das rote Kästchen gekennzeichnet sind. Der Burger-Agent basiert auf dem CrewAI-Agent-Framework und der Pizza-Agent auf dem Langgraph-Agent.

e91777eecfbae4f7.png

4. 🚀 Burger Seller-Agent – 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-Kundenservicedienste über den Browser auf. Dies ist die URL für den Zugriff auf die bereitgestellte A2A-Server-Agent-Karte.

Wenn die Bereitstellung erfolgreich war, wird beim Zugriff auf die Agent-Karte in Ihrem Browser die folgende Antwort angezeigt.

72fdf3f52b5e8313.png

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

Beachten Sie, dass der Wert url hier weiterhin auf http://0.0.0.0:8080/ festgelegt ist. Dieser url-Wert sollte die Hauptinformationen 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“.

1adde569bb345b48.png

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

9091c12526fb7f41.png

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

2701da8b124793b9.png

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

31ea00e12134d74d.png

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

52b382da7cf33cd5.png

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

11464f4a51ffe54.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.

2ed7ebcb530f070a.png

5. 🚀 Pizza Seller-Agent bereitstellen – 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 der 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“.

1adde569bb345b48.png

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

5743b0aa0555741f.png

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

d60ba267410183be.png

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

618e9da2f94ed415.png

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

214a6eb98f877e65.png

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

11464f4a51ffe54.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.

c37b26ec80c821b6.png

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

6. 🚀 Einsatz des Purchasing Concierge – A2A-Client für die Agent Engine

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

c4a8e7a3d18b1ef.png

Der Quellcode unseres Purchasing Concierge-Agents befindet sich im Verzeichnis purchasing_concierge. Die Initialisierung des Agents kann im Script purchasing_concierge/purchasing_agent.py geprüft 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 Variable .env 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 auf einem neuen Tab zu öffnen.

1adde569bb345b48.png

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

179e55cc095723a8.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.

64c01403a92b1107.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 Dashboard der Agent-Engine prüfen (suchen Sie in der Suchleiste nach „Agent-Engine“), wird unsere vorherige Bereitstellung angezeigt.

e80f1c00ec9fbb38.png

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

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 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 eine Interaktion mit dem bereitgestellten Agenten zu starten.

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

Sie können das Script untersuchen und sehen, dass wir versuchen, den Agenten zu fragen: List available burger menu please (Bitte liste das verfügbare Burgermenü auf).

Bei Erfolg werden in der Konsole mehrere Antwort-Ereignisse gestreamt, wie hier zu sehen:

{
  "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 erläutern.

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

b38b428d9e4582bc.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 Tool-Aufruf und die Antwort sind. Das folgende Bild zeigt ein Beispiel für das Interaktionsergebnis.

ff5f752965816b2b.png

6f65155c7a289964.png

b390f4b15f1c5a8c.png

ff44c54b50c36e1a.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-Kundenservicemitarbeiter.

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 Agent-Karte 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 Agent-Karte unseres bereitgestellten Burger-Agents.

{
  "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 dieser Agent-Karte

In unserem Code wird die Implementierung der Agent-Karte 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.

b9eb6b4025db4642.jpeg

Daher sollte jeder A2A-Server eingehende Aufgaben verfolgen und entsprechende Informationen dazu speichern können. Das A2A SDK bietet Module, mit denen diese Herausforderung auf dem A2A-Server bewältigt werden kann. 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 wir die Ausführung und das Abbrechen von Aufgaben verwalten möchten. 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 Agent-Karte und 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-Warteschlange für Aufgaben 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 Purchasing Concierge-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 wird in der Agent Engine bereitgestellt.

Vertex AI Agent Engine ist eine Reihe von Diensten, mit denen Entwickler KI-Agents 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 Inhalte mit dem Skript 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}")

So stellen Sie Ihren ADK-KI-Agenten in der Agent Engine bereit. 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 Objekt adk_app, die Anforderungen im Feld requirements, den Agent-Verzeichnispfad 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

aa6c8bc5b5df73f1.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 Agent-Karte 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 gestartet 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, über das integrierte 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 in den Prompt aufnehmen, 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 Message (Nachricht) betrachtet, die an den Server gesendet wird. Es liegt am Server, eingehende Nachrichten vom Client als welche Aufgabe zu definieren 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:

65b8878a4854fd93.jpeg

9ddfae690d40cbbf.jpeg

Dieser Austausch von Nachricht -> Aufgabe wird mithilfe des Nutzlastformats auf Grundlage des JSON-RPC-Standards implementiert, wie im folgenden Beispiel für das message/send-Protokoll 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.