Pourquoi construire un n8n interne quand l’outil existe déjà ? Parce que parfois, le build l’emporte sur le buy. Chez Zadig&Voltaire, nous avons fait ce choix d’intégrer notre propre plateforme de workflows visuels dotée de capacités de génération par intelligence artificielle.

L’avantage :
C’est custom on est sur un outil réinventé spécifiquement pour notre besoin, donc c’est simple, ultra basic et ça se prend en main très facilement, même pour les novices en no-code.

Le problème : la gouvernance de la donnée

Nous avions besoin d’intégrer OpenAI directement dans nos workflows - pas via une API externe, mais comme un agent de première classe capable d’orchestrer des tâches complexes. Nos données internes (stocks, commandes, analytics) ne pouvaient pas transiter par des services tiers.

Et surtout, nos intégrations propriétaires - customisations Magento, sondes de monitoring internes, systèmes de notification spécifiques - nécessitaient une flexibilité que les connecteurs standards ne pouvaient offrir.

On a toute une stack interne qui nous permet de monitor approximativement tout, pourquoi ne pas simplement l’étendre tout en préservant la sécurité des données et leur stockage ?

En ayant la main dessus, on peut garantir et réduire la surface d’attaque - tout est tracé et loggé en interne et on peut pleinement se servir de l’IA sans crainte particulière.

L’architecture : un moteur d’exécution DAG

Au cœur de ce système se trouve un Directed Acyclic Graph (DAG) executor implémenté en PHP/Symfony avec Doctrine ORM.

L’algorithme est simple mais robuste : une file d’exécution en parcours par largeur (breadth-first).

Le WorkflowExecutor commence par les noeuds sans dépendances entrantes, les exécute, puis propage leur contexte aux noeuds suivants.
Chaque noeud reçoit le contexte cumulé de ses prédécesseurs et peut y ajouter ses propres outputs.

Le pattern handler chain permet l’extensibilité : chaque type de noeud est géré par un handler tagué dans le container Symfony. Un handler implémente trois méthodes :

// Exemple de définition de noeud
[
    'type' => 'notification_slack',
    'label' => 'Notification Slack',
    'category' => 'integration',
    'inputs' => [
        'channel' => ['type' => 'string', 'required' => true],
        'message' => ['type' => 'text', 'required' => true],
        'blocks' => ['type' => 'json', 'required' => false]
    ],
    'outputs' => [
        'message_ts' => ['type' => 'string'],
        'channel_id' => ['type' => 'string']
    ]
]

Les méthodes supports(), execute() et getNodeDefinition() forment le contrat que chaque handler respecte.

Les 18 types de noeuds

L’orchestrateur propose 18 types de noeuds répartis en trois catégories.

Intégrations

  • http_request : appels REST avec support complet des méthodes, headers et body
  • notification_slack : envoi de messages avec conversion automatique Markdown vers mrkdwn Slack
  • notification_email : emails HTML avec pièces jointes, templates intégrés
  • probe_check : vérification de nos sondes de monitoring internes

Contrôle de flux

  • control_condition : 15+ opérateurs incluant regex, comparaisons numériques et textuelles
  • control_switch : pattern matching pour router vers différentes branches
  • control_delay : pause d’exécution (max 5 minutes pour éviter les blocages)
  • control_on_error : récupération d’erreurs avec injection du contexte d’échec
  • control_subworkflow : appel de workflows imbriqués (profondeur max 10)

Noeuds IA

  • ai_agent : conversations multi-tours avec Claude ou OpenAI, support du tool calling
  • claude_agent : tâches fire-and-forget (code-review, feature-dev, jira-ticket automation)
  • task_agent : 11 processeurs pré-configurés (traducteur, analyseur de sentiment, transformateur de données…)

La génération IA de workflows

C’est la fonctionnalité qui change tout. Un utilisateur décrit son workflow en langage naturel :

“Vérifie si l’API catalogue est up toutes les 5 minutes. Si elle est down, envoie une alerte Slack dans #incidents.”

Génération de workflow par IA

Le système envoie cette description accompagnée des 18 définitions de noeuds à GPT-5.2.

Le modèle retourne un DAG complet valide au format JSON :

Workflow généré automatiquement

{
  "nodes": [
    {
      "id": "probe_1",
      "type": "probe_check",
      "position": { "x": 100, "y": 200 },
      "config": { "probe_name": "api-catalogue" }
    },
    {
      "id": "condition_1",
      "type": "control_condition",
      "position": { "x": 300, "y": 200 },
      "config": {
        "field": "{{ probe_1.output.status }}",
        "operator": "equals",
        "value": "down"
      }
    },
    {
      "id": "slack_1",
      "type": "notification_slack",
      "position": { "x": 500, "y": 200 },
      "config": {
        "channel": "#incidents",
        "message": "API Catalogue DOWN"
      }
    }
  ],
  "edges": [
    { "source": "probe_1", "target": "condition_1" },
    { "source": "condition_1", "target": "slack_1", "branch": "true" }
  ]
}

Le workflow est immédiatement exécutable. Pas de configuration manuelle, pas de documentation à consulter.

Résolution de variables : la syntaxe Twig-style

Le système utilise une syntaxe inspirée de Twig pour la résolution de variables.

Le template {{ node_name.output.field }} est résolu récursivement à travers les tableaux imbriqués, avec conversion JSON automatique des objets.

Template : "Commande {{ http_call.output.order.id }} - Total : {{ http_call.output.order.total }}€"
Contexte : { "http_call": { "output": { "order": { "id": "ZV-2026-0142", "total": 450 }}}}
Résultat : "Commande ZV-2026-0142 - Total : 450€"

L’éditeur visuel

L’interface Vue.js 2 propose une expérience drag-and-drop intuitive. À gauche, une palette des 18 types de noeuds groupés par catégorie. Au centre, le canvas où l’on dessine le graphe en connectant les noeuds par des edges. À droite, le panneau de configuration contextuel qui s’adapte au noeud sélectionné.

L’AiGeneratorDialog permet de basculer vers la génération par prompt : on décrit, on génère, on ajuste visuellement si nécessaire.

Système de déclenchement dual

L’orchestrateur supporte deux modes de déclenchement. Les schedules cron avec support des fuseaux horaires (daily, weekdays, weekly, monthly). Et les webhooks qui permettent de trigger un workflow depuis n’importe quel outil.

Dashboard d'un workflow avec historique des runs

Gestion des erreurs

Le noeud control_on_error vit en dehors du flux normal. Quand une exception survient, l’executor le recherche et lui injecte le contexte _error contenant le message, l’ID du noeud en échec et son type. Cette approche permet une récupération gracieuse sans polluer le graphe principal.

On a également un suivi complet et une traçabilité totale de l’exécution :

Détail d'une exécution avec logs

Les compromis assumés

L’exécution est synchrone - adaptée à nos cas d’usage internes où les workflows durent rarement plus de 30 secondes.

L’objet ici est de répondre à des problèmes du quotidien avec des agents IA, une base vectorisée commune et du RAG facile à intégrer et à mutualiser.

Pour illustrer, on fait pas de retry automatique, ça reste possible en le prévoyant dans le workflow (mais pas utile vu le volume). L’architecture est single-threaded par workflow, suffisante pour notre volume.


À terme, on imagine très bien que tout le run pourra être orchestré et automatisé via cet outil interne.

“L’orchestrateur nous permet d’automatiser et d’intégrer en quelques clics, ou quelques mots des scopes entiers qui auraient nécessité du développement custom.” — L’équipe Tech Z&V