KI-Agenten mit ADK erstellen: Graph-Workflows orchestrieren

1. Übersicht

Um eine Reiseanfrage mit mehreren Einschränkungen zu erfüllen (z. B. die Planung eines Tagesausflugs in Kyoto für 100 $, der historische Tempel, lokale Ramen und keine Museen für moderne Kunst umfasst), müssen strukturierte Präferenzen extrahiert, Orte gleichzeitig recherchiert, ein detaillierter Entwurf erstellt und die Gesamtkosten geprüft werden, bevor eine Antwort gegeben wird. In ADK 1.x mussten Sie zum Orchestrieren dieser Phasen die Wrapper SequentialAgent, ParallelAgent und LoopAgent verschachteln, jede Zwischenausgabe im Sitzungsstatus speichern und einen zusätzlichen LLM-Toolaufruf ausführen, nur um eine Optimierungsschleife zu beenden.

In diesem Codelab erstellen Sie einen Multi-Agenten-Reiseplaner auf der Agent Platform mit Agent Development Kit (ADK) 2-Graph-Workflows (Workflow). In drei aufeinanderfolgenden Phasen verbinden Sie spezialisierte Agent-Knoten (unterstützt von gemini-3.8-flash) in einer sequenziellen Edge-Kette (node_input), fächern gleichzeitige google_search-Researcher auf, die mit JoinNode synchronisiert sind, und setzen Budget- und Ausschlussregeln mit einem deterministischen Python-Router (Event(route=...)) durch, der die Optimierung überspringt, wenn der ursprüngliche Entwurf die Prüfung besteht.

Vorbereitung

Lerninhalte

  • Multi-Agenten-Pipeline in ADK 2 mit Workflow-Edge-Tupeln deklarieren
  • Wie ADK 2 Ausgaben direkt über Kanten als node_input übergibt und Sitzungsstatusschlüssel als Funktionsparameter bindet
  • Gleichzeitige Recherche-Zweige aufteilen und ihre Ausgaben mit JoinNode zusammenführen
  • Begrenzte Maker-Checker-Zyklen in Python mit Event(route=...) deterministisch weiterleiten
  • Kompilierte Workflow-Diagramme, Zeitachsen für die parallele Ausführung und Statusdeltas in der ADK-Web-UI prüfen

Voraussetzungen

  • Ein Google-Konto (verwenden Sie ein privates @gmail.com-Konto, wenn Sie Workshop-Guthaben einlösen möchten)
  • Einen Link für Workshop-Guthaben von Ihrem Kursleiter (plus eine Smartphone-Kamera zum Scannen des QR-Codes) oder ein aktives Cloud-Rechnungskonto
  • Google Chrome (ein Inkognitofenster wird empfohlen, um eine Vermischung von privaten und geschäftlichen Konten zu vermeiden)

2. Google Cloud-Guthaben einlösen (optional)

Wenn Sie an einem Workshop mit einem Link für Veranstaltungsguthaben teilnehmen, fordern Sie Ihr Google Developer Program-Guthaben an, um ein Rechnungskonto ohne Kreditkarte bereitzustellen.

Event-Guthaben erhalten

  1. Öffnen Sie den Link für das Workshop-Guthaben in einem Inkognitofenster und melden Sie sich mit Ihrem @gmail.com-Konto an.
  2. Klicken Sie unter Vorteil erhalten auf Guthaben erhalten:

Karte „Vorteil einlösen“ im Google Builders Hub mit der Schaltfläche „Guthaben einlösen“

  1. Wenn Sie aufgefordert werden, ein Google Developer Program-Profil zu erstellen, füllen Sie das Formular aus.
  2. Wenn Scan to Verify You're Human (Scannen, um zu bestätigen, dass Sie ein Mensch sind) angezeigt wird, scannen Sie den QR-Code mit Ihrem Smartphone und schließen Sie die Bestätigung ab. Wenn der QR-Code nicht angezeigt wird, aktualisieren Sie die Seite und klicken Sie noch einmal auf Claim Credit (Guthaben einlösen):

Dialogfeld „Scannen Sie den QR-Code, um zu bestätigen, dass Sie ein Mensch sind“ des Google Developer Program

  1. Prüfen Sie, ob die Meldung Sie haben Ihr Event-Guthaben erhalten angezeigt wird, und klicken Sie dann auf Rechnungskonto öffnen:

Google Builders Hub mit der Meldung „Sie haben Ihr Event-Guthaben erhalten“ und der Schaltfläche „Rechnungskonto öffnen“

🔍 Arbeit überprüfen lassen

Die Einrichtung des Rechnungskontos dauert bis zu 3 Minuten:

  1. Öffnen Sie die Google Cloud-Abrechnung (oder kopieren Sie die URL in ein Inkognitofenster) und wählen Sie Meine Rechnungskonten aus:
https://console.cloud.google.com/billing
  1. Aktualisieren Sie die Seite, bis für Ihr GDP Credit-Konto der Status Aktiv angezeigt wird:

Google Cloud-Rechnungskontoverwaltung mit einem aktiven GDP-Guthaben-Rechnungskonto

3. Google Cloud-Projekt erstellen (optional)

Erstellen Sie ein dediziertes Google Cloud-Projekt, damit alle Ressourcen aus diesem Codelab isoliert bleiben und sich leicht bereinigen lassen.

  1. Öffnen Sie Projekt erstellen oder kopieren Sie die URL in Ihr Inkognitofenster:
https://console.cloud.google.com/projectcreate
  1. Geben Sie die Projektdetails ein:
    • Projektname: z. B. google-cloud-workshop
    • Rechnungskonto (falls angezeigt): Wählen Sie GDP Credit (oder Ihr aktives Rechnungskonto) aus.
    • Übergeordnete Ressource: Keine Organisation (oder wählen Sie bei Bedarf Ihre Organisation aus)
  2. Notieren Sie sich die generierte Projekt-ID unter dem Projektnamen und klicken Sie dann auf Erstellen:

Bildschirm „Google Cloud-Projekt erstellen“ mit Projektname, Projekt-ID, übergeordneter Ressource und Schaltfläche „Erstellen“

🔍 Arbeit überprüfen lassen

Klicken Sie in der Symbolleiste oben rechts auf Benachrichtigungen und dann auf Projekt auswählen, sobald das Projekt erstellt wurde:

Menü „Benachrichtigungen“ in der Google Cloud Console mit dem Link „Projekt erstellen“ und „Projekt auswählen“

4. Umgebung einrichten

Google Cloud Shell konfigurieren, die Agent Platform API aktivieren und mit uv eine isolierte virtuelle Python 3.12-Umgebung erstellen.

Cloud Shell konfigurieren

  1. Klicken Sie in der Symbolleiste der Google Cloud Console auf Cloud Shell aktivieren (>_) oder öffnen Sie die Google Cloud Shell direkt (oder kopieren Sie die URL in Ihr Inkognitofenster):
https://shell.cloud.google.com/?show=ide,terminal

Button „Cloud Shell aktivieren“ in der Symbolleiste der Google Cloud Console

  1. Klicken Sie auf Autorisieren, wenn Sie dazu aufgefordert werden:

Dialogfeld „Cloud Shell autorisieren“

  1. Wählen Sie im nummerierten Menü in Ihrem Terminal die aktive Google Cloud-Projekt-ID aus:
unset CLOUDSDK_CORE_PROJECT
PS3="Select your project (e.g. 1): "
select PROJECT_ID in $(gcloud projects list --format="value(projectId)"); do
  [ -n "$PROJECT_ID" ] && gcloud config set project "$PROJECT_ID" && break
done

Die Ausgabe sollte in etwa so aussehen (für Projekte ohne Tags wird auch eine Informationszeile [environment: untagged] ausgegeben):

1) google-cloud-workshop-4210
2) my-cloud-project-8812
Select your project (e.g. 1): 1
Updated property [core/project].

Prüfen Sie, ob die ausgewählte Projekt-ID in der Cloud Shell-Eingabeaufforderung gelb hervorgehoben ist:

Cloud Shell-Terminal mit gelb hervorgehobener ausgewählter Projekt-ID

Erforderliche APIs aktivieren

Aktivieren Sie die Agent Platform API, damit Ihre ADK-Agenten Gemini-Modelle aufrufen können:

gcloud services enable aiplatform.googleapis.com

Die Ausgabe sollte etwa so aussehen:

Operation "operations/acat.p2-..." finished successfully.

Virtuelle Python-Umgebung erstellen und ADK installieren

Erstellen Sie den Arbeitsbereich ~/adk-graph-agents und aktivieren Sie eine virtuelle Python 3.12-Umgebung:

cd ~
mkdir -p adk-graph-agents && cd ~/adk-graph-agents

which uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"

uv venv .venv --python 3.12
source .venv/bin/activate

Prüfen Sie, ob das Präfix (.venv) am Anfang der Terminal-Eingabeaufforderung angezeigt wird:

Cloud Shell-Terminal mit dem Präfix „.venv“ in einer aktiven virtuellen Python-Umgebung

Installieren Sie ADK 2 in der aktiven virtuellen Umgebung:

uv pip install --no-cache "google-adk==2.14.0"

🔍 Arbeit überprüfen lassen

Prüfen Sie die installierte adk-CLI-Version:

adk --version

Die Ausgabe sollte etwa so aussehen:

adk, version 2.14.0

5. Reiseplaner erstellen

Generieren Sie das Starterpaket für travel_planner mit adk create und testen Sie die Standard-Baseline für einen einzelnen Agenten in adk web.

Starterpaket generieren

Führen Sie adk create aus ~/adk-graph-agents aus:

cd ~/adk-graph-agents
adk create travel_planner

Wählen Sie die folgenden Optionen aus, wenn Sie dazu aufgefordert werden. Wenn Sie beim ersten Ausführen die Aufforderung Enable telemetry? [Y/n]: erhalten, drücken Sie die Eingabetaste oder geben Sie n ein und drücken Sie die Eingabetaste:

  1. Modell für den Root-Agenten auswählen: Geben Sie 2 ein, um gemini-3.8-flash auszuwählen (mit Option 1 wird gemini-3.5-flash ausgewählt), und drücken Sie die Eingabetaste.
  2. Backend auswählen: Geben Sie 2 ein, um das Google Cloud Agent Platform-Backend auszuwählen (Option 2 im Befehlszeilenmenü unten), und drücken Sie die Eingabetaste.
  3. Google Cloud-Projekt-ID eingeben: Drücken Sie die Eingabetaste, um die erkannte Projekt-ID in Klammern zu akzeptieren.
  4. Google Cloud-Region eingeben: Geben Sie global ein, um den globalen Gemini-Endpunkt zu verwenden, und drücken Sie die Eingabetaste.

adk create schreibt GOOGLE_GENAI_USE_ENTERPRISE=1, Ihre Projekt-ID und GOOGLE_CLOUD_LOCATION=global in travel_planner/.env, damit Ihre Anmeldedaten intakt bleiben, wenn Sie agent.py später ersetzen.

Die Ausgabe sollte etwa so aussehen:

Choose a model for the root agent:
1. gemini-3.5-flash
2. gemini-3.8-flash
3. Other models (fill later)
Choose model (1, 2, 3): 2
1. Google AI
2. Vertex AI
3. Login with Google
Choose a backend (1, 2, 3): 2

You need an existing Google Cloud account and project, check out this link for details:
https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai

Enter Google Cloud project ID [google-cloud-workshop-4210]:
Enter Google Cloud region [us-central1]: global

Agent created in /home/your_username/adk-graph-agents/travel_planner:
- .env
- .gitignore
- __init__.py
- agent.py

⚠️  WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env.

Next steps:
- Chat with your agent in the terminal: adk run travel_planner
- Or in the browser: adk web .
- Have your coding agent evaluate and deploy it: uvx google-agents-cli setup
  (other install options: https://adk.dev/get-started/agents-cli/)

Öffnen Sie ~/adk-graph-agents im Cloud Shell-Code-Editor:

which cloudshell >/dev/null 2>&1 && cloudshell workspace ~/adk-graph-agents || true

Aktivieren Sie die virtuelle Umgebung im neu geladenen Terminal wieder:

cd ~/adk-graph-agents
source .venv/bin/activate

Starter-KI-Agenten testen

Starten Sie die ADK-Web-UI, um zu sehen, wie ein einzelner nicht orchestrierter Starter-Agent auf einen Prompt zum Thema Reisen antwortet:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Klicken Sie rechts oben in der Cloud Shell-Symbolleiste auf das Symbol Webvorschau, wählen Sie Port ändern aus, geben Sie 8000 ein und klicken Sie auf Ändern und Vorschau ansehen:

Dialogfeld zur Portkonfiguration für die Cloud Shell-Webvorschau, auf 8000 festgelegt

🔍 Arbeit überprüfen lassen

Wählen Sie im Drop-down-Menü oben links in adk web die Option travel_planner aus und senden Sie "Help me plan a trip to Japan":

ADK-Entwicklungs-Web-UI mit einer einfachen Unterhaltung mit einem einzelnen Agenten

Im Chatbereich sollte eine Antwort in Form einer Unterhaltung mit einem einzigen Durchlauf angezeigt werden (mit einem einzigen Aufruf von root_agent in Ereignisse):

root_agent -> responds in one pass without structured preference extraction, live search, or budget verification

Drücken Sie in Ihrem Cloud Shell-Terminal Ctrl + C, um adk web zu beenden, bevor Sie im nächsten Schritt Dateien bearbeiten.

6. Workflow für ein lineares Diagramm erstellen

Erstellen Sie Ihren ersten ADK 2-Workflow: eine sequenzielle Kette, die den reservierten Einstiegspunkt "START" mit user_profiler_agent und itinerary_synthesizer_agent verbindet (jeder Knoten ohne ausgehende Kanten fungiert als Endknoten). Jede Edge (a, b) führt automatisch Agent-Knoten (ein Alias für LlmAgent) im isolierten single_turn-Modus aus und liefert die Ausgabe von Knoten a als node_input (die eingehende Nutzernachricht) an Knoten b, während {user_preferences} in einem Anweisungsstring den entsprechenden Sitzungsstatusschlüssel interpoliert, der über output_key gespeichert wurde.

Architekturdiagramm, das zeigt, wie „travel_workflow“ (Workflow) START mit „user_profiler_agent“ und „itinerary_synthesizer_agent“ verbindet

Erste Spezialisten erstellen

Achten Sie darauf, dass adk web beendet ist (Ctrl + C), und öffnen Sie dann eine neue Datei mit dem Namen travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Fügen Sie den folgenden Code in travel_planner/specialists.py ein, um user_profiler_agent und itinerary_synthesizer_agent zu definieren. Importieren Sie vorab google_search für den nächsten Schritt:

from google.adk import Agent
from google.adk.tools import google_search

MODEL = "gemini-3.8-flash"

# --- Specialist 1: The User Profiler ---
user_profiler_agent = Agent(
    model=MODEL,
    name="user_profiler_agent",
    description="Extracts travel preferences and constraints from user input.",
    instruction="""
        Extract destination, duration (default 1 day), budget, interests, and exclusions.
        Return a single JSON object with keys: "destination", "duration", "budget", "interests", "exclusions".
    """,
    output_key="user_preferences",  # Saved for multi-hop constraints downstream
)

# --- Specialist 2: The Synthesizer ---
itinerary_synthesizer_agent = Agent(
    model=MODEL,
    name="itinerary_synthesizer_agent",
    description="Compiles preferences and research into a final Markdown itinerary.",
    instruction="""
        You are an elite Travel Concierge. Using the incoming input and
        User Preferences ({user_preferences}), write a Markdown itinerary
        with an itemized USD and local currency cost breakdown.
    """,
    output_key="final_itinerary",
)

Sequenzielle Edge-Kette definieren

Öffnen Sie eine neue Datei mit dem Namen travel_planner/workflows.py:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Fügen Sie die folgende Workflow-Definition ein (wobei ein Tupel aus 3 oder mehr Knoten in eine sequenzielle Kette aus "START" kompiliert wird):

from google.adk import Workflow
from .specialists import (
    itinerary_synthesizer_agent,
    user_profiler_agent,
)

# 1. SEQUENTIAL GRAPH: START -> user_profiler_agent -> itinerary_synthesizer_agent
travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        ("START", user_profiler_agent, itinerary_synthesizer_agent),
    ],
)

Workflow als root_agent freigeben

Rufen Sie travel_planner/agent.py auf:

cloudshell edit ~/adk-graph-agents/travel_planner/agent.py

Ersetzen Sie den gesamten Inhalt von travel_planner/agent.py durch diese beiden Zeilen:

from .workflows import travel_workflow

root_agent = travel_workflow

🔍 Arbeit überprüfen lassen

Starten Sie adk web von ~/adk-graph-agents:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Öffnen Sie die Webvorschau auf Port 8000, klicken Sie auf + Neue Sitzung und senden Sie Folgendes:

Help me plan a trip to Kyoto

In der Ansicht Ereignisse sollte eine Ereignissequenz ähnlich der folgenden angezeigt werden:

1. user_profiler_agent -> outputs JSON {"destination": "Kyoto", "duration": "1 day", ...} and writes state["user_preferences"]
2. itinerary_synthesizer_agent -> receives preferences via node_input and outputs the Markdown itinerary

ADK 2.14.0-Web-UI mit der Ausführung des Graphen von START über user_profiler_agent zu itinerary_synthesizer_agent und dem generierten Reiseplan für Kyoto

Klicken Sie unter Ereignisse auf ein beliebiges Ereignis und dann auf das Symbol Diagramm (account_tree in der Symbolleiste für Ereignisdetails), um die kompilierte START -> user_profiler_agent -> itinerary_synthesizer_agent-Topologie zu prüfen. Sehen Sie sich dann den Tab Status an, um zu prüfen, ob user_preferences und final_itinerary ausgefüllt sind.

Drücken Sie in Ihrem Terminal Ctrl + C, um adk web zu beenden, bevor Sie fortfahren.

7. Fan-out und Join mit JoinNode

Fundieren Sie den Reiseplan mit Live-Webdaten, indem Sie zwei gleichzeitige google_search-Spezialisten (activity_finder_agent und restaurant_finder_agent) hinzufügen und sie mit JoinNode synchronisieren:

  • Fan-out-Tupel: Wenn Sie (activity_finder_agent, restaurant_finder_agent) in das Edge-Tupel einfügen, wird die Ausgabe von user_profiler_agent als node_input gleichzeitig an beide Forscher gesendet.
  • Fan-In-Barriere (JoinNode): Wenn Sie JoinNode(name="research_join") direkt nach dem Tupel platzieren, wird gewartet, bis jeder eingehende Zweig abgeschlossen ist. Dann wird ein zusammengeführtes dict ({"activity_finder_agent": ..., "restaurant_finder_agent": ...}) als node_input an itinerary_synthesizer_agent übergeben, anstatt die Synthese zweimal auszulösen.

Architekturdiagramm, das zeigt, wie „travel_workflow“ von „user_profiler_agent“ über „node_input“ parallel zu „activity_finder_agent“ und „restaurant_finder_agent“ verzweigt, bei „research_join“ (JoinNode) zusammengeführt wird und „node_input“ (dict) an „itinerary_synthesizer_agent“ übergibt

Forschungsspezialisten anhängen

Prüfen Sie, ob adk web beendet ist (Ctrl + C), und öffnen Sie dann travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Hängen Sie activity_finder_agent und restaurant_finder_agent an das Ende von travel_planner/specialists.py an (für beide ist kein output_key erforderlich, da research_join beide Ausgaben direkt über node_input weiterleitet):

# --- Specialist 3: The Activity Finder ---
activity_finder_agent = Agent(
    model=MODEL,
    name="activity_finder_agent",
    description="Finds 3 attractions matching the user's destination and interests.",
    instruction="""
        Using the travel preferences in the input, call google_search to find 3 specific attractions
        (including budget-friendly options).
        Return a JSON list with keys: "attraction_name", "estimated_cost_local", "estimated_cost_usd", "notes".
    """,
    tools=[google_search],
)

# --- Specialist 4: The Restaurant Finder ---
restaurant_finder_agent = Agent(
    model=MODEL,
    name="restaurant_finder_agent",
    description="Finds 3 restaurants matching the destination and budget.",
    instruction="""
        Using the travel preferences in the input, call google_search to find 3 highly-rated restaurants
        across price points.
        Return a JSON list with keys: "restaurant_name", "cuisine", "estimated_cost_local", "estimated_cost_usd".
    """,
    tools=[google_search],
)

Fan-out und JoinNode zu workflows.py hinzufügen

Rufen Sie travel_planner/workflows.py auf:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Ersetzen Sie den gesamten Inhalt von travel_planner/workflows.py durch den Fan-out- und JoinNode-Graphen:

from google.adk import Workflow
from google.adk.workflow import JoinNode
from .specialists import (
    activity_finder_agent,
    itinerary_synthesizer_agent,
    restaurant_finder_agent,
    user_profiler_agent,
)

research_join = JoinNode(name="research_join")

# 2. FAN-OUT / FAN-IN GRAPH: Profile -> (Activities || Restaurants) -> Join -> Synthesize
travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        (
            "START",
            user_profiler_agent,
            (activity_finder_agent, restaurant_finder_agent),
            research_join,
            itinerary_synthesizer_agent,
        ),
    ],
)

🔍 Arbeit überprüfen lassen

Starten Sie adk web, um die gleichzeitige Suche und die JoinNode-Synchronisierung zu testen:

cd ~/adk-graph-agents
adk web --allow_origins "*"

Öffnen Sie die Webvorschau auf Port 8000, klicken Sie auf + Neue Sitzung und senden Sie Folgendes:

Help me plan a trip to Kyoto focused on historic temples and ramen

In der Ansicht Ereignisse sollte eine Ereignissequenz ähnlich der folgenden angezeigt werden:

1. user_profiler_agent -> emits JSON preferences via node_input
2. activity_finder_agent & restaurant_finder_agent -> invoke google_search concurrently
3. research_join -> merges both researcher outputs into one dict node_input
4. itinerary_synthesizer_agent -> drafts final_itinerary from the merged dict + {user_preferences}

Drücken Sie in Ihrem Terminal Ctrl + C, um adk web zu beenden, bevor Sie fortfahren.

8. Zyklen für die Routenüberarbeitung

Erzwingen Sie Budget- und negative Einschränkungen, indem Sie einen itinerary_critic_agent, einen itinerary_refiner_agent und zwei deterministische Python-Funktionsknoten (route_critique und finalize_itinerary) hinzufügen, die ADK-Event-Objekte zurückgeben:

  • route: Wählt aus, welcher benannte Zweigschlüssel in einer Dict-Edge ({"revise": ..., "approved": ...}) als Nächstes ausgeführt wird.
  • output: Übergibt einen typisierten Python-Wert oder String entlang der Kante als node_input an den nächsten Knoten, ohne eine Chatnachricht zu rendern.
  • message und state: message gibt für den Nutzer sichtbaren Text im Chatprotokoll aus, während state Schlüssel/Wert-Updates (stateDelta) im Sitzungsstatus speichert.

Architekturdiagramm, das den „travel_workflow“ zeigt, wobei der „itinerary_critic_agent“ die „route_critique“ füttert, die „revise“ an den „itinerary_refiner_agent“ (mit Schleife zurück zum „itinerary_critic_agent“) oder „approved“ an „finalize_itinerary“ weiterleitet

Kritiker- und Optimierungsspezialisten anhängen

Prüfen Sie, ob adk web beendet ist (Ctrl + C), und öffnen Sie dann travel_planner/specialists.py:

cloudshell edit ~/adk-graph-agents/travel_planner/specialists.py

Hängen Sie itinerary_critic_agent und itinerary_refiner_agent unten an travel_planner/specialists.py an (der Refiner benötigt kein google_search- oder exit_loop-Tool, da er Elemente austauscht, die bereits in {final_itinerary} erfasst wurden, und nur ausgeführt wird, wenn route_critique "revise" auswählt):

# --- Specialist 5: The Budget & Constraint Critic ---
itinerary_critic_agent = Agent(
    model=MODEL,
    name="itinerary_critic_agent",
    description="Audits the itinerary draft against budget and negative constraints.",
    instruction="""
        Audit the itinerary in the input against User Preferences ({user_preferences}).
        Verify that the USD total stays within the user's budget and no excluded venue types appear.
        If all checks pass, respond EXACTLY with the single word "APPROVED".
        Otherwise, output 1-2 concise revision instructions explaining what to swap or adjust.
    """,
)

# --- Specialist 6: The Itinerary Refiner ---
itinerary_refiner_agent = Agent(
    model=MODEL,
    name="itinerary_refiner_agent",
    description="Revises the itinerary draft using the critic's feedback.",
    instruction="""
        Revise Current Itinerary ({final_itinerary}) using the auditor critique in the input
        so all USD budget and exclusion rules in {user_preferences} pass.
        Output ONLY the updated Markdown itinerary.
    """,
    output_key="final_itinerary",
)

route_critique und den Zyklus hinzufügen

Rufen Sie travel_planner/workflows.py auf:

cloudshell edit ~/adk-graph-agents/travel_planner/workflows.py

Ersetzen Sie den gesamten Inhalt von travel_planner/workflows.py durch den vollständigen Graph-Workflow:

from google.adk import Event, Workflow
from google.adk.workflow import JoinNode
from .specialists import (
    activity_finder_agent, itinerary_critic_agent, itinerary_refiner_agent,
    itinerary_synthesizer_agent, restaurant_finder_agent, user_profiler_agent,
)

MAX_REVISIONS = 2
research_join = JoinNode(name="research_join")


def route_critique(node_input: str, revision_count: int = 0):
    """Routes to 'approved' when constraints pass, or 'revise' up to MAX_REVISIONS."""
    approved = node_input.strip().rstrip(".").upper() == "APPROVED"
    if approved or revision_count >= MAX_REVISIONS:
        return Event(route="approved", output=approved)
    return Event(
        route="revise", output=node_input, state={"revision_count": revision_count + 1}
    )


def finalize_itinerary(node_input: bool, final_itinerary: str, revision_count: int = 0):
    """Emits the verified itinerary and resets revision_count for the next turn."""
    status = (
        f"Itinerary approved after {revision_count} revision(s)."
        if node_input
        else f"Max revisions ({revision_count}) reached; returning best-effort draft."
    )
    return Event(
        message=f"{status}\n\n{final_itinerary}",
        output=final_itinerary,
        state={"revision_count": 0},
    )


travel_workflow = Workflow(
    name="travel_workflow",
    description="Orchestrates the end-to-end travel planning process as a graph workflow.",
    edges=[
        (
            "START",
            user_profiler_agent,
            (activity_finder_agent, restaurant_finder_agent),
            research_join,
            itinerary_synthesizer_agent,
            itinerary_critic_agent,
            route_critique,
        ),
        (route_critique, {"revise": itinerary_refiner_agent, "approved": finalize_itinerary}),
        (itinerary_refiner_agent, itinerary_critic_agent),
    ],
)

🔍 Arbeit überprüfen lassen

Prüfen Sie, ob travel_planner/workflows.py fehlerfrei kompiliert wird und die Kanten des gerichteten Graphen ausgibt:

cd ~/adk-graph-agents && source .venv/bin/activate
python3 -c "from travel_planner.agent import root_agent; print('\n'.join(f'{e.from_node.name} -> {e.to_node.name} (route={e.route})' for e in root_agent.graph.edges))"

Die Ausgabe sollte etwa so aussehen:

__START__ -> user_profiler_agent (route=None)
user_profiler_agent -> activity_finder_agent (route=None)
user_profiler_agent -> restaurant_finder_agent (route=None)
activity_finder_agent -> research_join (route=None)
restaurant_finder_agent -> research_join (route=None)
research_join -> itinerary_synthesizer_agent (route=None)
itinerary_synthesizer_agent -> itinerary_critic_agent (route=None)
itinerary_critic_agent -> route_critique (route=None)
route_critique -> itinerary_refiner_agent (route=revise)
route_critique -> finalize_itinerary (route=approved)
itinerary_refiner_agent -> itinerary_critic_agent (route=None)

Starten Sie als Nächstes adk web, um sowohl die sofortige Genehmigung als auch die durch das Budget ausgelösten Überarbeitungen zu testen:

adk web --allow_origins "*"

Öffnen Sie die Webvorschau auf Port 8000, klicken Sie auf + Neue Sitzung und senden Sie den Prompt mit mehreren Einschränkungen für Kyoto:

Design a full-day itinerary for Kyoto with a total budget of $100. My main interests are historical landmarks, temples, and authentic local cuisine. Please do not include any modern art museums or galleries.

Wenn Sie die route="revise"-Schleife in Aktion sehen möchten, senden Sie einen weiterführenden Prompt mit einem knappen Budget von 15 $:

Now design a full-day Kyoto itinerary with paid temple admissions, lunch, and dinner on a strict total budget of $15 USD.

In der Ansicht Ereignisse sollte eine Ausführungssequenz ähnlich der folgenden angezeigt werden:

1. user_profiler_agent -> writes JSON constraints to state["user_preferences"]
2. (activity_finder_agent, restaurant_finder_agent) -> run google_search concurrently -> research_join
3. itinerary_synthesizer_agent -> writes initial draft to state["final_itinerary"]
4. itinerary_critic_agent -> outputs "APPROVED" (or revision instructions when over budget)
5. route_critique -> emits route="approved" (skipping refiner) or route="revise" -> itinerary_refiner_agent -> itinerary_critic_agent
6. finalize_itinerary -> emits "Itinerary approved after N revision(s)." (or max-revisions notice) and resets revision_count=0

Drücken Sie im Terminal Ctrl + C, um adk web zu beenden.

9. Fehlerbehebung

Das Drop-down-Menü für KI-Agenten in adk web ist leer.

  • Ursache: adk web wurde in travel_planner/ statt im übergeordneten Verzeichnis ~/adk-graph-agents gestartet oder die Cloud Shell-Sitzung wurde neu gestartet.
  • Lösung: Drücken Sie Ctrl + C, kehren Sie zum übergeordneten Verzeichnis zurück und starten Sie mit cd ~/adk-graph-agents && source .venv/bin/activate && adk web --allow_origins "*" neu.

404 NOT_FOUND Modellfehler

  • Ursache: Sie haben während adk create die Eingabetaste gedrückt, um die Standardregion us-central1 zu akzeptieren, anstatt global einzugeben.
  • Lösung: Öffnen Sie ~/adk-graph-agents/travel_planner/.env und prüfen Sie, ob GOOGLE_CLOUD_LOCATION=global festgelegt ist.

ERROR: [Errno 98] address already in use an Port 8000

  • Ursache: Ein vorheriger adk web-Server wird noch in Cloud Shell ausgeführt.
  • Lösung: Drücken Sie im aktiven Terminal Ctrl + C oder beenden Sie den vorhandenen Prozess mit pkill -f "adk web", bevor Sie adk web noch einmal starten.

10. Bereinigen

Entfernen Sie den lokalen Arbeitsbereich und deaktivieren Sie optional die API oder löschen Sie ein dediziertes Workshop-Projekt.

Lokale Projektdateien löschen

Entfernen Sie das Verzeichnis ~/adk-graph-agents und die virtuelle Umgebung:

cd ~
rm -rf ~/adk-graph-agents

Agent Platform API deaktivieren (optional)

Deaktivieren Sie die Agent Platform API, wenn Sie sie in diesem Projekt nicht mehr benötigen:

gcloud services disable aiplatform.googleapis.com --quiet

🔍 Arbeit überprüfen lassen

Bestätigen Sie, dass ~/adk-graph-agents entfernt wurde:

test ! -d ~/adk-graph-agents && echo "Workspace ~/adk-graph-agents removed"

Die Ausgabe sollte etwa so aussehen:

Workspace ~/adk-graph-agents removed

11. Glückwunsch

Sie haben mit ADK 2 Workflow einen Multi-Agenten-Reiseplaner erstellt, der sequenzielle Ketten, gleichzeitiges google_search-Fan-out mit JoinNode und bedingte Maker-Checker-Zyklen in einem einzigen deklarativen Edge-Graphen vereint.

Was Sie erreicht haben

  • Multi-Agenten-Pipeline mit ADK 2 deklariert: Workflow(edges=[...])
  • Daten direkt zwischen Agent-, JoinNode- und Python-Funktionsknoten über node_input und zustandsgebundene Parameter übergeben, während der Sitzungszustand minimal gehalten wird
  • Gleichzeitige google_search-Zweige aufgefächert und mit JoinNode synchronisiert
  • LoopAgent und die toolbasierte Schleifeneskalation wurden durch einen deterministischen Event(route=...)-Router ersetzt, der unnötige LLM-Aufrufe bei genehmigten Entwürfen überspringt.

Nächste Schritte