Leçon 5 — Tester, évaluer, exploiter

Essais réels et limites de la modération

6 min de lecture

Essais réels et limites de la modération

Trois briefs, trois comportements

terminal
python agent.py brief_produit.md     # propre, avec un contact presse à masquer
python agent.py brief_piege.md       # exige « garantie à vie », « 100 % sans risque »
python agent.py brief_ambigu.md      # pousse vers l'exagération sans les mots interdits
BriefAppels au modèleCe qui s'est passé (2026-10-15)
brief_produit.md4e-mail et téléphone masqués pour les 4 canaux ; 4 textes « ok », dans les longueurs
brief_piege.md0refusé par before_model pour 4 motifs ; aucun token consommé
brief_ambigu.md4aucun mot interdit écrit par le modèle ; journal « rien à signaler » ; mais une exagération est passée
flowchart TB
  B["Brief"] --> M1{"Promesse interdite dans le brief ?"}
  M1 -->|"oui"| R["Refus, 0 appel"]
  M1 -->|"non"| G["4 rédacteurs Gemini"]
  G --> M2{"Promesse ou donnée personnelle dans le texte ?"}
  M2 -->|"oui"| BL["Texte bloqué"]
  M2 -->|"non"| H["Relecture humaine"]
  H --> PUB["Publication"]

Ce que la modération laisse passer

Le brief ambigu dit : « imbattable, aucune autre gourde ne fait mieux », « achetez-la les yeux fermés, satisfaction assurée ». Le modèle a bien suivi les règles du prompt : aucun « meilleur du marché », aucune garantie. Mais la newsletter générée contient :

« La gourde Clairo 500 a pleinement convaincu nos testeurs sur le terrain. Après plusieurs mois d'utilisation, leurs retours sont unanimes [...] »

Le brief cite trois testeurs, rien ne dit que tous les testeurs sont d'accord. « Unanimes » est une affirmation inventée, invisible pour une expression régulière : elle ne contient aucun mot interdit.

Ce que les règles attrapentCe qu'elles ne voient pas
formats réguliers : e-mail, téléphone, IBAN, cartenoms propres, adresses postales
expressions listées : « garanti à vie », « 100 % efficace »paraphrases : « vous ne serez jamais déçu »
superlatifs listés : « le meilleur du marché »exagérations : « retours unanimes », « tout le monde l'adore »
—chiffres faux mais plausibles (« 48 h » au lieu de 24 h)

Le texte généré dit « froid pendant 48 h » alors que le brief dit 24 h. Quelle brique du lab le détecte ?

Renforcer sans tout réécrire

Trois pistes, de la plus simple à la plus lourde :

  1. Contrôle des chiffres dans after_model_callback : extraire tous les nombres du texte (re.findall(r"\d+[.,]?\d*", texte)) et bloquer ceux qui n'apparaissent pas dans le brief.
  2. Relecteur LLM après les rédacteurs (exercice de la leçon « Un sous-agent par canal ») : un agent qui compare chaque texte au brief et liste les affirmations non sourcées. Il coûte un appel de plus par brief.
  3. Service de détection de données personnelles pour les noms et adresses, appelé dans before_model_callback.

La relecture humaine reste obligatoire

ÉtapeQuiOutil
écrire le brief, sans données personnelles inutilesmarketingmodèle de brief
générer et modérer automatiquementl'agentpython agent.py brief.md
relire chaque texte « ok », corriger ou rejetermarketingrapport Markdown
examiner les textes bloqués et le journalconformitéjournal de modération
publiermarketingoutils de chaque réseau

Coût par brief : 4 appels au modèle (0 si le brief est refusé). Pour de gros volumes, essayez MODEL=gemini-3.5-flash-lite et comparez les textes sur quelques briefs.

Pourquoi ne pas publier automatiquement les textes marqués « ok » ?

Exercice : bloquer les chiffres absents du brief

Ajoutez à moderation.py une fonction chiffres_inventes(texte, brief) qui renvoie les nombres du texte absents du brief, puis utilisez-la dans moderer_sortie.

Voir la solution
files/moderation.py (ajout)
_NOMBRE = re.compile(r"\d+(?:[.,]\d+)?")

def chiffres_inventes(texte: str, brief: str) -> list[str]:
    connus = set(_NOMBRE.findall(brief))
    return sorted(set(_NOMBRE.findall(texte)) - connus)

Dans moderer_sortie, le brief se lit dans callback_context.user_content (le message de l'utilisateur qui a lancé l'invocation) :

files/agent.py (variante)
brief = "".join(p.text or "" for p in callback_context.user_content.parts)
inventes = chiffres_inventes(texte, brief)
if inventes:
    motifs.append("chiffres absents du brief : " + ", ".join(inventes))

Attention aux faux positifs : « 2 paragraphes », « 1 emoji » ou une année calculée (« 2027 ») ne sont pas dans le brief. Commencez par signaler dans le journal plutôt que bloquer, et observez quelques semaines.

Résultat obtenu

Exécution réelle le 2026-10-15 (gemini-3.5-flash) sur brief_ambigu.md : extrait du rapport.

## newsletter (673/1500 car., ok)
Objet : La gourde Clairo 500 validée par nos testeurs !

La gourde Clairo 500 : la tranquillité au quotidien

Vous cherchez un contenant fiable pour vos boissons ? La gourde Clairo 500 a pleinement
convaincu nos testeurs sur le terrain. Après plusieurs mois d'utilisation, leurs retours
sont unanimes : ils soulignent notamment l'absence de fuite sur une période de 6 mois [...]

## whatsapp (236/350 car., ok)
Découvrez la gourde Clairo 500 au prix de 29,90 €. Après 6 mois de test sans aucune fuite
signalée par nos utilisateurs, elle est prête à devenir votre alliée au quotidien. [...]

## Journal de modération
- rien à signaler

Je sais faire

  • Lancer l'agent sur des briefs propres, pièges et ambigus, et comparer les résultats
  • Citer ce qu'une modération par expressions régulières ne peut pas voir
  • Proposer un renforcement adapté (contrôle des chiffres, relecteur, détection de données personnelles)
  • Organiser une relecture humaine avant publication