Workflows en tant que code
Présentation
Un workflow est stocké sous forme de graphe de nœuds et d’arêtes. Écrire ce graphe à la main implique de maintenir vous-même la cohérence des identifiants d’arête, des listes edge_order et des objets de condition. Le générateur Workflow des SDK Python et JavaScript vous permet de décrire le même graphe avec des appels de méthodes chaînés. Il produit ensuite la valeur workflow qu’acceptent déjà agents.create() et agents.update().
Utilisez-le pour :
- Concevoir un workflow en code et le réviser comme toute autre modification de code.
- Charger le workflow d’un agent, modifier un nœud et le renvoyer sans perturber le reste du graphe.
- Stocker les workflows au format JSON dans le contrôle de version et les valider dans votre CI.
Le générateur s’exécute entièrement dans le SDK. Il n’appelle aucun nouveau point de terminaison d’API, et tout ce qu’il génère peut être ouvert et modifié dans l’éditeur visuel du Dashboard.
Prérequis
- Python : le package
elevenlabs. Le générateur est importé depuiselevenlabs.agent_workflows. - JavaScript : le package
@elevenlabs/elevenlabs-js. Le générateur est exporté depuis la racine du package.
Concevoir un workflow
L’objet Workflow représente le nœud de départ. Chaque verbe ajoute un nœud et le renvoie, ce qui vous permet d’enchaîner l’étape suivante à partir de celui-ci :
Les méthodes de routage déterminent quelle arête mène au nœud suivant :
Les verbes appelés directement sur le workflow créent une branche depuis le nœud de départ avec une arête inconditionnelle. Cet exemple dirige les appelants vers une recherche de commande, relance l’identification si la recherche échoue et transfère les appelants VIP ou frustrés :
build() valide l’ensemble du graphe et renvoie le modèle de requête. Il :
- Attribue au nœud de départ l’identifiant
start_node, requis par l’API. - Génère des identifiants d’arête sous la forme
source__target. - Renseigne le
edge_orderde chaque nœud dans l’ordre où vous avez ajouté les arêtes. - Positionne tout nœud sans position, afin que le graphe s’affiche de gauche à droite dans l’éditeur visuel.
Écrire un workflow en une seule chaîne
up() renvoie le nœud depuis lequel le nœud actuel a été chaîné. Vous pouvez ainsi décrire un workflow entier dans une seule expression plutôt que de conserver chaque nœud dans une variable. Dans une seule chaîne, utilisez go_to() / goTo() avec un identifiant de nœud, car aucune variable n’est disponible à transmettre :
Pour un handle de nœud issu de wf.node(id), up() renvoie le nœud dont provient la première arête qui y entre. Pour le nœud de départ, il renvoie le nœud de départ.
Options de nœud
Les paramètres facultatifs sont transmis comme arguments nommés en Python et dans un objet d’options final en JavaScript. Leurs noms correspondent aux champs du nœud dans l’API :
Chaque verbe accepte également position si vous souhaitez positionner le nœud vous-même. Workflow(prevent_subagent_loops=True) en Python, ou new Workflow({ preventSubagentLoops: true }) en JavaScript, empêche la conversation de réintégrer un sous-agent déjà visité.
Destinations de transfert
Conditions
when() accepte une chaîne simple, une Condition ou un Expr :
- Une chaîne est une condition LLM : le LLM détermine si elle est remplie.
Condition.llm(text, label=...)est identique, avec un libellé affiché sur l’arête dans l’éditeur visuel. UtilisezCondition.expr(expr, label=...)pour libeller une expression.- Un
Exprest évalué par rapport aux variables dynamiques, sans appeler le LLM.
Construisez des expressions à partir de Expr.variable(name) et Expr.literal(value). Comparez-les avec eq, neq, gt, gte, lt et lte, et effectuez des opérations arithmétiques avec add, sub, mul et div. Combinez-les avec all_of / allOf, any_of / anyOf et if_else / ifElse. Les valeurs simples sont encapsulées pour vous dans Expr.literal(). Expr.llm(description) demande au LLM d’extraire une valeur de la conversation ; transmettez type et enum pour obtenir une chaîne, un nombre ou l’une d’un ensemble fixe plutôt qu’un booléen.
Boucles et arêtes inversées
L’API autorise une arête entre deux nœuds, dans l’un ou l’autre sens. Pour permettre à la conversation de revenir sur son chemin, attribuez à l’arête une condition inversée avec back :
go_to() / goTo() gère le cas courant pour vous. Lorsque le nœud cible possède déjà une arête menant ici, la nouvelle arête devient la condition inversée de cette arête. Dans le premier exemple, failed.go_to(identify) est envoyé comme condition inversée de l’arête identify → lookup_order. Toute autre seconde arête entre les deux mêmes nœuds, ainsi que toute arête d’un nœud vers lui-même, échoue à la validation.
Modifier un agent existant
Workflow.from_agent() / Workflow.fromAgent() charge le workflow d’un agent renvoyé par agents.get(). Les identifiants de nœud, les identifiants d’arête, les positions dans l’éditeur et l’ordre des arêtes sont conservés. Le renvoi ne modifie donc que ce que vous avez changé.
insert_between() / insertBetween() transmet à votre fonction une branche qui porte la condition de l’arête remplacée. La fonction renvoie le dernier nœud ajouté, qui est ensuite connecté à la cible d’origine. La méthode renvoie ce nœud, ou None / undefined s’il n’existe aucune arête entre les deux nœuds.
Stocker les workflows dans le contrôle de version
to_json_string() / toJSONString() écrit le workflow au format de transmission de l’API : des clés en snake_case, triées à tous les niveaux, avec une indentation de 2 espaces. Il s’agit du même format que celui utilisé par l’API REST et la CLI, et les deux SDK écrivent des fichiers identiques octet par octet pour un même workflow, afin de limiter les différences. Workflow.from_json() / Workflow.fromJSON() le relit et accepte également une configuration complète d’agent avec une clé workflow, comme un fichier du répertoire agent_configs/ de la CLI.
Configuration type :
Initialiser le fichier
Chargez l’agent avec from_agent() / fromAgent() et écrivez-le dans un fichier, ou récupérez-le avec elevenlabs agents pull.
Modifier
Modifiez directement le JSON, ou chargez-le avec from_json() / fromJSON() et modifiez-le avec le
générateur dans un script.
Visualiser un workflow
La CLI représente un fichier de workflow sous forme d’organigramme. Vous pouvez ainsi vérifier ce que votre code a généré sans ouvrir le Dashboard. Elle accepte un fichier de workflow seul écrit par to_json_string() / toJSONString(), ou une configuration d’agent avec une clé workflow :
Par défaut, elle dessine des boîtes et des flèches dans le terminal, chaque condition d’arête étant numérotée sur son arête et détaillée dans une légende en dessous. Utilisez --format mermaid pour afficher à la place le code source Mermaid, ou --format mermaid-md pour l’encapsuler dans un bloc de code clôturé rendu par GitHub, par exemple dans un commentaire de pull request :
La commande lit uniquement des fichiers locaux. Elle ne nécessite donc aucune clé API et peut s’exécuter dans la CI.
Validation
Les appels chaînés n’échouent jamais seuls. build(), to_json() / toJSON() et to_json_string() / toJSONString() vérifient l’ensemble du graphe et lèvent ou génèrent une unique WorkflowValidationError, dont la liste issues répertorie chaque problème avec son code, son message et le node_id / nodeId concerné.
Les erreurs incluent :
- Deux arêtes entre la même paire de nœuds, ou une arête d’un nœud vers lui-même.
- Une arête qui entre dans le nœud de départ ou qui sort d’un nœud de fin.
- Une arête depuis un nœud d’outil qui n’est pas une arête de réussite ou d’échec, ou une arête de réussite ou d’échec depuis tout autre type de nœud.
- Deux nœuds avec le même identifiant, ou une arête vers un nœud qui n’existe pas.
Les nœuds inaccessibles depuis le nœud de départ sont signalés comme avertissements, via on_warning / onWarning, et n’empêchent pas la génération.
Types de nœuds plus récents que votre SDK
Un workflow chargé depuis l’API ou depuis un fichier peut contenir des types de nœuds que votre version du SDK ne connaît pas encore. Ils effectuent un aller-retour inchangés via from_json() / fromJSON() et to_json_string() / toJSONString(), et build() signale chacun d’eux comme un avertissement. Le modèle de requête typé ne peut pas les transporter. Mettez donc à niveau le SDK ou envoyez directement le format de transmission :