Le cas d'usage et l'architecture
Le besoin
La boutique fictive « Atelier Son » vend des casques, des enceintes et des accessoires. Le service client reçoit toujours les mêmes demandes : « vous avez ce produit ? », « il est en stock ? », « je veux commander », « où est mon colis ? », et parfois « je veux être remboursé ! ».
Un agent convient ici parce que les demandes sont ouvertes et que l'ordre des étapes dépend du client. Mais un agent qui enregistre des commandes touche à de l'argent : on va donc encadrer chaque action sensible par du code, pas par une simple consigne dans le prompt.
Ce que l'agent a le droit de faire
| Action | Autorisée ? | Comment c'est garanti |
|---|---|---|
| Chercher un produit, donner un prix | oui | outil chercher_produits : le prix vient du catalogue, jamais du modèle |
| Vérifier le stock | oui | outil verifier_stock |
| Ajouter au panier (1 à 5 unités) | oui | outil ajouter_au_panier, plafond codé en Python |
| Enregistrer une commande | seulement après « je confirme » | commande en deux temps + callback avant outil |
| Suivre une livraison | oui | outil statut_livraison |
| Rembourser, gérer un litige | non | outil escalader_vers_humain |
| Recevoir un numéro de carte | non | callback avant modèle qui bloque le message |
Les briques ADK utilisées
Rappel : le function calling (appel de fonction) permet au modèle de répondre « appelle verifier_stock avec sku="CASQ-01" » au lieu de répondre du texte. Votre code exécute la fonction et renvoie le résultat au modèle.
| Brique ADK | Rôle dans ce lab |
|---|---|
Agent | le modèle + ses consignes (instruction) + ses outils |
| Outil fonction | une fonction Python ordinaire ; ADK lit son nom, sa docstring et ses types pour la décrire au modèle |
Runner (ici InMemoryRunner) | la boucle : envoie le message, exécute les outils demandés, renvoie les résultats, jusqu'à la réponse finale |
Session et state | la mémoire d'une conversation ; state est un dictionnaire (le panier y vit) |
| Callbacks | des fonctions appelées par ADK avant le modèle ou avant un outil, qui peuvent court-circuiter l'étape |
Le chemin d'une commande
sequenceDiagram
participant C as Client
participant A as Agent (Gemini)
participant T as Outils Python
participant S as État de session
C->>A: "Ajoutez 2 casques Nova"
A->>T: ajouter_au_panier(CASQ-01, 2)
T->>S: panier = {CASQ-01: 2}
C->>A: "Je veux commander"
A->>T: preparer_commande()
T->>S: commande_en_attente = récapitulatif
A-->>C: "Total 178 €. Écrivez « je confirme »"
C->>A: "Je confirme"
Note over A,S: le callback avant modèle voit « je confirme » et pose client_a_confirme = True
A->>T: confirmer_commande()
T-->>A: numéro CMD-1003
A-->>C: "Commande CMD-1003 enregistrée"
Pourquoi le prix d'un produit doit-il venir d'un outil plutôt que de la mémoire du modèle ?
Le modèle n'a jamais vu le catalogue fictif d'Atelier Son. Sans outil, il produirait un prix vraisemblable mais faux. L'outil est la seule source de vérité.
Pourquoi une commande en deux temps ?
Si l'agent avait un seul outil passer_commande, il pourrait l'appeler dès que le client dit « je veux commander », sans montrer le total. On sépare donc :
preparer_commande: calcule le récapitulatif et le range dans l'état, sans rien enregistrer ;confirmer_commande: enregistre, mais un callback refuse de l'exécuter tant que le client n'a pas écrit « je confirme ».
La consigne du prompt dit la même chose, mais c'est le code qui garantit la règle : un modèle peut oublier une consigne, un if ne l'oublie pas.
Quels éléments sont garantis par du code Python dans cet agent, et pas seulement par le prompt ? (plusieurs réponses)
Le plafond est dans ajouter_au_panier, la confirmation dans le callback avant outil, le blocage de carte dans le callback avant modèle. Le ton, lui, ne dépend que de l'instruction : c'est acceptable car une erreur de ton n'a pas de conséquence irréversible.
Exercice : délimiter un autre agent
Une pharmacie en ligne veut le même type d'assistant. Remplissez le tableau « Action / Autorisée ? / Comment c'est garanti » pour : conseiller un produit, vérifier le stock, commander un médicament sur ordonnance, donner une posologie, suivre un colis.
Voir la solution
| Action | Autorisée ? | Garantie |
|---|---|---|
| Conseiller un produit sans ordonnance | oui, avec mention « demandez conseil à votre pharmacien » | consigne + outil catalogue |
| Vérifier le stock | oui | outil |
| Commander sur ordonnance | non pour l'agent | l'outil de commande refuse les produits marqués « ordonnance » (champ dans le catalogue) et escalade |
| Donner une posologie | non | escalade vers un pharmacien ; un callback peut détecter les questions de dosage |
| Suivre un colis | oui | outil |
Le principe ne change pas : tout ce qui est risqué est refusé par une fonction, pas par une phrase du prompt.
Résultat obtenu
Premier échange du scénario réel python run.py (gemini-3.5-flash, 2026-10-15) : l'agent appelle l'outil avant de répondre et ne cite que les prix du catalogue.
CLIENT > Bonjour, vous avez des casques audio ?
[outil] chercher_produits({'requete': 'casque'})
AGENT > Bonjour ! Nous proposons actuellement deux modèles de casques audio : le Casque audio
sans fil Nova à 89 € (ref: CASQ-01) et le Casque audio filaire Studio à 49 € (ref: CASQ-02).
Souhaitez-vous en savoir plus sur l'un d'eux ou en ajouter un à votre panier ?Je sais faire
- Lister les actions d'un agent et dire lesquelles sont interdites ou conditionnelles
- Expliquer le rôle d'
Agent, d'un outil fonction, duRunner, de la session et des callbacks - Justifier une commande en deux temps
- Distinguer un garde-fou dans le prompt d'un garde-fou dans le code