Lesson 3 — Construire l'agent pas à pas

Graphique et contrôle des chiffres

5 min read

This content is not translated yet. Showing the original version.

Graphique et contrôle des chiffres

Où passe l'image ?

Quand le code matplotlib du modèle produit une figure, Gemini la renvoie comme une partie inline_data (image PNG). Avec BuiltInCodeExecutor, ADK 2.10 la range dans le service d'artefacts (un stockage de fichiers lié à la session) et remplace la partie par le texte Saved as artifact: <nom>.png.

flowchart LR
  MPL["matplotlib dans le bac à sable"] --> G["Gemini : partie inline_data image/png"]
  G --> P["Post-traitement ADK (BuiltInCodeExecutor)"]
  P -->|"save_artifact"| AS[("InMemoryArtifactService")]
  P -->|"texte"| T["'Saved as artifact: 20261015_163646.png'"]
  AS -->|"load_artifact dans run.py"| F["graphique_20261015_163646.png sur disque"]

Une artefact ADK est un fichier binaire versionné, rattaché à une application, un utilisateur et une session. InMemoryRunner fournit un InMemoryArtifactService ; en production on utilise par exemple GcsArtifactService (Cloud Storage).

files/run.py
# Les images produites par le bac à sable sont rangées par ADK dans le service d'artefacts.
for nom in await runner.artifact_service.list_artifact_keys(app_name="analyse", user_id="moi", session_id=s.id):
    image = await runner.artifact_service.load_artifact(app_name="analyse", user_id="moi",
                                                        session_id=s.id, filename=nom)
    open(f"graphique_{nom}", "wb").write(image.inline_data.data)
    print("Graphique enregistré :", f"graphique_{nom}")

Et on ignore ce texte technique quand on assemble le rapport :

files/run.py
if p.text and ev.is_final_response() and not p.text.startswith("Saved as artifact"):
    rapport += p.text

Avec BuiltInCodeExecutor et InMemoryRunner, où trouvez-vous le PNG du graphique après l'exécution ?

Voici le graphique réellement produit le 2026-10-15 :

Chiffre d'affaires mensuel par catégorie, graphique produit par l'agent

Contrôler les chiffres

Même avec l'exécution de code, le texte final est écrit par le modèle : il peut recopier un chiffre de travers. On calcule donc nous-mêmes la vérité terrain avec pandas et on vérifie que le rapport la cite.

files/run.py
def reference(chemin_csv: str) -> dict:
    """Les chiffres attendus, calculés par nous avec pandas : la « vérité terrain »."""
    d = pd.read_csv(chemin_csv)
    par_region = d.groupby("region").chiffre_affaires.sum()
    return {"ca_total": int(d.chiffre_affaires.sum()),
            "meilleure_region": par_region.idxmax(), "ca_meilleure_region": int(par_region.max())}


def verifier(rapport: str, ref: dict) -> dict:
    """Le rapport cite-t-il les bons chiffres ? (on ignore les séparateurs : 414 644 = 414,644 = 414644)"""
    nombres = {int(re.sub(r"[\s .,]", "", n)) for n in re.findall(r"\d[\d\s .,]*\d|\d", rapport)
               if re.sub(r"[\s .,]", "", n).isdigit()}
    return {"ca_total": ref["ca_total"] in nombres,
            "meilleure_region": ref["meilleure_region"] in rapport and ref["ca_meilleure_region"] in nombres}
Format dans le rapportNormalisé enReconnu ?
414 644 € (espace, ou espace fine  )414644oui
414,644 € (style anglais)414644oui
environ 415 000 €415000non : c'est voulu, un arrondi n'est pas le chiffre exact
414,6 k€4146non

Le rapport écrit « CA total : environ 415 000 € ». Que renvoie verifier() pour ca_total ?

Exercice : contrôler le CA par catégorie

Étendez reference() et verifier() pour vérifier que le CA de chaque catégorie apparaît dans le rapport.

Voir la solution
def reference(chemin_csv):
    d = pd.read_csv(chemin_csv)
    par_region = d.groupby("region").chiffre_affaires.sum()
    return {"ca_total": int(d.chiffre_affaires.sum()),
            "meilleure_region": par_region.idxmax(), "ca_meilleure_region": int(par_region.max()),
            "ca_categories": {c: int(v) for c, v in d.groupby("categorie").chiffre_affaires.sum().items()}}

# dans verifier(), ajoutez :
#   "categories": all(v in nombres for v in ref["ca_categories"].values()),

Valeurs attendues : Casques 185 654, Enceintes 152 250, Accessoires 76 740. Le rapport réel du 2026-10-15 les contient toutes les trois. Pensez à mettre à jour test_reference_et_controle, qui compare reference() à un dictionnaire exact.

Résultat obtenu

Fin du run réel (gemini-3.5-flash, 2026-10-15) :

Graphique enregistré : graphique_20261015_163646.png

=== RAPPORT ===
## Chiffres clés
- **Chiffre d'affaires total 2025** : **414 644 €** (pour 14 746 unités vendues)
- **Chiffre d'affaires par région** :
  - **Sud** : **123 269 €** (29,73 % du CA total)
  [...]
CONTRÔLE : {'ca_total': True, 'meilleure_region': True}

Je sais faire

  • Expliquer le chemin d'une image depuis le bac à sable jusqu'au disque
  • Lister et charger des artefacts d'une session ADK
  • Calculer une vérité terrain et contrôler les chiffres d'un rapport
  • Repérer les limites d'une normalisation de nombres
Next