1. Instaurer la confiance pour encourager la générosité

Le moment d'inspiration
Votre téléphone vibre. Vous voyez un article sur un programme d'alphabétisation réussi qui aide les enfants des communautés défavorisées à apprendre à lire. Vous ressentez une forte envie de contribuer. Vous ouvrez votre navigateur et recherchez dons pour les programmes d'alphabétisation des enfants.

Des centaines de résultats s'affichent.
Vous cliquez sur le premier lien. Le site Web a l'air professionnel. Faites défiler la page jusqu'à leurs informations financières. "Coûts administratifs : 28 %." Vous mettez en pause. Seuls 72 centimes de chaque euro que vous donnez seront réellement utilisés pour financer le programme. Est-ce que ça vous convient ? Vous n'êtes pas sûr.
Vous essayez une autre organisation. Vous n'en avez jamais entendu parler. Sont-elles légitimes ? Une recherche rapide vous entraîne dans un véritable labyrinthe. Vous trouvez un fil de discussion Reddit datant de deux ans dans lequel un utilisateur affirme : "C'est une arnaque, mon don n'est jamais arrivé à destination." Un autre les défend avec passion : "Ils sont sur le terrain et font du vrai travail !" L'ambiguïté est paralysante.
Trente minutes plus tard, vous êtes perdu dans un labyrinthe d'avis contradictoires, de notes d'efficacité et de documents de l'IRS, et vous n'avez toujours pas fait de don. L'étincelle initiale de générosité a été remplacée par la friction de la recherche. L'onglet reste ouvert pendant quelques jours, comme un petit rappel d'une bonne intention, jusqu'à ce que vous le fermiez.
Ce n'est pas un échec personnel, mais un échec du système
Cette expérience est universelle. L'envie de donner est bien présente, mais le processus est semé d'embûches qui suscitent hésitation et doute :
- ❌ Friction de recherche : chaque organisation caritative nécessite une enquête distincte.
- ❌ Validation de la fiabilité : il est difficile de distinguer les organisations très efficaces de celles qui le sont moins, voire des escroqueries.
- ❌ Paralysie décisionnelle : un nombre écrasant de choix entraîne une fatigue décisionnelle.
- ❌ Perte de motivation : l'envie de faire un don s'estompe à mesure que la charge logistique augmente.
Cette friction a un coût réel et stupéfiant. Les dons individuels aux États-Unis sont considérables. Selon Giving USA 2024, les donateurs individuels ont donné environ 374 milliards de dollars rien qu'en 2023. Pourtant, des études montrent que les obstacles aux dons (y compris les coûts de recherche, les frictions psychologiques et les contraintes de temps) réduisent considérablement le montant qui parvient aux organisations caritatives. Des études menées auprès de millions de donateurs ont montré que même de petits points de friction dans le processus de don en ligne empêchent les utilisateurs de concrétiser leurs intentions caritatives.
Cela représente des milliards de dollars de dons prévus qui n'atteignent jamais les causes qui en ont besoin.
La vision
Imaginez une autre expérience. Au lieu d'une session de recherche de 30 minutes, dites simplement :
"Je veux faire un don de 50 € à un programme d'alphabétisation pour les enfants. Trouve-moi une organisation caritative très bien notée, efficace et validée."
En quelques secondes, vous obtenez une réponse qui vous met en confiance :
C'est la promesse d'un agent d'IA pour les dons. Mais pour concrétiser cette vision, nous devons relever un défi fondamental : lorsqu'un agent d'IA autonome gère de l'argent, la confiance n'est pas facultative, elle est la base de tout.
- Comment prouver ce qu'un utilisateur a autorisé ?
- Qui est responsable en cas d'erreur ?
- Comment donner aux donateurs, aux associations caritatives et aux réseaux de paiement la confiance nécessaire pour participer ?
Votre mission aujourd'hui
Dans cet atelier, vous allez créer cet agent fiable en combinant deux technologies puissantes :
Google Agent Development Kit (ADK) | Protocole de paiement des agents (AP2) | |
Rôle | La fabrique pour créer des agents IA de niveau production | Le plan d'architecture pour la confiance dans les transactions d'IA |
Ce que vous obtenez | • Framework pour l'orchestration multi-agents | • Limites de sécurité basées sur les rôles |
En savoir plus |
Ce que vous allez faire
À la fin de cet atelier, vous aurez créé :
✅ Un système multi-agents avec des rôles spécialisés :
- Un agent Shopping qui trouve des associations caritatives validées
- Un agent marchand qui crée des offres de dons contraignantes
- Un fournisseur d'identifiants qui traite les paiements de manière sécurisée
- Un orchestrateur qui coordonne l'ensemble du flux
✅ Trois types d'identifiants vérifiables :
- IntentMandate: "Find me an education charity"
- CartMandate: "$50 to Room to Read, signed by merchant"
- PaymentMandate : "Process via simulated payment" (Traiter via un paiement simulé)
✅ Sécurité à tous les niveaux :
- Limites de confiance basées sur les rôles
- Consentement explicite de l'utilisateur
✅ Piste d'audit complète :
- Chaque décision est traçable
- Chaque consentement enregistré
- Chaque transfert est visible
🔒 Important : Il s'agit d'un environnement d'apprentissage sécurisé
Prêt à gagner la confiance des utilisateurs ?
Dans le prochain module, nous allons configurer votre environnement de développement et créer votre premier agent d'IA. Vous découvrirez rapidement pourquoi les agents simples ne sont pas fiables, puis vous passerez le reste de l'atelier à apprendre à résoudre ce problème.
Commençons par comprendre le problème de première main.
2. Préparer votre espace de travail
La Fondation pour les agents fiables
Avant de pouvoir créer notre agent d'IA pour les dons, nous devons préparer un environnement de développement propre, cohérent et correctement configuré. Ce module est une étape ciblée pour s'assurer que tous les outils et services nécessaires sont en place.
Si vous réussissez cette configuration, vous pourrez vous concentrer entièrement sur la tâche passionnante de création de la logique de l'agent dans les modules à venir, sans vous soucier des problèmes de configuration.
Accéder à Cloud Shell
Nous allons commencer par ouvrir Cloud Shell, un terminal basé sur navigateur avec le SDK Google Cloud et d'autres outils essentiels préinstallés.
Vous avez besoin de crédits Google Cloud ?
Cliquez sur Activer Cloud Shell en haut de la console Google Cloud (il s'agit de l'icône de terminal dans la barre de navigation en haut à droite).

Trouvez votre ID de projet Google Cloud :
- Ouvrez la console Google Cloud : https://console.cloud.google.com.
- Sélectionnez le projet que vous souhaitez utiliser pour cet atelier dans le menu déroulant en haut de la page.
- L'ID de votre projet est affiché dans la fiche "Informations sur le projet" du tableau de bord
.
Une fois Cloud Shell ouvert, vérifiez que vous êtes authentifié :
# Check that you are logged in
gcloud auth list
Votre compte devrait être listé comme (ACTIVE).
Configurer votre projet
Nous allons maintenant configurer votre projet Google Cloud et activer les API nécessaires.
Définir l'ID de votre projet
# Set your project using the auto-detected environment variable in Cloud Shell
gcloud config set project $GOOGLE_CLOUD_PROJECT
# Verify the project has been set
echo "Your active Google Cloud project is: $(gcloud config get-value project)"
Activer les API requises
Vos agents doivent avoir accès à plusieurs services Google Cloud :
gcloud services enable \
aiplatform.googleapis.com \
secretmanager.googleapis.com \
cloudtrace.googleapis.com
L'opération peut prendre 1 à 2 minutes. Cette page vous indique les informations suivantes :
Operation "operations/..." finished successfully.
Voici ce que ces API fournissent :
- aiplatform.googleapis.com : accès aux modèles Gemini pour le raisonnement des agents
- secretmanager.googleapis.com : stockage sécurisé des clés API (bonne pratique de production)
- cloudtrace.googleapis.com : observabilité pour notre journal d'audit
Cloner le code de démarrage
Récupérez le dépôt de l'atelier avec tous les codes et ressources des modèles :
git clone https://github.com/ayoisio/adk-ap2-charity-agents
cd adk-ap2-charity-agents
git checkout codelab
Vérifions ce que nous avons :
ls -la
Vous devriez obtenir le résultat suivant :
charity_advisor/: emplacement où nous allons créer nos agents et nos outilsscripts/: scripts d'aide pour les tests et la validationdeploy.sh: script d'assistance pour le déploiementsetup.py: script d'assistance pour l'installation du module.env.template: fichier de variables d'environnement
Configurer l'environnement Python
Nous allons maintenant créer un environnement Python isolé pour notre projet.
Créer et activer un environnement virtuel
# Create the virtual environment
python3 -m venv venv
# Activate it
source venv/bin/activate
✅ Validation : votre requête doit maintenant afficher le préfixe (venv).
Installer des dépendances
pip install -r charity_advisor/requirements.txt
pip install -e .
Les éléments suivants sont installés :
- google-adk : framework de l'Agent Development Kit
- google-cloud-aiplatform : intégration de Vertex AI et Gemini
- ap2 : SDK du protocole de paiement des agents (depuis GitHub)
- python-dotenv : gestion des variables d'environnement
L'indicateur -e vous permet d'importer des modules adk_ap2_charity_agents depuis n'importe où.
Configurer le fichier d'environnement
Créez votre configuration à partir du modèle :
# Copy the template
cp .env.template .env
# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)
# Replace the placeholder with your actual project ID
sed -i "s/your-project-id/$PROJECT_ID/g" .env
# Verify the replacement worked
grep GOOGLE_CLOUD_PROJECT .env
Vous devriez obtenir le résultat suivant :
GOOGLE_CLOUD_PROJECT=your-actual-project-id
Validation
Exécutez le script de validation pour vous assurer que tout est correctement configuré :
python scripts/verify_setup.py
Toutes les coches vertes devraient s'afficher :
======================================================================
SETUP VERIFICATION
======================================================================
✓ Python version: 3.11.x
✓ google-adk: 1.17.0
✓ google-cloud-aiplatform: 1.111.0+
✓ ap2: 0.1.0
✓ python-dotenv: 1.0.0+
✓ .env file found and contains project ID
✓ Google Cloud project configured: your-project-id
✓ Mock charity database found
✓ Agent templates ready
✓ All directories present
======================================================================
✓ Setup complete! You are ready to build trustworthy agents.
======================================================================
Dépannage
Et maintenant ?
Votre environnement est désormais entièrement préparé. Vous devez avoir :
- ✅ Projet Google Cloud configuré
- ✅ API requises activées
- ✅ Bibliothèques ADK et AP2 installées
- ✅ Code du modèle prêt à être modifié
Dans le prochain module, vous allez créer votre premier agent d'IA en quelques lignes de code et découvrir pourquoi les agents simples ne sont pas fiables pour gérer les transactions financières.
3. Votre premier agent et la découverte du manque de confiance

De l'idée à l'interaction
Dans le module précédent, nous avons préparé notre environnement de développement. C'est maintenant que les choses sérieuses commencent. Nous allons créer et exécuter notre premier agent, lui donner sa première capacité et, ce faisant, découvrir les défis fondamentaux que nous devons relever pour le rendre vraiment fiable.
Ce module est votre "avant" : le moment qui révèle pourquoi la création d'agents fiables nécessite plus que de simplement donner à un LLM l'accès à des outils.
Étape 1 : Examiner l'agent de démarrage
Commençons par examiner le modèle de notre premier agent. Il contient une structure de base avec des espaces réservés que nous allons compléter dans les étapes suivantes.
👉 Ouvrez le fichier.
charity_advisor/simple_agent/agent.py
dans votre éditeur.
Cette page vous indique les informations suivantes :
"""
A simple agent that can research charities using Google Search.
"""
# MODULE_3_STEP_2_IMPORT_COMPONENTS
simple_agent = Agent(
name="SimpleAgent",
model="gemini-2.5-flash",
# MODULE_3_STEP_3_WRITE_INSTRUCTION
instruction="""""",
# MODULE_3_STEP_4_ADD_TOOLS
tools=[]
)
Notez que les commentaires d'espace réservé suivent un schéma : MODULE_3_STEP_X_DESCRIPTION. Nous remplacerons ces repères afin de créer progressivement notre agent.
Étape 2 : Importer les composants requis
Avant de pouvoir instancier la classe Agent ou utiliser l'outil google_search, nous devons les importer dans notre fichier.
👉 Trouver :
# MODULE_3_STEP_2_IMPORT_COMPONENTS
👉 Remplacez cette ligne par :
from google.adk.agents import Agent
from google.adk.tools import google_search
La classe Agent et l'outil google_search sont désormais disponibles dans notre fichier.
Étape 3 : Rédigez l'instruction de l'agent
L'instruction est la "description du poste" de l'agent. Elle indique au LLM quand et comment utiliser ses outils. Écrivons-en une qui guide notre agent pour rechercher des informations sur des organisations caritatives.
👉 Trouver :
# MODULE_3_STEP_3_WRITE_INSTRUCTION
instruction="""""",
👉 Remplacez ces deux lignes par :
instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",
Étape 4 : Ajoutez l'outil de recherche
Un agent sans outils n'est qu'un simple interlocuteur. Donnons à notre agent sa première capacité : la possibilité d'effectuer des recherches sur le Web.
👉 Trouver :
# MODULE_3_STEP_4_ADD_TOOLS
tools=[]
👉 Remplacez ces deux lignes par :
tools=[google_search]
Étape 5 : Valider votre agent complet
Avant de tester, vérifions que tous les éléments sont en place.
👉 Votre
charity_advisor/simple_agent/agent.py
Votre fichier devrait maintenant se présenter exactement comme suit :
"""
A simple agent that can research charities using Google Search.
"""
from google.adk.agents import Agent
from google.adk.tools import google_search
simple_agent = Agent(
name="SimpleAgent",
model="gemini-2.5-flash",
instruction="""You are a helpful research assistant. When a user asks you to find information about charities,
use the google_search tool to find the most relevant and up-to-date results from the web.
Synthesize the search results into a helpful summary.""",
tools=[google_search]
)
Étape 6 : Tester l'agent et identifier les lacunes en termes de confiance
Maintenant que notre agent est entièrement configuré, testons-le et analysons son comportement. Nous allons découvrir pourquoi les agents simples ne sont pas fiables pour prendre des décisions financières.
Test 1 : Le problème de la découverte
👉 Dans votre terminal Cloud Shell, exécutez la commande suivante :
adk run charity_advisor/simple_agent
Le résultat doit ressembler à ceci :
INFO:google.adk.agents:Loading agent from charity_advisor/simple_agent
INFO:google.adk.agents:Agent 'SimpleAgent' ready
[user]:
L'invite [user]: attend désormais votre saisie.
👉 À l'invite [user], saisissez :
Can you find me a verified, highly-rated charity for children's literacy?
👉 Appuyez sur Entrée et observez la réponse.
Au bout d'un moment, l'agent synthétise les résultats de recherche dans une réponse comme celle-ci :
D'après une recherche sur le Web, Reading Is Fundamental et Room to Read semblent être des organisations caritatives réputées pour l'alphabétisation des enfants. Il est souvent recommandé de vérifier leur statut et leurs notes sur des sites comme Charity Navigator et GuideStar. J'ai également trouvé plusieurs discussions en ligne, y compris sur des forums comme Reddit, où les utilisateurs partagent leurs expériences personnelles avec divers programmes d'alphabétisation locaux plus petits.
Analysons cela. L'agent a-t-il résolu notre problème ?
❌ Non.Il a parfaitement reproduit l'expérience humaine que nous avons décrite dans le module 1. Il a réussi à automatiser le processus de recherche sur Google et nous a renvoyé le problème de "paralysie décisionnelle".
Cela révèle le premier manque de confiance : l'absence de données faisant autorité.
L'agent effectue une recherche sur le Web ouvert, ce qui signifie :
- ✅ Il a trouvé des résultats rapidement (expérience utilisateur améliorée).
- ❌ Il mélange des organisations très bien notées avec des discussions Reddit (sources non fiables).
- ❌ Il ne peut pas faire la distinction entre les organisations caritatives approuvées et les escroqueries potentielles (aucune vérification).
- ❌ Elle nous demande à nous de valider les informations qu'elle vient de fournir (en nous transférant la responsabilité).
Test 2 : Le problème d'exécution
Passons maintenant au deuxième test crucial. À l'invite [user]:, essayez de finaliser le don :
Okay, please donate $50 to Room to Read for me.
L'agent répond en s'excusant et en reconnaissant sa limite :
Vous souhaitez faire un don, ce qui est formidable ! Toutefois, je suis un assistant de recherche et je ne suis pas en mesure de gérer les transactions financières ni de traiter les paiements. Pour faire un don, vous devez accéder directement au site Web officiel de Room to Read.
Il s'agit du deuxième moment "Aha !", tout aussi important.
Non seulement l'agent n'est pas fiable pour trouver la bonne organisation caritative, mais il n'est pas encore fiable pour effectuer l'action de don.
👉 Appuyez sur
Ctrl+C
pour quitter une fois les tests terminés.
Visualisation des deux écarts
Ce que vous venez d'apprendre
Dans ce module, vous avez réussi à créer et à équiper votre premier agent d'IA. Ce faisant, vous avez découvert les deux défis fondamentaux liés à la création d'un système fiable.
Concepts clés maîtrisés
✅ La classe Agent :
- Composant de base d'ADK
- Combine le raisonnement du LLM (cerveau) avec des outils (mains)
- Configuré avec le modèle, l'instruction et les outils
✅ Structure basée sur les dossiers :
- Chaque agent se trouve dans son propre dossier.
- ADK recherche
agent_folder/agent.py - Courir avec
adk run agent_folder
✅ Liste des outils :
- Définit les capacités de l'agent
- Le LLM décide quand et comment utiliser les outils
- Peut contenir plusieurs outils pour différentes actions
✅ Requête d'instruction :
- Guider le comportement de l'agent comme une description de poste
- Spécifie le rôle, les déclencheurs, les actions et le format de sortie
- Essentiel pour une utilisation fiable des outils
✅ Le problème de confiance :
- Lacune de découverte : sources non vérifiées, qualité variable
- Écart d'exécution : aucune fonctionnalité sécurisée, aucun consentement, aucune piste d'audit
Étape suivante
Dans le prochain module, nous commencerons à créer la solution en implémentant l'architecture basée sur les rôles d'AP2.
Créons le premier agent et observons la séparation des rôles en action.
4. Créer l'agent Shopping : découverte basée sur les rôles

Base de confiance : séparation des rôles
Dans le dernier module, vous avez découvert qu'un agent simple et polyvalent échoue sur deux fronts : il ne peut pas fournir de découvertes fiables et il ne peut pas exécuter de transactions sécurisées. Nous allons maintenant commencer à résoudre ces problèmes en implémentant le premier principe du protocole Agent Payments Protocol : l'architecture basée sur les rôles.
Avant d'écrire du code, comprenons pourquoi ce principe est important.
Principe AP2 : Séparation des rôles
Problèmes liés aux agents "tout faire"
Imaginez que vous embauchiez une personne pour qu'elle soit à la fois votre conseiller financier, votre comptable et votre courtier en investissement. Pratique ? Oui. Sécurisé ? Jamais de la vie. Voici ce qu'il aurait :
- Vos objectifs d'investissement (rôle de conseiller)
- Accès à vos comptes (rôle de comptable)
- Autorisation de transférer votre argent (rôle d'intermédiaire)
Si cette personne est piratée ou commet une erreur, tout est menacé.
Solution d'AP2 : un agent, un job
AP2 applique le principe de séparation des préoccupations pour créer des limites de confiance :
Pourquoi est-ce important ?
- ✅ Rayon d'explosion limité : si l'agent Shopping est piraté, le pirate informatique ne peut pas accéder aux informations de paiement.
- ✅ Confidentialité : le fournisseur d'identifiants ne voit jamais votre conversation d'achat.
- ✅ Conformité : il est plus facile de répondre aux exigences de la norme PCI-DSS lorsque les données de paiement sont isolées.
- ✅ Responsabilité : la responsabilité de chaque étape est clairement définie.
Comment les agents communiquent : l'état comme bloc-notes partagé
Étant donné que les agents ne peuvent pas accéder directement aux données des autres, ils communiquent par le biais d'un état partagé. Considérez-le comme un tableau blanc sur lequel tous les agents peuvent écrire et lire :
# Shopping Agent writes:
state["intent_mandate"] = {
"natural_language_description": "Donate $50 to Room to Read",
"merchants": ["Room to Read"],
"intent_expiry": "2024-11-07T15:32:16Z",
"amount": 50.0
}
# Merchant Agent reads:
intent = state["intent_mandate"]
charity_name = intent["merchants"][0]
amount = intent["amount"]
# Creates CartMandate based on IntentMandate...
# Credentials Provider reads:
cart_mandate = state["cart_mandate"]
# Processes payment...
C'est ainsi que nous maintenons les limites de confiance tout en permettant la collaboration.
Notre premier agent : l'agent Shopping
La responsabilité de l'agent Shopping est simple et ciblée :
- Utiliser l'outil
find_charitiespour interroger notre base de données fiable - Présenter des options à l'utilisateur
- Utilisez l'outil
save_user_choicepour créer un IntentMandate et l'enregistrer dans l'état. - Transférer la conversation à l'agent suivant (le marchand)
Et voilà ! Aucune gestion des paiements ni création de panier : uniquement la découverte et le transfert.
Construisons-le étape par étape.
Étape 1 : Ajoutez Input Validation Helper
La validation des entrées est essentielle lors de la création d'outils de production. Créons une fonction d'assistance qui valide les données caritatives avant de les enregistrer dans l'état.
👉 Ouvrir
charity_advisor/tools/charity_tools.py
La fonction find_charities (déjà complète) s'affiche en haut de la page. Faites défiler l'écran vers le bas pour trouver les éléments suivants :
# MODULE_4_STEP_1_ADD_VALIDATION_HELPER
👉 Remplacez cette ligne par :
def _validate_charity_data(charity_name: str, charity_ein: str, amount: float) -> tuple[bool, str]:
"""
Validates charity selection data before saving to state.
This helper function performs basic validation to ensure data quality
before it gets passed to other agents in the pipeline.
Args:
charity_name: Name of the selected charity
charity_ein: Employer Identification Number (should be format: XX-XXXXXXX)
amount: Donation amount in USD
Returns:
(is_valid, error_message): Tuple where is_valid is True if all checks pass,
and error_message contains details if validation fails
"""
# Validate charity name
if not charity_name or not charity_name.strip():
return False, "Charity name cannot be empty"
# Validate EIN format (should be XX-XXXXXXX)
if not charity_ein or len(charity_ein) != 10 or charity_ein[2] != '-':
return False, f"Invalid EIN format: {charity_ein}. Expected format: XX-XXXXXXX"
# Validate amount
if amount <= 0:
return False, f"Donation amount must be positive, got: ${amount}"
if amount > 1_000_000:
return False, f"Donation amount exceeds maximum of $1,000,000: ${amount}"
# All checks passed
return True, ""
Étape 2 : Ajouter l'assistant de création IntentMandate
Créons maintenant le helper qui crée la structure AP2 IntentMandate. Il s'agit de l'un des trois identifiants vérifiables dans AP2.
👉 Dans le même fichier, recherchez :
# MODULE_4_STEP_2_ADD_INTENTMANDATE_CREATION_HELPER
👉 Remplacez cette ligne par :
def _create_intent_mandate(charity_name: str, charity_ein: str, amount: float) -> dict:
"""
Creates an IntentMandate - AP2's verifiable credential for user intent.
This function uses the official Pydantic model from the `ap2` package
to create a validated IntentMandate object before converting it to a dictionary.
Args:
charity_name: Name of the selected charity
charity_ein: Employer Identification Number
amount: Donation amount in USD
Returns:
Dictionary containing the IntentMandate structure per AP2 specification
"""
from datetime import datetime, timedelta, timezone
from ap2.types.mandate import IntentMandate
# Set the expiry for the intent
expiry = datetime.now(timezone.utc) + timedelta(hours=1)
# Step 1: Instantiate the Pydantic model with official AP2 fields
intent_mandate_model = IntentMandate(
user_cart_confirmation_required=True,
natural_language_description=f"Donate ${amount:.2f} to {charity_name}",
merchants=[charity_name],
skus=None,
requires_refundability=False,
intent_expiry=expiry.isoformat()
)
# Step 2: Convert the validated model to a dictionary for state storage
intent_mandate_dict = intent_mandate_model.model_dump()
# Step 3: Add the codelab's custom fields to the dictionary
timestamp = datetime.now(timezone.utc)
intent_mandate_dict.update({
"timestamp": timestamp.isoformat(),
"intent_id": f"intent_{charity_ein.replace('-', '')}_{int(timestamp.timestamp())}",
"charity_ein": charity_ein,
"amount": amount,
"currency": "USD"
})
return intent_mandate_dict
Étape 3 : Créez l'outil de transfert d'état avec IntentMandate
Nous allons maintenant créer l'outil qui crée l'IntentMandate et l'enregistre dans l'état.
👉 Dans le même fichier, faites défiler la page jusqu'à
save_user_choice
. Rechercher :
# MODULE_4_STEP_3_COMPLETE_SAVE_TOOL
👉 Remplacez cette ligne par :
# Validate inputs before creating IntentMandate
is_valid, error_message = _validate_charity_data(charity_name, charity_ein, amount)
if not is_valid:
logger.error(f"Validation failed: {error_message}")
return {"status": "error", "message": error_message}
# Create AP2 IntentMandate using our updated helper function
intent_mandate = _create_intent_mandate(charity_name, charity_ein, amount)
# Write the IntentMandate to shared state for the next agent
tool_context.state["intent_mandate"] = intent_mandate
logger.info(f"Successfully created IntentMandate and saved to state")
logger.info(f"Intent ID: {intent_mandate['intent_id']}")
logger.info(f"Intent expires: {intent_mandate['intent_expiry']}")
# Return success confirmation
return {
"status": "success",
"message": f"Created IntentMandate: ${amount:.2f} donation to {charity_name} (EIN: {charity_ein})",
"intent_id": intent_mandate["intent_id"],
"expiry": intent_mandate["intent_expiry"]
}
Étape 4 : Ajoutez l'assistant de mise en forme de l'affichage
Avant de créer l'agent, ajoutons un autre assistant qui met en forme les données caritatives pour les afficher de manière conviviale.
👉 Faites défiler l'écran pour trouver :
# MODULE_4_STEP_4_ADD_FORMATTING_HELPER
👉 Remplacez cette ligne par :
def _format_charity_display(charity: dict) -> str:
"""
Formats a charity dictionary into a user-friendly display string.
This helper function demonstrates how to transform structured data
into readable text for the user.
Args:
charity: Dictionary containing charity data (name, ein, mission, rating, efficiency)
Returns:
Formatted string suitable for display to the user
"""
name = charity.get('name', 'Unknown')
ein = charity.get('ein', 'N/A')
mission = charity.get('mission', 'No mission statement available')
rating = charity.get('rating', 0.0)
efficiency = charity.get('efficiency', 0.0)
# Format efficiency as percentage
efficiency_pct = int(efficiency * 100)
# Build formatted string
display = f"""
**{name}** (EIN: {ein})
⭐ Rating: {rating}/5.0
💰 Efficiency: {efficiency_pct}% of funds go to programs
📋 Mission: {mission}
""".strip()
return display
Étape 5 : Créer l'agent Shopping – Importer des composants
Maintenant que nos outils sont complets et robustes, créons l'agent qui les utilisera.
👉 Ouvrir
charity_advisor/shopping_agent/agent.py
Un modèle avec des commentaires de substitution s'affiche. Construisons-le étape par étape.
👉 Trouver :
# MODULE_4_STEP_5_IMPORT_COMPONENTS
👉 Remplacez cette ligne par :
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice
Étape 6 : Rédigez l'instruction de l'agent
L'instruction est l'endroit où nous définissons la description du poste et le workflow de l'agent. C'est un point essentiel : une instruction mal rédigée entraîne un comportement peu fiable.
👉 Trouver :
# MODULE_4_STEP_6_WRITE_INSTRUCTION
instruction="""""",
👉 Remplacez ces deux lignes par :
instruction="""You are a research specialist helping users find verified charities.
Your workflow:
1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
use the find_charities tool to search our vetted database.
2. Present the results clearly. The tool returns formatted charity information that you should
show to the user.
3. When the user selects a charity and specifies an amount, use the save_user_choice tool
to create an IntentMandate and record their decision. You MUST call save_user_choice with:
- charity_name: The exact name of the chosen charity
- charity_ein: The EIN of the chosen charity
- amount: The donation amount in dollars (as a number, not a string)
4. After successfully saving, inform the user:
- That you've created an IntentMandate (mention the intent ID if provided)
- When the intent expires
- That you're passing their request to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done
WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required
This is the first of three verifiable credentials in our secure payment system.
If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",
Étape 7 : Ajouter des outils à l'agent
Donnons maintenant à l'agent l'accès aux deux outils.
👉 Trouver :
# MODULE_4_STEP_7_ADD_TOOLS
👉 Remplacez ces deux lignes par :
tools=[
FunctionTool(func=find_charities),
FunctionTool(func=save_user_choice)
]
Étape 8 : Validez votre agent complet
Vérifions que tout est correctement branché.
👉 Votre
charity_advisor/shopping_agent/agent.py
devrait désormais se présenter comme ceci :
"""
Shopping Agent - Finds charities from a trusted database and saves the user's choice.
This agent acts as our specialized "Research Analyst."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.charity_tools import find_charities, save_user_choice
shopping_agent = Agent(
name="ShoppingAgent",
model="gemini-2.5-pro",
description="Finds and recommends vetted charities from a trusted database, then creates an IntentMandate capturing the user's donation intent.",
instruction="""You are a research specialist helping users find verified charities.
Your workflow:
1. When the user describes what cause they want to support (e.g., "education", "health", "environment"),
use the find_charities tool to search our vetted database.
2. Present the results clearly. The tool returns formatted charity information that you should
show to the user.
3. When the user selects a charity and specifies an amount, use the save_user_choice tool
to create an IntentMandate and record their decision. You MUST call save_user_choice with:
- charity_name: The exact name of the chosen charity
- charity_ein: The EIN of the chosen charity
- amount: The donation amount in dollars (as a number, not a string)
4. After successfully saving, inform the user:
- That you've created an IntentMandate (mention the intent ID if provided)
- When the intent expires
- That you're passing their request to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is discovery and creating the IntentMandate
- You do NOT process payments
- You do NOT see the user's payment methods
- You do NOT create cart offers (that's the Merchant Agent's job)
- After calling save_user_choice, your work is done
WHAT IS AN INTENTMANDATE:
An IntentMandate is a structured record of what the user wants to do. It includes:
- Natural language description ("Donate $50 to Room to Read")
- Which merchants can fulfill it
- When the intent expires
- Whether user confirmation is required
This is the first of three verifiable credentials in our secure payment system.
If the user asks you to do anything related to payment processing, politely explain that
you don't have that capability and that their request will be handled by the appropriate
specialist agent.""",
tools=[
FunctionTool(func=find_charities),
FunctionTool(func=save_user_choice)
]
)
✅ Parfait ! Vous avez créé un agent conforme à AP2 et de qualité pour la production, avec les éléments suivants :
- Validation des entrées
- Création appropriée d'IntentMandate à l'aide des modèles Pydantic AP2
- Sortie formatée
- Des limites de rôle claires
- Instructions détaillées
- Gestion des exceptions
Étape 9 : Testez l'agent Shopping
Vérifions que notre agent fonctionne correctement, crée les IntentMandates appropriés et respecte ses limites.
👉 Dans votre terminal Cloud Shell, exécutez la commande suivante :
adk run charity_advisor/shopping_agent
L'invite [user]: s'affiche.
Test 1 : Découverte avec la base de données fiable
👉 Type :
I want to donate to an education charity. What are my options?
Après un instant, l'agent vous répondra. Grâce à notre assistant _format_charity_display, les résultats sont magnifiquement mis en forme :
J'ai trouvé trois organisations caritatives éducatives validées dans notre base de données :
Room to Read (EIN : 77-0479905)
⭐ Note : 4,9/5,0
💰 Efficacité : 88 % des fonds sont alloués aux programmes
📋 Mission : transformer la vie de millions d'enfants dans les communautés à faible revenu en se concentrant sur l'alphabétisation et l'égalité des genres dans l'éducation.
Teach For America (EIN : 13-3541913)
⭐ Note : 4,7/5,0
💰 Efficacité : 81 % des fonds sont consacrés aux programmes
📋 Mission : œuvre pour élargir les opportunités éducatives des enfants en difficulté.
Tech Education Alliance (EIN : 45-2345678)
⭐ Note : 4,8/5,0
💰 Efficacité : 92 % des fonds sont alloués aux programmes
📋 Mission : proposer des cours d'informatique dans les établissements scolaires défavorisés.
Quelle association caritative souhaitez-vous soutenir et quel montant souhaitez-vous donner ?
Comparez-le à l'agent simple du module 3, qui vous a fourni des résultats Google non vérifiés. C'est la différence entre la découverte non approuvée et la découverte approuvée.
Test 2 : Enregistrer le choix de l'utilisateur et créer un IntentMandate
👉 Type :
I'll donate $50 to Room to Read.
Vous devriez voir l'agent appeler l'outil save_user_choice avec les paramètres corrects. Grâce à la création de IntentMandate à l'aide des modèles AP2, vous obtiendrez une réponse plus structurée :
Parfait ! J'ai créé un IntentMandate pour votre don :
Détails de l'intention :
- ID de l'intention : intent_774795905_1730927536
- Montant : 50 $ à Room to Read (EIN : 77-0479905)
- Expire le 2024-11-07T15:32:16Z (dans 1 heure)
IntentMandate capture votre intention de faire un don et inclut des contraintes pour garantir le traitement sécurisé de la transaction. Je vais maintenant transmettre votre demande à notre processeur de paiement sécurisé pour qu'il crée une offre formelle et finalise votre don.
En coulisses, plusieurs choses viennent de se passer :
_validate_charity_data()a validé les entrées_create_intent_mandate()a utilisé le modèle Pydantic AP2 pour créer la structure :
# Created and validated via Pydantic
intent_mandate_model = IntentMandate(
user_cart_confirmation_required=True,
natural_language_description="Donate $50.00 to Room to Read",
merchants=["Room to Read"],
skus=None,
requires_refundability=False,
intent_expiry="2024-11-07T15:32:16Z"
)
# Converted to dict and extended with custom fields
intent_mandate_dict = intent_mandate_model.model_dump()
intent_mandate_dict.update({
"charity_ein": "77-0479905",
"amount": 50.0,
"currency": "USD"
})
- L'outil a ÉCRIT UNIQUEMENT IntentMandate dans l'état partagé :
state["intent_mandate"] = intent_mandate_dict
- Un message de réussite contenant des informations sur l'intention a été renvoyé au LLM.
- Le LLM a composé le message final de l'utilisateur.
Cette IntentMandate est maintenant prête à être récupérée par l'agent marchand (module 5). Le marchand extrait le nom et le montant de l'association caritative de l'IntentMandate et vérifie qu'il n'a pas expiré.
Test 3 : Validation en action
Vérifions que notre assistant de validation détecte les entrées incorrectes.
👉 Type :
I'll donate -$25 to Room to Read.
L'agent doit détecter le montant non valide :
J'ai rencontré un problème : le montant du don doit être positif, mais il est de -25 $.
Veuillez indiquer un montant de don positif. Je créerai l'IntentMandate pour vous.
C'est de la programmation défensive en action. Notre helper _validate_charity_data a empêché des données non valides d'entrer dans le système et de créer un IntentMandate mal formé.
Test 4 : Vérifier la limite de confiance
👉 Demandez à l'agent de traiter le paiement :
Now process my credit card payment.
L'agent doit refuser, en respectant les limites de son rôle :
Je ne suis pas en mesure de traiter les paiements, car cela ne fait pas partie de mon rôle. Mon rôle est de vous aider à trouver des organisations caritatives validées et à créer l'IntentMandate qui capture votre intention de faire un don.
Votre IntentMandate a déjà été créé et transmis à notre processeur de paiement sécurisé. L'agent marchand créera une offre formelle (CartMandate), puis le fournisseur d'identifiants gérera le paiement proprement dit avec votre consentement explicite.
C'est la limite de confiance en action. L'agent sait qu'il n'est pas autorisé à traiter les données de paiement. Ses instructions lui demandent explicitement d'expliquer cela aux utilisateurs tout en leur présentant le concept d'IntentMandate.
👉 Appuyez sur
Ctrl+C
pour quitter une fois les tests terminés.
Ce que vous venez de créer
Vous avez implémenté avec succès la première partie de l'architecture AP2 avec la création appropriée d'IntentMandate à l'aide des modèles Pydantic AP2.
Concepts clés maîtrisés
✅ Architecture basée sur les rôles :
- Chaque agent a une tâche clairement définie.
- Les agents communiquent via un état partagé, et non par accès direct
- Les limites de confiance limitent l'impact d'une compromission
✅ IntentMandate (identifiant AP2 n° 1) :
- Créé à l'aide de modèles Pydantic AP2 officiels pour la validation
- Capture structurée de l'intention de l'utilisateur
- Inclut une date d'expiration pour la sécurité (empêche les attaques par relecture)
- Spécifie les contraintes (marchands, remboursement, confirmation)
- Description en langage naturel pour les humains
- Lisible par les agents
- Modèle validé avant la conversion en dictionnaire
✅ État en tant que mémoire partagée :
tool_context.stateest le "bloc-notes" auquel tous les agents peuvent accéder.- Écrire dans l'état = rendre les identifiants vérifiables disponibles
- Lecture à partir de l'état : utilisation et validation des identifiants
- Les agents en aval extraient ce dont ils ont besoin des identifiants.
✅ FunctionTool :
- Convertit les fonctions Python en outils appelables par LLM
- S'appuie sur les docstrings et les indications de type pour la compréhension des LLM
- Gère automatiquement l'invocation
- Composabilité des outils : petits outils ciblés > outils monolithiques
✅ Instructions destinées aux agents :
- Conseils de workflow étape par étape
- Limites explicites ("NE PAS…")
- Spécifications des paramètres pour éviter les erreurs
- Définitions techniques (qu'est-ce qu'IntentMandate)
- Gestion des cas particuliers (que dire quand…)
Étape suivante
Dans le prochain module, nous allons créer l'agent marchand pour recevoir IntentMandate et créer la deuxième attestation vérifiable : CartMandate.
L'agent d'achat a créé un IntentMandate qui capture l'intention de l'utilisateur avec une date d'expiration. Nous avons maintenant besoin d'un agent pour lire cet identifiant, vérifier qu'il n'a pas expiré et créer une offre formelle et signée indiquant : "Moi, le marchand, m'engage à respecter ce prix et à livrer ces biens."
Créons l'agent marchand et voyons la deuxième identifiants AP2 en action.
5. Créer l'agent marchand : offres contraignantes et CartMandate

De la découverte à l'engagement
Dans le module précédent, vous avez créé l'agent d'achat, un spécialiste qui trouve des organisations caritatives validées et crée un IntentMandate pour capturer l'intention de l'utilisateur. Nous avons maintenant besoin d'un agent pour recevoir cette IntentMandate et créer une offre formelle et contraignante.
C'est là qu'intervient le deuxième principe clé d'AP2 : les identifiants vérifiables via CartMandate.
Principe AP2 : CartMandate et offres contraignantes
Pourquoi avons-nous besoin d'un rôle de marchand ?
Dans le module 4, l'agent Shopping a créé un IntentMandate et l'a enregistré dans l'état :
state["intent_mandate"] = {
"natural_language_description": "Donate $50 to Room to Read",
"merchants": ["Room to Read"],
"amount": 50.0,
"intent_expiry": "2024-11-07T15:32:16Z"
}
Mais il ne s'agit que de l'intention de l'utilisateur. Avant de pouvoir traiter un paiement, nous avons besoin des informations suivantes :
- Une structure d'offre formelle que les systèmes de paiement comprennent
- Preuve que le marchand respectera ce prix
- Un engagement contraignant qui ne peut pas être modifié en cours de transaction
- Validation que l'intention n'a pas expiré
C'est le rôle de l'agent marchand.
Qu'est-ce qu'un CartMandate ?
Un CartMandate est le terme utilisé par AP2 pour désigner un "panier d'achat numérique" qui sert d'offre contraignante. Il est structuré selon la norme W3C PaymentRequest, ce qui signifie :
- Les sociétés de traitement des paiements du monde entier reconnaissent ce format.
- Il contient tous les détails des transactions de manière standardisée.
- Il peut être signé de manière cryptographique pour prouver son authenticité.
Pensez-y comme à un devis écrit d'un entrepreneur :
- ❌ Exemple verbal : "Oui, je peux faire ce travail pour environ 50 $"
- ✅ Devis écrit : coûts détaillés, total, signature, date
Le devis écrit est contraignant. Le CartMandate est l'équivalent numérique.
Structure d'un CartMandate
Dans AP2, un CartMandate présente une structure imbriquée spécifique :
cart_mandate = {
"contents": { # ← AP2 wrapper
"id": "cart_xyz123",
"cart_expiry": "2024-11-07T15:47:16Z",
"merchant_name": "Room to Read",
"user_cart_confirmation_required": False,
"payment_request": { # ← W3C PaymentRequest nested inside
"method_data": [...],
"details": {...},
"options": {...}
}
},
"merchant_authorization": "SIG_a3f7b2c8" # ← Merchant signature
}
Trois composants principaux :
1. contents : wrapper du panier contenant :
- ID et expiration du panier
- Nom du marchand
- W3C PaymentRequest
2. payment_request (contenu) : ce qui est acheté
- method_data: types de paiement acceptés
- Détails : articles et total
- Options : exigences concernant la livraison et les informations sur le payeur
3. merchant_authorization : signature cryptographique
Signatures des marchands : preuve d'engagement
La signature du marchand est essentielle. Il prouve :
- Cette offre provient d'un marchand agréé
- Le marchand s'engage à respecter ce prix exact.
- L'offre n'a pas été modifiée depuis sa création.
En production, il s'agirait d'une signature cryptographique utilisant PKI (Public Key Infrastructure) ou JWT (JSON Web Tokens). Pour notre atelier pédagogique, nous allons simuler cela avec un hachage SHA-256.
# Production (real signature):
signature = sign_with_private_key(cart_data, merchant_private_key)
# Workshop (simulated signature):
cart_hash = hashlib.sha256(cart_json.encode()).hexdigest()
signature = f"SIG_{cart_hash[:16]}"
Notre mission : créer l'agent marchand
L'Agent du marchand :
- Lire l'IntentMandate à partir de l'état (ce qu'a écrit l'agent Shopping)
- Valider que l'intention n'a pas expiré
- Extraire le nom de l'association caritative, le montant et d'autres informations
- Créer une structure PaymentRequest conforme à la norme W3C à l'aide des modèles Pydantic AP2
- Encapsulez-le dans CartMandate d'AP2 avec une date d'expiration.
- Ajouter une signature de marchand simulée
- Écrire le CartMandate à indiquer pour le fournisseur d'informations d'identification (module suivant)
Construisons-le étape par étape.
Étape 1 : Ajoutez le helper de validation de l'expiration
Commençons par configurer le fichier d'outils liés au marchand et ajoutons un assistant pour valider l'expiration d'IntentMandate.
👉 Ouvrir
charity_advisor/tools/merchant_tools.py
Ajoutons la validation de l'expiration :
👉 Trouver :
# MODULE_5_STEP_1_ADD_EXPIRY_VALIDATION_HELPER
👉 Remplacez cette ligne par :
def _validate_intent_expiry(intent_expiry_str: str) -> tuple[bool, str]:
"""
Validates that the IntentMandate hasn't expired.
This is a critical security check - expired intents should not be processed.
Args:
intent_expiry_str: The ISO 8601 timestamp string from the IntentMandate.
Returns:
(is_valid, error_message): Tuple indicating if intent is still valid.
"""
try:
# The .replace('Z', '+00:00') is for compatibility with older Python versions
expiry_time = datetime.fromisoformat(intent_expiry_str.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
if expiry_time < now:
return False, f"IntentMandate expired at {intent_expiry_str}"
time_remaining = expiry_time - now
logger.info(f"IntentMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
return True, ""
except (ValueError, TypeError) as e:
return False, f"Invalid intent_expiry format: {e}"
Étape 2 : Ajoutez l'assistant de génération de signature
Créons maintenant un helper qui génère la signature du marchand simulé.
👉 Trouver :
# MODULE_5_STEP_2_ADD_SIGNATURE_HELPER
👉 Remplacez cette ligne par :
def _generate_merchant_signature(cart_contents: CartContents) -> str:
"""
Generates a simulated merchant signature for the CartMandate contents.
In production, this would use PKI or JWT with the merchant's private key.
For this codelab, we use a SHA-256 hash of the sorted JSON representation.
Args:
cart_contents: The Pydantic model of the cart contents to sign.
Returns:
Simulated signature string (format: "SIG_" + first 16 chars of hash).
"""
# Step 1: Dump the Pydantic model to a dictionary. The `mode='json'` argument
# ensures that complex types like datetimes are serialized correctly.
cart_contents_dict = cart_contents.model_dump(mode='json')
# Step 2: Use the standard json library to create a stable, sorted JSON string.
# separators=(',', ':') removes whitespace for a compact and canonical representation.
cart_json = json.dumps(cart_contents_dict, sort_keys=True, separators=(',', ':'))
# Step 3: Generate SHA-256 hash.
cart_hash = hashlib.sha256(cart_json.encode('utf-8')).hexdigest()
# Step 4: Create signature in a recognizable format.
signature = f"SIG_{cart_hash[:16]}"
logger.info(f"Generated merchant signature: {signature}")
return signature
Étape 3A : Créez la signature et la configuration de l'outil
Commençons maintenant à créer l'outil principal. Nous allons le créer progressivement en quatre sous-étapes. Tout d'abord, la signature de la fonction et la configuration initiale.
👉 Trouver :
# MODULE_5_STEP_3A_CREATE_TOOL_SIGNATURE
👉 Remplacez cette ligne par :
async def create_cart_mandate(tool_context: Any) -> Dict[str, Any]:
"""
Creates a W3C PaymentRequest-compliant CartMandate from the IntentMandate.
This tool reads the IntentMandate from shared state, validates it, and
creates a formal, signed offer using the official AP2 Pydantic models.
Returns:
Dictionary containing status and the created CartMandate.
"""
logger.info("Tool called: Creating CartMandate from IntentMandate")
# MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC
Étape 3B : Ajouter une logique de validation
Ajoutons maintenant la logique pour lire et valider l'IntentMandate à l'aide des modèles Pydantic AP2, et extrayons les données dont nous avons besoin.
👉 Trouver :
# MODULE_5_STEP_3B_ADD_VALIDATION_LOGIC
👉 Remplacez cette ligne par :
# 1. Read IntentMandate dictionary from state
intent_mandate_dict = tool_context.state.get("intent_mandate")
if not intent_mandate_dict:
logger.error("No IntentMandate found in state")
return {
"status": "error",
"message": "No IntentMandate found. Shopping Agent must create intent first."
}
# 2. Parse dictionary into a validated Pydantic model
try:
intent_mandate_model = IntentMandate.model_validate(intent_mandate_dict)
except Exception as e:
logger.error(f"Could not validate IntentMandate structure: {e}")
return {"status": "error", "message": f"Invalid IntentMandate structure: {e}"}
# 3. Validate that the intent hasn't expired (CRITICAL security check)
is_valid, error_message = _validate_intent_expiry(intent_mandate_model.intent_expiry)
if not is_valid:
logger.error(f"IntentMandate validation failed: {error_message}")
return {"status": "error", "message": error_message}
# 4. Extract data. Safely access standard fields from the model, and
# custom fields (like 'amount') from the original dictionary.
charity_name = intent_mandate_model.merchants[0] if intent_mandate_model.merchants else "Unknown Charity"
amount = intent_mandate_dict.get("amount", 0.0)
# MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE
Étape 3C : Créer la structure CartMandate
Nous allons maintenant créer la structure PaymentRequest conforme à W3C et l'encapsuler dans le CartMandate AP2 à l'aide des modèles Pydantic.
👉 Trouver :
# MODULE_5_STEP_3C_CREATE_CARTMANDATE_STRUCTURE
👉 Remplacez cette ligne par :
# 5. Build the nested Pydantic models for the CartMandate
timestamp = datetime.now(timezone.utc)
cart_id = f"cart_{hashlib.sha256(f'{charity_name}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}"
cart_expiry = timestamp + timedelta(minutes=15)
payment_request_model = PaymentRequest(
method_data=[PaymentMethodData(
supported_methods="CARD",
data={"supported_networks": ["visa", "mastercard", "amex"], "supported_types": ["debit", "credit"]}
)],
details=PaymentDetailsInit(
id=f"order_{cart_id}",
display_items=[PaymentItem(
label=f"Donation to {charity_name}",
amount=PaymentCurrencyAmount(currency="USD", value=amount) # Pydantic v2 handles float -> str conversion
)],
total=PaymentItem(
label="Total Donation",
amount=PaymentCurrencyAmount(currency="USD", value=amount)
)
),
options=PaymentOptions(request_shipping=False)
)
cart_contents_model = CartContents(
id=cart_id,
cart_expiry=cart_expiry.isoformat(),
merchant_name=charity_name,
user_cart_confirmation_required=False,
payment_request=payment_request_model
)
# MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE
Étape 3D : Ajouter une signature et enregistrer dans l'état
Enfin, signons le CartMandate à l'aide de notre modèle Pydantic et enregistrons-le dans l'état pour l'agent suivant.
👉 Trouver :
# MODULE_5_STEP_3D_ADD_SIGNATURE_AND_SAVE
👉 Remplacez cette ligne par :
# 6. Generate signature from the validated Pydantic model
signature = _generate_merchant_signature(cart_contents_model)
# 7. Create the final CartMandate model, now including the signature
cart_mandate_model = CartMandate(
contents=cart_contents_model,
merchant_authorization=signature
)
# 8. Convert the final model to a dictionary for state storage and add the custom timestamp
cart_mandate_dict = cart_mandate_model.model_dump(mode='json')
cart_mandate_dict["timestamp"] = timestamp.isoformat()
# 9. Write the final dictionary to state
tool_context.state["cart_mandate"] = cart_mandate_dict
logger.info(f"CartMandate created successfully: {cart_id}")
return {
"status": "success",
"message": f"Created signed CartMandate {cart_id} for ${amount:.2f} donation to {charity_name}",
"cart_id": cart_id,
"cart_expiry": cart_expiry.isoformat(),
"signature": signature
}
Étape 4 : Créez l'agent marchand : importez les composants
Créons maintenant l'agent qui utilisera cet outil.
👉 Ouvrir
charity_advisor/merchant_agent/agent.py
Un modèle avec des espaces réservés s'affiche. Commençons par importer ce dont nous avons besoin.
👉 Trouver :
# MODULE_5_STEP_4_IMPORT_COMPONENTS
👉 Remplacez cette ligne par :
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate
Étape 5 : Rédigez l'instruction de l'agent marchand
Écrivons maintenant l'instruction qui indique à l'agent quand et comment utiliser son outil.
👉 Trouver :
# MODULE_5_STEP_5_WRITE_INSTRUCTION
instruction="""""",
👉 Remplacez ces deux lignes par :
instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).
Your workflow:
1. Read the IntentMandate from shared state.
The IntentMandate was created by the Shopping Agent and contains:
- merchants: List of merchant names
- amount: Donation amount
- charity_ein: Tax ID
- intent_expiry: When the intent expires
2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
This tool will:
- Validate the IntentMandate hasn't expired (CRITICAL security check)
- Extract the charity name and amount from the IntentMandate
- Create a structured offer with payment methods, transaction details, and merchant info
- Generate a merchant signature to prove authenticity
- Save the CartMandate to state for the payment processor
3. After creating the CartMandate, inform the user:
- That you've created a formal, signed offer
- The cart ID
- When the cart expires (15 minutes)
- That you're passing it to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done
WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."
This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)
This is the second of three verifiable credentials in our secure payment system.""",
Étape 6 : Ajoutez des outils à l'agent marchand
👉 Trouver :
# MODULE_5_STEP_6_ADD_TOOLS
tools=[],
👉 Remplacez ces deux lignes par :
tools=[
FunctionTool(func=create_cart_mandate)
],
Étape 7 : Validez l'agent marchand complet
Vérifions que tout est correctement branché.
👉 Votre
charity_advisor/merchant_agent/agent.py
devrait désormais se présenter comme ceci :
"""
Merchant Agent - Creates W3C-compliant CartMandates with merchant signatures.
This agent acts as our "Contract Creator."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.merchant_tools import create_cart_mandate
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
tools=[
FunctionTool(func=create_cart_mandate)
],
instruction="""You are a merchant specialist responsible for creating formal, signed offers (CartMandates).
Your workflow:
1. Read the IntentMandate from shared state.
The IntentMandate was created by the Shopping Agent and contains:
- merchants: List of merchant names
- amount: Donation amount
- charity_ein: Tax ID
- intent_expiry: When the intent expires
2. Use the create_cart_mandate tool to create a W3C PaymentRequest-compliant CartMandate.
This tool will:
- Validate the IntentMandate hasn't expired (CRITICAL security check)
- Extract the charity name and amount from the IntentMandate
- Create a structured offer with payment methods, transaction details, and merchant info
- Generate a merchant signature to prove authenticity
- Save the CartMandate to state for the payment processor
3. After creating the CartMandate, inform the user:
- That you've created a formal, signed offer
- The cart ID
- When the cart expires (15 minutes)
- That you're passing it to the secure payment processor
IMPORTANT BOUNDARIES:
- Your ONLY job is creating signed CartMandates from valid IntentMandates
- You do NOT process payments
- You do NOT see the user's payment methods or credentials
- You do NOT interact with payment networks
- You MUST validate that the IntentMandate hasn't expired before creating a cart
- After calling create_cart_mandate, your work is done
WHAT IS A CARTMANDATE:
A CartMandate is a binding commitment that says:
"I, the merchant, commit to accepting $X for this charity donation, and I prove it with my signature."
This commitment is structured using the W3C PaymentRequest standard and includes:
- Payment methods accepted (card, bank transfer)
- Transaction details (amount, charity name)
- Cart expiry (15 minutes from creation)
- Merchant signature (proof of commitment)
This is the second of three verifiable credentials in our secure payment system."""
)
✅ Point de contrôle : vous disposez désormais d'un agent marchand complet avec une création appropriée de CartMandate AP2 à l'aide de modèles Pydantic.
Étape 8 : Testez l'agent marchand
Vérifions maintenant que notre agent crée correctement des CartMandates avec des signatures et valide l'expiration.
Configuration du test : exécuter le script de test
👉 Dans votre terminal Cloud Shell, exécutez la commande suivante :
python scripts/test_merchant.py
Résultat attendu :
======================================================================
MERCHANT AGENT TEST
======================================================================
Simulated IntentMandate from Shopping Agent:
charity: Room to Read
amount: $50.00
expiry: 2024-11-07T16:32:16Z
----------------------------------------------------------------------
Merchant Agent Response:
----------------------------------------------------------------------
Perfect! I've received your IntentMandate and created a formal, signed offer (CartMandate) for your donation.
**CartMandate Details:**
- **Cart ID**: cart_3b4c5d6e7f8a
- **Donation Amount**: $50.00 to Room to Read
- **Payment Methods Accepted**: Credit/debit cards (Visa, Mastercard, Amex) or bank transfer
- **Cart Expires**: 2024-11-07T15:47:16Z (in 15 minutes)
- **Merchant Signature**: SIG_a3f7b2c8d9e1f4a2
This signed CartMandate proves my commitment to accept this donation amount. I'm now passing this to the secure payment processor to complete your transaction.
======================================================================
CARTMANDATE CREATED:
======================================================================
ID: cart_3b4c5d6e7f8a
Amount: 50.00
Merchant: Room to Read
Expires: 2024-11-07T15:47:16Z
Signature: SIG_a3f7b2c8d9e1f4a2
======================================================================
Test 2 : Vérifier la conformité W3C
Vérifions que notre structure CartMandate est entièrement conforme aux normes AP2 et W3C PaymentRequest.
👉 Exécutez le script de validation :
python scripts/validate_cartmandate.py
Résultat attendu :
======================================================================
AP2 & W3C PAYMENTREQUEST VALIDATION
======================================================================
✅ CartMandate is AP2 and W3C PaymentRequest compliant
Structure validation passed:
✓ AP2 'contents' wrapper present
✓ AP2 'merchant_authorization' signature present
✓ cart_expiry present
✓ payment_request nested inside contents
✓ method_data present and valid
✓ details.total.amount present with currency and value
✓ All required W3C PaymentRequest fields present
======================================================================
Ce que vous venez de créer
Vous avez implémenté avec succès CartMandate d'AP2 à l'aide de modèles Pydantic pour une structure appropriée, la validation de l'expiration et les signatures du marchand.
Concepts clés maîtrisés
✅ CartMandate (identifiant AP2 n° 2) :
- Créé à l'aide des modèles Pydantic officiels AP2
- Structure AP2 avec wrapper de contenu
- W3C PaymentRequest imbriqué dans
- Expiration du panier (durée inférieure à l'intention)
- Signature du marchand pour un engagement contraignant
- La validation du modèle garantit la conformité aux spécifications
✅ Validation de l'expiration :
- Lecture de IntentMandate à partir de l'état
- Valider la structure avec
IntentMandate.model_validate() - Analyser les codes temporels ISO 8601
- Comparaison avec l'heure actuelle
- Fonction de sécurité empêchant le traitement obsolète
✅ Signature du marchand :
- Prouve l'authenticité et l'engagement
- Généré à partir d'un modèle Pydantic validé
- Utilise
model_dump(mode='json')pour la représentation canonique - Simulé avec SHA-256 pour l'éducation
- La production utilise PKI/JWT
- Signe le modèle de contenu, pas les dictionnaires
✅ W3C PaymentRequest :
- Construit à l'aide du modèle Pydantic PaymentRequest d'AP2
- Norme du secteur pour les données de paiement
- Imbriquée dans la structure AP2
- Contient method_data, details, options
- Permet l'interopérabilité
✅ Chaîne d'identifiants avec des modèles :
- Shopping → IntentMandate (validé)
- Merchant reads IntentMandate → CartMandate (les deux modèles sont validés)
- Le fournisseur d'informations d'identification lira CartMandate → PaymentMandate
- Chaque étape valide les identifiants précédents à l'aide de Pydantic.
✅ Développement piloté par les modèles :
- Validation des entrées via
model_validate() - Construction avec sûreté de typage
- Sérialisation automatique via
model_dump() - Modèles prêts pour la production
Étape suivante
Dans le prochain module, nous allons créer le fournisseur d'identifiants pour traiter les paiements de manière sécurisée.
L'agent marchand a créé une offre ferme avec une date d'expiration à l'aide des modèles AP2. Nous avons maintenant besoin d'un agent pour lire ce CartMandate, obtenir le consentement de l'utilisateur et exécuter le paiement.
Créons le fournisseur d'informations d'identification et complétons la chaîne d'informations d'identification AP2.
6. Créer le fournisseur d'identifiants : exécution de paiements sécurisés

De l'offre ferme à l'exécution du paiement
Dans le module 5, vous avez créé l'agent marchand, un spécialiste qui lit les IntentMandates, vérifie qu'ils n'ont pas expiré et crée des CartMandates contraignants avec les signatures des marchands. Nous avons maintenant besoin d'un agent pour recevoir ce CartMandate et exécuter le paiement.
C'est là qu'intervient le troisième et dernier principe d'AP2 : l'exécution sécurisée des paiements via PaymentMandate.
Principe AP2 : Mandat de paiement et exécution des paiements
Pourquoi avons-nous besoin d'un rôle de fournisseur d'identifiants ?
Dans le module 5, l'agent marchand a créé un CartMandate et l'a enregistré dans l'état :
state["cart_mandate"] = {
"contents": {
"id": "cart_abc123",
"cart_expiry": "2025-11-07:15:47:16Z",
"payment_request": {
"details": {
"total": {
"amount": {"currency": "USD", "value": "50.00"}
}
}
}
},
"merchant_authorization": "SIG_a3f7b2c8"
}
Mais il ne s'agit que d'une offre ferme. Avant de pouvoir effectuer un paiement, nous avons besoin des informations suivantes :
- Validation que le panier n'a pas expiré
- Consentement de l'utilisateur pour procéder au paiement
- Un identifiant qui autorise l'exécution du paiement
- Traitement réel des paiements (ou simulation pour notre atelier)
C'est le rôle du fournisseur d'identifiants.
Qu'est-ce qu'un PaymentMandate ?
Un PaymentMandate est le terme utilisé par AP2 pour désigner l'autorisation finale qui permet d'exécuter un paiement. Il s'agit de la troisième et dernière attestation vérifiable de la chaîne AP2.
Considérez les trois identifiants comme un processus de signature de contrat :
- IntentMandate : "Je suis intéressé par l'achat de ce produit" (lettre d'intention)
- CartMandate : "Moi, le marchand, propose de vendre à ce prix" (citation écrite)
- PaymentMandate : "Je vous autorise à débiter mon mode de paiement" (contrat signé)
Le paiement ne peut être effectué qu'une fois les trois identifiants disponibles.
Structure d'un mandat de paiement
Dans AP2, un PaymentMandate présente une structure spécifique :
payment_mandate = {
"payment_mandate_contents": { # ← AP2 wrapper
"payment_mandate_id": "payment_xyz123",
"payment_details_id": "cart_abc123", # Links to CartMandate
"user_consent": True,
"consent_timestamp": "2025-11-07T15:48:00Z",
"amount": {
"currency": "USD",
"value": "50.00"
},
"merchant_name": "Room to Read"
},
"agent_present": True, # Human-in-the-loop flow
"timestamp": "2025-11-07T15:48:00Z"
}
Composants clés :
1. payment_mandate_contents : wrapper d'autorisation contenant :
- payment_mandate_id : identifiant unique
- payment_details_id : renvoie à CartMandate
- user_consent: indique si l'utilisateur a donné son accord.
- amount : montant du paiement (extrait de CartMandate)
2. agent_present : indique s'il s'agit d'un flux avec intervention humaine.
3. timestamp : date et heure de création de l'autorisation
Notre mission : créer le fournisseur d'identifiants
Le fournisseur d'informations d'identification :
- Lire le CartMandate à partir de l'état (ce qu'a écrit l'agent du marchand)
- Valider que le panier n'a pas expiré à l'aide des modèles Pydantic AP2
- Extraire les informations de paiement de la structure imbriquée
- Créer un PaymentMandate avec l'autorisation de l'utilisateur à l'aide des modèles AP2
- Simuler le traitement des paiements (en production, l'API de paiement réelle serait appelée)
- Écrire le PaymentMandate et le résultat du paiement dans l'état
Construisons-le étape par étape.
Étape 1 : Ajoutez l'assistant de validation de l'expiration du panier
Commençons par créer un helper qui valide que CartMandate n'a pas expiré, tout comme nous avons validé l'expiration d'IntentMandate dans le module 5.
👉 Ouvrir
charity_advisor/tools/payment_tools.py
Ajoutons la validation de l'expiration :
👉 Trouver :
# MODULE_6_STEP_1_ADD_CART_EXPIRY_VALIDATION_HELPER
👉 Remplacez cette ligne par :
def _validate_cart_expiry(cart: CartMandate) -> tuple[bool, str]:
"""
Validates that the CartMandate hasn't expired.
This is a critical security check - expired carts should not be processed.
Args:
cart: The Pydantic CartMandate model to validate.
Returns:
(is_valid, error_message): Tuple indicating if cart is still valid.
"""
try:
expiry_str = cart.contents.cart_expiry
expiry_time = datetime.fromisoformat(expiry_str.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
if expiry_time < now:
return False, f"CartMandate expired at {expiry_str}"
time_remaining = expiry_time - now
logger.info(f"CartMandate valid. Expires in {time_remaining.total_seconds():.0f} seconds")
return True, ""
except (ValueError, TypeError, AttributeError) as e:
return False, f"Invalid cart_expiry format or structure: {e}"
Étape 2 : Ajoutez l'assistant de création PaymentMandate
Nous allons maintenant créer un helper qui crée la structure PaymentMandate à l'aide des modèles Pydantic officiels AP2.
👉 Trouver :
# MODULE_6_STEP_2_ADD_PAYMENT_MANDATE_CREATION_HELPER
👉 Remplacez cette ligne par :
def _create_payment_mandate(cart: CartMandate, consent_granted: bool) -> dict:
"""
Creates a PaymentMandate using the official AP2 Pydantic models.
It links to the CartMandate and includes user consent status.
Args:
cart: The validated Pydantic CartMandate model being processed.
consent_granted: Whether the user has consented to the payment.
Returns:
A dictionary representation of the final, validated PaymentMandate.
"""
timestamp = datetime.now(timezone.utc)
# Safely extract details from the validated CartMandate model
cart_id = cart.contents.id
merchant_name = cart.contents.merchant_name
total_item = cart.contents.payment_request.details.total
# Create the nested PaymentResponse model for the mandate
payment_response_model = PaymentResponse(
request_id=cart_id,
method_name="CARD", # As per the simulated flow
details={"token": "simulated_payment_token_12345"}
)
# Create the PaymentMandateContents model
payment_mandate_contents_model = PaymentMandateContents(
payment_mandate_id=f"payment_{hashlib.sha256(f'{cart_id}{timestamp.isoformat()}'.encode()).hexdigest()[:12]}",
payment_details_id=cart_id,
payment_details_total=total_item,
payment_response=payment_response_model,
merchant_agent=merchant_name,
timestamp=timestamp.isoformat()
)
# Create the top-level PaymentMandate model
# In a real system, a user signature would be added to this model
payment_mandate_model = PaymentMandate(
payment_mandate_contents=payment_mandate_contents_model
)
# Convert the final Pydantic model to a dictionary for state storage
final_dict = payment_mandate_model.model_dump(mode='json')
# Add any custom/non-standard fields required by the codelab's logic to the dictionary
# The spec does not have these fields, but your original code did. We add them
# back to ensure compatibility with later steps.
final_dict['payment_mandate_contents']['user_consent'] = consent_granted
final_dict['payment_mandate_contents']['consent_timestamp'] = timestamp.isoformat() if consent_granted else None
final_dict['agent_present'] = True
return final_dict
Étape 3A : Créez la signature et la configuration de l'outil
Commençons maintenant à créer l'outil principal de manière incrémentielle. Tout d'abord, la signature de la fonction et la configuration initiale.
👉 Trouver :
# MODULE_6_STEP_3A_CREATE_TOOL_SIGNATURE
👉 Remplacez cette ligne par :
async def create_payment_mandate(tool_context: Any) -> Dict[str, Any]:
"""
Creates a PaymentMandate and simulates payment processing using Pydantic models.
This tool now reads the CartMandate from state, parses it into a validated model,
and creates a spec-compliant PaymentMandate.
"""
logger.info("Tool called: Creating PaymentMandate and processing payment")
# MODULE_6_STEP_3B_VALIDATE_CARTMANDATE
Étape 3B : Valider CartMandate
Ajoutons maintenant la logique pour lire et valider CartMandate à l'aide des modèles Pydantic AP2 et vérifions la date d'expiration.
👉 Trouver :
# MODULE_6_STEP_3B_VALIDATE_CARTMANDATE
👉 Remplacez cette ligne par :
# 1. Read CartMandate dictionary from state
cart_mandate_dict = tool_context.state.get("cart_mandate")
if not cart_mandate_dict:
logger.error("No CartMandate found in state")
return { "status": "error", "message": "No CartMandate found. Merchant Agent must create cart first." }
# 2. Parse dictionary into a validated Pydantic model
try:
cart_model = CartMandate.model_validate(cart_mandate_dict)
except Exception as e:
logger.error(f"Could not validate CartMandate structure: {e}")
return {"status": "error", "message": f"Invalid CartMandate structure: {e}"}
# 3. Validate that the cart hasn't expired using the Pydantic model
is_valid, error_message = _validate_cart_expiry(cart_model)
if not is_valid:
logger.error(f"CartMandate validation failed: {error_message}")
return {"status": "error", "message": error_message}
# MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS
Étape 3C : Extraire les informations de paiement d'une structure imbriquée
Maintenant, parcourons le modèle CartMandate validé pour extraire les informations de paiement dont nous avons besoin.
👉 Trouver :
# MODULE_6_STEP_3C_EXTRACT_PAYMENT_DETAILS
👉 Remplacez cette ligne par :
# 4. Safely extract data from the validated model
cart_id = cart_model.contents.id
merchant_name = cart_model.contents.merchant_name
amount_value = cart_model.contents.payment_request.details.total.amount.value
currency = cart_model.contents.payment_request.details.total.amount.currency
consent_granted = True # Assume consent for this codelab flow
# MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE
Étape 3D : Créer un mandat de paiement et simuler un paiement
Enfin, créons le PaymentMandate à l'aide de notre outil basé sur Pydantic, simulons le traitement des paiements et enregistrons tout dans l'état.
👉 Trouver :
# MODULE_6_STEP_3D_CREATE_PAYMENTMANDATE_AND_SIMULATE
👉 Remplacez cette ligne par :
# 5. Create the spec-compliant PaymentMandate using the validated CartMandate model
payment_mandate_dict = _create_payment_mandate(cart_model, consent_granted)
# 6. Simulate payment processing
transaction_id = f"txn_{hashlib.sha256(f'{cart_id}{datetime.now(timezone.utc).isoformat()}'.encode()).hexdigest()[:16]}"
payment_result = {
"transaction_id": transaction_id,
"status": "completed",
"amount": amount_value,
"currency": currency,
"merchant": merchant_name,
"timestamp": datetime.now(timezone.utc).isoformat(),
"simulation": True
}
# 7. Write the compliant PaymentMandate dictionary and result to state
tool_context.state["payment_mandate"] = payment_mandate_dict
tool_context.state["payment_result"] = payment_result
logger.info(f"Payment processed successfully: {transaction_id}")
return {
"status": "success",
"message": f"Payment of {currency} {amount_value:.2f} to {merchant_name} processed successfully",
"transaction_id": transaction_id,
"payment_mandate_id": payment_mandate_dict["payment_mandate_contents"]["payment_mandate_id"]
}
Étape 4 : Créez l'agent du fournisseur d'identifiants : importez les composants
Créons maintenant l'agent qui utilise cet outil.
👉 Ouvrir
charity_advisor/credentials_provider/agent.py
Un modèle avec des espaces réservés s'affiche. Commençons par importer ce dont nous avons besoin.
👉 Trouver :
# MODULE_6_STEP_4_IMPORT_COMPONENTS
👉 Remplacez cette ligne par :
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate
Étape 5 : Rédigez l'instruction du fournisseur d'identifiants
Écrivons maintenant l'instruction qui guide l'agent.
👉 Trouver :
# MODULE_6_STEP_5_WRITE_INSTRUCTION
instruction="""""",
👉 Remplacez ces deux lignes par :
instruction="""You are a payment specialist responsible for securely processing payments with user consent.
Your workflow:
1. Read the CartMandate from shared state.
The CartMandate was created by the Merchant Agent and has this structure:
- contents: AP2 wrapper containing:
- id: Cart identifier
- cart_expiry: When the cart expires
- merchant_name: Who is receiving payment
- payment_request: W3C PaymentRequest with transaction details
- merchant_authorization: Merchant's signature
2. Extract payment details from the nested structure:
- Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
- This gives you the currency and value
3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
Before calling create_payment_mandate, you MUST:
- Present the payment details clearly to the user
- Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
- WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
- ONLY call create_payment_mandate AFTER receiving explicit confirmation
- If user says "no" or "cancel", DO NOT call the tool
4. After user confirms, use the create_payment_mandate tool to:
- Validate the CartMandate hasn't expired (CRITICAL security check)
- Create a PaymentMandate (the third AP2 credential)
- Simulate payment processing
- Record the transaction result
5. After processing, inform the user:
- That payment was processed successfully (this is a simulation)
- The transaction ID
- The amount and merchant
- That this completes the three-agent AP2 credential chain
IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust
WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction
This is the third and final verifiable credential in our secure payment system.
THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)
Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust""",
Étape 6 : Ajoutez des outils au fournisseur d'identifiants
👉 Trouver :
# MODULE_6_STEP_6_ADD_TOOLS
tools=[],
👉 Remplacez ces deux lignes par :
tools=[
FunctionTool(func=create_payment_mandate)
],
Étape 7 : Vérifiez le fournisseur d'identifiants complets
Vérifions que tout est correctement branché.
👉 Votre
charity_advisor/credentials_provider/agent.py
devrait désormais se présenter comme ceci :
"""
Credentials Provider Agent - Handles payment processing with user consent.
This agent acts as our "Payment Processor."
"""
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from charity_advisor.tools.payment_tools import create_payment_mandate
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
tools=[
FunctionTool(func=create_payment_mandate)
],
instruction="""You are a payment specialist responsible for securely processing payments with user consent.
Your workflow:
1. Read the CartMandate from shared state.
The CartMandate was created by the Merchant Agent and has this structure:
- contents: AP2 wrapper containing:
- id: Cart identifier
- cart_expiry: When the cart expires
- merchant_name: Who is receiving payment
- payment_request: W3C PaymentRequest with transaction details
- merchant_authorization: Merchant's signature
2. Extract payment details from the nested structure:
- Navigate: cart_mandate["contents"]["payment_request"]["details"]["total"]["amount"]
- This gives you the currency and value
3. **IMPORTANT - Two-Turn Conversational Confirmation Pattern:**
Before calling create_payment_mandate, you MUST:
- Present the payment details clearly to the user
- Ask explicitly: "I'm ready to process a payment of $X to [Charity Name]. Do you want to proceed with this donation?"
- WAIT for the user's explicit confirmation (e.g., "yes", "proceed", "confirm")
- ONLY call create_payment_mandate AFTER receiving explicit confirmation
- If user says "no" or "cancel", DO NOT call the tool
4. After user confirms, use the create_payment_mandate tool to:
- Validate the CartMandate hasn't expired (CRITICAL security check)
- Create a PaymentMandate (the third AP2 credential)
- Simulate payment processing
- Record the transaction result
5. After processing, inform the user:
- That payment was processed successfully (this is a simulation)
- The transaction ID
- The amount and merchant
- That this completes the three-agent AP2 credential chain
IMPORTANT BOUNDARIES:
- Your ONLY job is creating PaymentMandates and processing payments
- You do NOT discover charities (that's Shopping Agent's job)
- You do NOT create offers (that's Merchant Agent's job)
- You MUST validate that the CartMandate hasn't expired before processing
- You MUST get explicit user confirmation before calling create_payment_mandate
- In production, this consent mechanism would be even more robust
WHAT IS A PAYMENTMANDATE:
A PaymentMandate is the final credential that authorizes payment execution. It:
- Links to the CartMandate (proving the merchant's offer)
- Records user consent
- Contains payment details extracted from the CartMandate
- Enables the actual payment transaction
This is the third and final verifiable credential in our secure payment system.
THE COMPLETE AP2 CREDENTIAL CHAIN:
1. Shopping Agent creates IntentMandate (user's intent)
2. Merchant Agent reads IntentMandate, creates CartMandate (merchant's binding offer)
3. You read CartMandate, get user confirmation, create PaymentMandate (authorized payment execution)
Each credential:
- Has an expiry time (security feature)
- Links to the previous credential
- Is validated before the next step
- Creates an auditable chain of trust"""
)
✅ Point de contrôle : vous disposez désormais d'un fournisseur d'identifiants complet avec une lecture appropriée de CartMandate et une création de PaymentMandate à l'aide des modèles Pydantic AP2.
Étape 8 : Testez le fournisseur d'identifiants
Vérifions maintenant que notre agent traite correctement les paiements et complète la chaîne d'identifiants.
👉 Dans votre terminal Cloud Shell, exécutez la commande suivante :
python scripts/test_credentials_provider.py
Résultat attendu :
======================================================================
CREDENTIALS PROVIDER TEST (MOCK - NO CONFIRMATION)
======================================================================
Simulated CartMandate from Merchant Agent:
- Cart ID: cart_test123
- Merchant: Room to Read
- Amount: $50.00
- Expires: 2025-11-07T15:47:16Z
- Signature: SIG_test_signature
Calling Credentials Provider to process payment...
======================================================================
INFO:charity_advisor.tools.payment_tools:Tool called: Creating PaymentMandate and processing payment
INFO:charity_advisor.tools.payment_tools:CartMandate valid. Expires in 900 seconds
INFO:charity_advisor.tools.payment_tools:Payment processed successfully: txn_a3f7b2c8d9e1f4a2
======================================================================
CREDENTIALS PROVIDER RESPONSE:
======================================================================
I've successfully processed your payment. Here are the details:
**Payment Completed** (Simulated)
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Amount: USD 50.00
- Merchant: Room to Read
- Status: Completed
This completes the three-agent AP2 credential chain:
1. ✓ Shopping Agent created IntentMandate (your intent)
2. ✓ Merchant Agent created CartMandate (binding offer)
3. ✓ Credentials Provider created PaymentMandate (payment authorization)
Your donation has been processed securely through our verifiable credential system.
======================================================================
PAYMENTMANDATE CREATED:
======================================================================
Payment Mandate ID: payment_3b4c5d6e7f8a
Linked to Cart: cart_test123
User Consent: True
Amount: USD 50.00
Merchant: Room to Read
Agent Present: True
======================================================================
======================================================================
PAYMENT RESULT:
======================================================================
Transaction ID: txn_a3f7b2c8d9e1f4a2
Status: completed
Amount: USD 50.00
Merchant: Room to Read
Simulation: True
======================================================================
Étape 9 : Tester le pipeline complet à trois agents
Testons maintenant les trois agents ensemble !
👉 Exécutez le test complet du pipeline :
python scripts/test_full_pipeline.py
Résultat attendu :
======================================================================
THREE-AGENT PIPELINE TEST (AP2 CREDENTIAL CHAIN)
======================================================================
[1/3] SHOPPING AGENT - Finding charity and creating IntentMandate...
----------------------------------------------------------------------
✓ IntentMandate created
- Intent ID: intent_774799058_1730927536
- Description: Donate $75.00 to Room to Read
- Merchant: Room to Read
- Amount: $75.0
- Expires: 2025-11-07T16:32:16Z
[2/3] MERCHANT AGENT - Reading IntentMandate and creating CartMandate...
----------------------------------------------------------------------
✓ CartMandate created
- ID: cart_3b4c5d6e7f8a
- Expires: 2025-11-07T15:47:16Z
- Signature: SIG_a3f7b2c8d9e1f4a2
[3/3] CREDENTIALS PROVIDER - Creating PaymentMandate and processing...
----------------------------------------------------------------------
NOTE: In the web UI, this would show a confirmation dialog
For this test, consent is automatically granted
✓ Payment processed (SIMULATED)
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Amount: $75.0
- Status: completed
======================================================================
COMPLETE AP2 CREDENTIAL CHAIN
======================================================================
✓ Credential 1: IntentMandate (User's Intent)
- Intent ID: intent_774799058_1730927536
- Description: Donate $75.00 to Room to Read
- Expiry: 2025-11-07T16:32:16Z
✓ Credential 2: CartMandate (Merchant's Offer)
- Cart ID: cart_3b4c5d6e7f8a
- Cart Expiry: 2025-11-07T15:47:16Z
- Merchant Signature: SIG_a3f7b2c8d9e1f4a2
✓ Credential 3: PaymentMandate (Payment Execution)
- Payment Mandate ID: payment_3b4c5d6e7f8a
- Linked to Cart: cart_3b4c5d6e7f8a
- Agent Present: True
✓ Transaction Result:
- Transaction ID: txn_a3f7b2c8d9e1f4a2
- Simulation: True
======================================================================
✅ COMPLETE PIPELINE TEST PASSED
======================================================================
Voici la chaîne d'identifiants AP2 complète en action !
Chaque agent :
- Lit un identifiant à partir de l'état
- Valide le jeton à l'aide des modèles Pydantic (structure + vérification de l'expiration)
- Crée les prochaines identifiants à l'aide des modèles AP2
- Écrit dans l'état pour le prochain agent
Ce que vous venez de créer
Vous avez terminé l'atelier sur la chaîne d'identifiants AP2 à trois agents avec validation de la structure appropriée à l'aide de modèles Pydantic et de simulation de paiement.
Concepts clés maîtrisés
✅ PaymentMandate (identifiant AP2 n° 3) :
- Créé à l'aide des modèles Pydantic officiels AP2
- Identifiant final autorisant l'exécution du paiement
- Liens vers CartMandate via payment_details_id
- Enregistre le consentement de l'utilisateur et l'horodatage
- Contient le montant du paiement extrait de CartMandate
- Inclut l'indicateur agent_present pour human-in-the-loop
- La validation du modèle garantit la conformité aux spécifications
✅ Lecture depuis CartMandate :
- Valider la structure avec
CartMandate.model_validate() - Accès aux attributs avec sécurité du typage :
cart_model.contents.payment_request.details.total.amount - Comprendre la différence entre le wrapper AP2 et la séparation standard W3C
- Extraire de manière sécurisée le nom du marchand, le montant et la devise à partir du modèle
- Pydantic détecte automatiquement les erreurs de structure
✅ Validation de l'expiration du panier :
- Accepte le modèle Pydantic
CartMandatevalidé - Lecture à partir de
cart.contents.cart_expiry(accès aux attributs) - Fonctionnalité de sécurité empêchant le traitement des paniers obsolètes
- Durée plus courte (15 min) que l'intention (1 h)
✅ Simulation de paiement :
- Simulation pédagogique d'une société de traitement des paiements réelle
- Génère un ID de transaction
- Enregistre payment_result dans l'état
- Clairement identifié comme une simulation (indicateur "simulation" défini sur "True")
✅ Chaîne AP2 complète avec des modèles :
- Trois agents, trois identifiants, trois validations Pydantic
- Chaque agent valide la structure des identifiants précédents à l'aide de modèles.
- Chaque identifiant est associé au précédent pour l'audit trail.
- Les transferts basés sur l'état maintiennent la séparation des rôles
- Sûreté du typage tout au long de la chaîne
✅ Développement piloté par les modèles :
- Validation des entrées via
model_validate() - Construction avec sûreté de typage avec des modèles imbriqués
- Sérialisation automatique via
model_dump(mode='json') - Des modèles prêts pour la production dès le départ
Étape suivante
Dans le prochain module, nous allons créer l'agent d'orchestration qui coordonne les trois agents spécialisés.
Vous avez créé trois puissants agents spécialisés à l'aide des modèles Pydantic AP2. Nous allons maintenant créer le chef d'orchestre qui les coordonne pour offrir une expérience de don fluide.
Construisons l'orchestrateur et observons le système complet en action.
7. Orchestration : tout rassembler
Des spécialistes à une expérience fluide
Dans les modules précédents, vous avez créé trois agents spécialisés :
- Agent Shopping : trouve des associations caritatives, crée un IntentMandate
- Agent marchand : crée un CartMandate à partir d'un IntentMandate.
- Fournisseur d'identifiants : crée PaymentMandate, traite le paiement
Ces agents se répartissent naturellement en deux phases :
- Phase 1 (Shopping) : conversation à plusieurs tours pour trouver et sélectionner une association caritative
- Phase 2 (Traitement) : Exécution atomique de la création de l'offre et du paiement
Mais pour l'instant, vous devez orchestrer manuellement ces phases.
C'est là que les modèles d'orchestration de l'ADK entrent en jeu.
Principe AP2 : l'orchestration applique les limites de confiance
Pourquoi l'orchestration est-elle importante pour la sécurité ?
L'orchestration n'est pas qu'une question de commodité, elle permet d'appliquer des limites de confiance grâce à l'architecture.
Sans orchestration :
# User could accidentally skip steps or reorder them
shopping_agent.run("Find charity")
# Oops, forgot to create CartMandate!
credentials_provider.run("Process payment") # No offer to validate!
Avec orchestration :
# Pipeline enforces correct order
donation_processing_pipeline = SequentialAgent(
sub_agents=[
merchant_agent, # Must run first
credentials_provider # Must run second
]
)
# Steps ALWAYS run in order, no skipping allowed
Le pipeline séquentiel garantit les éléments suivants :
- ✅ IntentMandate créé avant CartMandate
- ✅ CartMandate créé avant le traitement du paiement
- ✅ Chaque agent s'exécute dans son propre contexte isolé.
- ✅ L'état progresse dans la chaîne d'identifiants.
Notre mission : créer un système complet
Nous allons créer deux calques :
Calque 1 : Pipeline de traitement (SequentialAgent)
- Câbles ensemble Marchand → Identifiants
- S'exécute automatiquement dans l'ordre après la sélection d'une organisation caritative
- Exécution atomique de l'offre et du paiement
Couche 2 : Orchestrateur racine (Agent destiné aux utilisateurs)
- Personnalité amicale
- Délègue la sélection d'une association caritative à shopping_agent
- Délègue au pipeline de traitement après la création d'IntentMandate
- Gère les transitions de conversation et de phase
Cette approche à deux niveaux correspond au flux naturel :
- Phase d'achat : conversation en plusieurs tours (l'utilisateur parcourt les produits, pose des questions et prend une décision)
- Phase de traitement : exécution atomique (offre → paiement)
Créons les deux.
Étape 1 : Importez les composants d'orchestration
Commençons par configurer le fichier d'orchestration avec les importations nécessaires.
👉 Ouvrir
charity_advisor/agent.py
Commençons par les importations :
👉 Trouver :
# MODULE_7_STEP_1_IMPORT_COMPONENTS
👉 Remplacez cette ligne par :
from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider
Étape 2 : Créer le pipeline de traitement
Créons maintenant le pipeline qui exécute la création d'offres et le traitement des paiements de manière atomique.
👉 Trouver :
# MODULE_7_STEP_2_CREATE_SEQUENTIAL_PIPELINE
👉 Remplacez ces deux lignes par :
# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
name="DonationProcessingPipeline",
description="Creates signed offer and processes payment after charity is selected",
sub_agents=[
merchant_agent,
credentials_provider
]
)
Étape 3A : Créez la configuration de l'agent racine
Créons maintenant l'agent destiné aux utilisateurs qui orchestre les deux phases. Nous allons le construire en trois parties : la configuration (3A), les instructions (3B) et les sous-agents (3C).
👉 Trouver :
# MODULE_7_STEP_3A_CREATE_ROOT_AGENT_SETUP
👉 Remplacez cette ligne par :
# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
name="CharityAdvisor",
model="gemini-2.5-pro",
description="A friendly charity giving assistant that helps users donate to verified organizations.",
# MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION
Étape 3B : Rédigez l'instruction de l'agent racine
Ajoutons maintenant l'instruction qui guide le comportement du conseiller caritatif dans les deux phases.
👉 Trouver :
# MODULE_7_STEP_3B_WRITE_ROOT_AGENT_INSTRUCTION
👉 Remplacez cette ligne par :
instruction="""You are a helpful and friendly charity giving advisor.
Your workflow has TWO distinct phases:
PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
- Search for charities matching their cause
- Present verified options with ratings
- Engage in conversation (user may ask questions, change their mind)
- Wait for user to select a specific charity and amount
- Create an IntentMandate when user decides
3. Wait for shopping_agent to complete
You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx"
- Charity name and donation amount
PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
"Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
- Create signed cart offer (MerchantAgent)
- Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction
CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically
EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"
Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS
Étape 3C : Ajouter les sous-agents
Enfin, accordons à l'assistant caritatif l'accès à l'agent d'achat et au pipeline de traitement, puis fermons la définition de l'agent.
👉 Trouver :
# MODULE_7_STEP_3C_ADD_ROOT_AGENT_SUBAGENTS
👉 Remplacez cette ligne par :
sub_agents=[
shopping_agent,
donation_processing_pipeline
]
)
Étape 4 : Vérifiez le système complet
Vérifions que l'orchestration est correctement configurée.
👉 Votre
charity_advisor/agent.py
devrait désormais se présenter comme ceci :
"""
Main orchestration: The donation processing pipeline and root orchestrator agent.
"""
from google.adk.agents import Agent, SequentialAgent
from charity_advisor.shopping_agent.agent import shopping_agent
from charity_advisor.merchant_agent.agent import merchant_agent
from charity_advisor.credentials_provider.agent import credentials_provider
# Create the donation processing pipeline
# This runs Merchant → Credentials in sequence AFTER charity is selected
donation_processing_pipeline = SequentialAgent(
name="DonationProcessingPipeline",
description="Creates signed offer and processes payment after charity is selected",
sub_agents=[
merchant_agent,
credentials_provider
]
)
# Create the root orchestrator agent
# This is what users interact with directly
root_agent = Agent(
name="CharityAdvisor",
model="gemini-2.5-flash",
description="A friendly charity giving assistant that helps users donate to verified organizations.",
instruction="""You are a helpful and friendly charity giving advisor.
Your workflow has TWO distinct phases:
PHASE 1: CHARITY SELECTION (delegate to shopping_agent)
When a user expresses interest in donating:
1. Delegate to shopping_agent immediately
2. The shopping_agent will:
- Search for charities matching their cause
- Present verified options with ratings
- Engage in conversation (user may ask questions, change their mind)
- Wait for user to select a specific charity and amount
- Create an IntentMandate when user decides
3. Wait for shopping_agent to complete
You'll know Phase 1 is complete when shopping_agent's response includes:
- "IntentMandate created" or "Intent ID: intent_xxx"
- Charity name and donation amount
PHASE 2: PAYMENT PROCESSING (delegate to DonationProcessingPipeline)
After shopping_agent completes:
1. Acknowledge the user's selection naturally:
"Perfect! Let me process your $X donation to [Charity]..."
2. Delegate to DonationProcessingPipeline
3. The pipeline will automatically:
- Create signed cart offer (MerchantAgent)
- Get consent and process payment (CredentialsProvider)
4. After pipeline completes, summarize the transaction
CRITICAL RULES:
- Phase 1 may take multiple conversation turns (this is normal)
- Only proceed to Phase 2 after IntentMandate exists
- Don't rush the user during charity selection
- Don't ask user to "proceed" between phases - transition automatically
EXAMPLE FLOW:
User: "I want to donate to education"
You: [delegate to shopping_agent]
Shopping: "Here are 3 education charities..." [waits]
User: "Tell me more about the first one"
Shopping: "Room to Read focuses on..." [waits]
User: "Great, I'll donate $50 to Room to Read"
Shopping: "IntentMandate created (ID: intent_123)..."
You: "Perfect! Processing your $50 donation to Room to Read..." [delegate to DonationProcessingPipeline]
Pipeline: [creates offer, gets consent, processes payment]
You: "Done! Your donation was processed successfully. Transaction ID: txn_456"
Your personality:
- Warm and encouraging
- Patient during charity selection
- Clear about educational nature
- Smooth transitions between phases""",
sub_agents=[
shopping_agent,
donation_processing_pipeline
]
)
Étape 5 : Renforcez la sécurité avec les rappels de validation (facultatif, passez à l'étape 7)

L'agent séquentiel garantit l'ordre d'exécution, mais que se passe-t-il si :
- L'agent Shopping échoue sans message d'erreur (IntentMandate n'est jamais créé)
- Une heure s'écoule entre Shopping et Merchant (l'intention expire)
- L'état est corrompu ou effacé
- Un utilisateur tente d'appeler le marchand directement, en contournant Shopping
Les rappelsajoutent une application architecturale : ils valident les prérequis avant même qu'un agent ne commence son appel LLM. Il s'agit d'une défense en profondeur : les outils valident pendant l'exécution, les rappels valident avant l'exécution.
Ajoutons des rappels de validation à nos agents Merchant et Credentials Provider.
Étape 5A : Ajouter la validation du marchand – Importer les types de rappel
Commençons par ajouter les importations nécessaires pour les rappels.
👉 Ouvrir
charity_advisor/merchant_agent/agent.py
En haut du fichier, après les importations existantes, ajoutez :
from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging
logger = logging.getLogger(__name__)
Étape 5B : Créez la fonction de validation de l'intention
Nous allons maintenant créer une fonction de rappel qui valide IntentMandate avant l'exécution de l'agent marchand.
👉 Dans
charity_advisor/merchant_agent/agent.py
, ajoutez cette fonction AVANT
merchant_agent = Agent(...)
définition :
def validate_intent_before_merchant(
callback_context: CallbackContext,
) -> Optional[Content]:
"""
Validates IntentMandate exists and hasn't expired before Merchant runs.
This callback enforces that the Shopping Agent completed successfully
before the Merchant Agent attempts to create a CartMandate.
Returns:
None: Allow Merchant Agent to proceed normally
Content: Skip Merchant Agent and return error to user
"""
state = callback_context.state
# Check credential exists
if "intent_mandate" not in state:
logger.error("❌ IntentMandate missing - Shopping Agent may have failed")
return Content(parts=[Part(text=(
"Error: Cannot create cart. User intent was not properly recorded. "
"Please restart the donation process."
))])
intent_mandate = state["intent_mandate"]
# Validate expiry (critical security check)
try:
expiry_time = datetime.fromisoformat(
intent_mandate["intent_expiry"].replace('Z', '+00:00')
)
now = datetime.now(timezone.utc)
if expiry_time < now:
logger.error(f"❌ IntentMandate expired at {intent_mandate['intent_expiry']}")
return Content(parts=[Part(text=(
"Error: Your donation intent has expired. "
"Please select a charity again to restart."
))])
time_remaining = expiry_time - now
logger.info(f"✓ IntentMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
except (KeyError, ValueError) as e:
logger.error(f"❌ Invalid IntentMandate structure: {e}")
return Content(parts=[Part(text=(
"Error: Invalid intent data. Please restart the donation."
))])
# All checks passed - allow Merchant Agent to proceed
logger.info(f"✓ Prerequisites met for Merchant Agent: {intent_mandate['intent_id']}")
return None
Étape 5C : Associer le rappel à l'agent marchand
Connectons maintenant le rappel à l'agent.
👉 Dans
charity_advisor/merchant_agent/agent.py
, modifie le
merchant_agent = Agent(...)
définition :
Localisez la ligne suivante dans la définition de l'agent :
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
Ajoutez cette ligne juste après
description
line:
before_agent_callback=validate_intent_before_merchant,
La définition de votre agent devrait maintenant ressembler à ceci :
merchant_agent = Agent(
name="MerchantAgent",
model="gemini-2.5-flash",
description="Creates formal, signed CartMandates for charity donations following W3C PaymentRequest standards.",
before_agent_callback=validate_intent_before_merchant,
tools=[
FunctionTool(func=create_cart_mandate)
],
instruction="""..."""
)
Étape 6 : Ajoutez la validation du fournisseur d'identifiants (facultatif, passez à l'étape 7)
Suivons le même schéma et ajoutons une validation pour l'étape de paiement.
Étape 6A : Importer les types de rappel
👉 Ouvrir
charity_advisor/credentials_provider/agent.py
En haut du fichier, après les importations existantes, ajoutez :
from typing import Optional
from datetime import datetime, timezone
from google.adk.agents.callback_context import CallbackContext
from google.genai.types import Content, Part
import logging
logger = logging.getLogger(__name__)
Étape 6B : Créer la fonction de validation du panier
👉 Dans
charity_advisor/credentials_provider/agent.py
, ajoutez cette fonction AVANT
credentials_provider = Agent(...)
définition :
def validate_cart_before_payment(
callback_context: CallbackContext,
) -> Optional[Content]:
"""
Validates CartMandate exists and hasn't expired before payment processing.
This callback enforces that the Merchant Agent completed successfully
before the Credentials Provider attempts to process payment.
Returns:
None: Allow Credentials Provider to proceed
Content: Skip payment processing and return error
"""
state = callback_context.state
# Check credential exists
if "cart_mandate" not in state:
logger.error("❌ CartMandate missing - Merchant Agent may have failed")
return Content(parts=[Part(text=(
"Error: Cannot process payment. Cart was not properly created. "
"Please restart the donation process."
))])
cart_mandate = state["cart_mandate"]
# Validate AP2 structure
if "contents" not in cart_mandate:
logger.error("❌ CartMandate missing AP2 contents wrapper")
return Content(parts=[Part(text=(
"Error: Invalid cart structure. Please restart."
))])
# Validate expiry
try:
contents = cart_mandate["contents"]
expiry_time = datetime.fromisoformat(
contents["cart_expiry"].replace('Z', '+00:00')
)
now = datetime.now(timezone.utc)
if expiry_time < now:
logger.error(f"❌ CartMandate expired at {contents['cart_expiry']}")
return Content(parts=[Part(text=(
"Error: Your cart has expired (15 minute limit). "
"Please restart the donation to get a fresh offer."
))])
time_remaining = expiry_time - now
logger.info(f"✓ CartMandate validated. Expires in {time_remaining.total_seconds():.0f}s")
except (KeyError, ValueError) as e:
logger.error(f"❌ Invalid CartMandate structure: {e}")
return Content(parts=[Part(text=(
"Error: Invalid cart data. Please restart the donation."
))])
# All checks passed - allow payment processing
logger.info(f"✓ Prerequisites met for Credentials Provider: {contents['id']}")
return None
Étape 6C : Associez le rappel au fournisseur d'identifiants
👉 Dans
charity_advisor/credentials_provider/agent.py
, modifie le
credentials_provider = Agent(...)
définition :
Localisez la ligne suivante dans la définition de l'agent :
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
Ajoutez cette ligne juste après
description
line:
before_agent_callback=validate_cart_before_payment,
La définition de votre agent devrait maintenant ressembler à ceci :
credentials_provider = Agent(
name="CredentialsProvider",
model="gemini-2.5-flash",
description="Securely processes payments by creating PaymentMandates and executing transactions with user consent.",
before_agent_callback=validate_cart_before_payment,
tools=[
FunctionTool(func=create_payment_mandate)
],
instruction="""..."""
)
Étape 7 : Tester avec l'UI Web de l'ADK
Testons maintenant le système renforcé complet avec les rappels de validation actifs.
👉 Dans votre terminal Cloud Shell, exécutez la commande suivante :
adk web
Le résultat doit ressembler à ceci :
+-----------------------------------------------------------------------------+
| ADK Web Server started |
| |
| For local testing, access at http://localhost:8000. |
+-----------------------------------------------------------------------------+
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
👉 Ensuite, pour accéder à l'UI Web d'ADK depuis votre navigateur :
Dans la barre d'outils Cloud Shell (généralement en haut à droite), cliquez sur l'icône Aperçu sur le Web (en forme d'œil ou de carré avec une flèche), puis sélectionnez Modifier le port. Dans la fenêtre pop-up, définissez le port sur 8000, puis cliquez sur Modifier et prévisualiser. Cloud Shell ouvre alors un nouvel onglet de navigateur affichant l'UI Web de l'ADK.

👉 Sélectionnez votre agent dans le menu déroulant :
Dans l'interface utilisateur Web de l'ADK, un menu déroulant s'affiche en haut de l'écran. Sélectionnez charity_advisor dans la liste.

L'interface Web de l'ADK s'affiche et comprend les éléments suivants :
- Panneau de chat : à gauche, pour la conversation
- Panneau "Traces" : à droite, pour l'observabilité (nous l'utiliserons dans le module 9)
Test 1 : Effectuer un parcours de don (cas normal)
👉 Dans l'interface de chat, saisissez :
I want to donate to an education charity
Regardez le déroulement complet du processus :


Ce qui se passe (visible dans le panneau de trace à droite) :
1. Le conseiller délègue à ShoppingAgent :
- ShoppingAgent recherche des associations caritatives dans le domaine de l'éducation
- Affiche trois options validées avec des détails
2. Vous interagissez avec ShoppingAgent (cela peut prendre plusieurs tours) :
User: "Tell me more about Room to Read"
Shopping: [explains mission and impact]
User: "I'll donate $50 to Room to Read"
3. ShoppingAgent crée IntentMandate :
- Crée et signe l'intent
- Renvoie une confirmation avec l'ID d'intention
4. L'agent passe à la phase de traitement :
Parfait ! Traitement de votre don de 50 $à Room to Read…
5. DonationProcessingPipeline s'active :
- Le rappel du marchand valide IntentMandate (✓ réussi) ← NOUVEAU !
- L'agent du marchand crée CartMandate avec une signature
- Le rappel des identifiants valide CartMandate (✓ réussi) ← NOUVEAU !
- Le fournisseur d'identifiants prépare le paiement
6. Processus de paiement :
- Le fournisseur d'identifiants crée PaymentMandate
- Simule le traitement des paiements
- ID de la transaction de retour
7. L'assistant résume :
Parfait ! Votre don a bien été traité. 🎉
Détails :
- Montant : 50 $
- Association caritative : Room to Read (EIN : 77-0479905)
- ID de la transaction : txn_a3f7b2c8d9e1f4a2
Test 2 : Vérifier que les rappels détectent les échecs (test avancé facultatif)
Vous souhaitez voir les rappels en action pour détecter les erreurs ? Vous devrez corrompre manuellement l'état (débogage avancé), mais en production, les rappels intercepteront :
- Échec de l'outil Shopping Agent → Blocage du rappel du marchand : "Erreur : Impossible de créer le panier…"
- 2 heures s'écoulent → Blocage du rappel du marchand : "Erreur : L'intention a expiré..."
- Expiration du panier → Les rappels d'identifiants bloquent : "Erreur : Le panier a expiré (limite de 15 min)..."
Ces cas extrêmes sont désormais appliqués au niveau de l'architecture par vos rappels de validation.
Ce que vous venez de créer
Vous avez orchestré trois agents spécialisés dans un système fiable et fluide avec validation architecturale.
Étape suivante
Vous avez terminé le cœur technique de la création d'agents fiables :
Vous avez créé un système fiable complet en local qui applique la chaîne d'identifiants. Nous allons maintenant le rendre accessible aux utilisateurs réels grâce au déploiement en production et activer le journal d'audit qui rend le module 9 possible.
Déployons votre agent renforcé sur Google Cloud.
8. Déploiement

Votre système de don fiable est désormais complet avec trois agents spécialisés travaillant localement :
mais il ne s'exécute que sur votre ordinateur de développement. Pour que ce système soit utile aux utilisateurs réels et pour capturer les journaux de responsabilité qui prouvent la fiabilité, vous devez le déployer en production.
Ce module vous explique comment déployer votre agent sur Google Cloud avec l'observabilité activée dès le premier jour. L'indicateur --trace_to_cloud que vous utiliserez lors du déploiement est ce qui rend possible la chaîne de responsabilité du module 9.
Comprendre les options de déploiement
L'ADK est compatible avec plusieurs cibles de déploiement. Chacun présente des caractéristiques différentes en termes de complexité, de gestion des sessions, de mise à l'échelle et de coût :
Facteur | Local ( | Agent Engine | Cloud Run |
Complexité | Minimale | Faible | Moyenne |
Persistance de session | En mémoire uniquement (perdu au redémarrage) | Géré par Vertex AI (automatique) | Cloud SQL (PostgreSQL) ou en mémoire |
Infrastructure | Aucun (machine de développement uniquement) | Entièrement géré | Conteneur + base de données facultative |
Démarrage à froid | N/A | 100 à 500 ms | 100 à 2 000 ms |
Scaling | Instance unique | Automatique | Automatique (à zéro) |
Modèle de coût | Sans frais (calcul local) | Basé sur le calcul | Basée sur les requêtes + niveau sans frais |
Assistance pour l'UI | Oui (intégré) | Non (API uniquement) | Oui (avec l'indicateur |
Configurer l'observabilité | Lecteur de traces local | Automatique avec | Nécessite l'indicateur |
Recommandée pour | Développement et tests | Agents de production | Agents de production |
Recommandation : Pour ce système de dons fiable, nous vous recommandons d'utiliser Agent Engine comme déploiement de production principal, car il offre les avantages suivants :
- Infrastructure entièrement gérée (aucun conteneur à gérer)
- Persistance de session intégrée via
VertexAiSessionService - Scaling automatique sans démarrages à froid
- Déploiement simplifié (aucune connaissance de Docker requise)
- Intégration native à Cloud Trace
Option supplémentaire : Google Kubernetes Engine (GKE)
Pour les utilisateurs avancés qui ont besoin d'un contrôle au niveau de Kubernetes, d'une mise en réseau personnalisée ou d'une orchestration multiservice, le déploiement GKE est disponible. Cette option offre une flexibilité maximale, mais nécessite une expertise opérationnelle plus poussée (gestion des clusters, fichiers manifestes, comptes de service).
Le déploiement de GKE n'est pas abordé dans cet atelier, mais il est entièrement documenté dans le Guide de déploiement ADK GKE.
Prérequis
1. Configuration du projet Google Cloud
Vous devez disposer d'un projet Google Cloud pour lequel la facturation est activée. Si vous n'en avez pas :
- Créer un projet : Google Cloud Console
- Activer la facturation : Activer la facturation
- Notez votre ID de projet (et non le nom ni le numéro du projet).
2. Réauthentification (facultatif)
Authentifiez-vous avec Google Cloud :
gcloud auth application-default login
gcloud config set project YOUR_PROJECT_ID
Remplacez YOUR_PROJECT_ID par l'ID de votre projet Google Cloud.
Vérifiez votre authentification :
gcloud config get-value project
# Should output: YOUR_PROJECT_ID
3. Variables d'environnement
Utilisez ces commandes pour remplir automatiquement votre fichier .env :
# Get your current Project ID
PROJECT_ID=$(gcloud config get-value project)
STAGING_BUCKET_VALUE="gs://${PROJECT_ID}-staging"
ENV_FILE=".env"
# Check if STAGING_BUCKET is already set in the .env file
if grep -q "^STAGING_BUCKET=" "${ENV_FILE}"; then
# If it exists, replace the line
# The sed command finds the line starting with STAGING_BUCKET= and replaces the entire line.
# Using | as a delimiter to avoid issues with slashes in the bucket name.
sed -i "s|^STAGING_BUCKET=.*|STAGING_BUCKET=${STAGING_BUCKET_VALUE}|" "${ENV_FILE}"
echo "Updated STAGING_BUCKET in ${ENV_FILE}"
else
# If it doesn't exist, add it to the end of the file
echo "STAGING_BUCKET=${STAGING_BUCKET_VALUE}" >> "${ENV_FILE}"
echo "Added STAGING_BUCKET to ${ENV_FILE}"
fi
# Verify it was added or updated correctly
echo "Current STAGING_BUCKET setting:"
grep "^STAGING_BUCKET=" "${ENV_FILE}"
Vous devriez obtenir le résultat suivant :
STAGING_BUCKET=gs://your-actual-project-id-staging
Remarques importantes :
- Remplacez
YOUR_PROJECT_IDpar l'ID de votre projet (ou utilisez les commandes ci-dessus). - Pour
GOOGLE_CLOUD_LOCATION, utilisez une région disponible. - Le bucket de préproduction sera créé automatiquement s'il n'existe pas lorsque vous exécuterez le script de déploiement.
4. Activer les API requises
Le processus de déploiement nécessite l'activation de plusieurs API Google Cloud. Exécutez la commande suivante pour les activer :
gcloud services enable \
aiplatform.googleapis.com \
storage.googleapis.com \
cloudbuild.googleapis.com \
cloudtrace.googleapis.com \
compute.googleapis.com
Cette commande active les éléments suivants :
- API AI Platform : pour les modèles Agent Engine et Vertex AI
- API Cloud Storage : pour le bucket de préproduction
- API Cloud Build : pour la création de conteneurs (Cloud Run)
- API Cloud Trace : pour l'observabilité et les journaux d'audit
- API Compute Engine : pour la gestion des comptes de service
Étape 1 : Comprendre l'infrastructure de déploiement
Votre projet inclut un script de déploiement unifié (deploy.sh) qui gère tous les modes de déploiement.
👉 Examinez le script de déploiement (facultatif) :
cat deploy.sh
Le script propose trois modes de déploiement :
./deploy.sh local: exécutez le serveur localement avec le stockage en mémoire../deploy.sh agent-engine: déployer sur Vertex AI Agent Engine (recommandé)./deploy.sh cloud-run: déployer sur Cloud Run avec une UI facultative
Fonctionnement :
Pour le déploiement d'Agent Engine, le script exécute les opérations suivantes :
adk deploy agent_engine \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
--staging_bucket=$STAGING_BUCKET \
--display_name="Charity Advisor" \
--trace_to_cloud \
charity_advisor
Pour le déploiement Cloud Run, il exécute les opérations suivantes :
adk deploy cloud_run \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
--service_name="charity-advisor" \
--app_name="charity_advisor" \
--with_ui \
--trace_to_cloud \
charity_advisor
L'indicateur --trace_to_cloud est essentiel pour les deux types de déploiement. Il permet l'intégration de Cloud Trace pour la chaîne de responsabilité que vous explorerez dans le module 9.
Étape 2 : Préparez le wrapper Agent Engine
Agent Engine nécessite un point d'entrée spécifique qui encapsule votre agent pour l'environnement d'exécution géré. Ce fichier a été créé pour vous.
👉 Vérifier
charity_advisor/agent_engine_app.py
:
"""Agent Engine application wrapper.
This file prepares the Charity Advisor agent for deployment to Vertex AI Agent Engine.
"""
from vertexai import agent_engines
from .agent import root_agent
# Wrap the agent in an AdkApp object for Agent Engine deployment
app = agent_engines.AdkApp(
agent=root_agent,
enable_tracing=True, # Enables Cloud Trace integration automatically
)
Pourquoi ce fichier est-il nécessaire ?
- Agent Engine exige que l'agent soit encapsulé dans un objet
AdkApp. - Le paramètre
enable_tracing=Trueactive automatiquement l'intégration de Cloud Trace. - Ce wrapper est référencé par l'ADK CLI lors du déploiement.
- Il configure
VertexAiSessionServicepour la persistance automatique des sessions.
Étape 3 : Déployer sur Agent Engine (RECOMMANDÉ)
Agent Engine est le déploiement en production recommandé pour votre système de dons fiable, car il fournit une infrastructure entièrement gérée avec persistance de session intégrée.
Exécuter le déploiement
Depuis la racine de votre projet :
chmod +x deploy.sh
./deploy.sh agent-engine
Phases de déploiement
Regardez le script exécuter ces phases :
Phase 1: API Enablement
✓ aiplatform.googleapis.com
✓ storage.googleapis.com
✓ cloudbuild.googleapis.com
✓ cloudtrace.googleapis.com
✓ compute.googleapis.com
Phase 2: IAM Setup
✓ Getting project number
✓ Granting Storage Object Admin
✓ Granting Vertex AI User
✓ Granting Cloud Trace Agent
Phase 3: Staging Bucket
✓ Creating gs://your-project-id-staging (if needed)
✓ Setting permissions
Phase 4: Validation
✓ Checking agent.py exists
✓ Verifying root_agent defined
✓ Checking agent_engine_app.py exists
✓ Validating requirements.txt
Phase 5: Build & Deploy
✓ Packaging agent code
✓ Uploading to staging bucket
✓ Creating Agent Engine instance
✓ Configuring session persistence
✓ Setting up Cloud Trace integration
✓ Running health checks
Ce processus prend 5 à 10 minutes, car il consiste à empaqueter l'agent et à le déployer sur l'infrastructure Vertex AI.
Enregistrer votre ID Agent Engine
Une fois le déploiement réussi :
✅ Agent Engine created successfully!
Agent Engine ID: 7917477678498709504
Resource Name: projects/123456789/locations/us-central1/reasoningEngines/7917477678498709504
Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...
⚠️ IMPORTANT: Save the Agent Engine ID from the output above
Add it to your .env file as:
AGENT_ENGINE_ID=7917477678498709504
This ID is required for:
- Testing the deployed agent
- Updating the deployment later
- Accessing logs and traces
Mettez à jour votre fichier .env immédiatement :
echo "AGENT_ENGINE_ID=7917477678498709504" >> .env
Ce qui a été déployé
Votre déploiement Agent Engine inclut désormais les éléments suivants :
✅ Les trois agents (Shopping, Merchant, Credentials) s'exécutent dans le runtime géré
✅ Logique de chaîne d'identifiants complète (intention → panier → mandats de paiement)
✅ Mécanisme de consentement de l'utilisateur avec workflow de confirmation
✅ Persistance de session automatique via VertexAiSessionService
✅ Infrastructure à autoscaling gérée par Google
✅ Intégration de Cloud Trace pour une observabilité complète
Étape 4 : Tester votre agent déployé
Mettre à jour votre environnement
Vérifiez que votre .env inclut l'ID Agent Engine :
AGENT_ENGINE_ID=7917477678498709504 # From deployment output
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://your-project-id-staging
Exécuter le script de test
Votre projet inclut un script de test spécifique aux déploiements Agent Engine.
👉 Exécutez le test :
python scripts/test_deployed_agent.py
Résultat attendu
Testing Agent Engine deployment...
Project: your-project-id
Location: us-central1
Agent Engine ID: 7917477678498709504
Endpoint: https://us-central1-aiplatform.googleapis.com/v1/...
Creating session...
✓ Session created: 4857885913439920384
Sending donation query...
✓ Response received:
Event 1: I'll help you donate $50 to a children's education charity...
Event 2: Here are some highly-rated children's education charities...
Event 3: Which charity would you like to support?...
✅ Test completed successfully!
Session ID: 4857885913439920384
This donation generated a trace in Cloud Trace.
View it in Module 9: Observability
To view traces:
https://console.cloud.google.com/traces/list?project=your-project-id
Checklist de validation
Après les tests, vérifiez les points suivants :
✅ L'agent répond aux requêtes
✅ Les trois agents s'exécutent séquentiellement (Shopping → Marchand → Identifiants)
✅ Le mécanisme de consentement s'active (confirmation requise)
✅ La session persiste d'une requête à l'autre
✅ Aucune erreur d'authentification
✅ Aucun délai de connexion dépassé
Si vous rencontrez des erreurs :
- Vérifier que vos variables d'environnement sont correctement définies
- Vérifiez que les API sont activées :
gcloud services list --enabled - Consulter les journaux Agent Engine dans la console Vertex AI
- Vérifiez que le fichier
agent_engine_app.pyse trouve dans votre dossiercharity_advisor.
Étape 5 : Déployer sur Cloud Run (facultatif)
Bien qu'Agent Engine soit recommandé pour un déploiement de production simplifié, Cloud Run offre plus de contrôle et est compatible avec l'interface utilisateur Web ADK. Cette rubrique est facultative.
Quand utiliser Cloud Run ?
Choisissez Cloud Run si vous avez besoin des éléments suivants :
- Interface utilisateur Web de l'ADK pour l'interaction utilisateur
- Contrôle total sur l'environnement de conteneur
- Configurations de base de données personnalisées
- Intégration aux services Cloud Run existants
Exécuter le déploiement
chmod +x deploy.sh
./deploy.sh cloud-run
Quelles sont les différences ?
Le script va automatiquement :
- Créer un conteneur Docker avec le code de votre agent
- Créer une base de données PostgreSQL Cloud SQL (si nécessaire)
- Configurer la connexion à la base de données
- Déployer avec l'interface utilisateur Web ADK activée
Le déploiement prend 10 à 15 minutes en raison du provisionnement de Cloud SQL.
Gestion des sessions :
- Utilisation de
DatabaseSessionServiceau lieu deVertexAiSessionService - Nécessite des identifiants de base de données dans
.env(ou générés automatiquement) - L'état persiste dans la base de données PostgreSQL
Assistance pour l'UI :
- Interface utilisateur Web disponible à l'adresse :
https://charity-advisor-xyz.a.run.app
Tester le déploiement Cloud Run
Si vous avez déployé sur Cloud Run avec --with_ui, vous pouvez effectuer des tests directement dans votre navigateur :
- Accédez à l'URL de votre service (fournie dans le résultat du déploiement).
- L'interface Web de l'ADK s'affiche. Sélectionnez votre agent dans le menu déroulant.
- Effectuer un don test :
I want to donate $50 to a children's education charity
- Observez le flux d'exécution :
- ShoppingAgent trouve des associations caritatives et enregistre votre intention
- MerchantAgent crée le mandat du panier
- CredentialsProvider crée un mandat de paiement et demande une confirmation
- Une fois que vous avez confirmé, le paiement est traité.
- Vérifiez que la réponse inclut les éléments suivants :
- Recommandations d'associations caritatives
- Demande de confirmation
- Message de confirmation après approbation
Dépannage
Problèmes courants
Problème : ERROR: GOOGLE_CLOUD_PROJECT is not set
Solution : Assurez-vous que votre fichier .env contient l'ID de projet approprié :
GOOGLE_CLOUD_PROJECT=your-actual-project-id
Problème : Bucket de préproduction non créé automatiquement
Solution : Le script doit créer le bucket automatiquement. Si ce n'est pas le cas, créez-le manuellement :
gsutil mb -p $GOOGLE_CLOUD_PROJECT -l $GOOGLE_CLOUD_LOCATION $STAGING_BUCKET
Résumé
Vous avez :
✅ Vous avez compris l'infrastructure de déploiement fournie par deploy.sh
. ✅ Vous avez examiné la configuration du wrapper Agent Engine.
✅ Vous avez déployé votre système de dons fiable sur Agent Engine (recommandé).
✅ Vous avez activé l'intégration de Cloud Trace avec --trace_to_cloud
. ✅ Vous avez vérifié que l'agent est accessible et fonctionnel.
✅ Vous avez créé la base des journaux d'audit dans le module 9.
Dans le prochain module, vous verrez exactement ce que cet indicateur déverrouille : une visibilité complète sur chaque don, chaque moment de consentement et chaque étape de la chaîne d'identifiants.
9. Observabilité


Dans le module 1, vous avez découvert un problème fondamental : lorsqu'un agent d'IA gère de l'argent, comment prouver ce qu'il s'est passé ?
Un utilisateur peut revendiquer :
- "Je n'ai jamais choisi cette association caritative !"
- "Je n'ai pas autorisé ce paiement !"
- "Le système m'a débité sans mon consentement !"
Dans un système d'IA à boîte noire traditionnel, vous n'auriez aucun moyen de prouver le contraire. Mais votre système de dons fiable est différent. Dans le module 8, vous avez déployé avec l'indicateur --trace_to_cloud, ce qui signifie que chaque don crée désormais une piste d'audit complète et inviolable dans Cloud Trace.
Ce module vous apprend à lire ces traces et à les utiliser comme preuves. Vous apprendrez à :
- Accéder à l'explorateur Cloud Trace pour trouver les traces de production
- Lire la vue en cascade pour comprendre le flux d'exécution
- Trouver la chaîne d'identifiants (Intent → Cart → Payment mandates)
- Identifier les moments de consentement avec des preuves d'horodatage
- Utiliser les traces pour résoudre les litiges
- Exporter des traces pour la conformité et les audits
C'est ce qui distingue les systèmes fiables de ceux qui sont performants, mais opaques : la capacité à prouver ce qui s'est passé avec une précision médico-légale.
Comprendre les traces et les spans
Avant d'afficher les traces dans Cloud Trace, vous devez comprendre ce que vous regardez.
Qu'est-ce qu'une trace ?
Une trace correspond à la chronologie complète du traitement d'une seule requête par votre agent. Il capture tout, depuis le moment où un utilisateur envoie une requête jusqu'à la réponse finale.
Chaque trace indique :
- Durée totale de la demande
- Toutes les opérations exécutées
- Relation entre les opérations (relations parent-enfant)
- Début et fin de chaque opération
- État de réussite ou d'échec
Pour votre agent caritatif : une trace correspond à un parcours de don complet, de "Je souhaite faire un don" à "Paiement réussi".
Qu'est-ce qu'un span ?
Une span représente une unité de travail unique dans une trace. Considérez les spans comme les blocs de construction d'une trace.
Types de plages courants dans votre système de dons :
Type de plage | Ce que cela représente | Exemple |
| Exécution d'un agent |
|
| Requête adressée à un modèle de langage |
|
| Exécution de la fonction d'outil |
|
| Lecture à partir de la mémoire de session | Récupérer |
| Écrire dans la mémoire de session | Stocker |
Chaque span contient les éléments suivants :
- Nom : opération représentée
- Durée (heure de début → heure de fin)
- Attributs : métadonnées telles que les entrées d'outil, les réponses du modèle et le nombre de jetons
- État : succès (
OK) ou erreur (ERROR) - Relations parent-enfant : quelles opérations ont déclenché quelles opérations
Comment les spans forment une trace
Les portées s'imbriquent les unes dans les autres pour montrer la causalité :
Root Span: CharityAdvisor.run (entire request)
└─ Child: DonationPipeline.run (sequential workflow)
├─ Child: ShoppingAgent.run
│ ├─ Grandchild: call_llm (Gemini processes charity search)
│ ├─ Grandchild: execute_tool (find_charities)
│ └─ Grandchild: execute_tool (save_user_choice)
├─ Child: MerchantAgent.run
│ ├─ Grandchild: call_llm (Gemini generates cart)
│ └─ Grandchild: execute_tool (create_cart_mandate)
└─ Child: CredentialsProvider.run
├─ Grandchild: call_llm (Gemini processes payment)
└─ Grandchild: execute_tool (create_payment_mandate) [CONSENT!]
Cette hiérarchie indique exactement ce qui s'est passé et dans quel ordre. Vous pouvez voir que le mandat de paiement a été créé après le mandat de panier, qui a été créé après que l'utilisateur a sélectionné une association caritative.
Étape 1 : Accéder à l'explorateur Cloud Trace
Affichons maintenant les traces réelles de votre agent déployé.
Accéder à Cloud Trace
- Ouvrez la console Google Cloud : console.cloud.google.com.
- Sélectionnez votre projet dans le menu déroulant en haut de la page (il devrait être présélectionné si vous y avez déjà travaillé).
- Accédez à l'explorateur Cloud Trace :
- Dans la barre latérale de gauche, faites défiler la page jusqu'à la section Observability (Observabilité).
- Cliquez sur Trace.
- Vous pouvez également utiliser le lien direct : console.cloud.google.com/traces/list.
Ce que vous voyez
L'explorateur de traces affiche la liste de toutes les traces de votre projet :
Colonne | Informations incluses |
Demande | Méthode et point de terminaison HTTP (pour les requêtes d'API) |
Heure de début | Date de début de la demande |
Latence | Durée totale de la demande |
Spans | Nombre d'opérations dans la trace |
Chaque ligne représente une requête complète adressée à votre agent déployé.
Générer des traces de test (si nécessaire)
Si aucune trace ne s'affiche, il est possible que la liste soit vide pour les raisons suivantes :
- Aucune demande n'a encore été envoyée à votre agent déployé
- L'affichage des traces prend une à deux minutes après une requête.
Générez une trace de test :
Si vous avez déployé sur Cloud Run avec l'interface utilisateur, accédez à l'URL de votre service et effectuez un don dans le navigateur.
Si vous avez déployé sur Agent Engine, exécutez le script de test du module 8 :
python scripts/test_deployed_agent.py
Patientez une à deux minutes, puis actualisez la page de l'explorateur Cloud Trace. Vous devriez maintenant voir des traces.
Filtrer les traces
Utilisez les options de filtrage en haut de l'écran pour trouver des traces spécifiques :
- Période : si nécessaire, remplacez "Dernière heure" par "Dernières 24 heures".
- Latence min./Latence max. : filtrez les requêtes lentes.
- Filtre de requête : recherchez des opérations spécifiques (par exemple, "DonationPipeline")
Pour ce module, concentrez-vous sur les traces avec des durées plus longues (> 5 secondes), car elles représentent des parcours de don complets avec les trois agents en cours d'exécution.
Étape 2 : Examiner un parcours de don complet
Cliquez sur une trace dans la liste pour ouvrir la vue en cascade. C'est là que vous passerez le plus de temps à analyser le comportement de l'agent.
Comprendre la vue en cascade
La vue en cascade est un diagramme de Gantt qui affiche la chronologie d'exécution complète :
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Timeline (horizontal = time) →
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invocation ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.2s
agent_run: CharityAdvisor ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 8.1s
agent_run: DonationPipeline ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 7.9s
agent_run: ShoppingAgent ▓▓▓▓▓▓ 2.1s
call_llm: gemini-2.5-flash ▓▓▓▓ 1.2s
execute_tool: find_charities ▓▓ 0.5s
execute_tool: save_user_choice ▓ 0.3s
agent_run: MerchantAgent ▓▓▓ 1.8s
call_llm: gemini-2.5-flash ▓▓ 0.9s
execute_tool: create_cart_mandate ▓ 0.7s
agent_run: CredentialsProvider ▓▓▓▓▓▓▓▓ 4.0s
call_llm: gemini-2.5-flash ▓▓ 0.8s
execute_tool: create_payment_mandate ▓▓▓▓▓ 3.0s [CONSENT]
Lire le graphique
Chaque barre représente une étendue :
- Position horizontale : début de l'incident
- Durée : durée de l'opération
- Retrait : affiche les relations parent-enfant.
- Couleur : généralement bleue pour un état normal et rouge en cas d'erreur
Principales observations de cet exemple de trace :
✅ Durée totale : 8,2 secondes
✅ Exécution séquentielle : ShoppingAgent terminé avant le début de MerchantAgent
✅ MerchantAgent terminé
before
CredentialsProvider démarré
✅ Le consentement était l'opération la plus longue : 3 secondes pour create_payment_mandate (car il a attendu la confirmation de l'utilisateur)
✅ Les appels LLM sont visibles : chaque agent a effectué une requête Gemini
✅ Les appels d'outils sont capturés : les six outils ont été exécutés avec succès.
Ce graphique vous montre immédiatement où le temps est passé et dans quel ordre les opérations ont été exécutées.
Cliquez sur un segment pour afficher les détails
Cliquez sur l'étendue invocation (l'étendue racine en haut de l'écran). Dans le panneau de droite, vous trouverez des attributs détaillés :
{
"http.method": "POST",
"http.status_code": 200,
"http.url": "https://charity-advisor-xyz.a.run.app/api/run",
"user_id": "test_user_123",
"session_id": "4857885913439920384",
"trace_id": "a1b2c3d4e5f6...",
"span_id": "1234567890abcdef"
}
Ces attributs fournissent un contexte sur l'ensemble de la requête.
Étape 3 : Recherchez la chaîne d'identifiants
Votre système fiable utilise une chaîne d'identifiants pour prouver l'autorisation à chaque étape :
IntentMandate (User chose charity)
↓
CartMandate (Merchant created cart, signed IntentMandate)
↓
PaymentMandate (Payment provider created payment, signed CartMandate)
Recherchons chaque mandat dans la trace.
Trouver l'IntentMandate
Cliquez sur l'étendue execute_tool: save_user_choice (sous ShoppingAgent).
Dans le panneau "Attributs", vous verrez les éléments suivants :
{
"tool.name": "save_user_choice",
"tool.input.charity_name": "Save the Children",
"tool.input.amount": 50,
"tool.output.status": "success",
"tool.output.intent_mandate": {
"charity_name": "Save the Children",
"amount": 50,
"timestamp": "2024-11-08T15:30:12.345Z",
"signature": "a3f7b9c1d2e4..."
}
}
Cela prouve :
- ✅ L'utilisateur a sélectionné "Save the Children".
- ✅ Le montant était de 50 $
- ✅ Votre choix a été enregistré à 15:30:12 UTC
- ✅ La signature a été générée (en production, elle serait cryptographique).
IntentMandate est désormais dans l'état de session et disponible pour les agents suivants.
Trouver le CartMandate
Cliquez sur l'étendue execute_tool: create_cart_mandate (sous MerchantAgent).
Dans le panneau "Attributs" :
{
"tool.name": "create_cart_mandate",
"tool.input.intent_mandate": {
"charity_name": "Save the Children",
"amount": 50,
"signature": "a3f7b9c1d2e4..."
},
"tool.output.status": "success",
"tool.output.cart_mandate": {
"cart_id": "cart_7893",
"intent_signature": "a3f7b9c1d2e4...",
"cart_signature": "e8f2a9b3c7d1...",
"timestamp": "2024-11-08T15:30:14.789Z"
}
}
Cela prouve :
- ✅ MerchantAgent a reçu IntentMandate (l'entrée le montre)
- ✅ Panier créé avec l'ID "cart_7893"
- ✅ La signature du panier fait référence à la signature IntentMandate (icône de chaîne).
- ✅ Créé à 15:30:14 UTC (2,4 secondes après l'intention)
CartMandate fait désormais référence à IntentMandate, formant ainsi la chaîne.
Trouver le PaymentMandate
Cliquez sur l'étendue execute_tool: create_payment_mandate (sous CredentialsProvider).
Dans le panneau "Attributs" :
{
"tool.name": "create_payment_mandate",
"tool.input.cart_mandate": {
"cart_id": "cart_7893",
"intent_signature": "a3f7b9c1d2e4...",
"cart_signature": "e8f2a9b3c7d1..."
},
"tool.confirmation_required": true,
"tool.confirmation_timestamp": "2024-11-08T15:30:17.891Z",
"tool.user_response": "CONFIRMED",
"tool.wait_duration_ms": 29168,
"tool.output.status": "success",
"tool.output.payment_mandate": {
"payment_id": "pay_9821",
"cart_signature": "e8f2a9b3c7d1...",
"payment_signature": "b4c9e2a7f8d3...",
"timestamp": "2024-11-08T15:30:47.059Z"
}
}
Cela prouve la chaîne complète :
- ✅ CredentialsProvider a reçu CartMandate (l'entrée le montre)
- ✅ La référence de paiement fait référence à la signature CartMandate (icône en forme de chaîne).
- ✅ Une confirmation était requise (
confirmation_required: true) - ✅ Utilisateur confirmé à 15:30:17 UTC
- ✅ Le système a attendu 29,2 secondes la décision de l'utilisateur.
- ✅ Paiement créé après confirmation (code temporel : 15:30:47)
Visualiser la chaîne
La trace prouve que la chaîne d'identifiants s'est exécutée correctement :
15:30:12 UTC → IntentMandate created (signature: a3f7...)
↓
15:30:14 UTC → CartMandate created (references: a3f7...)
↓
15:30:17 UTC → User consent requested
↓
15:30:47 UTC → PaymentMandate created (references: e8f2...)
Chaque mandat fait référence à la signature du précédent. Il s'agit d'une preuve d'inviolabilité. Vous pouvez vérifier la chaîne en vous assurant que les signatures correspondent.
Étape 4 : Analyser les performances et les goulots d'étranglement
Cloud Trace ne se contente pas de prouver ce qui s'est passé, il vous montre où le temps est passé afin que vous puissiez optimiser.
Identifier le chemin critique
Dans la vue en cascade, recherchez les durées les plus longues dans la pile verticale. Ils représentent vos goulots d'étranglement en termes de performances.
Dans notre exemple de trace :
Total: 8.2 seconds
Breakdown:
- ShoppingAgent: 2.1s (26%)
- MerchantAgent: 1.8s (22%)
- CredentialsProvider: 4.0s (49%) ← Bottleneck
- Other overhead: 0.3s (3%)
Insight critique : CredentialsProvider représente 49 % du temps total. Pourquoi ?
Explorez l'étendue CredentialsProvider :
CredentialsProvider: 4.0s
- call_llm: 0.8s (20%)
- create_payment_mandate: 3.0s (75%) ← User consent wait
- Other: 0.2s (5%)
Le délai de 3 secondes est normal et souhaitable : il correspond au temps de réflexion de l'utilisateur avant de confirmer. Il ne s'agit pas d'un problème de performances, mais d'une preuve de consentement réfléchi.
Suivre les coûts des LLM
Cliquez sur une étendue call_llm pour afficher l'utilisation des jetons :
{
"llm.model": "gemini-2.5-flash",
"llm.usage.prompt_tokens": 487,
"llm.usage.completion_tokens": 156,
"llm.usage.total_tokens": 643,
"llm.response_time_ms": 1243
}
Utilisez-la pour :
- Suivre le coût par requête (jetons × tarif du modèle)
- Identifier les requêtes inutilement longues
- Comparer les performances des modèles (Flash et Pro)
- Optimiser la latence par rapport à la qualité
Exemple de calcul :
Gemini 2.5 Flash pricing (as of Nov 2024):
Input: $0.075 per 1M tokens
Output: $0.30 per 1M tokens
This request:
Input: 487 tokens × $0.075 / 1M = $0.000037
Output: 156 tokens × $0.30 / 1M = $0.000047
Total: = $0.000084 (~$0.00008)
For 10,000 donations/month:
10,000 × 3 agents × $0.00008 = $2.40/month in LLM costs
Cette visibilité précise vous aide à prendre des décisions basées sur les données concernant la sélection de modèles.
Comparer les traces
Filtrez plusieurs traces et comparez les durées :
Trace 1: 8.2s (with consent wait: 3.0s)
Trace 2: 12.5s (with consent wait: 7.8s) ← User took longer
Trace 3: 5.1s (with consent wait: 0.2s) ← User clicked fast
Trace 4: 6.3s (with consent wait: 1.5s)
Insight : La plupart des variations proviennent du temps de décision des utilisateurs, et non des performances du système. L'exécution de l'agent principal (sans le consentement) est cohérente et dure environ cinq secondes.
Cela signifie que le système fonctionne de manière fiable.
Pour les systèmes de production, configurez des alertes afin de détecter les problèmes avant que les utilisateurs ne s'en plaignent.
Alerte sur les taux d'erreur élevés
Créez une alerte lorsque plus de 5 % des traces contiennent des erreurs :
- Accédez à Cloud Monitoring.
- Cliquez sur Alertes → Créer une règle.
- Configurer :
Resource: Cloud Trace Span Metric: Span error count Condition: Rate > 5% over 5 minutes Notification: Email your-team@example.com
Alerte de latence élevée
Créez une alerte lorsque la latence P95 dépasse 15 secondes :
Resource: Cloud Trace
Metric: Span duration (95th percentile)
Condition: > 15000ms for 5 minutes
Notification: PagerDuty
Cela permet de détecter la dégradation des performances avant qu'elle n'ait un impact sur l'expérience utilisateur.
Alerte sur l'absence de consentement
Créez une alerte si un paiement est traité sans confirmation :
Resource: Cloud Trace Span
Filter: tool.name="create_payment_mandate" AND tool.confirmation_required!=true
Condition: Any match
Notification: Critical alert to security team
Il s'agit d'un détecteur de non-respect des règles de sécurité. S'il se déclenche, cela signifie que votre mécanisme de consentement présente un problème grave.
Ce que vous avez appris
Grâce à Cloud Trace, vous savez désormais comment :
✅ Parcourir l'explorateur Cloud Trace pour trouver les traces de production
✅ Lire les vues en cascade pour voir le flux d'exécution complet
✅ Tracer la chaîne d'identifiants via IntentMandate → CartMandate → PaymentMandate ✅ Utiliser les traces comme preuve pour résoudre les litiges
✅ Analyser les performances pour identifier les goulots d'étranglement
✅ Suivre les coûts des LLM de manière précise
L'impact de cette fonctionnalité
Comparons deux systèmes traitant la même réclamation "Je n'ai jamais autorisé cela !" :
Système sans observabilité
User: "I never authorized that $50 donation!"
You: "Our logs show the transaction completed successfully."
User: "But I didn't approve it!"
You: "The system requires confirmation before processing."
User: "I never saw any confirmation!"
You: "..." [no way to prove what happened]
Result: Refund issued, trust lost, user never returns.
Système avec Cloud Trace
User: "I never authorized that $50 donation!"
You: "Let me pull up the trace from your session..."
[Shows waterfall with consent span]
You: "Here's the evidence:
- 15:30:17 UTC: System asked for confirmation
- Message shown: 'You are about to donate $50...'
- 15:30:47 UTC: You clicked 'CONFIRM'
- Wait time: 29.2 seconds
The system waited almost 30 seconds for your decision.
Here's the exact timestamp of your confirmation."
User: "Oh... I remember now. My mistake. Sorry!"
Result: Trust preserved, no refund needed, user continues using service.
C'est tout l'intérêt des journaux d'audit. Vous passez de "faites-nous confiance" à "laissez-nous vous montrer exactement ce qui s'est passé".
Étape suivante
Vous avez terminé le cœur technique de la création d'agents fiables :
✅ Modules 1 à 6 : conçu une architecture fiable (rôles, identifiants, consentement)
✅ Module 7 : orchestré des workflows complexes (SequentialAgent)
✅ Module 8 : déployé avec l'observabilité activée
✅ Module 9 : appris à lire et à utiliser les journaux de responsabilité
L'architecture que vous avez créée (séparation des rôles, chaînes d'identifiants, mécanismes de consentement, observabilité complète) est directement transférée aux systèmes de production qui gèrent de l'argent réel, des données réelles et des conséquences réelles.
10. Votre parcours
Ce que vous avez créé
Vous avez commencé cet atelier par une question : "Comment créer des agents d'IA auxquels je peux réellement confier de l'argent ?"
Vous avez maintenant la réponse.
Où vous en étiez (module 3) :
simple_agent = Agent(
model="gemini-2.5-flash",
instruction="Find charities and donate",
tools=[google_search]
)
Où en êtes-vous (module 10) ?
- ✅ Trois agents spécialisés avec séparation des rôles
- ✅ Trois identifiants vérifiables (intention → panier → mandats de paiement)
- ✅ Chaîne d'identifiants complète avec validation de l'expiration à chaque étape
- ✅ Mécanisme de consentement explicite avec preuve d'horodatage
- ✅ Déploiement en production sur Agent Engine avec observabilité
- ✅ Journal complet des responsabilités dans Cloud Trace
- ✅ Preuves médico-légales pour la résolution des litiges
Atelier vs production : l'écart
Votre système présente l'architecture et les modèles corrects, mais utilise des simplifications pédagogiques qui doivent être mises à niveau pour l'argent réel et les utilisateurs réels.
Voici exactement ce qui a été simplifié et ce que la production exige :
Composant | Mise en œuvre de l'atelier | Exigences de production |
Signatures | Hachages SHA-256 ( | Véritables signatures cryptographiques utilisant PKI ou JWT avec des clés privées |
Traitement des paiements | Retours simulés (flag | Intégration avec des API de paiement réelles (Stripe, PayPal, Square) |
Authentification des utilisateurs | Confiance implicite (aucune connexion requise) | OAuth 2.0, WebAuthn ou gestion de session |
Gestion des secrets | Variables d'environnement dans le fichier | Google Secret Manager ou Cloud KMS avec chiffrement |
Base de données des organisations caritatives | Fichier JSON fictif avec neuf organisations caritatives | Intégration de l'API Live (recherche d'organismes exonérés d'impôt de l'IRS, API Charity Navigator) |
Gestion des erreurs | Bloc try-catch de base avec messages d'erreur | Logique de nouvelle tentative avec intervalle exponentiel entre les tentatives, disjoncteurs, files d'attente de lettres mortes |
Test | Validation manuelle via des scripts | Suite de tests unitaires/d'intégration/E2E complète avec CI/CD |
Persistance de session | En mémoire (local) ou automatique (Agent Engine) | Base de données de production avec sauvegardes et reprise après sinistre |
Limitation du débit | Aucun (environnement éducatif) | Limites de débit par utilisateur, limitation basée sur l'adresse IP, détection des utilisations abusives |
Principaux schémas d'architecture que vous avez maîtrisés
Les modèles que vous avez appris dans cet atelier sont des modèles de production. Ne doutez pas d'eux.
Séparation des rôles (principe 1 d'AP2)
Chaque agent a UNE tâche claire et ne voit QUE ce dont il a besoin. Si un agent est compromis, le pirate informatique ne peut pas accéder aux données des autres agents. Cela limite le rayon d'action.
Systèmes de production utilisant cette fonctionnalité : traitement des paiements, workflows de documents, chaînes d'approbation, formulaires à plusieurs étapes avec portes de validation.
Identifiants vérifiables (principe 2 de l'AP2)
Chaque identifiant a une date d'expiration, fait référence à l'identifiant précédent et nécessite une validation avant l'étape suivante. Cela crée une chaîne d'audit inviolable.
Valeur de production : preuve complète de ce qui s'est passé, quand et dans quel ordre. Essentiel pour la résolution des litiges et la conformité réglementaire.
Consentement explicite (principe 3 de l'AP2)
Code temporel prouvant que l'utilisateur a approuvé l'action. Ne peut pas être contesté.
Valeur de production : exigence légale pour les transactions financières. Protège à la fois l'utilisateur et l'entreprise.
Orchestration séquentielle (modèle ADK)
Applique l'ordre d'exécution correct. empêche de passer des étapes ; Garantit que chaque agent voit la sortie de l'agent précédent.
Valeur de production : idéale pour les systèmes avec humain dans la boucle où les utilisateurs s'attendent à des résultats immédiats. Il s'agit du bon modèle pour les parcours de dons, les processus de paiement et les chaînes d'approbation.
Observabilité complète (OpenTelemetry + Cloud Trace)
Chaque décision, appel d'outil, moment de consentement et transfert d'identifiants sont capturés automatiquement.
Valeur de production : éléments de preuve médico-légaux pour les litiges. Données d'optimisation des performances. Pistes d'audit de conformité. Déboguez les problèmes de production avec précision.
Ressources pour la formation continue
Documentation ADK :
AP2 et normes associées :
Services Google Cloud :
Nettoyer les ressources
Pour éviter que des frais ne vous soient facturés, supprimez votre déploiement :
Agent Engine : suivez les étapes de la documentation Agent Engine.
Cloud Run (si le service est déployé) :
gcloud run services delete charity-advisor \
--region=$GOOGLE_CLOUD_LOCATION
Buckets de stockage :
gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-staging
gsutil -m rm -r gs://$GOOGLE_CLOUD_PROJECT-artifacts
Votre parcours continue
Vous avez commencé par une question simple et avez élaboré une réponse complète. Vous avez maîtrisé les modèles de base pour les agents d'IA fiables. Ces schémas s'appliquent à tous les domaines dans lesquels les agents d'IA gèrent des opérations sensibles (transactions financières, décisions médicales, documents juridiques, opérations de la chaîne d'approvisionnement, etc.).
Les principes sont transférés. Le modèle de confiance fonctionne.
À présent, créez quelque chose de fiable ! ❤️
