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éthode | Pour qui | Ce qui est fait à la main |
|---|---|---|
| A. Shell (gcloud + scripts) | Comprendre chaque ressource, tout reproduire en copier-coller | Tout, commande par commande |
| B. Terraform | La cible : reproductible, relu, défait proprement | 3 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 :
- déployer : 12-1-1 Shell · 12-1-2 Terraform · 12-1-3 Console ;
- connecter à l'app : 12-1-4 ;
- simuler l'appel : 12-1-5 ;
- la console de l'app : 12-1-6 ;
- OAuth, identité, outils : 12-1-7 ;
- 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
AGENTSdu fichier de configuration.6 agents, pas 3 : le catalogue
agents/trio/catalogue.jsoncontient 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
- Ce qu'on construit, et les protocoles possibles
- Préparation commune (une fois)
- Méthode A : shell (gcloud + scripts)
- Méthode B : Terraform
- Méthode C : console (interface)
- 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'app | Fonctionne 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) | Oui | roles/discoveryengine.serviceAgent sur le projet |
| A2A (agent hébergé sur Cloud Run, protocole ouvert A2A v0.3) | Oui | roles/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 | — |
| Dialogflow | Non 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
| Outil | Mac (Homebrew) | Vérifier |
|---|---|---|
| gcloud | brew install --cask google-cloud-sdk puis gcloud components install beta | gcloud version |
| Terraform 1.9+ (méthode B) | brew tap hashicorp/tap && brew install hashicorp/tap/terraform | terraform version |
| uv (Python 3.12 à 3.14) | brew install uv | uv --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.pyRé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.envRé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| Projet | Rôles nécessaires (ou roles/owner) |
|---|---|
aiml-gemini-ent-exp-0zga | aiplatform.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-prod | discoveryengine.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.comRé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_APPRé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
doneRé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
doneRé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"
doneRé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 .
doneRé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
doneRé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 |
|---|---|
AGENT | Quel agent ce service sert (meteo_agent) |
AGENT_CARD | La carte A2A v0.3, servie sur /.well-known/agent-card.json |
GOOGLE_CLOUD_PROJECT, MODEL | Projet et modèle Gemini (Vertex AI) |
PROMPT_TEMPLATE, RESPONSE_TEMPLATE | Les 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 traductionRé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)")"; doneRé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"
doneA2A (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 listRé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-*.jsonRé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.serviceAgentque 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 planRé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 minutesRé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.shRé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.shRé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 planRé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 applyRé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 # yesRé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 :
| Champ | Valeur |
|---|---|
| ID du template | console-prompt-shield (puis un second : console-response-shield) |
| Région | Multirégion → eu |
| Détection des URL malveillantes | Activée |
| Injection de prompt et jailbreak | Activée, confiance Moyenne et supérieure |
| Protection des données sensibles | De base, activée |
| IA responsable | Incitation à 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
doneAttendu : 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; doneAttendu : 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 :
| Champ | Valeur (exemple : météo) |
|---|---|
| URL de l'image du conteneur | Sélectionner → agents-console → meteo → v1 (l'image de cet agent) |
| Nom du service | meteo-a2a-console |
| Région | europe-west1 |
| Authentification | Exiger l'authentification |
| Conteneur → Variables et secrets | AGENT = 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 → Ressources | Mémoire 1 Gio, 1 processeur |
| Sécurité → Compte de service | meteo-a2a-console-sa |
| Scaling | Minimum 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
- 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. - 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 deagents/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 voyez | Cause | Que faire |
|---|---|---|
MANQUANT : … ou À CORRIGER au chargement de la configuration | Valeur vide ou incohérente dans le fichier | Corriger le fichier, recharger |
Commandes avec --project= vide | Configuration non chargée dans ce terminal | source scripts/config.sh config/12-1-agents-dans-projet-exp.env |
PERMISSION_DENIED | Un rôle manque | Partie 1.5 |
| Toutes les réponses : « … filtrée par Model Armor » juste après le déploiement | Droit modelarmor.user du nouveau compte pas encore actif | Attendre 2 à 5 minutes, retester |
Error code 13 (Agent Runtime) | Erreur interne de Google | Relancer la commande (ou terraform apply) |
PERMISSION_DENIED à gcloud builds submit juste après avoir activé Cloud Build ou créé agents-build-sa | Droits tout neufs, pas encore actifs | Attendre 1 à 2 minutes, relancer |
… does not have storage.objects.get access to the Google Cloud Storage object | Compte 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 FAILURE | Erreur dans l'image | Ouvrir 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 chat | Pas d'Agent User pour le groupe, ou pas de licence | A6, « Donner l'accès » |
| « L'agent n'a pas pu répondre » dans le chat | Droit 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égion | Agent hors europe-* | REGION=europe-west1 |
| Carte A2A refusée à la prévisualisation | JSON 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.