Lección 21 — Tutoriels pas à pas

12-1. Agents dans `aiml-gemini-ent-exp-0zga`, utilisés dans l'app de `acme-gemini-prod`

27 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Le but : déployer des agents dans le projet d'expérimentation, les tester seuls, puis les connecter à l'app Gemini Enterprise dev_gemini-entreprise-app du projet principal.

Trois méthodes, chacune de bout en bout : faites-en une, jusqu'au test dans l'app et au nettoyage, puis passez à la suivante si vous voulez. Les noms des ressources diffèrent d'une méthode à l'autre (suffixe -shell, -console ; sans suffixe pour Terraform), donc elles ne se gênent pas.

MéthodePour quiCe qui est fait à la main
A. Shell (gcloud + scripts)Comprendre chaque ressource, tout reproduire en copier-collerTout, commande par commande
B. TerraformLa cible : reproductible, relu, défait proprement3 commandes par étape ; Terraform crée le reste
C. Console (interface)Voir chaque écran, sans ligne de commande (sauf 2 commandes inévitables)Tout, écran par écran

Le parcours pas à pas, guide par guide :

  1. déployer : 12-1-1 Shell · 12-1-2 Terraform · 12-1-3 Console ;
  2. connecter à l'app : 12-1-4 ;
  3. simuler l'appel : 12-1-5 ;
  4. la console de l'app : 12-1-6 ;
  5. OAuth, identité, outils : 12-1-7 ;
  6. Un agent Gmail, Agenda, Drive, Sheets (sans suppression), un ou plusieurs fournisseurs OAuth : 12-1-8.

Ce document-ci reste la vue d'ensemble (trois méthodes, de bout en bout).

Seulement déployer les agents (pas encore d'app), un, plusieurs ou tous ? Guides pas à pas dédiés : 12-1-1 Shell · 12-1-2 Terraform · 12-1-3 Console. Le choix des agents : ligne AGENTS du fichier de configuration.

6 agents, pas 3 : le catalogue agents/trio/catalogue.json contient aussi Conseil taille, Retours produits et Identité utilisateur. Terraform (méthode B) déploie tout le catalogue ; les boucles shell et la console (A, C) montrent les 3 premiers : pour les autres, ou pour ajouter vos agents un par un, voir 12-3.

Testé en vrai (9 octobre 2026, deux projets de test jouant ces deux rôles) : méthodes A et B de bout en bout, jusqu'au droit de l'app vérifié. Non testable sans votre app : l'écran d'ajout dans l'app et la réponse dans le chat (étapes A6, B5, C7). Méthode C : les écrans sont décrits d'après la documentation Google ; les libellés peuvent varier légèrement selon la version de la console.


Sommaire

  1. Ce qu'on construit, et les protocoles possibles
  2. Préparation commune (une fois)
  3. Méthode A : shell (gcloud + scripts)
  4. Méthode B : Terraform
  5. Méthode C : console (interface)
  6. Ce qui peut arriver

0. Ce qu'on construit, et les protocoles possibles

  aiml-gemini-ent-exp-0zga (433175138344) : LES AGENTS        acme-gemini-prod (523307489860) : L'APP
 ┌───────────────────────────────────────────────────┐       ┌──────────────────────────────────────────────┐
 │ Agent Runtime : météo, rédaction, traduction      │◀──────│ App Gemini Enterprise dev_gemini-entreprise- │
 │ Cloud Run (A2A) : les mêmes, en protocole A2A     │ appel │ app (eu)                                     │
 │ Agent Registry : les agents (catalogue)           │       │                                              │
 │ Model Armor : filtre questions et réponses        │       │ Compte de service de Gemini Enterprise :     │
 │ Un compte de service par agent                    │       │ service-100000000003@gcp-sa-discoveryengine… │
 │ IAM : UN droit donné au compte de l'app ──────────┼──────▶│                                              │
 └───────────────────────────────────────────────────┘       └──────────────────────────────────────────────┘

Quels protocoles pour un agent d'un AUTRE projet que l'app ?

Façon d'ajouter dans l'appFonctionne depuis aiml-gemini-ent-exp-0zga ?Droit à donner dans le projet des agents
Agent Runtime (« Vertex AI Agent Engine », l'hébergement géré de Google)Ouiroles/discoveryengine.serviceAgent sur le projet
A2A (agent hébergé sur Cloud Run, protocole ouvert A2A v0.3)Ouiroles/run.invoker sur chaque service
Agent Registry (import depuis le catalogue)Non : l'app n'importe que depuis le registre de son projet → 12-2—
DialogflowNon documenté par Google → 12-2—

« Vertex AI » n'est pas un mode à part : Agent Runtime fait partie de Vertex AI (Agent Platform). Le registre sert quand même ici : les agents s'y inscrivent, d'autres équipes et agents les y trouvent.


1. Préparation commune (une fois)

1.1 Les outils sur votre poste

OutilMac (Homebrew)Vérifier
gcloudbrew install --cask google-cloud-sdk puis gcloud components install betagcloud version
Terraform 1.9+ (méthode B)brew tap hashicorp/tap && brew install hashicorp/tap/terraformterraform version
uv (Python 3.12 à 3.14)brew install uvuv --version

Pas de Docker : les images Cloud Run sont construites dans Google Cloud (Cloud Build), avec gcloud seulement. Un terminal Linux ou Mac, ou Cloud Shell, suffit.

1.2 Le dossier et l'environnement Python

Le dossier 09-agents-multi-projets-gemini-enterprise est sur votre Bureau.

cd ~/Desktop/09-agents-multi-projets-gemini-enterprise
uv venv -p '>=3.12' .venv && source .venv/bin/activate
uv pip install -r agents/trio/requirements.txt
python scripts/test_trio.py

Résultat obtenu : tests trio OK (9 scénarios, 6 agents). Votre invite affiche (.venv).

1.3 Le fichier de configuration (le seul fichier à modifier)

Ouvrez config/12-1-agents-dans-projet-exp.env dans un éditeur. Il est déjà rempli avec vos projets :

PROJET_APP=acme-gemini-prod
NUM_APP=523307489860
APP_ID=dev_gemini-entreprise-app        # Gemini Enterprise > l'app > Présentation : ID de l'app
GE_LOCATION=eu
PROJET_AGENTS=aiml-gemini-ent-exp-0zga
NUM_AGENTS=433175138344
REGION=europe-west1
AGENTS=""                               # vide = tous les agents du catalogue ; ex. "meteo taille"
PUBLIER=non
AGENTS_OAUTH=""
GROUPE_UTILISATEURS=equipe-agents@acme.example
DOSSIER=~/Desktop/09-agents-multi-projets-gemini-enterprise

À vérifier : APP_ID est bien l'ID de l'app (console → 🔎 « Gemini Enterprise » → l'app → Présentation), pas son nom affiché ; GROUPE_UTILISATEURS est le groupe Google qui testera.

Charger la configuration (à refaire dans chaque nouveau terminal, toujours seule sur sa ligne) :

cd ~/Desktop/09-agents-multi-projets-gemini-enterprise && source .venv/bin/activate
source scripts/config.sh config/12-1-agents-dans-projet-exp.env

Résultat obtenu :

== Configuration chargée : config/12-1-agents-dans-projet-exp.env
   App Gemini Enterprise : dev_gemini-entreprise-app   (projet acme-gemini-prod, numéro 523307489860, eu)
   Projet des agents     : aiml-gemini-ent-exp-0zga (numéro 433175138344), région europe-west1   [même projet que l'app : non]
   Compte de l'app       : service-100000000003@gcp-sa-discoveryengine.iam.gserviceaccount.com
   Terraform             : espace « scenario-12-1 », publication dans l'app : non
   Dossier               : /Users/<vous>/Desktop/09-agents-multi-projets-gemini-enterprise
   OK

Le script donne aussi ces valeurs à gcloud (projet par défaut, point d'accès européen de Model Armor) et à Terraform. Ne le mettez jamais derrière un | (par exemple | grep) : les valeurs ne resteraient pas dans le terminal.

1.4 Se connecter, vérifier les numéros

gcloud auth login
gcloud auth application-default login
gcloud projects describe $PROJET_APP --format='value(projectNumber)'
gcloud projects describe $PROJET_AGENTS --format='value(projectNumber)'

Résultat attendu : 523307489860 puis 433175138344. S'ils diffèrent, corrigez le fichier de configuration et rechargez-le.

1.5 Vos droits

for P in $PROJET_AGENTS $PROJET_APP; do echo "== $P"
  gcloud projects get-iam-policy $P --flatten=bindings \
    --filter="bindings.members:user:$(gcloud config get-value account 2>/dev/null)" --format="value(bindings.role)"; done
ProjetRôles nécessaires (ou roles/owner)
aiml-gemini-ent-exp-0zgaaiplatform.admin, iam.serviceAccountAdmin, iam.serviceAccountUser, resourcemanager.projectIamAdmin, serviceusage.serviceUsageAdmin, modelarmor.admin, agentregistry.admin, run.admin, artifactregistry.admin, cloudbuild.builds.editor, storage.admin (les deux derniers : construction des images Cloud Run par Cloud Build ; gcloud crée le bucket gs://aiml-gemini-ent-exp-0zga_cloudbuild à la 1re construction)
acme-gemini-proddiscoveryengine.admin (Gemini Enterprise Admin)

Un rôle donné via un groupe n'apparaît pas dans cette commande : vérifiez alors dans la console (IAM du projet).

1.6 Les API : vérifier, activer seulement celles qui manquent

./scripts/verifier_api.sh $PROJET_AGENTS cloudresourcemanager.googleapis.com serviceusage.googleapis.com iam.googleapis.com \
  aiplatform.googleapis.com agentregistry.googleapis.com modelarmor.googleapis.com logging.googleapis.com \
  run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com
./scripts/verifier_api.sh $PROJET_APP cloudresourcemanager.googleapis.com serviceusage.googleapis.com discoveryengine.googleapis.com

Résultat obtenu :

OK        cloudresourcemanager.googleapis.com
OK        serviceusage.googleapis.com
…
OK        artifactregistry.googleapis.com
OK        cloudbuild.googleapis.com
rien à activer

S'il en manquait : MANQUANTE … puis activées : …. Cloud Build tout juste activé : la 1re construction d'image peut répondre PERMISSION_DENIED ; attendez une minute et relancez.

1.7 Le compte de service de l'app

C'est lui qui appellera vos agents. Il existe déjà (l'app existe) ; on vérifie son adresse :

gcloud beta services identity create --service=discoveryengine.googleapis.com --project=$PROJET_APP

Résultat obtenu : Service identity created: service-100000000003@gcp-sa-discoveryengine.iam.gserviceaccount.com (le message dit « created » même s'il existait : rien ne change). Il doit être identique à echo $GE_SA.


Méthode A : shell (gcloud + scripts)

Chaque ressource est créée par une commande que vous voyez. Noms : suffixe -shell.

A1. Les templates Model Armor (filtre des questions et réponses)

Gemini Enterprise ne filtre pas les agents ajoutés : chaque agent filtre lui-même. Deux templates : questions, réponses.

for T in prompt response; do
gcloud model-armor templates create agents-$T-shield --location=$GE_LOCATION --project=$PROJET_AGENTS \
  --pi-and-jailbreak-filter-settings-enforcement=enabled --pi-and-jailbreak-filter-settings-confidence-level=medium-and-above \
  --malicious-uri-filter-settings-enforcement=enabled --basic-config-filter-enforcement=enabled \
  --rai-settings-filters='[{"filterType":"HATE_SPEECH","confidenceLevel":"MEDIUM_AND_ABOVE"},{"filterType":"HARASSMENT","confidenceLevel":"MEDIUM_AND_ABOVE"},{"filterType":"SEXUALLY_EXPLICIT","confidenceLevel":"MEDIUM_AND_ABOVE"},{"filterType":"DANGEROUS","confidenceLevel":"MEDIUM_AND_ABOVE"}]' \
  --template-metadata-log-operations
done
gcloud model-armor templates list --location=$GE_LOCATION --project=$PROJET_AGENTS --format="value(name)"

Résultat obtenu :

Created template [agents-prompt-shield].
Created template [agents-response-shield].
projects/aiml-gemini-ent-exp-0zga/locations/eu/templates/agents-prompt-shield
projects/aiml-gemini-ent-exp-0zga/locations/eu/templates/agents-response-shield

Leurs chemins sont déjà dans $PROMPT_TEMPLATE et $RESPONSE_TEMPLATE (définis par scripts/config.sh). Templates centraux de la sécurité : sautez la création et ajoutez PROMPT_TEMPLATE=… et RESPONSE_TEMPLATE=… au fichier de configuration.

A2. Agent Runtime : comptes de service, déploiement, test

Un compte de service par agent, avec 3 rôles : appeler Gemini (aiplatform.user), écrire ses journaux (logging.logWriter), utiliser Model Armor (modelarmor.user).

for K in meteo redaction traduction; do
  gcloud iam service-accounts create $K-shell-sa --project=$PROJET_AGENTS --display-name="Agent $K (Agent Runtime, méthode shell)"
  for R in aiplatform.user logging.logWriter modelarmor.user; do
    gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
      --member=serviceAccount:$K-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null && echo "  $K-shell-sa : roles/$R"
  done
done

Résultat obtenu : pour chaque agent, Created service account [meteo-shell-sa]. puis ses 3 rôles.

Déployer les 3 agents (le script empaquette le code de agents/trio et appelle l'API Agent Runtime ; 3 à 5 minutes par agent) :

for K in meteo redaction traduction; do
  DESC=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['description'])")
  python scripts/deployer_agent_runtime.py --projet $PROJET_AGENTS --region $REGION --agent ${K}_agent --nom $K-shell \
    --description "$DESC" --compte-service $K-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com \
    --env PROMPT_TEMPLATE=$PROMPT_TEMPLATE --env RESPONSE_TEMPLATE=$RESPONSE_TEMPLATE
done

Résultat obtenu :

opération : projects/100000000002/locations/europe-west1/reasoningEngines/255731011457908736/operations/2062430170119143424
  en cours… 0 s
  …
déployé : projects/100000000002/locations/europe-west1/reasoningEngines/255731011457908736
…
déployé : projects/100000000002/locations/europe-west1/reasoningEngines/7607857403140243456
…
déployé : projects/100000000002/locations/europe-west1/reasoningEngines/3342948556020383744

Notez les 3 noms projects/…/reasoningEngines/… (dans l'ordre : météo, rédaction, traduction). Les retrouver plus tard :

curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJET_AGENTS/locations/$REGION/reasoningEngines" \
  | python3 -c 'import json,sys; [print(e["displayName"], e["name"]) for e in json.load(sys.stdin).get("reasoningEngines",[])]'

Attendre 5 minutes (les droits des nouveaux comptes s'appliquent), puis tester chaque agent seul :

AGENT_NAME=projects/$NUM_AGENTS/locations/$REGION/reasoningEngines/ID_TRADUCTION \
  python scripts/query.py - "Traduis en espagnol : Votre tente Quechua est disponible en retrait en magasin."

Résultat obtenu :

  -> outil : glossaire({'langue_cible': 'es'})
  -> outil : verifier_traduction({'traduction': 'Su tienda de campaña Quechua está disponible para recogida en tienda.', …})
agent : Su tienda de campaña Quechua está disponible para recogida en tienda.

Contrôle : conforme

Et pour la météo (ID_METEO, « Je cours à Lille demain matin, quoi porter ? ») :

  -> outil : meteo({'ville': 'Lille', 'jours': 2})
  -> outil : conseil_equipement({'activite': 'course à pied', 'pluie_mm': 6.1, 'temperature_c': 9, 'vent_kmh': 24.5})
agent : **Météo à Lille demain :** Pluie faible prévue avec des températures fraîches (environ 9°C le matin) …

Dans la console : 🔎 « Agent Runtime » → Déploiements → traduction-shell → onglet Playground : même test à la souris.

A3. Cloud Run (A2A) : image, comptes de service, services, test

Pas besoin de Docker : les images sont construites dans Google Cloud par Cloud Build. Il faut d'abord (une fois) un dépôt d'images et un compte de service qui construit les images (le compte par défaut de Cloud Build n'a souvent aucun droit : … -compute@developer.gserviceaccount.com does not have storage.objects.get access …).

gcloud artifacts repositories create agents-shell --repository-format=docker --location=$REGION --project=$PROJET_AGENTS
gcloud iam service-accounts create agents-build-sa --project=$PROJET_AGENTS --display-name="Construction des images des agents (Cloud Build)"
for R in storage.objectViewer artifactregistry.writer logging.logWriter; do
  gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
    --member=serviceAccount:agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null && echo "  agents-build-sa : roles/$R"
done

Résultat attendu : Created repository [agents-shell]., Created service account [agents-build-sa]., puis les 3 lignes agents-build-sa : roles/…. Attendez 1 à 2 minutes (les nouveaux droits mettent ce temps à s'appliquer).

Les images, une par agent (depuis le dossier du projet ; ~1 min 20 s par image) :

for K in meteo redaction traduction; do
  gcloud builds submit --region=$REGION --project=$PROJET_AGENTS \
    --service-account=projects/$PROJET_AGENTS/serviceAccounts/agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com \
    --config=01-bis-cloud-run-a2a/cloudbuild.yaml \
    --substitutions=_AGENT_DIR=${K}_agent,_IMAGE=$REGION-docker.pkg.dev/$PROJET_AGENTS/agents-shell/$K:v1 .
done

Résultat obtenu (pour chaque agent) :

Creating temporary archive of 20 file(s) totalling 61.4 KiB before compression.
Uploading tarball of [.] to [gs://aiml-gemini-ent-exp-0zga_cloudbuild/source/….tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/builds/…].
…
ID  CREATE_TIME  DURATION  SOURCE  IMAGES                                                                 STATUS
…   …            …         gs://…  europe-west1-docker.pkg.dev/aiml-gemini-ent-exp-0zga/agents-shell/meteo:v1  SUCCESS

À vérifier : SUCCESS en fin de ligne. Seul le code des agents est envoyé (20 fichiers, filtrés par .gcloudignore). PERMISSION_DENIED juste après la création du compte : attendez 1 à 2 minutes et relancez. Dans la console : 🔎 « Cloud Build » → Historique (région europe-west1) : chaque construction et son journal. Le détail commande par commande : 12-1-1, partie 7.

Les 3 services privés. Pour chacun : un compte de service et ses rôles, la carte A2A et les variables d'environnement (générées depuis agents/trio/catalogue.json), puis le déploiement.

for K in meteo redaction traduction; do
  gcloud iam service-accounts create $K-a2a-shell-sa --project=$PROJET_AGENTS --display-name="Agent $K (Cloud Run A2A, méthode shell)"
  for R in aiplatform.user logging.logWriter modelarmor.user; do
    gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
      --member=serviceAccount:$K-a2a-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null && echo "  $K-a2a-shell-sa : roles/$R"
  done
  URL=https://$K-a2a-shell-$NUM_AGENTS.$REGION.run.app          # adresse connue d'avance : elle va dans la carte
  python3 scripts/carte_a2a.py $K $URL --env-yaml > env-$K.yaml
  gcloud run deploy $K-a2a-shell --image=$REGION-docker.pkg.dev/$PROJET_AGENTS/agents-shell/$K:v1 --region=$REGION --project=$PROJET_AGENTS \
    --service-account=$K-a2a-shell-sa@$PROJET_AGENTS.iam.gserviceaccount.com --no-allow-unauthenticated \
    --env-vars-file=env-$K.yaml --memory=1Gi --cpu=1 --min-instances=0 --max-instances=1 --quiet
done

Résultat obtenu (pour chaque agent) :

Service account email: meteo-a2a-shell-sa@aiml-gemini-ent-exp-0zga.iam.gserviceaccount.com
  meteo-a2a-shell-sa : roles/aiplatform.user
  meteo-a2a-shell-sa : roles/logging.logWriter
  meteo-a2a-shell-sa : roles/modelarmor.user
Service URL: https://meteo-a2a-shell-433175138344.europe-west1.run.app

À vérifier : Service URL est exactement l'adresse mise dans la carte ($URL). --no-allow-unauthenticated : le service est privé (403 sans jeton).

Variable du service (fichier env-meteo.yaml)Rôle
AGENTQuel agent ce service sert (meteo_agent)
AGENT_CARDLa carte A2A v0.3, servie sur /.well-known/agent-card.json
GOOGLE_CLOUD_PROJECT, MODELProjet et modèle Gemini (Vertex AI)
PROMPT_TEMPLATE, RESPONSE_TEMPLATELes templates Model Armor de A1

Attendre 3 à 5 minutes, puis tester un agent avec le protocole de Gemini Enterprise :

URL=https://traduction-a2a-shell-$NUM_AGENTS.$REGION.run.app ./01-bis-cloud-run-a2a/test.sh traduction

Résultat obtenu :

== traduction  carte : traduction_agent (A2A 0.3)
   Q1 > Traduis en espagnol : 'Votre tente Quechua est disponible en retrait en magasin.'
   R1 < Su tienda Quechua está disponible para recogida en tienda.  Contrôle : conforme
   Q2 > Et en italien ?
   R2 < La tua tenda Quechua è disponibile per il ritiro in negozio.  Contrôle : conforme
OK : les agents répondent en A2A v0.3, avec mémoire de conversation

A4. Agent Registry (le catalogue du projet des agents)

Les agents Agent Runtime s'y sont inscrits seuls. Les agents Cloud Run, on les déclare avec leur carte :

for K in meteo redaction traduction; do
  python3 scripts/carte_a2a.py $K https://$K-a2a-shell-$NUM_AGENTS.$REGION.run.app > carte-$K.json
  NOM=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])")
  gcloud agent-registry services create $K-a2a-shell --location=$REGION --project=$PROJET_AGENTS \
    --display-name="$NOM" --description="$(python3 -c "import json; print(json.load(open('carte-$K.json'))['description'])")" \
    --agent-spec-type=A2A_AGENT_CARD --agent-spec-content="$(cat carte-$K.json)"
done
gcloud agent-registry agents list --location=$REGION --project=$PROJET_AGENTS --format="table(displayName,agentId)"

Résultat obtenu :

Created service [meteo-a2a-shell].
Created service [redaction-a2a-shell].
Created service [traduction-a2a-shell].
DISPLAY_NAME      AGENT_ID
meteo_agent       urn:agent:projects-433175138344:…:agentregistry:services:meteo-a2a-shell
redaction_agent   urn:agent:projects-433175138344:…:agentregistry:services:redaction-a2a-shell
traduction_agent  urn:agent:projects-433175138344:…:agentregistry:services:traduction-a2a-shell
meteo-shell       urn:agent:projects-433175138344:…:aiplatform:reasoningEngines:255731011457908736
traduction-shell  urn:agent:projects-433175138344:…:aiplatform:reasoningEngines:3342948556020383744
redaction-shell   urn:agent:projects-433175138344:…:aiplatform:reasoningEngines:7607857403140243456

Pas de --interfaces avec une carte A2A : l'API le refuse (l'adresse est dans la carte).

A5. Donner à l'app le droit d'appeler les agents

# Agent Runtime : un droit sur le PROJET des agents
gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None \
  --role=roles/discoveryengine.serviceAgent --member=serviceAccount:$GE_SA
# Cloud Run : un droit sur CHAQUE service
for K in meteo redaction traduction; do
  gcloud run services add-iam-policy-binding $K-a2a-shell --region=$REGION --project=$PROJET_AGENTS \
    --role=roles/run.invoker --member=serviceAccount:$GE_SA
done
# Vérifier
gcloud projects get-iam-policy $PROJET_AGENTS --flatten=bindings --filter="bindings.members:$GE_SA" --format="value(bindings.role)"
for K in meteo redaction traduction; do echo "$K-a2a-shell : $(gcloud run services get-iam-policy $K-a2a-shell --region=$REGION \
  --project=$PROJET_AGENTS --flatten=bindings --filter="bindings.members:$GE_SA" --format="value(bindings.role)")"; done

Résultat obtenu (vérification) :

roles/discoveryengine.serviceAgent
meteo-a2a-shell : roles/run.invoker
redaction-a2a-shell : roles/run.invoker
traduction-a2a-shell : roles/run.invoker

A6. Ajouter les agents dans l'app, donner l'accès, tester dans le chat

Agent Runtime (avec les 3 noms de ressource de A2) :

for K in meteo redaction traduction; do
  RES=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJET_AGENTS/locations/$REGION/reasoningEngines" \
    | python3 -c "import json,sys; print(next(e['name'] for e in json.load(sys.stdin)['reasoningEngines'] if e['displayName']=='$K-shell'))")
  NOM=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])")
  DESC=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['description'])")
  ./scripts/add_agent_to_ge.sh adk "$RES" "$NOM (shell)" "$DESC"
done

A2A (avec les cartes de A4) :

for K in meteo redaction traduction; do
  NOM=$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])")
  ./scripts/add_agent_to_ge.sh a2a carte-$K.json "$NOM (A2A shell)"
done
./scripts/add_agent_to_ge.sh list

Résultat attendu : pour chaque agent ajouté : projects/…/engines/dev_gemini-entreprise-app/assistants/default_assistant/agents/<ID> (Agent Runtime : avant, droit accordé : …, le droit existant déjà). list montre 6 agents, adkAgentDefinition et a2aAgentDefinition.

Donner l'accès (console, pour chaque agent) : 🔎 « Gemini Enterprise » → dev_gemini-entreprise-app → Agents → l'agent → onglet Autorisations utilisateur → Ajouter → equipe-agents@acme.example (votre GROUPE_UTILISATEURS) → rôle Agent User → Enregistrer. Les membres doivent avoir une licence Gemini Enterprise.

Tester dans le chat : app → Intégration → lien de l'app web, avec un compte du groupe → Agents → « Traduction Acme (shell) » → « Traduis en allemand : retour gratuit sur les chaussures Kiprun ».

Résultat attendu : « Kostenlose Rücksendung … Kiprun … — Contrôle : conforme ». Première réponse : 20 à 40 s. Les sessions apparaissent dans aiml-gemini-ent-exp-0zga (Agent Runtime → l'agent → Sessions).

A7. Nettoyer la méthode A

for K in meteo redaction traduction; do ./scripts/add_agent_to_ge.sh delete "$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])") (shell)"; done
for K in meteo redaction traduction; do ./scripts/add_agent_to_ge.sh delete "$(python3 -c "import json; print(json.load(open('agents/trio/catalogue.json'))['$K']['nom_affiche'])") (A2A shell)"; done
for R in $(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJET_AGENTS/locations/$REGION/reasoningEngines" \
  | python3 -c 'import json,sys; [print(e["name"]) for e in json.load(sys.stdin).get("reasoningEngines",[]) if e["displayName"].endswith("-shell")]'); do
  python scripts/deployer_agent_runtime.py --projet $PROJET_AGENTS --supprimer $R
done
for K in meteo redaction traduction; do
  gcloud run services delete $K-a2a-shell --region=$REGION --project=$PROJET_AGENTS --quiet
  gcloud agent-registry services delete $K-a2a-shell --location=$REGION --project=$PROJET_AGENTS --quiet
  for SA in $K-shell-sa $K-a2a-shell-sa; do
    for R in aiplatform.user logging.logWriter modelarmor.user; do
      gcloud projects remove-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
        --member=serviceAccount:$SA@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null 2>&1
    done
    gcloud iam service-accounts delete $SA@$PROJET_AGENTS.iam.gserviceaccount.com --project=$PROJET_AGENTS --quiet
  done
done
gcloud projects remove-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/discoveryengine.serviceAgent \
  --member=serviceAccount:$GE_SA >/dev/null && echo "droit de l'app retiré"
for T in agents-prompt-shield agents-response-shield; do gcloud model-armor templates delete $T --location=$GE_LOCATION --project=$PROJET_AGENTS --quiet; done
gcloud artifacts repositories delete agents-shell --location=$REGION --project=$PROJET_AGENTS --quiet
for R in storage.objectViewer artifactregistry.writer logging.logWriter; do   # le compte de construction (gardez-le si vous faites la méthode C)
  gcloud projects remove-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
    --member=serviceAccount:agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null 2>&1
done
gcloud iam service-accounts delete agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com --project=$PROJET_AGENTS --quiet
rm -f env-*.yaml carte-*.json

Résultat obtenu : supprimé : projects/…/reasoningEngines/… ×3, Deleted service […] (Cloud Run puis registre), deleted service account […] ×6, droit de l'app retiré, Deleted template […] ×2, Deleted repository [agents-shell]., deleted service account [agents-build-sa@…]. Le bucket gs://…_cloudbuild (créé par Google, le code envoyé aux constructions) reste ; à la main : gcloud storage rm -r gs://${PROJET_AGENTS}_cloudbuild. Inventaire de ce qui reste : python scripts/nettoyer.py (et --supprimer pour tout retirer).

Ne retirez le droit discoveryengine.serviceAgent que si aucun autre agent Agent Runtime de ce projet n'est utilisé par l'app (le droit vaut pour tout le projet).


Méthode B : Terraform

Terraform crée tout (comptes de service, droits, templates Model Armor, agents, registre, droit de l'app) à partir du fichier de configuration. Il s'exécute sur votre poste : l'état (terraform.tfstate) est gardé dans terraform.tfstate.d/scenario-12-1/ du dossier Terraform ; ne le supprimez pas, sauvegardez-le.

B1. Agent Runtime (dossier 02-bis)

source scripts/config.sh config/12-1-agents-dans-projet-exp.env
cd 02-bis-agent-runtime/terraform
terraform init
terraform plan

Résultat obtenu (fin du plan) : Plan: 49 to add, 0 to change, 0 to destroy. — dont 6 google_vertex_ai_reasoning_engine (les agents du catalogue : météo, rédaction, traduction, taille, retour, identite), 6 google_service_account (leurs identités) et google_project_iam_member.ge_uses_agents_project[0] (le droit de l'app sur ce projet).

terraform apply       # taper yes ; 10 à 15 minutes

Résultat obtenu :

Apply complete! Resources: 49 added, 0 changed, 0 destroyed.

Outputs:

agents = {
  "identite" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/…"
  "meteo" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/5587992970264576000"
  "redaction" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/1022468848017735680"
  "retour" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/…"
  "taille" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/…"
  "traduction" = "projects/aiml-gemini-ent-exp-0zga/locations/europe-west1/reasoningEngines/976306951837188096"
}
ge_agents_page = "(ge_app_id vide : agents non publiés)"
ge_service_agent = "serviceAccount:service-100000000003@gcp-sa-discoveryengine.iam.gserviceaccount.com"

Error code 13 sur un agent ? Erreur interne de Google : relancez terraform apply, seul l'agent manquant est recréé.

Attendre 5 minutes, puis tester les 6 agents seuls (./test.sh taille : un seul) :

cd .. && ./test.sh

Résultat obtenu : pour chaque agent, les outils appelés puis la réponse (comme en A2).

B2. Cloud Run A2A (dossier 01-bis)

cd $DOSSIER/01-bis-cloud-run-a2a/terraform
terraform init
terraform plan        # « Plan: 63 to add » : par agent (×6) une image, un service, une identité, un droit run.invoker pour l'app, une entrée de registre…
terraform apply       # yes ; ~10 min (Cloud Build construit les images dans Google Cloud : pas de Docker)

Résultat obtenu : Apply complete! Resources: 63 added, puis cards (les cartes A2A) et urls. Le plan compte 23 ressources pour un agent, +8 par agent en plus (63 pour 6). Il contient aussi le compte qui construit les images, google_service_account.build (agents-a2a-build-sa), ses 3 rôles google_project_iam_member.build["roles/…"] et l'API google_project_service.agents["cloudbuild.googleapis.com"]. Chaque image est construite par gcloud builds submit (~1 min 20 s ; Terraform réessaie jusqu'à 4 fois si les droits tout neufs ne sont pas encore actifs). Dans la console : 🔎 « Cloud Build » → Historique (région europe-west1). Attendre 5 minutes, puis :

cd .. && ./test.sh

Résultat obtenu : pour chaque agent carte : … (A2A 0.3), deux réponses dans la même conversation, puis OK : ….

B3. Agent Registry

gcloud agent-registry agents list --location=$REGION --project=$PROJET_AGENTS --format="table(displayName,agentId)"

Résultat attendu : meteo-agent, redaction-agent, traduction-agent (Agent Runtime, inscrits seuls) et meteo_agent, redaction_agent, traduction_agent (cartes A2A déclarées par Terraform), et de même pour taille, retour et identite.

B4. Le droit de l'app (déjà posé par Terraform)

gcloud projects get-iam-policy $PROJET_AGENTS --flatten=bindings --filter="bindings.members:$GE_SA" --format="value(bindings.role)"

Résultat obtenu : roles/discoveryengine.serviceAgent (et roles/run.invoker sur chaque service *-a2a).

B5. Publier dans l'app, donner l'accès, tester dans le chat

Dans config/12-1-agents-dans-projet-exp.env, passez PUBLIER=non à PUBLIER=oui, puis :

cd $DOSSIER && source scripts/config.sh config/12-1-agents-dans-projet-exp.env     # « publication dans l'app : oui »
cd 02-bis-agent-runtime/terraform && terraform plan

Résultat obtenu (plan) : google_project_service.ge[0] et terraform_data.publish["meteo"], ["redaction"], ["traduction"], … (un par agent, 6) à créer.

terraform apply
cd ../../01-bis-cloud-run-a2a/terraform && terraform apply

Résultat attendu : registered Météo & équipement (×6 noms), Apply complete! Resources: 7 added pour chaque dossier (l'API Discovery Engine + 6 publications) (les agents A2A apparaissent avec « (A2A) » dans leur nom). terraform output ge_agents_page donne le lien de la page Agents de l'app.

Puis donner l'accès et tester dans le chat exactement comme en A6.

B6. Nettoyer la méthode B

cd $DOSSIER && source scripts/config.sh config/12-1-agents-dans-projet-exp.env
terraform -chdir=01-bis-cloud-run-a2a/terraform destroy     # yes -> retire aussi les agents de l'app
terraform -chdir=02-bis-agent-runtime/terraform destroy     # yes

Résultat attendu : Destroy complete! Resources: 70 destroyed. et Resources: 56 destroyed. (avec la publication), ou 63 et 49 sans.


Méthode C : console (interface)

Tout à la souris, sauf deux commandes inévitables, lancées depuis Cloud Shell (icône >_ de la console) : la console n'a pas de formulaire pour envoyer du code à Agent Runtime, ni pour construire une image à partir du dossier (on la fait construire par Cloud Build, sans Docker). Noms : suffixe -console. Projet sélectionné en haut de la console : aiml-gemini-ent-exp-0zga, sauf mention contraire.

C1. Les templates Model Armor

🔎 « Model Armor » → Templates → Créer un template :

ChampValeur
ID du templateconsole-prompt-shield (puis un second : console-response-shield)
RégionMultirégion → eu
Détection des URL malveillantesActivée
Injection de prompt et jailbreakActivée, confiance Moyenne et supérieure
Protection des données sensiblesDe base, activée
IA responsableIncitation à la haine, Harcèlement, Contenu sexuel explicite, Contenu dangereux : Moyenne et supérieure

Créer, deux fois. Attendu : les deux templates dans la liste, région eu.

C2. Les comptes de service des agents

🔎 « Comptes de service » (IAM et administration) → Créer un compte de service, 6 fois : meteo-console-sa, redaction-console-sa, traduction-console-sa (Agent Runtime) et meteo-a2a-console-sa, redaction-a2a-console-sa, traduction-a2a-console-sa (Cloud Run).

Pour chacun : Nom → Créer et continuer → Attribuer des rôles : Utilisateur Vertex AI (Agent Platform User), Rédacteur de journaux (Logs Writer), Utilisateur Model Armor → OK.

Attendu : les 6 comptes dans la liste ; IAM du projet : chacun avec ses 3 rôles.

C3. Agent Runtime : déployer (1 commande), tester (console)

Cloud Shell (icône >_), après avoir importé le dossier (menu à trois points → Importer) et chargé la configuration (partie 1.3, avec DOSSIER=~/09-agents-multi-projets-gemini-enterprise dans le fichier si vous êtes dans Cloud Shell) :

for K in meteo redaction traduction; do
  python scripts/deployer_agent_runtime.py --projet $PROJET_AGENTS --agent ${K}_agent --nom $K-console \
    --compte-service $K-console-sa@$PROJET_AGENTS.iam.gserviceaccount.com \
    --env PROMPT_TEMPLATE=projects/$PROJET_AGENTS/locations/eu/templates/console-prompt-shield \
    --env RESPONSE_TEMPLATE=projects/$PROJET_AGENTS/locations/eu/templates/console-response-shield
done

Attendu : déployé : projects/…/reasoningEngines/… ×3 (comme en A2).

Tester (console) : 🔎 « Agent Runtime » → Déploiements → traduction-console → Playground → « Traduis en espagnol : Votre tente Quechua est disponible en retrait en magasin. » Attendu : « … recogida en tienda — Contrôle : conforme ». Onglet Sessions : la conversation. Copiez le nom de la ressource affiché sur la page de l'agent (projects/…/reasoningEngines/…).

C4. Cloud Run A2A : image (1 commande), services (console), test

Les images, dans Cloud Shell, depuis le dossier du projet (cd $DOSSIER). Le compte de construction agents-build-sa : déjà créé si vous avez fait la méthode A (ALREADY_EXISTS : rien à faire) ; sinon les 2 premières commandes le créent, puis attendez 1 à 2 minutes.

gcloud iam service-accounts create agents-build-sa --project=$PROJET_AGENTS --display-name="Construction des images des agents (Cloud Build)"
for R in storage.objectViewer artifactregistry.writer logging.logWriter; do
  gcloud projects add-iam-policy-binding $PROJET_AGENTS --condition=None --role=roles/$R \
    --member=serviceAccount:agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com >/dev/null && echo "  agents-build-sa : roles/$R"
done
gcloud artifacts repositories create agents-console --repository-format=docker --location=$REGION --project=$PROJET_AGENTS
for K in meteo redaction traduction; do
  gcloud builds submit --region=$REGION --project=$PROJET_AGENTS \
    --service-account=projects/$PROJET_AGENTS/serviceAccounts/agents-build-sa@$PROJET_AGENTS.iam.gserviceaccount.com \
    --config=01-bis-cloud-run-a2a/cloudbuild.yaml \
    --substitutions=_AGENT_DIR=${K}_agent,_IMAGE=$REGION-docker.pkg.dev/$PROJET_AGENTS/agents-console/$K:v1 .
done
for K in meteo redaction traduction; do python3 scripts/carte_a2a.py $K https://$K-a2a-console-$NUM_AGENTS.$REGION.run.app; echo; done

Attendu : pour chaque agent, une ligne qui finit par …/agents-console/meteo:v1 SUCCESS (~1 min 20 s par image). Les constructions et leurs journaux : 🔎 « Cloud Build » → Historique (région europe-west1). La dernière commande affiche les 3 cartes : gardez-les (copier-coller) pour les étapes suivantes.

Les services : 🔎 « Cloud Run » → Déployer un conteneur (ou Créer un service), 3 fois :

ChampValeur (exemple : météo)
URL de l'image du conteneurSélectionner → agents-console → meteo → v1 (l'image de cet agent)
Nom du servicemeteo-a2a-console
Régioneurope-west1
AuthentificationExiger l'authentification
Conteneur → Variables et secretsAGENT = meteo_agent ; AGENT_CARD = la carte affichée ci-dessus (tout le JSON) ; GOOGLE_CLOUD_PROJECT = aiml-gemini-ent-exp-0zga ; MODEL = gemini-3.5-flash ; PROMPT_TEMPLATE = projects/aiml-gemini-ent-exp-0zga/locations/eu/templates/console-prompt-shield ; RESPONSE_TEMPLATE = …/console-response-shield
Conteneur → RessourcesMémoire 1 Gio, 1 processeur
Sécurité → Compte de servicemeteo-a2a-console-sa
ScalingMinimum 0, maximum 1

Créer. Attendu : coche verte, et l'URL https://meteo-a2a-console-433175138344.europe-west1.run.app parmi les URL du service (c'est celle de la carte).

Tester (Cloud Shell, 3 à 5 minutes après) : URL=https://traduction-a2a-console-$NUM_AGENTS.$REGION.run.app ./01-bis-cloud-run-a2a/test.sh traduction → Attendu : OK : les agents répondent en A2A v0.3, avec mémoire de conversation.

C5. Agent Registry

Les agents Agent Runtime y sont déjà. Pour les agents Cloud Run : 🔎 « Agent Registry » → région europe-west1 → Enregistrer → type Agent → Nom (meteo-a2a-console), Nom à afficher, Description, spécification Carte d'agent A2A : coller la carte → Enregistrer. Attendu : les 6 agents dans la liste.

C6. Donner à l'app le droit d'appeler les agents

  1. Agent Runtime, sur le projet : 🔎 « IAM » → Accorder l'accès → Nouveaux comptes principaux : service-100000000003@gcp-sa-discoveryengine.iam.gserviceaccount.com → rôle Agent de service Discovery Engine (Discovery Engine Service Agent) → Enregistrer. Si la console refuse ce rôle d'« agent de service », passez la commande de A5 (première ligne) dans Cloud Shell.
  2. Cloud Run, sur chaque service : 🔎 « Cloud Run » → meteo-a2a-console → onglet Sécurité (ou Autorisations) → Ajouter un compte principal → le même compte → rôle Demandeur Cloud Run (Cloud Run Invoker) → Enregistrer. Idem pour les deux autres services.

Attendu : IAM du projet (case Inclure les attributions de rôles fournies par Google cochée) : le compte avec Discovery Engine Service Agent ; chaque service : le compte avec Cloud Run Invoker.

C7. Ajouter dans l'app, donner l'accès, tester dans le chat

Sélectionnez le projet acme-gemini-prod → 🔎 « Gemini Enterprise » → dev_gemini-entreprise-app → Agents → + Ajouter un agent :

  • Agent personnalisé via Agent Runtime → Ajouter → Nom de l'agent (Traduction Acme (console)), Décrivez votre agent (la description de agents/trio/catalogue.json), Chemin de ressource Agent Runtime (copié en C3) → Créer. Idem pour météo et rédaction.
  • Agent personnalisé via A2A → Ajouter → coller la carte (JSON) → Prévisualiser les détails de l'agent (nom, description, compétences) → Suivant → Authentification : ignorer → Terminer. Idem pour les deux autres.

Puis, pour chaque agent : Autorisations utilisateur → Ajouter → le groupe → Agent User → Enregistrer, et le test dans le chat de A6.

C8. Nettoyer la méthode C

Dans l'app : chaque agent « (console) » → Supprimer. Projet des agents : Agent Runtime → chaque agent -console → Supprimer ; Cloud Run → chaque service -console → Supprimer ; Agent Registry → les 3 entrées → Supprimer ; Comptes de service → les 6 -console-sa → Supprimer ; Model Armor → les 2 templates console-* → Supprimer ; Artifact Registry → agents-console → Supprimer ; Comptes de service → agents-build-sa → Supprimer (si la méthode A ne s'en sert plus). IAM : retirer le rôle Discovery Engine Service Agent du compte de l'app si plus aucun agent Agent Runtime de ce projet n'est utilisé.


5. Ce qui peut arriver

Ce que vous voyezCauseQue faire
MANQUANT : … ou À CORRIGER au chargement de la configurationValeur vide ou incohérente dans le fichierCorriger le fichier, recharger
Commandes avec --project= videConfiguration non chargée dans ce terminalsource scripts/config.sh config/12-1-agents-dans-projet-exp.env
PERMISSION_DENIEDUn rôle manquePartie 1.5
Toutes les réponses : « … filtrée par Model Armor » juste après le déploiementDroit modelarmor.user du nouveau compte pas encore actifAttendre 2 à 5 minutes, retester
Error code 13 (Agent Runtime)Erreur interne de GoogleRelancer la commande (ou terraform apply)
PERMISSION_DENIED à gcloud builds submit juste après avoir activé Cloud Build ou créé agents-build-saDroits tout neufs, pas encore actifsAttendre 1 à 2 minutes, relancer
… does not have storage.objects.get access to the Google Cloud Storage objectCompte de construction absent, ou --service-account oublié (le compte par défaut de Cloud Build n'a pas de droits)Créer agents-build-sa (A3) et garder --service-account=…
Construction FAILUREErreur dans l'imageOuvrir le lien du journal affiché par gcloud ; console : 🔎 « Cloud Build » → Historique (région europe-west1)
ÉCHEC : 403 dans test.sh (Cloud Run)Votre compte n'a pas run.invoker sur le serviceÊtre propriétaire du projet, ou se donner ce rôle sur le service
Agent absent du chatPas d'Agent User pour le groupe, ou pas de licenceA6, « Donner l'accès »
« L'agent n'a pas pu répondre » dans le chatDroit de l'app absent (A5 / B4 / C6), ou donné à une autre adresse (NUM_APP faux)Vérifier avec la commande de A5 ; attendre 2 à 3 minutes après l'ajout d'un droit
Ajout refusé : régionAgent hors europe-*REGION=europe-west1
Carte A2A refusée à la prévisualisationJSON tronquéRecopier la carte complète (carte-*.json ou terraform output -json cards)

Journaux : console → 🔎 « Journaux » (projet des agents), ou gcloud logging read 'resource.type="cloud_run_revision" AND severity>=WARNING' --project=$PROJET_AGENTS --freshness=30m --limit=10.

Suite : les agents dans le projet de l'app (et les modes Agent Registry, Dialogflow) : 12-2.

Siguiente