Les notebooks Argumentation-03-Dung-AF-Semantics-Python, Argumentation-03b-Value-Based-AF-Python et Argumentation-03c-Ranking-Semantics-Python traitent l’argumentation formelle/abstraite : des arguments anonymes reliés par une relation d’attaque. Mais dans la pratique — un débat politique, un mémoire d’expertise, une plaidoirie — un argument n’est pas un nœud anonyme : il a une structure interne. Le philosophe Stephen Toulmin (1958, The Uses of Argument) a proposé une anatomie de cette structure, devenu l’outil de référence en analyse informelle de l’argumentation (rhétorique, droit, éthique appliquée, communication scientifique).
Toulmin observe qu’un argument complet ne se résume pas à « voici des faits, donc voici une conclusion ». Entre les faits (Data) et la conclusion (Claim), il y a toujours une inférence autorisée — le Warrant — qui dit pourquoi ces faits autorisent cette conclusion. Et ce warrant repose lui-même sur un Backing (un fondement), tolère un Qualifier (une modalité), et affronte des Rebuttals (des exceptions). Omettre ces pièces, c’est produire un argument qui paraît solide mais dont la chaîne logique est invisible — donc impossible à contester précisément.
Ce notebook reconstruit le schéma à 6 composants de Toulmin en pur Python (stdlib), montre comment auditer la complétude d’un argument, et — c’est le pont computationnel — comment traduire un débat d’arguments Toulmin en un cadre de Dung : les rebuttals deviennent des attaques, et les sémantiques (grounded, preferred) décident quels claims survivent.
Le schéma à 6 composants
Un argument, selon Toulmin, se déploie en six pièces. Les trois premières sont essentielles (sans elles, il n’y a pas d’argument) ; les trois dernières le qualifient et le durcissent.
Composant
Rôle
Question qu’il répond
Claim (conclusion, C)
La thèse défendue
« Que veux-tu établir ? »
Data (données, D)
Les faits/observations invoqués
« Sur quoi t’appuies-tu ? »
Warrant (garant, W)
La règle d’inférence D → C
« Comment passes-tu de D à C ? »
Backing (fondement, B)
Le support du warrant (loi, autorité, théorie)
« Pourquoi cette règle vaut-elle ? »
Qualifier (modalité, Q)
La force de la conclusion (« nécessairement », « probablement »)
« Avec quelle certitude ? »
Rebuttal (réfutation, R)
Les conditions d’exception
« Quand ton argument tombe-t-il ? »
La pièce sous-enseignée est le Warrant. Beaucoup d’arguments implicites sautent de Data à Claim sans expliciter la règle — et c’est précisément là que se logent les sophismes et les désaccords. Rendre le warrant explicite est l’acte analytique central du modèle Toulmin.
Exemple concret : un argument complet
Pour rendre les composants concrets, déployons un argument familier :
« Le projet X doit probablement être financé, car son ROI projeté est de 15 % ; or les projets à ROI élevé méritent financement — principe d’allocation rationnelle du capital — sauf si la situation de défaut attendue le disqualifie. »
Décomposé selon Toulmin :
Claim : « Le projet X doit être financé »
Data : « X a un ROI projeté de 15 % »
Warrant : « Les projets à ROI élevé méritent financement »
Backing : « Principe d’allocation rationnelle du capital »
Qualifier : « probablement »
Rebuttal (condition d’exception) : « sauf si le risque de défaut est prohibitif »
Implémentons ce schéma comme une classe Python, puis vérifions sa complétude.
# --- Le schema de Toulmin (1958), pure stdlib ---class ToulminArgument:"""Un argument structure selon le schema de Toulmin (6 composants). Les 3 composants essentiels (claim, data, warrant) doivent etre non vides pour que l'argument soit COMPLETE. Les 3 autres (backing, qualifier, rebuttal_targets) le qualifient. """def__init__(self, name, claim, data, warrant, backing="", qualifier="", rebuttal_targets=()):self.name = nameself.claim = claimself.data = dataself.warrant = warrantself.backing = backingself.qualifier = qualifier# rebuttal_targets = ensemble des NOMS d'arguments que celui-ci refuteself.rebuttal_targets =set(rebuttal_targets)def is_complete(self):"""True si les 3 composants essentiels sont presents (claim/data/warrant)."""returnbool(self.claim andself.data andself.warrant)def missing_pieces(self):"""Liste des composants essentiels manquants (pour diagnostic).""" missing = []ifnotself.claim: missing.append("claim")ifnotself.data: missing.append("data")ifnotself.warrant: missing.append("warrant")return missingdef describe(self):"""Affiche l'argument deploye en ses 6 pieces.""" lines = [f"[{self.name}] Argument Toulmin (complet: {self.is_complete()})"] lines.append(f" Claim : {self.claim or'(manquant)'}") lines.append(f" Data : {self.data or'(manquant)'}") lines.append(f" Warrant : {self.warrant or'(manquant)'}") lines.append(f" Backing : {self.backing or'(non precise)'}") lines.append(f" Qualifier: {self.qualifier or'(non precise)'}") rt =sorted(self.rebuttal_targets) ifself.rebuttal_targets else ["(aucun)"] lines.append(f" Rebuttals cibles: {rt}")return"\n".join(lines)def__repr__(self): q =self.qualifier +" "ifself.qualifier else""returnf"[{self.name}] {q}{self.claim or'(incomplet)'}".strip()# Deploiement de l'exemple "projet X".arg_X = ToulminArgument( name="X", claim="Le projet X doit etre finance", data="X a un ROI projete de 15%", warrant="Les projets a ROI eleve meritent financement", backing="Principe d'allocation rationnelle du capital", qualifier="probablement", rebuttal_targets=set(), # on ajoutera la cible plus tard, avec l'argument adverse)print(arg_X.describe())print()print(f"Complet ? {arg_X.is_complete()} ; pieces manquantes : {arg_X.missing_pieces()}")
[X] Argument Toulmin (complet: True)
Claim : Le projet X doit etre finance
Data : X a un ROI projete de 15%
Warrant : Les projets a ROI eleve meritent financement
Backing : Principe d'allocation rationnelle du capital
Qualifier: probablement
Rebuttals cibles: ['(aucun)']
Complet ? True ; pieces manquantes : []
Auditer la complétude
Le piège classique de l’argumentation implicite : un énoncé qui ressemble à un argument mais saute le warrant. « X a un ROI de 15 %, donc X doit être financé » omet la règle d’inférence — le lecteur doit la deviner. La fonction missing_pieces détecte ces trous, ce qui est précisément le travail d’un auditeur d’argumentation.
# Un argument INCOMPLET (warrant implicite) : diagnostic automatique.arg_leak = ToulminArgument( name="leak", claim="X doit etre finance", data="X a un ROI de 15%", warrant="", # le warrant est implicite -> trou analytique)print(arg_leak.describe())print()miss = arg_leak.missing_pieces()if miss:print(f">>> Argument INCOMPLET : piece(s) essentielle(s) manquante(s) = {miss}")print(">>> Le warrant (D -> C) doit etre explicite : sur quelle regle d'inference ""passe-t-on du ROI a l'obligation de financer ?")else:print(">>> Argument complet.")
[leak] Argument Toulmin (complet: False)
Claim : X doit etre finance
Data : X a un ROI de 15%
Warrant : (manquant)
Backing : (non precise)
Qualifier: (non precise)
Rebuttals cibles: ['(aucun)']
>>> Argument INCOMPLET : piece(s) essentielle(s) manquante(s) = ['warrant']
>>> Le warrant (D -> C) doit etre explicite : sur quelle regle d'inference passe-t-on du ROI a l'obligation de financer ?
Le pont vers Dung : rebuttals = attaques
Voici le saut computationnel. Le modèle Toulmin décrit un argument isolé. Mais un débat réel en confronte plusieurs — et ces arguments se réfutent mutuellement (le composant Rebuttal). Or « A réfute B » est exactement « A attaque B » au sens de Argumentation-03-Dung-AF-Semantics-Python. Donc :
On déploie chaque argument en sa forme Toulmin (6 composants).
On lit les rebuttal_targets de chacun → on construit la relation d’attaque du cadre de Dung.
On applique la sémantique grounded : les claims qui survivent sont ceux défendus dans le débat.
Construisons un débat à deux arguments qui se réfutent mutuellement, puis regardons le verdict du grounded.
# Primitives de Dung (comme Dung_AF_Semantics / Value_Based_AF).class AF:def__init__(self, args, attacks):self.args =set(args);self.attacks =set(attacks)def attackers(self, x):return {a for (a, b) inself.attacks if b == x}def defeats(af, S, x):returnany((a, x) in af.attacks for a in S)def defends(af, S, x):returnall(defeats(af, S, b) for b in af.attackers(x))def grounded(af): E =set()whileTrue: E_new = E | {x for x in af.args if defends(af, E, x)}if E_new == E:return E E = E_newdef toulmin_debate_to_af(arguments):"""Traduit un debat d'arguments Toulmin en un cadre de Dung. Chaque argument Toulmin devient un noeud ; chaque rebuttal_target (A refute B) devient une attaque (A -> B) dans le AF. """ names = {a.name for a in arguments} attacks =set()for a in arguments:for tgt in a.rebuttal_targets:if tgt in names: # ne cree l'attaque que si la cible existe attacks.add((a.name, tgt))return AF(names, attacks)# Un debat a deux arguments qui se refutent mutuellement (pro/contra).A = ToulminArgument( name="A", claim="Le projet X doit etre finance", data="X a un ROI projete de 15%", warrant="Les projets a ROI eleve meritent financement", backing="Principe d'allocation rationnelle du capital", qualifier="probablement", rebuttal_targets={"B"}, # A refute B)B = ToulminArgument( name="B", claim="Le projet X ne doit pas etre finance", data="X presente un risque de defaut de 40%", warrant="Les projets trop risques doivent etre evites", backing="Principe de prudence", qualifier="possiblement", rebuttal_targets={"A"}, # B refute A)print("=== Debat a 2 arguments (rebuttal mutuel) ===")for arg in (A, B):print(arg.describe());print()af2 = toulmin_debate_to_af([A, B])print(f"Cadre de Dung : args={sorted(af2.args)}, attacks={sorted(af2.attacks)}")g2 = grounded(af2)print(f"Extension grounded : {sorted(g2) if g2 else'{} (vide)'}")print(">>> Verdict : A<->B forment un cycle. Ni l'un ni l'autre ne defend l'autre")print(" -> grounded VIDE = standoff, aucune conclusion ne survit seule.")
=== Debat a 2 arguments (rebuttal mutuel) ===
[A] Argument Toulmin (complet: True)
Claim : Le projet X doit etre finance
Data : X a un ROI projete de 15%
Warrant : Les projets a ROI eleve meritent financement
Backing : Principe d'allocation rationnelle du capital
Qualifier: probablement
Rebuttals cibles: ['B']
[B] Argument Toulmin (complet: True)
Claim : Le projet X ne doit pas etre finance
Data : X presente un risque de defaut de 40%
Warrant : Les projets trop risques doivent etre evites
Backing : Principe de prudence
Qualifier: possiblement
Rebuttals cibles: ['A']
Cadre de Dung : args=['A', 'B'], attacks=[('A', 'B'), ('B', 'A')]
Extension grounded : {} (vide)
>>> Verdict : A<->B forment un cycle. Ni l'un ni l'autre ne defend l'autre
-> grounded VIDE = standoff, aucune conclusion ne survit seule.
Le verdict bascule : introduire un arbitre
Le standoff (grounded vide) est insatisfaisant : le débat est indécis. Mais ajoutons un troisième argumentC qui réfute B seulement (sans toucher à A). Concrètement, C conteste le Data de B (le risque de défaut est sur-estimé). Le cycle se brise : C défait B, donc B n’attaque plus A, donc A redevient défendable.
# On ajoute un 3e argument C qui refute B seulement (arbitre).C = ToulminArgument( name="C", claim="Le risque de defaut de X est surestime", data="L'historique montre 10% de defaut reel sur projets similaires", warrant="Les projections de risque doivent etre calibrees sur donnees passees", backing="Principe de calibration empirique", qualifier="fortement", rebuttal_targets={"B"}, # C refute B, MAIS PAS A)print("=== Debat a 3 arguments (C arbitre en refutant B) ===")print(C.describe());print()af3 = toulmin_debate_to_af([A, B, C])print(f"Cadre de Dung : args={sorted(af3.args)}")print(f" attacks={sorted(af3.attacks)}")g3 = grounded(af3)print(f"Extension grounded : {sorted(g3)}")print()print(">>> Lecture : C defait B -> B ne peut plus attaquer A -> A est defendu.")print(" Les claims A et C survivent ; B (le contre-argument) est exclu.")print(" Le warrant sous-jacent : un seul arbitre peut faire basculer un debat")print(" indécis vers une conclusion, SANS toucher aux arguments principaux.")
=== Debat a 3 arguments (C arbitre en refutant B) ===
[C] Argument Toulmin (complet: True)
Claim : Le risque de defaut de X est surestime
Data : L'historique montre 10% de defaut reel sur projets similaires
Warrant : Les projections de risque doivent etre calibrees sur donnees passees
Backing : Principe de calibration empirique
Qualifier: fortement
Rebuttals cibles: ['B']
Cadre de Dung : args=['A', 'B', 'C']
attacks=[('A', 'B'), ('B', 'A'), ('C', 'B')]
Extension grounded : ['A', 'C']
>>> Lecture : C defait B -> B ne peut plus attaquer A -> A est defendu.
Les claims A et C survivent ; B (le contre-argument) est exclu.
Le warrant sous-jacent : un seul arbitre peut faire basculer un debat
indécis vers une conclusion, SANS toucher aux arguments principaux.
Exercices
Les trois exercices approfondissent le modèle. Chaque stub est à compléter — le notebook s’exécute de bout en bout même non complété (les exercices renvoient None/valeurs neutres et affichent un message).
Exercice 1 — Diagnostiquer un argument incomplet
Étant donné un énoncé familier d’opinion, identifiez la pièce essentielle manquante et complétez l’argument Toulmin pour qu’il soit is_complete() == True.
Objectif : prendre l’énoncé « Il pleut, donc je prends mon parapluie », le modéliser (claim + data fournis, warrant à expliciter), et le rendre complet.
# Exercice 1 : a completerdef argument_parapluie_complet():"""Renvoie un ToulminArgument complet modelisant : 'Il pleut, donc je prends mon parapluie'. Indice : le DATA = 'il pleut', le CLAIM = 'je prends mon parapluie'. Etape 1 : quel est le WARRANT (regle D -> C) implicite ? L'expliciter. Etape 2 : construire le ToulminArgument avec les 3 composants essentiels. """# TODO etudiantreturnNone# arg = argument_parapluie_complet()# if arg is not None:# print(arg.describe())# miss = arg.missing_pieces()# if miss:# print(f"ENCORE INCOMPLET : manque {miss}")# else:# print("SUCCES : argument complet (warrant explicite).")# else:# print("Exercice a completer.")print("Exercice 1 a completer.")
Exercice 1 a completer.
Exercice 2 — Construire un débat équilibré (standoff)
Construisez deux arguments Toulmin complets qui se réfutent mutuellement (comme A et B ci-dessus), sur un sujet de votre choix (ex. « le télétravail devrait être la norme »). Vérifiez via toulmin_debate_to_af + grounded que le débat est un standoff (grounded vide).
Objectif : sentir que deux arguments corrects mais opposés produisent une indécision — c’est pourquoi un débat pur pro/contra est rarement tranché sans un troisième élément.
# Exercice 2 : a completerdef debat_teletravail_standoff():"""Construisez deux ToulminArgument complets (PRO et CONTRA le teletravail comme norme) qui se refutent mutuellement. Renvoie (pro, contra). Indice : chaque argument doit avoir claim + data + warrant non vides, et rebuttal_targets pointant vers le nom de l'autre. """# TODO etudiantreturnNone, None# pro, contra = debat_teletravail_standoff()# if pro is not None and contra is not None:# af_ex2 = toulmin_debate_to_af([pro, contra])# g_ex2 = grounded(af_ex2)# print(f"Attaques : {sorted(af_ex2.attacks)}")# print(f"Grounded : {sorted(g_ex2) if g_ex2 else '{} (vide = standoff)'}")# if len(g_ex2) == 0:# print("SUCCES : standoff confirme (debat equilibre).")# else:# print("Exercice a completer.")print("Exercice 2 a completer.")
Exercice 2 a completer.
Exercice 3 — Trouver l’arbitre qui fait basculer le débat
Reprenant votre débat de l’exercice 2 (pro/contra en standoff), construisez un troisième argument C qui réfute un seul des deux, de sorte que le grounded passe de vide à une conclusion non vide. Identifiez lequel des deux claims survit.
Objectif : comprendre que la conclusion d’un débat Toulmin-Dung dépend de où l’arbitre frappe — réfuter pro fait gagner contra, et inversement.
# Exercice 3 : a completerdef arbitre_qui_bascule(pro, contra, cible):"""Construit un 3e argument C qui refute `cible` (parmi 'pro'/'contra') et renvoie (C, ensemble_grounded_obtenu). Indice : rebuttal_targets de C = {nom de l'argument cible}. Puis calculer le grounded du debat a 3 arguments. Renvoyer (C, set(grounded)). """# TODO etudiantreturnNone, None# Supposons pro.name='PRO', contra.name='CONTRA' (a adapter a votre exo 2).# C, g = arbitre_qui_bascule(pro, contra, "CONTRA")# if C is not None:# print(f"Arbitre C refute CONTRA -> grounded = {sorted(g)}")# print("Le claim survivant est celui dont l'adversaire a ete refute.")# else:# print("Exercice a completer (depend de l'exercice 2).")print("Exercice 3 a completer.")
Exercice 3 a completer.
Conclusion
Ce que vous avez appris
Un argument n’est pas un bloc monolithique : le schéma de Toulmin le déploie en six pièces, dont trois essentielles (claim, data, warrant). Le warrant — la règle d’inférence D → C — est la pièce la plus souvent laissée implicite, et c’est précisément là que se logent les désaccords et les sophismes.
Auditer la complétude (is_complete / missing_pieces) est un acte analytique : il force à expliciter la chaîne logique plutôt qu’à la présupposer.
Le pont vers Dung : en déployant plusieurs arguments Toulmin et en lisant leurs rebuttals comme des attaques, on obtient un cadre de Dung. Les sémantiques (grounded) tranchent alors le débat — un standoff (grounded vide) signifie que le débat pro/contra est structurellement indécis, et qu’un troisième argument (un arbitre) peut seul le faire basculer.
Prochaines étapes
Argumentation graduée : plutôt qu’un verdict accepté/rejeté, Argumentation-03c-Ranking-Semantics-Python attribue une force numérique à chaque argument — utile quand un débat ne se résout pas par grounded seul.
Valeurs et audiences : les warrants reposent souvent sur des valeurs (cf. Argumentation-03b-Value-Based-AF-Python) ; deux audiences aux valeurs différentes peuvent accepter le même Data mais rejeter le Warrant — d’où l’intérêt de croiser Toulmin (structure) et VAF (préférences).
Argumentation bipolaire : Toulmin distingue l’attaque (rebuttal) du support implicite entre data et claim ; les cadres bipolaires (Cayrol & Lagasquie-Schiex, 2005) modélisent explicitement une relation de support en plus de l’attaque.
Référence
Stephen Toulmin, The Uses of Argument (Cambridge University Press, 1958, mis à jour 2003) — le livre fondateur du schéma à six composants reconstruit ici.
Notebook pédagogique — pur stdlib Python, déterministe, sans LLM ni solveur externe. Conforme C.1 (stubs sans erreur volontaire), C.2 (sorties réelles), exercices à compléter.