{
  "name": "Jour 1 - Prompting Metier et Confidentialite",
  "nodes": [
    {
      "parameters": {
        "content": "## Jour 1 \u2014 Prompting M\u00e9tier & Confidentialit\u00e9\n\n**Flux :**\n1. **Contexte d'audit** (Set) \u2014 d\u00e9finit la clause \u00e0 analyser\n2. **Analyser clause** (Basic LLM Chain) \u2014 envoie le prompt au mod\u00e8le et impose le sch\u00e9ma JSON via le sous-n\u0153ud *Format JSON attendu*\n3. **Extraire champs** (Set) \u2014 rend visibles les 5 champs attendus\n4. **Sensibilit\u00e9 valide ?** (If) \u2014 v\u00e9rifie que `niveau_sensibilite` vaut Faible, Moyen ou Eleve\n5. **R\u00e9sultat OK / Erreur format** \u2014 deux branches lisibles\n\n**Point p\u00e9dagogique :** le Basic LLM Chain + Structured Output Parser garantit le format sans code. L'Agent (jours 2+) est r\u00e9serv\u00e9 aux workflows avec tools.\n\n**\u00c0 montrer :** changer la clause dans *Contexte d'audit*, ex\u00e9cuter, ouvrir *Extraire champs* pour voir le JSON, v\u00e9rifier la branche IF.",
        "height": 320,
        "width": 560,
        "color": 5
      },
      "id": "d1-sticky-overview",
      "name": "Vue d'ensemble",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {},
      "id": "d1-trigger",
      "name": "D\u00e9clencheur Manuel",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        280,
        360
      ]
    },
    {
      "parameters": {
        "content": "**Set \u2014 Contexte d'audit**\n\nModifie `clause` pour tester une autre clause contractuelle.\n\nLa check-list RGPD et les consignes mod\u00e8le sont des r\u00e9f\u00e9rences p\u00e9dagogiques inject\u00e9es dans le prompt.",
        "height": 180,
        "width": 320,
        "color": 7
      },
      "id": "d1-sticky-set",
      "name": "Note Set",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        500,
        140
      ]
    },
    {
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "d1-clause",
              "name": "clause",
              "value": "Prime annuelle li\u00e9e \u00e0 la performance, calcul\u00e9e sur la r\u00e9mun\u00e9ration brute, avec exclusion des absences injustifi\u00e9es.",
              "type": "string"
            },
            {
              "id": "d1-chatinput",
              "name": "chatInput",
              "value": "Analysez cette clause de paie et retournez un objet json : Prime annuelle li\u00e9e \u00e0 la performance, calcul\u00e9e sur la r\u00e9mun\u00e9ration brute, avec exclusion des absences injustifi\u00e9es.",
              "type": "string"
            },
            {
              "id": "d1-rgpd-1",
              "name": "rgpd_1",
              "value": "Supprimer les noms, NIR et identifiants avant traitement",
              "type": "string"
            },
            {
              "id": "d1-rgpd-2",
              "name": "rgpd_2",
              "value": "Ne pas envoyer de fichier brut contenant des donn\u00e9es personnelles vers une IA publique",
              "type": "string"
            },
            {
              "id": "d1-rgpd-3",
              "name": "rgpd_3",
              "value": "V\u00e9rifier le cadre RGPD et le secret professionnel avant toute exfiltration",
              "type": "string"
            },
            {
              "id": "d1-model-1",
              "name": "conseil_modele_1",
              "value": "Utiliser un mod\u00e8le de raisonnement pour une clause complexe",
              "type": "string"
            },
            {
              "id": "d1-model-2",
              "name": "conseil_modele_2",
              "value": "Garder une temp\u00e9rature basse (0) pour privil\u00e9gier la fiabilit\u00e9",
              "type": "string"
            },
            {
              "id": "d1-model-3",
              "name": "conseil_modele_3",
              "value": "Demander des justifications factuelles et non des suppositions",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "d1-set",
      "name": "Contexte d'audit",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        500,
        360
      ]
    },
    {
      "parameters": {
        "content": "**Basic LLM Chain \u2014 Analyser clause**\n\n\u00c0 montrer aux participants :\n- *Basic LLM Chain* = un prompt \u2192 une r\u00e9ponse structur\u00e9e. Pas de tools, pas de m\u00e9moire.\n- Le sous-n\u0153ud *Format JSON attendu* (Structured Output Parser) impose le sch\u00e9ma.\n- Le sous-n\u0153ud *Ollama* fournit le mod\u00e8le.\n\n**Diff\u00e9rence avec l'Agent (jours 2+) :** l'Agent peut appeler des tools et boucler. Ici on veut juste une r\u00e9ponse JSON fiable.",
        "height": 240,
        "width": 360,
        "color": 7
      },
      "id": "d1-sticky-chain",
      "name": "Note LLM Chain",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        760,
        100
      ]
    },
    {
      "parameters": {
        "prompt": {
          "values": [
            {
              "type": "HumanMessagePromptTemplate",
              "message": "={{ $json.chatInput }}"
            }
          ]
        },
        "hasOutputParser": true,
        "options": {
          "systemMessage": "Tu es un auditeur paie senior. On te soumet une clause contractuelle anonymis\u00e9e.\n\nR\u00e9ponds UNIQUEMENT avec un objet JSON valide (format json). Aucun texte en dehors du JSON.\n\nChamps obligatoires :\n- `lecture_metier` : r\u00e9sum\u00e9 m\u00e9tier court (string)\n- `risques_audit` : liste de risques (array de strings)\n- `questions_de_controle` : liste d'objets {question: string}\n- `anonymisation_requise` : bool\u00e9en\n- `niveau_sensibilite` : exactement `Faible`, `Moyen` ou `Eleve`\n\nSi la clause ne permet pas de conclure, ajoute une question de contr\u00f4le plut\u00f4t qu'une affirmation. Aucune donn\u00e9e nominative."
        }
      },
      "id": "d1-chain",
      "name": "Analyser clause",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.4,
      "position": [
        760,
        360
      ]
    },
    {
      "parameters": {
        "content": "**Extraire champs** (Set)\n\nRend visible chaque champ de la r\u00e9ponse du mod\u00e8le.\nOuvrir ce n\u0153ud apr\u00e8s ex\u00e9cution pour voir le r\u00e9sultat.\n\n**Sensibilit\u00e9 valide ?** (If)\n- Branche **true** = format respect\u00e9\n- Branche **false** = valeur inattendue, montrer l'erreur aux participants",
        "height": 200,
        "width": 340,
        "color": 7
      },
      "id": "d1-sticky-extract",
      "name": "Note Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1020,
        140
      ]
    },
    {
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "d1-extract-1",
              "name": "lecture_metier",
              "value": "={{ $json.output?.lecture_metier ?? $json.text?.lecture_metier ?? $json.lecture_metier }}",
              "type": "string"
            },
            {
              "id": "d1-extract-2",
              "name": "risques_audit",
              "value": "={{ $json.output?.risques_audit ?? $json.text?.risques_audit ?? $json.risques_audit }}",
              "type": "array"
            },
            {
              "id": "d1-extract-3",
              "name": "questions_de_controle",
              "value": "={{ $json.output?.questions_de_controle ?? $json.text?.questions_de_controle ?? $json.questions_de_controle }}",
              "type": "array"
            },
            {
              "id": "d1-extract-4",
              "name": "anonymisation_requise",
              "value": "={{ $json.output?.anonymisation_requise ?? $json.text?.anonymisation_requise ?? $json.anonymisation_requise }}",
              "type": "boolean"
            },
            {
              "id": "d1-extract-5",
              "name": "niveau_sensibilite",
              "value": "={{ ({faible: 'Faible', moyen: 'Moyen', eleve: 'Eleve', \u00e9lev\u00e9: 'Eleve'}[(($json.output?.niveau_sensibilite ?? $json.text?.niveau_sensibilite ?? $json.niveau_sensibilite) || '').toString().trim().toLowerCase()] ?? ($json.output?.niveau_sensibilite ?? $json.text?.niveau_sensibilite ?? $json.niveau_sensibilite)) }}",
              "type": "string"
            },
            {
              "id": "d1-extract-6",
              "name": "clause_analysee",
              "value": "={{ $('Contexte d\\'audit').item.json.clause }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "d1-extract",
      "name": "Extraire champs",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1020,
        360
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "conditions": [
            {
              "id": "d1-if-valid-sensitivity",
              "leftValue": "={{ ['Faible', 'Moyen', 'Eleve'].includes($json.niveau_sensibilite) }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "d1-if",
      "name": "Sensibilite valide ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1260,
        360
      ]
    },
    {
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "d1-ok-1",
              "name": "validation_format",
              "value": "ok",
              "type": "string"
            },
            {
              "id": "d1-ok-2",
              "name": "message",
              "value": "Format respect\u00e9 \u2014 ouvrir ce n\u0153ud pour voir l'analyse compl\u00e8te",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "d1-result-ok",
      "name": "Resultat OK",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1500,
        260
      ]
    },
    {
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "d1-err-1",
              "name": "validation_format",
              "value": "erreur",
              "type": "string"
            },
            {
              "id": "d1-err-2",
              "name": "message",
              "value": "={{ 'niveau_sensibilite invalide : ' + $json.niveau_sensibilite + ' \u2014 attendu : Faible, Moyen ou Eleve' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "d1-result-err",
      "name": "Erreur format",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1500,
        460
      ]
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"lecture_metier\": \"r\u00e9sum\u00e9 m\u00e9tier court\",\n  \"risques_audit\": [\"risque 1\", \"risque 2\"],\n  \"questions_de_controle\": [{\"question\": \"question \u00e0 poser\"}],\n  \"anonymisation_requise\": false,\n  \"niveau_sensibilite\": \"Moyen\"\n}"
      },
      "id": "d1-output-parser",
      "name": "Format JSON attendu",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.2,
      "position": [
        760,
        560
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4.1-nano",
          "mode": "id"
        },
        "options": {
          "temperature": 0
        }
      },
      "id": "d1-openai",
      "name": "OpenAI Gateway",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        760,
        560
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "**Exemples de clauses \u00e0 tester**\n\n- Prime annuelle li\u00e9e \u00e0 la performance\n- Indemnit\u00e9 de d\u00e9part \u00e0 la retraite\n- Clause de non-concurrence r\u00e9mun\u00e9r\u00e9e\n- Majoration pour travail de nuit\n- Cotisation patronale de pr\u00e9voyance",
        "height": 160,
        "width": 300,
        "color": 3
      },
      "id": "d1-sticky-examples",
      "name": "Exemples",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        280
      ]
    }
  ],
  "connections": {
    "D\u00e9clencheur Manuel": {
      "main": [
        [
          {
            "node": "Contexte d'audit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contexte d'audit": {
      "main": [
        [
          {
            "node": "Analyser clause",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyser clause": {
      "main": [
        [
          {
            "node": "Extraire champs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraire champs": {
      "main": [
        [
          {
            "node": "Sensibilite valide ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sensibilite valide ?": {
      "main": [
        [
          {
            "node": "Resultat OK",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Erreur format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Gateway": {
      "ai_languageModel": [
        [
          {
            "node": "Analyser clause",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Format JSON attendu": {
      "ai_outputParser": [
        [
          {
            "node": "Analyser clause",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "description": "Jour 1 - Prompting m\u00e9tier structur\u00e9: Set injecte la clause, Agent Auditeur demande un JSON strict, Code v\u00e9rifie la sortie et rend les erreurs visibles."
  }
}