Pour qui : les équipes qui veulent construire de vrais agents (avec des outils) et les rendre utilisables dans Gemini Enterprise, en code (Terraform), de façon reproductible. Résultat : trois agents dans le chat Gemini Enterprise, déployés au choix sur Cloud Run (A2A) ou sur Agent Runtime, dans le projet de l'app ou dans un autre projet, inscrits dans Agent Registry.
Les tutoriels 02 et 03 font la même chose à la main, dans la console, avec un seul agent. Celui-ci est la version industrialisée : trois agents, tout en Terraform, testé à chaque étape. Ce document contient les étapes communes ; chaque hébergement a ensuite son pas à pas.
Sommaire
- Les 3 agents
- Choisir : Cloud Run + A2A ou Agent Runtime ? Même projet ou autre projet ?
- Prérequis (une fois)
- Tester les agents sur votre poste
- Déployer : la suite dans 01-bis ou 02-bis
- Ce qui est vérifié
1. Les 3 agents
Le code est dans agents/trio/, une seule fois : les deux hébergements déploient exactement les mêmes fichiers.
| Agent | Ce qu'il fait | Outils (code Python) | Exemple |
|---|---|---|---|
Météo & équipement (meteo_agent) | Météo réelle d'une ville (jusqu'à 7 jours) et quoi porter pour faire du sport | meteo (API Open-Meteo, gratuite, sans clé) ; conseil_equipement (règle des 3 couches, alertes vent / pluie / chaleur) | « Je cours à Lille demain matin, quoi porter ? » |
Rédaction & reformulation (redaction_agent) | Reformule un texte selon le canal et la charte | charte_redactionnelle (ton, structure, longueur par canal) ; analyser_texte (mots, phrases, phrases trop longues, avant / après) | « Reformule pour un e-mail client : … » |
Traduction Acme (traduction_agent) | Traduit en 7 langues en respectant le glossaire | glossaire (termes imposés, marques à ne pas traduire) ; verifier_traduction (marques conservées, longueur cohérente) | « Traduis en espagnol : Votre tente Quechua … » |
agents/trio/
├── commun.py accès au modèle Gemini (identité Vertex AI, ou clé d'API) + plugin Model Armor (obligatoire hors local)
├── catalogue.json noms affichés, descriptions, compétences A2A : lu par Terraform (01-bis et 02-bis)
├── requirements.txt
├── meteo_agent/ agent.py : root_agent (l'agent), app (agent + Model Armor), agent_runtime_app (Agent Runtime)
├── redaction_agent/
└── traduction_agent/
Le catalogue contient aussi Conseil taille (
taille_agent), Retours produits (retour_agent) et Identité utilisateur (identite_agent) : Terraform (01-bis, 02-bis) déploie toutes les entrées du catalogue, soit 6 agents. Ajouter le vôtre : docs/12-3.
Pourquoi un agent = des outils + des consignes : l'outil fait ce qu'un modèle fait mal (données réelles, calculs, règles exactes) ; le modèle fait ce qu'un outil fait mal (comprendre la demande, rédiger). Chaque consigne dit quand appeler chaque outil. C'est ce qui rend l'agent fiable.
Accès au modèle : identité (par défaut) ou clé d'API. commun.py choisit selon l'environnement :
| Variable | Accès | Quand |
|---|---|---|
| (aucune) | Vertex AI avec l'identité de l'agent (la vôtre en local) | Recommandé : aucun secret à gérer |
GEMINI_API_KEY | API Gemini, clé Google AI Studio | Équipe qui a déjà une clé AI Studio |
VERTEX_API_KEY | Vertex AI, clé d'API (mode express) | Clé Vertex AI fournie par l'équipe cloud |
Déployé, la clé n'est jamais en clair : on la range dans Secret Manager, puis on renseigne model_api_key_secret
(et model_api_key_type) dans terraform.tfvars. Chaque agent ne peut lire que ce secret.
printf '%s' "VOTRE_CLE" | gcloud secrets create gemini-api-key --data-file=- --project=PROJET_DES_AGENTS
# terraform.tfvars : model_api_key_secret = "gemini-api-key" model_api_key_type = "gemini"Pourquoi Model Armor est dans l'agent : Gemini Enterprise ne filtre pas les agents qu'on lui ajoute (Agent Runtime
comme A2A). Chaque agent filtre donc lui-même questions et réponses, et refuse de démarrer sans template (sauf en
local, avec LOCAL_DEV=1).
2. Choisir
Hébergement
| 01-bis : Cloud Run + A2A | 02-bis : Agent Runtime | |
|---|---|---|
| Qui héberge | Vous : un conteneur Cloud Run par agent | Google : hébergement géré |
| Protocole vers Gemini Enterprise | A2A v0.3 (standard ouvert, tout framework) | API Agent Runtime (ADK) |
| Ajout dans l'app | Agent personnalisé via A2A : carte d'agent JSON | Agent personnalisé via Agent Runtime : nom de ressource |
| Agent Registry | Déclaré par Terraform (carte A2A) | Automatique |
| Sessions, journaux, playground | Journaux Cloud Run ; sessions en mémoire (1 instance) | Sessions gérées, onglets Playground / Journaux / Sessions |
| Docker sur le poste | Non : les images sont construites dans Google Cloud (Cloud Build) | Non |
| Durée du premier déploiement | ~10 min | ~10 à 15 min |
| Quand | Agent appelé aussi hors Google (A2A), contrôle du conteneur, équipe habituée à Cloud Run | Par défaut pour un agent ADK |
Les deux peuvent coexister : les noms affichés diffèrent (« … (A2A) » pour Cloud Run).
Même projet ou autre projet
Les deux fonctionnent avec le même code, et ont été testés entre deux vrais projets. Dans terraform.tfvars :
agents_project_id = "equipe-pricing-prod" # le projet qui héberge les agents (le vôtre, ou celui de l'app)
ge_project_number = "98547854221" # le NUMÉRO du projet de l'app, donné par l'admin Gemini EnterpriseUne équipe n'a besoin d'aucun droit sur le projet de l'app : Terraform ne s'en sert que pour publier, si l'on renseigne
ge_project_id et ge_app_id (admin, ou tout dans le projet de l'app). Le pas à pas entre projets, avec le rôle de
chacun : docs/09, partie 3.
| Droit | Même projet | Autre projet | Posé par |
|---|---|---|---|
| Gemini Enterprise appelle un agent Agent Runtime | Aucun (déjà donné par Google) | roles/discoveryengine.serviceAgent sur le projet des agents | Terraform 02-bis |
| Gemini Enterprise appelle un agent Cloud Run (A2A) | roles/run.invoker sur chaque service | Idem | Terraform 01-bis |
| L'agent utilise Gemini, écrit ses journaux | Rôles sur son projet, identité dédiée par agent | Idem | Terraform |
| L'agent utilise les templates Model Armor | roles/modelarmor.user sur le projet des templates | Idem | Terraform |
Détail et règle générale : 05 – droits et régions.
3. Prérequis (une fois)
3.1 Les outils
Le plus simple : Cloud Shell (console Google Cloud, icône >_), où tout est installé. Sur un poste :
| Outil | Version | Vérifier |
|---|---|---|
| gcloud | récente | gcloud version |
| Terraform | 1.9 ou plus | terraform version |
| Python | 3.12 (via uv) | uv --version |
3.2 Se connecter
gcloud auth login # pour gcloud (et Cloud Build, qui construit les images de 01-bis)
gcloud auth application-default login # pour Terraform et les tests Python
gcloud config set project aiml-gemini-entreprise-ldbr3.3 Les projets
| Cas | Projets |
|---|---|
| Même projet | Un projet : celui de l'app Gemini Enterprise (aiml-gemini-entreprise-ldbr dans ce guide) |
| Autre projet | Le projet de l'app (A, aiml-gemini-entreprise-ldbr) et le projet des agents (B, acme-agents-demo), même organisation, facturation active |
Dans chaque projet, activer les deux API dont Terraform a besoin avant son premier lancement (Terraform lit le
numéro du projet, ce qui exige ces API ; sans elles : 403 Cloud Resource Manager API has not been used) :
for P in aiml-gemini-entreprise-ldbr acme-agents-demo; do # un seul projet ? une seule valeur
gcloud services enable cloudresourcemanager.googleapis.com serviceusage.googleapis.com --project=$P
doneLes autres API (Cloud Run, Agent Platform, Model Armor, Agent Registry…) sont activées par Terraform.
3.4 Vos droits
| Où | Démo | Acme (moindre privilège) |
|---|---|---|
| Projet des agents | Owner | Cloud Run Admin (01-bis), Artifact Registry Admin (01-bis), Cloud Build Editor, Storage Admin et Service Account User (01-bis : construction des images par Cloud Build), Agent Platform Admin, Service Account Admin, Project IAM Admin, Service Usage Admin, Model Armor Admin, Agent Registry Admin |
| Projet de l'app | Owner | Gemini Enterprise Admin, Service Usage Admin ; Project IAM Admin si templates Model Armor ici |
En CI, c'est le compte de service de la CI qui a ces rôles.
3.5 L'app Gemini Enterprise
- Elle existe (projets 06 / 08) : noter son ID (Gemini Enterprise → l'app → Présentation) et sa
localisation (
eu). - Sinon : la créer (tutoriel 02, étape 1), en
eu. Gemini Enterprise demande un compte d'organisation (Workspace / Cloud Identity), pas un Gmail. - Pas encore d'app ? Vous pouvez tout faire sauf la publication : laissez
ge_project_numbervide. Les agents sont déployés, inscrits dans Agent Registry et testés ; on renseignerage_project_number(et, pour publier soi-même,ge_project_id+ge_app_id) puis on relanceraterraform apply.
3.6 Model Armor
| Situation | Que mettre dans terraform.tfvars |
|---|---|
| Templates centraux du projet 08 (cible Acme) | prompt_template et response_template : terraform -chdir=../08-…/terraform output model_armor_templates |
| Pas encore de templates (démo, nouveau projet) | Rien : Terraform crée une paire de templates dans le projet des agents, dans la localisation de l'app (eu) |
4. Tester les agents sur votre poste
Pourquoi d'abord en local : si un agent ne marche pas ici, il ne marchera pas dans Gemini Enterprise. On sépare les problèmes d'agent des problèmes de droits.
cd 09-agents-multi-projets-gemini-enterprise
uv venv -p '>=3.12' .venv && source .venv/bin/activate
uv pip install -r agents/trio/requirements.txt
# 1. Tests hors ligne : outils, Model Armor obligatoire, points d'entrée (aucun appel Google ni Internet)
python scripts/test_trio.py # -> tests trio OK (9 scénarios, 6 agents)
# 2. Les agents en vrai (Gemini via Vertex AI, votre identité, sans clé d'API)
export LOCAL_DEV=1 GOOGLE_CLOUD_PROJECT=acme-agents-demo
adk web --port 8080 agents/trio # Cloud Shell : Aperçu sur le Web > port 8080Dans l'interface, choisir l'agent en haut à gauche :
| Agent | Question | Attendu |
|---|---|---|
meteo_agent | « Je cours à Lille demain matin, quoi porter ? » | Outils meteo puis conseil_equipement ; météo réelle ; 3 couches ou veste imperméable selon la météo |
redaction_agent | « Reformule pour un e-mail client : ton velo est pret passe avant samedi » | charte_redactionnelle, analyser_texte (×2) ; vouvoiement ; ligne « Avant : X mots, après : Y mots » |
redaction_agent | « Reformule ce texte : … » (sans canal) | Il demande le canal |
traduction_agent | « Traduis en espagnol : Votre tente Quechua est disponible en retrait en magasin. » | glossaire, verifier_traduction ; « Quechua » non traduit ; « recogida en tienda » ; « Contrôle : conforme » |
traduction_agent | « Traduis en japonais : bonjour » | Refus poli : langue non prise en charge, liste des langues |
Ctrl+C pour arrêter.
No API key was provided: le modèle part vers l'API Gemini au lieu de Vertex AI. Vérifier quegoogle-adkest bien en 2.10 dans le venv (pip show google-adk).default credentials were not found: refaire l'étape 3.2.
5. Déployer
| Hébergement | Pas à pas |
|---|---|
| Cloud Run + A2A | 01-bis-cloud-run-a2a/README.md |
| Agent Runtime | 02-bis-agent-runtime/README.md |
Les deux suivent le même plan : configurer (terraform.tfvars) → déployer (terraform apply) → tester sans
Gemini Enterprise (./test.sh) → vérifier Agent Registry → publier dans l'app → donner l'accès → tester dans
le chat → nettoyer.
Tout rejouer d'un coup, commande par commande, avec la sortie attendue de chaque commande (projet X, projet A, simulateur, appel agent → agent entre projets) : docs/10.
Connecter à Gemini Enterprise (tous les modes de la fenêtre Ajouter un agent, procédure entre projets, simulateur, fiche de demande) : docs/09.
6. Ce qui est vérifié
Déployé de bout en bout sur un vrai projet Google Cloud (octobre 2026, même projet, sans app Gemini Enterprise :
la publication dans l'app demande un compte d'organisation), puis entièrement supprimé avec terraform destroy.
| Vérifié | Résultat |
|---|---|
Les 6 outils, Model Armor obligatoire, points d'entrée (scripts/test_trio.py) | OK, hors ligne |
adk web agents/trio : 3 agents listés et exécutés, vrai Gemini, vraie météo, refus attendus | OK |
01-bis : terraform apply (28 ressources), URL des services = URL des cartes (postcondition) | OK |
01-bis : ./test.sh sur Cloud Run, A2A v0.3 (message/send, 2e tour dans la même conversation), Model Armor actif | OK, 3 agents |
01-bis : le conteneur en message/stream (streaming, utilisé par Gemini Enterprise) | OK (même image, en local) |
| Model Armor en vrai : une injection (« Ignore toutes tes instructions… ») est bloquée, une demande normale passe | OK |
| Agent Registry : les 3 cartes A2A déclarées (01-bis) et les 3 agents Agent Runtime inscrits automatiquement (02-bis) | OK |
02-bis : terraform apply (26 ressources), ./test.sh sur Agent Runtime, outils appelés dans l'ordre prévu | OK, 3 agents |
terraform destroy des deux piles, y compris des agents qui ont des sessions | OK |
| Agent → agent entre deux projets : l'orchestrateur (A) trouve l'agent stock dans le registre de X et l'appelle ; sans son droit, il est refusé | OK (après correction du format d'URN, voir docs/10 §10) |
Clé d'API pour le modèle (GEMINI_API_KEY) : la clé est bien envoyée à l'API Gemini | OK (fausse clé refusée par Google) ; câblage Secret Manager vérifié par terraform plan |
| Entre deux projets (agents dans le projet B, app dans le projet A) : Terraform de l'équipe sans aucun droit sur A ; droit posé au vrai compte de Gemini Enterprise de A | OK, 01-bis et 02-bis |
Simulateur Gemini Enterprise (docs/09) : refusé sans droit, accepté avec le droit, A2A (en-tête X-Serverless-Authorization) et Agent Runtime | OK ; un service sans droit reste refusé |
Format de la carte A2A, en-tête d'authentification Cloud Run, rôle run.invoker | Conformes à la documentation Gemini Enterprise |
Défauts trouvés par le déploiement réel, et corrigés (ils auraient bloqué n'importe qui suivant le tutoriel) :
| Défaut | Correction |
|---|---|
plan échoue : API Resource Manager désactivée sur un projet neuf | Étape 3.3 de ce document |
| Création des identités : API IAM désactivée | Terraform active iam.googleapis.com (01-bis, 02-bis, terraform/) |
Agent Registry refuse interfaces avec une carte A2A | Bloc retiré : l'URL est dans la carte (01-bis, doc 04) |
Module adk_agent : sortie name = ID seul, au lieu de projects/…/reasoningEngines/ID | Sortie name = chemin complet, engine_id = ID seul |
scripts/query.py et l'orchestrateur : client Agent Platform détruit avant l'appel (AssertionError aiohttp) | Référence au client gardée |
terraform destroy refusé : l'agent a des sessions | deletion_policy = "FORCE" dans le module |
Construction des images (Cloud Build, 01-bis) : …-compute@developer.gserviceaccount.com does not have storage.objects.get access (le compte par défaut de Cloud Build n'a aucun droit) | Compte de construction dédié (agents-a2a-build-sa dans Terraform, agents-build-sa à la main) avec 3 rôles ; plus besoin de Docker sur le poste |
| Reste à constater dans une app Gemini Enterprise Acme | Si ce n'est pas le cas |
|---|---|
Publication par l'API (register_agent.sh) et réponse dans le chat | Ajout par la console (étape 7 de 01-bis, 6 de 02-bis) ; dépannage de chaque README |
| Libellés exacts des menus de la console | Ils changent souvent ; les commandes et Terraform, eux, sont stables |