1. Introduction

Découvrez comment créer un moteur multi-agent multimodal qui prend un brief thématique brut et orchestre la création d'assets sociaux très attrayants. À l'aide de l'Agent Development Kit (ADK) et du protocole Agent2Agent (A2A) de Google, vous allez composer des micro-agents autonomes, regrouper les règles de marque sous forme de compétence d'agent réutilisable, déployer un service d'agent sur Cloud Run et évaluer la conformité des visuels clés générés avec la marque à l'aide des fonctions d'IA BigQuery.
Objectifs de l'atelier
Dans cet atelier de programmation, vous allez apprendre à effectuer les tâches suivantes :
- Orchestrez plusieurs agents ADK avec un workflow de graphique déterministe.
- Regroupez les consignes relatives à la marque dans une compétence d'agent qui ne se charge qu'en cas de besoin.
- Équipez un agent d'un outil de génération d'images qui enregistre sa sortie en tant qu'artefact.
- Exposez un agent en tant que service A2A et appelez-le depuis un autre agent en tant que nœud distant.
- Déployez le Visual Director sur Cloud Run et appelez le workflow via A2A.
- Évaluez l'adéquation des visuels clés générés à la marque dans BigQuery à l'aide de fonctions d'IA.
Prérequis
- Un navigateur Web (tel que Chrome).
- Un compte Google Cloud et un projet Google Cloud pour lequel la facturation est activée.
2. Avant de commencer
Créer un projet Google Cloud
- Dans la console Google Cloud, sur la page du sélecteur de projet, sélectionnez ou créez un projet Google Cloud.
- Assurez-vous que la facturation est activée pour votre projet Cloud. Découvrez comment vérifier si la facturation est activée sur un projet.
Démarrer Cloud Shell
Vous utiliserez Google Cloud Shell pour télécharger le code, exécuter les scripts de configuration et déployer l'application.
- Ouvrez Google Cloud Shell dans votre navigateur (ou cliquez sur Activer Cloud Shell en haut de la console Google Cloud) :
Cliquez sur Continuer si vous recevez des notifications supplémentaires.Attendez que le terminal et l'éditeur soient entièrement chargés. L'opération peut prendre une à deux minutes.https://shell.cloud.google.com/ - Configurez l'ID et la région de votre projet Google Cloud (par exemple,
us-central1) dans votre environnement en collant cette commande dans le terminal (remplacezetpar vos valeurs) :export PROJECT_ID="<YOUR_PROJECT_ID>" export REGION="<YOUR_REGION>" gcloud config set project $PROJECT_ID
Un message semblable au suivant devrait s'afficher :Your active configuration is: [cloudshell-####] Updated property [core/project] - Activez les API Google Cloud requises pour votre projet :
gcloud services enable \ compute.googleapis.com \ cloudresourcemanager.googleapis.com \ aiplatform.googleapis.com \ storage.googleapis.com \ storage-component.googleapis.com \ bigqueryconnection.googleapis.com \ bigquery.googleapis.com \ run.googleapis.com \ secretmanager.googleapis.com \ cloudbuild.googleapis.com \ artifactregistry.googleapis.com \ iap.googleapis.com \ iam.googleapis.com
Cloner le dépôt
Nous avons un modèle de code pour vous aider à démarrer l'atelier de programmation. Il est relativement petit, mais le dépôt GitHub dans lequel il se trouve est plutôt volumineux. Pour accélérer le clonage et économiser de l'espace disque, nous utiliserions normalement git clone avec l'option --filter=blob:none, git sparse-checkout et d'autres commandes.
Cela peut sembler très complexe, mais Antigravity peut tout faire pour nous !
Commençons par configurer Antigravity CLI pour qu'il puisse résoudre notre problème directement, puis lançons-le.
Dans Cloud Shell, exécutez la commande suivante :
source <(curl -fsSL https://github.com/GoogleCloudPlatform/devrel-demos/raw/refs/heads/vladkol/cloud-shell-configure-agy/codelabs/labs-scripts/bwg-multi-agent-pitch-generator/cloud_shell_configure_agy.sh)
La commande configure la CLI Antigravity et la lance dans le même terminal. Lorsque vous quittez l'interface de ligne de commande Antigravity, vous revenez à l'invite Cloud Shell.

Nous n'avons besoin que du dossier codelabs/bwg-multi-agent-pitch-generator dans le dépôt. Demandons à Antigravity de télécharger uniquement ce dossier et de le placer localement dans ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/.
Donnez cette tâche à la CLI Antigravity :
Download files from under `https://github.com/GoogleCloudPlatform/devrel-demos/tree/main/codelabs/bwg-multi-agent-pitch-generator`
to folder `~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/`.
If `devrel-demos` folder already exists, rename it with a `.backup` suffix.

Antigravity exécutera la tâche. Il vous demandera l'autorisation d'exécuter quelques commandes. Une fois le code téléchargé, quittez la CLI Antigravity en exécutant la commande /exit :
/exit

Ouvrir l'espace de travail du dépôt
Ouvrons maintenant l'espace de travail de code dans Cloud Shell. Exécutez cette commande dans le terminal Cloud Shell :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
cloudshell workspace .
Exécuter le script de configuration
Pour rendre cette expérience plus fluide, exécutez le script de configuration à partir du dépôt. Il configure les variables d'environnement, installe agents-cli, crée le bucket Cloud Storage pour les artefacts, crée la connexion aux ressources Cloud BigQuery et accorde les autorisations IAM requises à son compte de service avec nouvelle tentative automatique.
Le script de configuration appelle également setenv.sh, un petit utilitaire qui dérive les variables dont les deux agents ont besoin (GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_REGION, GOOGLE_CLOUD_LOCATION et GOOGLE_GENAI_USE_VERTEXAI) à partir des PROJECT_ID et REGION que vous avez exportés ci-dessus. Il enregistre également ces deux valeurs dans un fichier .env de votre répertoire d'accueil afin que vous puissiez les récupérer ultérieurement.
- Dans Cloud Shell, rendez le script de configuration exécutable et exécutez-le :
chmod +x codelab-setup.sh setenv.sh ./codelab-setup.sh - L'exécution prend environ une minute. Le message suivant doit s'afficher pour indiquer que l'opération a réussi : 🎉 🦄 Script execution complete.

- Le script de configuration s'est exécuté dans un shell qui lui est propre. Ses variables n'ont donc pas atteint votre terminal. Chargez-les dans votre session :
Votre projet, votre région et votre emplacement devraient s'afficher.source ./setenv.sh
3. Orchestrer des agents avec un workflow de graphique
Dans cette tâche, vous allez créer le projet de générateur de pitch et créer un workflow de graphique qui exécute deux agents et combine leurs sorties.
Un argumentaire doit comporter un concept, c'est-à-dire l'idée et les éléments qui la vendent. Dans ce cas d'utilisation, nous allons concevoir des agents ayant différentes responsabilités dans le cadre du travail. Nous allons ainsi vous montrer comment dissocier des tâches complexes et les déléguer à différents agents ayant des responsabilités distinctes, ce qui les rend plus faciles à gérer.
Pour répartir ce type de travail entre plusieurs spécialistes, il faut un élément de coordination lorsque chaque agent s'exécute. Vous pouvez choisir de laisser votre agent décider quand appeler chaque sous-agent ou appliquer une approche plus déterministe. Dans cet atelier de programmation, vous allez utiliser une approche déterministe avec un workflow de graphiques.
Créer la structure du premier projet d'agent
- Dans Cloud Shell, créez le projet en collant la commande suivante dans le terminal :
Cette commande écrit un projet complet et exécutable : un agent, uncd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create pitch-generator \ --agent adk \ --agent-directory pitch_generator \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approveDockerfile, des tests, Terraform pour plus tard et un fichier.envavec son modèle.env.example. Deux parties sont importantes pour cet atelier de programmation :pitch_generator/agent.pyest l'agent et le fichier que vous réécrivez.pitch_generator/est le nom du package défini par--agent-directory.
setenv.sh. Il n'y a donc rien à configurer ici. - Installez les dépendances :
Remarque : L'échafaudage connecte également le projet pour qu'il serve A2A, le protocole utilisé plus loin dans cet atelier de programmation. Pour l'instant, ne touchez pas à ces fichiers.cd pitch-generator agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
Comprendre le graphique
L'ADK v2.x est compatible avec les workflows de graphiques. Un graphique est construit à partir de nœuds, qui sont les unités de travail, et d'arêtes, qui les relient. Un nœud est généralement un agent, mais une simple fonction Python fonctionne également. Une arête indique qu'un autre nœud s'exécute après la fin d'un nœud.
Les arêtes sont écrites sous forme de liste, et l'ADK détermine l'ordre :
edges=[
("START", creative_director), ## the graph begins here
(creative_director, copywriter), ## then this
]
L'imbrication donne un sens à l'avantage :
Edge | Signification |
| Une chaîne : a, puis b, puis c, l'un après l'autre |
| Distribution ramifiée : a, puis b et c en même temps |
| Un fan-in. c attend à la fois a et b |
Pour un fan-in, vous utilisez un JoinNode, qui attend chaque prédécesseur et transmet ses sorties ensemble.
Dans cette tâche, nous allons créer le workflow suivant :

Créer le pipeline
- Ouvrez le fichier de l'agent en collant ce dans le terminal :
Le fichiercd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.pyagent.pyéchafaudé s'affiche dans l'éditeur Cloud Shell.💡 Conseil : À tout moment, vous pouvez sélectionner le code et utiliser l'ampoule pour demander à Gemini de l'expliquer. Vous pouvez également interroger l'interface de ligne de commande Antigravity.
- Remplacez l'intégralité du fichier dans
pitch_generator/agent.pydans l'éditeur par le code suivant :import mimetypes import os from dotenv import load_dotenv from google.adk.agents import Agent from google.adk.agents.context import Context from google.adk.agents.remote_a2a_agent import ( AGENT_CARD_WELL_KNOWN_PATH, RemoteA2aAgent, ) from google.adk.apps import App from google.adk.events.event import Event from google.adk.models import Gemini from google.adk.workflow import JoinNode, Workflow from google.genai import types load_dotenv() MODEL = "gemini-3.8-flash" def _model() -> Gemini: return Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ) """ ⬇️ Configure visual-director RemoteA2aAgent agent below this comment """ creative_director = Agent( name="creative_director", model=_model(), description="Turns a raw idea into a campaign concept.", instruction=( "You are the Creative Director. Turn the idea you are given into ONE " "punchy campaign concept line with the rationale explanation behind it." ), output_key="creative_director", ) copywriter = Agent( name="copywriter", model=Gemini(model=MODEL, retry_options=types.HttpRetryOptions(attempts=3)), description="Writes social copy for a campaign concept.", instruction=( "You are the Copywriter. Write ONE short social caption for the " "campaign concept you are given. Under 25 words." ), ) """ Waits for every node wired into it, then hands their outputs on together.""" assemble = JoinNode(name="assemble") def package(node_input: dict): """Render the joined branches as the finished pitch. """ pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", ] ) """ The first event is what the user sees. The second is the node's output, which any downstream node would receive.""" yield Event(content=types.Content(role="model", parts=[types.Part(text=pitch)])) yield Event(output=pitch) """ we put creative_director before `assemble` so that we can gather the `Concept` output at assemble""" root_agent = Workflow( name="pitch_generator", edges=[ ("START", creative_director), (creative_director, copywriter), ((creative_director, copywriter), assemble), (assemble, package), ], ) app = App( root_agent=root_agent, name="pitch_generator", ) agents-cliinclut une UI de développement Web intégrée appeléeplaygroundpour l'inspection, comme ADK. Pour démarrer le bac à sable : Vous serez invité à activer la télémétrie. Saisissezagents-cli playground --port 8080net appuyez sur Entrée.- Cliquez sur Aperçu sur le Web (l'icône en forme d'œil en haut à droite du terminal), puis sélectionnez Prévisualiser sur le port 8080.

- L'interface suivante s'affiche pour vous permettre de discuter avec l'agent. Essayez d'envoyer la requête Skateboards volants pour chats. Vous verrez une réponse comme celle ci-dessous, où vous pourrez également inspecter le graphique complet du workflow.
Inspecter la façon dont cette réponse a été produite. L'atelier de programmation montre chaque étape effectuée par le graphique, dans l'ordre : creative_director, puiscopywriter, puisassemble, puispackage. Cette séquence correspond au graphique que vous avez câblé. Vous pouvez ainsi confirmer rapidement le graphique que vous venez de créer. - Revenez au terminal et arrêtez le processus
agents-cli playgrounden cours d'exécution en appuyant deux fois sur Ctrl+C.
4. Attribuer une compétence à un agent
Dans cette tâche, vous allez créer un deuxième agent et lui fournir un ensemble de consignes relatives à la marque sous forme de compétence.
Le pipeline écrit des mots. Une image a besoin d'un style : une palette, une façon d'éclairer les choses, des compositions que vous utilisez et celles que vous n'utilisez jamais. Il s'agit d'une page de règles, et une page de règles a besoin d'un meilleur mécanisme pour être gérée. Une façon de le faire est de l'empaqueter en tant que "compétence d'agent".
Une skill est un dossier contenant un fichier SKILL.md. La structure du répertoire de compétences ressemble à l'exemple suivant (à l'aide de visual_director, le prochain agent que vous allez créer) :
visual_director/
...
agent.py
skills/
brand-guidelines/
SKILL.md ## required: frontmatter + instructions
references/ ## optional: longer supporting documents
assets/ ## optional: templates, images, data
scripts/ ## optional: executable helpers
...
Le point d'entrée de la compétence de l'agent est le fichier SKILL.md, qui inclut une section de métadonnées YAML comme celle illustrée ci-dessous :
---
name: brand-guidelines
description: The house brand rules for a key visual. Load this before writing art direction, so the visual looks like it came from this brand.
---
## Brand guidelines
Deep indigo and slate as the ground. One warm accent, amber or terracotta...
Le frontmatter est le libellé. C'est tout ce que l'agent voit au départ. C'est pourquoi la description doit indiquer quand la compétence vaut la peine d'être chargée. Le corps correspond au contenu. Il reste hors contexte jusqu'à ce que l'agent appelle load_skill.
C'est le but de cette séparation. La requête reste courte, l'agent n'extrait les règles que lorsqu'il en a besoin, et le changement de style implique de modifier un seul fichier au lieu de chercher dans une chaîne d'instructions.
Nous allons commencer à créer le deuxième agent, visual-director, en utilisant les compétences de l'agent, comme indiqué dans le schéma ci-dessous :

Échafauder le Visual Director
Vous allez créer un agent spécialisé pour gérer le composant visuel, visual-director. Il s'agit d'un projet distinct, car il deviendra plus tard son propre service pour montrer comment plusieurs agents communiquent entre eux à l'aide du protocole A2A. Vous obtiendrez deux projets côte à côte :
bwg-multi-agent-pitch-generator/
├── pitch-generator/ ## built in the last task
│ ├── pitch_generator/
│ │ ├── agent.py ## the graph you wrote
│ │ ├── app_utils/ ## generated, A2A wiring
│ │ └── fast_api_app.py ## generated, serves the agent
│ └── pyproject.toml
└── visual-director/ ## created below
└── ... ## the same shape again
- Créez le projet et installez ses dépendances en collant ce dans le terminal :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator agents-cli create visual-director \ --agent adk \ --agent-directory visual_director \ --deployment-target cloud_run \ --session-type in_memory \ --cicd-runner skip \ --region <YOUR_REGION> \ --auto-approve cd visual-director agents-cli update -y && agents-cli install && uv sync --upgrade-package google-adk
Rédiger les consignes relatives à la marque
- Créez le dossier de compétence et ouvrez le fichier :
mkdir -p visual_director/skills/brand-guidelines cloudshell edit visual_director/skills/brand-guidelines/SKILL.md - Collez le contenu suivant dans le fichier
SKILL.mdouvert dans l'éditeur, puis enregistrez-le :
--- name: brand-guidelines description: The house brand rules for a key visual — palette, light, composition, subject treatment, and what never appears. Load this before writing art direction or rendering an image, so the visual looks like it came from this brand rather than from a generic image model. --- ## Brand guidelines House style for campaign key visuals. Every rule here beats a preference in the brief. If the brief asks for something forbidden below, follow the brief for the subject and the guidelines for the treatment. ## Palette Deep indigo and slate as the ground. One warm accent — amber or terracotta — carrying the eye to the subject. Nothing neon, nothing fluorescent. At most three colors with any weight. A fourth reads as clutter. ## Light One dominant source, low and raking. Long shadows are wanted. Golden hour or a single hard studio key, never flat overhead light and never a ring light. Rim light is allowed on the subject only, and only to separate it from the ground. ## Composition Subject off-center, roughly a third in. Generous negative space on the opposite side — copy lands there later, so leave it genuinely empty. Eye level or slightly below. No top-down flat lays. No fisheye, no Dutch tilt. ## Subject One subject. If the idea implies a crowd, pick the one that carries it. Photographic realism with a shallow depth of field. Not illustration, not 3D render, not clay, not pixel art. ## Never - Text, logos, watermarks, or signage anywhere in the frame - Collage or split-screen layouts - Chrome, lens flare, bokeh sparkle - Cool-toned neon cyan or magenta ## Rendering the prompt When you turn art direction into an image prompt, state the palette, the light, and the composition explicitly. An image model will not infer them from the subject alone. Put the "Never" items in as plain description of what the frame does contain, not as negatives — image models handle a positive description far better than a list of prohibitions.
Mettre à jour visual_director/agent.py
Mettez à jour le fichier agent.py et configurez-le pour qu'il soit équipé de la compétence définie précédemment.
- Ouvrez le fichier de l'agent :
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - Remplacez l'intégralité du contenu du fichier
visual_director/agent.pypar le code suivant : L'agentimport mimetypes from pathlib import Path from google import genai from google.adk.agents import Agent from google.adk.apps import App from google.adk.models import Gemini from google.adk.skills import load_skill_from_dir from google.adk.tools import ToolContext from google.adk.tools.skill_toolset import SkillToolset from google.genai import types MODEL = "gemini-3.8-flash" ## Configure the `brand-guidelines` skill for the agent BRAND_SKILL = load_skill_from_dir(Path(__file__).parent / "skills" / "brand-guidelines") ## Add definition of `generate_key_visual` tool below this comment root_agent = Agent( name="visual_director", model=Gemini( model=MODEL, client_kwargs={"location": "global"}, retry_options=types.HttpRetryOptions(attempts=3), ), description="Turns a campaign concept into art direction and a key visual.", instruction="""You are the Visual Director on a campaign pitch team. Call `load_skill` for `brand-guidelines` before you write anything. The house style is not optional and it is not in this prompt. You are given a campaign concept. Then, in order: 1. Write art direction for ONE key visual that sells it, obeying the brand guidelines: subject, composition, lighting, color, mood. Three or four sentences. 2. Call `generate_key_visual` with exactly that art direction. Your final reply is the art direction itself and nothing else. No preamble, no alternatives, no questions back. Do not mention the skill, the tool, or the image file — the image travels on its own.""", tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment ], ) app = App( root_agent=root_agent, name="visual_director", )visual-directorest désormais correctement configuré avec une compétence d'agent. Avant de le tester, vous allez équiper cet agent d'un outil permettant de générer des composants d'image, qui sera l'une de ses principales capacités.
5. Équiper un agent d'un outil de génération d'images
Dans cette tâche, vous allez fournir au directeur artistique un outil qui affiche la direction artistique sous forme d'image et l'enregistre en tant qu'artefact. Un artefact est un élément nommé et versionné de données binaires ou de contenu de fichier qu'un agent d'IA crée, modifie ou utilise lors d'une tâche.

Implémenter et ajouter l'outil à l'agent
- Ouvrez le fichier de l'agent :
cloudshell edit ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director/visual_director/agent.py - Copiez l'outil
generate_key_visualsuivant avant la définitionroot_agent:async def generate_key_visual(art_direction: str, tool_context: ToolContext) -> dict: """Render the art direction as the campaign's key visual. Args: art_direction: The art direction to render, in full. Returns: The saved artifact's filename, version, size and media type. """ IMAGE_MODEL = "gemini-3.1-flash-lite-image" response = await genai.Client(location="global").aio.models.generate_content( model=IMAGE_MODEL, contents=art_direction ) ## The image arrives as inline bytes on one of the response parts. image = next( ( part.inline_data for part in response.candidates[0].content.parts or [] if part.inline_data ), None, ) if image is None: raise ValueError(f"{IMAGE_MODEL} returned no image for: {art_direction[:120]}") filename = "key_visual" + ( mimetypes.guess_extension(image.mime_type or "") or ".bin" ) version = await tool_context.save_artifact(filename, types.Part(inline_data=image)) ## Return the artifact filename and version return { "filename": filename, "version": version, "bytes": len(image.data), "mime_type": image.mime_type, } - Ajoutez
generate_key_visualsousSkillToolsetpour équiper l'agent de l'outil :tools=[ SkillToolset(skills=[BRAND_SKILL]), ## Supply the `generate_key_visual` tool below this comment generate_key_visual, ], agents-cliinclut une UI de développement Web intégrée appeléeplaygroundpour l'inspection, comme ADK. Pour démarrer le bac à sable :agents-cli playground --port 8080- Cliquez sur Aperçu sur le Web (l'icône en forme d'œil en haut à droite du terminal), puis sélectionnez Prévisualiser sur le port 8080.

- L'interface suivante s'affiche pour vous permettre de discuter avec l'agent. Essayez d'envoyer la requête Neuf vies. Zéro gravité."
Vous pouvez inspecter les interactions pour voir comment l'agent visual_directorexécuteload_skill("brand-guidelines")pour lire la compétence des consignes relatives à la marque, puis exécutegenerate_key_visualpour commencer à générer l'image. L'image obtenue est stockée en tant qu'artefact, qui est également affiché dans l'UI et peut être facilement inspecté. - Revenez au terminal et arrêtez le processus
agents-cli playgrounden cours d'exécution en appuyant deux fois sur Ctrl+C.
6. Architecture multi-agents avec le protocole A2A
Dans cette tâche, vous allez exposer le Visual Director en tant que service que d'autres agents peuvent appeler, et le configurer pour qu'il réponde avec l'image générée.
Agent2Agent (A2A) est un protocole ouvert permettant à un agent d'en appeler un autre sur un réseau. L'élément central est la carte d'agent, un document JSON que l'agent publie sur lui-même via une URL bien connue, en indiquant son nom, sa description et ses capacités. Un appelant récupère la fiche et sait comment parler à l'agent qui se trouve derrière, sans code source, dépendances ni langage partagés.

agents-cli a déjà configuré cette option par défaut. Le scaffold généré visual_director/app_utils/a2a.py, qui crée la fiche à partir de votre agent et monte les routes, et visual_director/fast_api_app.py, qui les sert. Il vous suffit d'apporter une petite modification pour qu'il puisse également renvoyer les artefacts au client.
L'architecture se présentera comme suit. Notez que l'agent n'est pas encore intégré à notre workflow initial :

Structure du serveur A2A agents-cli
Le code et le module suivants sont déjà fournis lorsque nous initialisons l'agent visual-director à l'aide de agents-cli. Ouvrez ces fichiers en collant les commandes suivantes dans le terminal :
cloudshell edit visual_director/fast_api_app.py
cloudshell edit visual_director/app_utils/a2a.py
visual_director/fast_api_app.py démarre l'agent et monte les routes A2A sous un chemin d'accès créé à partir du nom de l'application :
await attach_a2a_routes(
app,
agent=root_agent,
runner=runner,
rpc_path=f"/a2a/{adk_app.name}", ## becomes /a2a/visual_director
)
visual_director/app_utils/a2a.py s'occupe du reste en trois étapes.
Tout d'abord, il crée la carte de l'agent à partir de l'agent lui-même. Le nom, la description et chaque outil deviennent des entrées qu'un appelant peut lire :
agent_card = await AgentCardBuilder(
agent=agent,
rpc_url=f"{resolved_app_url}{rpc_path}",
).build()
Deuxièmement, il place un exécuteur entre le protocole et votre agent. Les requêtes A2A entrantes sont traduites en exécutions ADK, et les résultats sont retraduits :
request_handler = DefaultRequestHandler(
agent_executor=A2aAgentExecutor(runner=runner, force_new_version=True),
task_store=task_store,
agent_card=agent_card,
)
Troisièmement, il monte deux routes : l'une servant la carte, l'autre acceptant les appels.
Route | Objectif |
| La carte. Le correspondant lit ce message en premier pour savoir ce que l'agent peut faire. |
| Point de terminaison JSON-RPC. Où sont envoyées les demandes |
Autoriser les artefacts à franchir la limite
Par défaut, une réponse A2A contient du texte. L'image est un artefact, et un artefact reste dans le magasin de l'agent de diffusion, sauf si vous configurez son inclusion.
- Ouvrez le fichier A2A généré :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director cloudshell edit visual_director/app_utils/a2a.py - Recherchez l'importation
AgentCardBuilderet ajoutez les importationsA2aAgentExecutorConfigetinclude_artifacts_in_a2a_event_interceptoren dessous :## ... ## from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder ## Add the following two below `AgentCardBuilder` import from google.adk.a2a.executor.config import A2aAgentExecutorConfig from google.adk.a2a.executor.interceptors.include_artifacts_in_a2a_event import ( include_artifacts_in_a2a_event_interceptor, ) - Recherchez la ligne
agent_executor=A2aAgentExecutor(runner=runner),et remplacez-la par la ligne suivante (en ajoutantA2aAgentExecutorConfig) :agent_executor=A2aAgentExecutor( runner=runner, force_new_version=True, config=A2aAgentExecutorConfig( execute_interceptors=[include_artifacts_in_a2a_event_interceptor] ), ),
Démarrer le service et lire la carte A2A publiée
- Démarrez le serveur en arrière-plan. Vous devez déclarer
APP_URL, car il s'agit de l'adresse que la carte indique comme étant la sienne. Collez-le dans le terminal :APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & - Attendez quelques secondes qu'il démarre, puis vérifiez qu'il est en cours d'exécution :
Vous devriez obtenir le résultat suivant :sleep 10 tail -2 /tmp/visual-director.logINFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8801 (Press CTRL+C to quit) - Lisez la fiche que l'agent publie maintenant :
La fiche liste le nom, la description, l'URL et les compétences de l'agent, y compriscurl -s http://localhost:8801/a2a/visual_director/.well-known/agent-card.json | python3 -m json.toolgenerate_key_visual. Il est généré directement à partir de la définition de l'agent dans le code. Vous êtes prêt à intégrer l'agent{ "name": "visual_director", "description": "Turns a campaign concept into art direction and a key visual.", "skills": [ { "id": "visual_director", "name": "model", "tags": [ "llm" ] }, { "id": "visual_director-generate_key_visual", "name": "generate_key_visual", "description": "Render the art direction as the campaign's key visual.\n\nArgs:\n art_direction: The art direction to render, in full.\n\nReturns:\n The saved artifact's filename, version, size and media type.", "tags": [ "llm", "tools" ] } ], "preferredTransport": "JSONRPC", "protocolVersion": "0.3", "url": "http://localhost:8801/a2a/visual_director" }visual-directordans le workflowpitch-generatorprincipal.
7. Intégrer l'agent distant A2A au workflow
Dans cette tâche, vous allez ajouter l'agent distant au graphique en tant que troisième branche.
Un agent à distance est encapsulé dans RemoteA2aAgent et placé dans le graphique comme n'importe quel autre nœud. Les arêtes conservent la même forme et le coordinateur ne sait pas lesquels de ses nœuds sont locaux.
Pointer le coordinateur vers le service et mettre à jour le workflow du graphique
- Ouvrez le fichier de l'agent :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cloudshell edit pitch_generator/agent.py - Ajoutez ces importations en haut du fichier, à côté de celles qui existent déjà :
import asyncio import subprocess import google.auth.transport.requests import google.oauth2.id_token import httpx from google.adk.a2a.converters.part_converter import convert_genai_part_to_a2a_part - Ajoutez la définition
RemoteA2aAgentsuivante au-dessus de la déclarationcreative_director:VISUAL_DIRECTOR_URL = os.getenv("VISUAL_DIRECTOR_URL", "http://localhost:8801") ## For deployment on Cloud Run def _cloud_run_client() -> httpx.AsyncClient | None: """An httpx client that signs each request with a Cloud Run ID token. Cloud Run deploys private, so both the agent-card fetch and the A2A calls need one. """ if not VISUAL_DIRECTOR_URL.startswith("https://"): return None async def sign(request: httpx.Request) -> None: token = None try: token = await asyncio.to_thread( google.oauth2.id_token.fetch_id_token, google.auth.transport.requests.Request(), VISUAL_DIRECTOR_URL, ) except Exception: token = subprocess.check_output( ["gcloud", "auth", "print-identity-token", "-q"], stderr=subprocess.PIPE ).decode().strip() if not token: raise Exception("Failed to fetch ID token") request.headers["Authorization"] = f"Bearer {token}" return httpx.AsyncClient(event_hooks={"request": [sign]}, timeout=600) ## Keep the approval's tool traffic out of the A2A request def _pitch_parts_only(part: types.Part): """Sends the Visual Director text and media only. RemoteA2aAgent replays the session on every call, and the Visual Director runs downstream of the human approval, so the approval's function_response would travel alongside the concept text. An ADK server reads a function response as "resume the paused invocation" and rejects a message that also carries text, so drop the tool parts here. """ if part.function_call or part.function_response: return None return convert_genai_part_to_a2a_part(part) visual_director = RemoteA2aAgent( name="visual_director", description="Turns a campaign concept into art direction for one key visual.", agent_card=( f"{VISUAL_DIRECTOR_URL}/a2a/visual_director{AGENT_CARD_WELL_KNOWN_PATH}" ), httpx_client=_cloud_run_client(), genai_part_converter=_pitch_parts_only, ) - Écrasez ou remplacez la fonction Python du nœud
packagepar la définition suivante :async def package(ctx: Context, node_input: dict): """Render the joined branches as the finished pitch.""" empty = [name for name, value in node_input.items() if not value] if empty: raise ValueError(f"nothing reached the join from: {', '.join(empty)}") def _key_visual(ctx: Context) -> types.Blob | None: """The image the Visual Director sent back, or None if it sent none.""" for event in reversed(ctx.session.events): if event.author != "visual_director" or not event.content: continue for part in event.content.parts or []: if part.inline_data and part.inline_data.data: return part.inline_data return None image = _key_visual(ctx) if image is None: raise ValueError("the Visual Director returned art direction but no image") suffix = mimetypes.guess_extension(image.mime_type or "") or ".bin" filename = f"key_visual{suffix}" await ctx.save_artifact(filename, types.Part(inline_data=image)) pitch = "\n\n".join( [ f"CONCEPT\n{node_input['creative_director']}", f"COPY\n{node_input['copywriter']}", f"ART DIRECTION\n{node_input['visual_director']}", f"KEY VISUAL\n{filename}, {len(image.data)} bytes, {image.mime_type}", ] ) yield Event( content=types.Content( role="model", parts=[types.Part(text=pitch), types.Part(inline_data=image)], ) ) yield Event(output=pitch) - Ajoutez un jalon d'approbation humaine avant que la génération en aval ne se poursuive. Dans
pitch_generator/agent.py, définissez les nœuds d'approbation au-dessus deroot_agent:@node(rerun_on_resume=False) async def approve_concept(ctx: Context): yield RequestInput( message="Please approve the campaign concept (yes/no).", response_schema=str ) @node(rerun_on_resume=True) async def user_approval(ctx: Context): user_response = await ctx.run_node(approve_concept) if str(user_response).lower() in ("yes", "y"): approved_concept = f"## Approved Concept\n\n{ctx.session.state['creative_director']}" yield Event( content=types.Content( role="model", parts=[types.Part(text=approved_concept)] ) ) else: raise ValueError("User rejected the concept") - Enfin, mettez à jour les importations en haut de la page pour inclure
RequestInputetnodeà partir degoogle.adk.eventsetgoogle.adk.workflow: et modifiez le workflowfrom google.adk.events import Event, RequestInput from google.adk.workflow import JoinNode, Workflow, noderoot_agentedgespour qu'il passe paruser_approval: Voici quelques points importants à retenir :edges=[ ("START", creative_director), (creative_director, user_approval, (copywriter, visual_director)), ((creative_director, copywriter, visual_director), assemble), (assemble, package), ],- Approbation avec intervention humaine (HITL) :
approve_conceptgénèreRequestInput. Lorsque le workflow atteint ce nœud, l'exécution s'interrompt et une interruption est émise à l'appelant. Les branches en aval (copywriteretvisual_director) ne s'exécuteront pas tant que l'approbation de l'utilisateur n'aura pas été confirmée. visual_directorapparaît dans les périphéries exactement commecopywriter, bien que l'un soit un appel de fonction et l'autre sur un réseau.- L'image renvoyée est lue à partir des événements de session plutôt que de
node_input, car actuellement, seul le texte est promu dans la sortie d'un nœud. L'image a franchi la limite via l'intercepteur A2A, mais est arrivée en pièce jointe aux événements de l'agent distant. La fonction d'assistance_key_visualla récupère donc à partir de là.
- Approbation avec intervention humaine (HITL) :
Tester l'intégration
Vous allez maintenant tester la communication entre le Visual Director (qui s'exécute en arrière-plan) et le générateur de pitch via le protocole A2A.
- Vérifiez que le Visual Director est toujours en cours d'exécution en arrière-plan :
Vous devriez obtenir un résultatcurl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.jsonvisual director: 200.Si vous obtenez un autre état, exécutez la commande suivante pour le redémarrer :fuser -k 8801/tcp 2>/dev/null || true cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director APP_URL=http://localhost:8801 nohup uv run uvicorn visual_director.fast_api_app:app --port 8801 > /tmp/visual-director.log 2>&1 & cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator sleep 10 curl -s -o /dev/null -w "visual director: %{http_code}\n" http://localhost:8801/a2a/visual_director/.well-known/agent-card.json - Lancez l'aperçu :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator/pitch_generator agents-cli playground --port 8080 - Cliquez sur Aperçu sur le Web (l'icône en forme d'œil en haut à droite du terminal), puis sélectionnez Prévisualiser sur le port 8080.

- L'interface de chat avec l'agent s'affiche. Essayez d'envoyer la requête "Skateboards volants pour chats".

Vous verrez l'intégralité de l'interaction, du début du workflow à l'exécution de chaque agent. Une fois que creative_directora rédigé le concept, le workflow s'interrompt au niveau de la porte d'approbation et vous demande de confirmer : Veuillez approuver le concept de la campagne (oui/non). Saisissez oui dans le champ de saisie pour continuer.Une fois approuvé, le graphique s'étend : vous pouvez voir quand l'agentvisual-directorcommence à charger la compétence et, au milieu de la génération d'image, l'agentcopywritertermine de générer la légende pour les réseaux sociaux, ce qui montre que les deux agents s'exécutent en parallèle sans attendre l'un l'autre. Une fois les deux tâches terminées, le nœudassemblecombine les résultats avec le concept approuvé généré parcreative_director, finalisant ainsi la diffusion du contenu de la présentation dans la fonctionpackage.
8. Conserver les principaux éléments visuels dans Cloud Storage
Jusqu'à présent, chaque élément visuel clé était stocké en mémoire. Au moment où le processus s'arrête, l'image disparaît, ce qui est acceptable pour un terrain de jeu, mais inutile pour une campagne. Dans cette tâche, vous allez attribuer un bucket au workflow pour l'écriture et créer un ensemble de données BigQuery que vous utiliserez dans la dernière tâche.
L'ADK décide où placer les artefacts au démarrage. Le app_utils/services.py généré lit une seule variable d'environnement :
def get_artifact_service():
"""Process-wide artifact service: GCS when a bucket is set, else in-memory."""
if bucket := os.environ.get("LOGS_BUCKET_NAME"):
return GcsArtifactService(bucket_name=bucket)
return InMemoryArtifactService()
Si vous définissez LOGS_BUCKET_NAME, chaque appel save_artifact sera redirigé vers Cloud Storage.

Créer l'ensemble de données BigQuery
- Dans Cloud Shell, exécutez la commande suivante pour créer un ensemble de données BigQuery :
bq mk --dataset --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> bwg - Pointez le magasin d'artefacts du coordinateur vers le bucket :
export LOGS_BUCKET_NAME="<YOUR_PROJECT_ID>-bwg"GcsArtifactServiceaccepte un nom de bucket brut, sans le préfixegs://. Comme les autres variables, celle-ci réside dans votre shell, et la tâche de déploiement la transmet à Cloud Run. - Vérifiez le contenu de votre bucket. Dans un nouvel onglet de navigateur, ouvrez l'URL suivante :
Cliquez sur le bucket. En fonction de vos tests précédents, il peut contenir des images générées précédemment.https://console.cloud.google.com/storage/browser?project=<YOUR_PROJECT_ID>
9. Déployer l'agent Visual Director sur Cloud Run
Jusqu'à présent, tout s'est exécuté sur une seule machine, avec le Visual Director accessible à l'adresse localhost:8801. Dans cette tâche, vous allez déployer l'agent Visual Director en tant que service Cloud Run distinct et permettre au générateur de pitch de communiquer avec lui sur le réseau à l'aide du protocole Agent2Agent (A2A).
Le directeur visuel obtient une véritable URL https://. Par conséquent, le _cloud_run_client que vous avez écrit précédemment commence à signer les requêtes au lieu de renvoyer None. De plus, Cloud Run déploie les services de manière privée par défaut.

Déployer Visual Director
- Arrêtez le service d'arrière-plan local et le bac à sable s'ils sont toujours en cours d'exécution :
fuser -k 8801/tcp 2>/dev/null || true fuser -k 8000/tcp 2>/dev/null || true - Déployez l'agent. Cette opération crée un conteneur et le publie.⏰ Cela prendra quelques minutes.
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/visual-director source .env agents-cli deploy \ --service-name visual-director \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --no-confirm-project \ --labels dev-tutorial=bwg001-devlab-1 \ --update-env-vars "LOGS_BUCKET_NAME=$LOGS_BUCKET_NAME,GOOGLE_GENAI_USE_VERTEXAI=true,GOOGLE_CLOUD_PROJECT=$GOOGLE_CLOUD_PROJECT,GOOGLE_CLOUD_LOCATION=$GOOGLE_CLOUD_LOCATION,GOOGLE_CLOUD_REGION=$GOOGLE_CLOUD_REGION"
Exécuter le générateur de pitchs qui utilise le Visual Director déployé sur Cloud Run
- Lisez l'URL du réalisateur et exécutez le générateur de pitch qui l'utilise :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator source .env export VISUAL_DIRECTOR_URL=$(gcloud run services list \ --project <YOUR_PROJECT_ID> \ --region <YOUR_REGION> \ --flatten='spec.template.spec.containers[0].env' \ --filter='metadata.name=visual-director AND spec.template.spec.containers[0].env.name=APP_URL' \ --format='value(spec.template.spec.containers[0].env.value)') echo "Visual Director is at $VISUAL_DIRECTOR_URL" APP_URL=http://localhost:8000 nohup uv run uvicorn pitch_generator.fast_api_app:app --port 8000 > /tmp/visual-pitch_generator.log 2>&1 &
Appeler le workflow déployé
Les deux agents sont compatibles avec le protocole A2A. Le dépôt fournit un petit client pour appeler le générateur de pitch via A2A.
PITCH_GENERATOR_URL doit être défini sur l'URL du générateur de suggestions qui s'exécute en local. Pendant ce temps, le Visual Director s'exécute dans Cloud Run, et le Pitch Generator communique avec lui via A2A.
- Copiez le client dans votre projet et exécutez-le :
Comme le workflow contient une étape d'approbation humaine, le script s'interrompt après avoir généré le brouillon du concept :cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/pitch-generator cp ../solution/pitch-generator/call_agent.py . PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "Flying skateboards for cats" --save-image ./key_visual.png Saisissez=== HUMAN APPROVAL REQUIRED === [DRAFT CONCEPT] Concept Line: "Gravity is a Suggestion." ... Please approve the campaign concept (yes/no):yeset appuyez sur Entrée pour approuver et poursuivre le workflow. (Vous pouvez également transmettre-you--auto-approvepour approuver automatiquement.) - Ouvrez
call_agent.pyet examinez comment il interagit avec l'agent à l'aide dea2a-sdk:ClientFactorycrée unClientA2A officiel ciblanthttps://SERVICE_URL/a2a/pitch_generator.generate_pitch_asyncenvoie unSendMessageRequestinitial. Lorsque la réponse renvoieTaskState.TASK_STATE_INPUT_REQUIRED, elle détecte la partieadk_request_input, affiche le concept de brouillon, recueille votre approbation et renvoie une demande de reprise contenant votre réponse à la tâche.- La boucle d'analyse lit les sections
CONCEPT,COPYetART DIRECTIONdes artefacts de la tâche terminée, puis enregistre l'image binaire danskey_visual.png.
key_visual.png. - Importez le visuel clé dans votre bucket, sous un préfixe vers lequel vous pouvez rediriger BigQuery :
gcloud storage cp ./key_visual.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png - Générez une deuxième suggestion pour avoir un élément de comparaison, puis importez-la également :
PITCH_GENERATOR_URL=http://localhost:8000 uv run python call_agent.py "A commuter bike built for rainy cities" --save-image ./bike.png gcloud storage cp ./bike.png gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png
10. Évaluer l'adéquation des principaux éléments visuels avec la marque dans BigQuery
Vous disposez maintenant d'images dans un bucket et des consignes relatives à la marque qui devaient les façonner. Dans cette tâche, vous allez combiner les deux : référencer les images depuis BigQuery, puis demander à un modèle Gemini de les évaluer par rapport aux consignes, sans déplacer un seul octet hors de Cloud Storage.
Deux fonctionnalités BigQuery sont utilisées :
ObjectRefest une valeur qui pointe vers un objet Cloud Storage.OBJ.MAKE_REFen crée un à partir d'un URI et d'une connexion qui accorde à BigQuery un accès délégué au bucket. Lepitch-connectioncréé par le script de configuration est cette connexion. Il contient déjà les rôles "Lecteur d'objets Storage" et "Utilisateur d'Agent Platform".AI.SCOREprend un prompt et renvoie unFLOAT64. La requête peut mélanger des chaînes avec des valeursObjectRef, de sorte que le modèle voit à la fois votre grille d'évaluation et l'image.

Créer un tableau des principaux éléments visuels
- Ouvrez BigQuery Studio dans un nouvel onglet du navigateur :
https://console.cloud.google.com/bigquery?project=<YOUR_PROJECT_ID> - Cliquez sur Créer une requête (icône +), puis collez et exécutez la requête suivante (en remplaçant
etpar l'ID de votre projet et votre région). Elle crée une ligne par visuel clé, en associant le concept de la campagne à une référence à l'image :SET @@location = '<YOUR_REGION>'; CREATE OR REPLACE TABLE bwg.key_visuals AS SELECT campaign, concept, OBJ.FETCH_METADATA( OBJ.MAKE_REF(uri, '<YOUR_REGION>.pitch-connection') ) AS key_visual FROM UNNEST([ STRUCT( 'cats' AS campaign, 'Flying skateboards for cats' AS concept, 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/cats.png' AS uri ), STRUCT( 'bike', 'A commuter bike built for rainy cities', 'gs://<YOUR_PROJECT_ID>-bwg/key-visuals/bike.png' ) ]);
OBJ.MAKE_REFcrée la référence à partir de l'URI et de la connexion.OBJ.FETCH_METADATAcontacte ensuite Cloud Storage et renseigne la taille, le type de contenu et la génération de l'objet. Ce deuxième appel est également le moyen le plus rapide de prouver que votre connexion fonctionne : si les autorisations sont incorrectes, le champdetailsrenvoie l'erreur au lieu des métadonnées. - Inspectez ce que vous avez stocké. Remplacez la requête précédente par celle-ci, puis exécutez-la :
La table contient un pointeur et ses métadonnées, mais pas l'image. Les octets n'ont jamais quitté le bucket.SELECT campaign, concept, key_visual.uri, key_visual.details FROM bwg.key_visuals;
Évaluez chaque image par rapport aux consignes relatives à la marque.
Le directeur visuel a été chargé de respecter une palette, une règle d'éclairage et une règle de composition. C'est à vous de décider si c'est le cas ou non. C'est à cela que sert AI.SCORE.
- Exécutez la requête suivante (en remplaçant
par votre région). La requête est un tuple : votre grille d'évaluation, le concept de la campagne et leObjectRefde l'image :SELECT campaign, concept, AI.SCORE( ('''You are the brand guardian reviewing a campaign key visual. Score the attached image from 1 to 10 on how closely it follows these house rules: - Palette: deep indigo and slate, with one warm accent of amber or terracotta. Nothing neon. - Light: one dominant low, raking source with long shadows. No flat overhead light. - Composition: subject off-center with generous empty negative space on the opposite side. - Subject: one subject only, photographic realism, shallow depth of field. - Never: text, logos, or watermarks anywhere in the frame. A 10 obeys every rule. A 1 ignores them. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ORDER BY brand_fit DESC; - Transformez le score en verdict sur lequel votre équipe peut agir :
CREATE OR REPLACE TABLE bwg.brand_review AS SELECT campaign, concept, brand_fit, IF(brand_fit >= 7, 'on brand', 'needs another pass') AS verdict FROM ( SELECT campaign, concept, AI.SCORE( ('''Score this campaign key visual from 1 to 10 on how closely it follows the house brand rules: deep indigo and slate palette with a single warm accent and nothing neon; one low raking light source with long shadows; the subject off-center with empty negative space opposite; a single photographic subject; and no text, logos, or watermarks in the frame. The campaign concept is: ''', concept, key_visual), connection_id => '<YOUR_REGION>.pitch-connection', endpoint => 'gemini-3.5-flash' ) AS brand_fit FROM bwg.key_visuals ); SELECT * FROM bwg.brand_review ORDER BY brand_fit DESC;AI.SCORErenvoie unFLOAT64et rien d'autre. Le seuil se trouve donc en SQL brut, où vous pouvez l'ajuster sans modifier la requête. La notation s'effectue par ligne, ce qui signifie que la même grille d'évaluation est appliquée à chaque composant généré par une campagne, et pas seulement aux deux que vous avez créés ici.
11. Étapes suivantes
Créer des évaluations
Les évaluations agentiques sont des tests automatisés utilisés pour mesurer la capacité des agents IA autonomes à raisonner, à planifier, à utiliser des outils et à effectuer des workflows en plusieurs étapes. Ils sont semblables aux tests unitaires pour les agents, mais tiennent compte de leur nature non déterministe.
L'un de nos agents inclut un Human in the loop, ce qui signifie qu'il attend une entrée. Vous devrez autoriser Antigravity à modifier le code actuel afin que ce comportement n'entrave pas les évaluations automatiques.
L'un des meilleurs moyens de commencer est de poser des questions à la CLI Antigravity.
Saisissez la commande suivante dans Cloud Shell pour démarrer l'interface CLI :
cd ~/devrel-demos/codelabs/bwg-multi-agent-pitch-generator/
agy
Voici un prompt de départ :
Explore this repository (`pitch-generator` and `visual-director`), including their agent instructions, tools, and `SKILL.md` files. Design and implement a creative `agents-cli eval` evaluation suite under `tests/eval/` that stress-tests the agent's behavior.
Vous trouverez également un exemple d'évaluations et des instructions pour les exécuter dans le dépôt cloné.
12. Effectuer un nettoyage
Pour éviter que les ressources utilisées dans cet atelier de programmation ne soient facturées sur votre compte Google Cloud, supprimez le projet (recommandé) ou supprimez les ressources individuelles créées pendant l'atelier de programmation :
gcloud run services delete visual-director --region=<YOUR_REGION> --project=<YOUR_PROJECT_ID> --quiet
bq rm -r -f -d <YOUR_PROJECT_ID>:bwg
bq rm --connection --location=<YOUR_REGION> --project_id=<YOUR_PROJECT_ID> pitch-connection
gcloud storage rm -r gs://<YOUR_PROJECT_ID>-bwg
13. Félicitations !
Dans cet atelier de programmation, vous avez créé un générateur de pitch de campagne multi-agents avec l'Agent Development Kit. Vous avez câblé trois agents dans un workflow de graphe déterministe, empaqueté les consignes relatives à la marque en tant que compétence d'agent qui se charge à la demande et fourni à un agent un outil de génération d'images qui enregistre sa sortie en tant qu'artefact. Vous avez ensuite divisé le Visual Director en son propre service A2A, l'avez réintégré dans le graphique en tant que nœud distant, l'avez déployé sur Cloud Run et avez appelé l'ensemble du workflow sur A2A à partir d'un coordinateur s'exécutant en local. Enfin, vous avez référencé les visuels clés générés à partir de BigQuery avec ObjectRef et utilisé AI.SCORE pour les évaluer par rapport à vos propres consignes relatives à la marque.