SystemTce/dify-skills

Guide complet pour le développement de plugins Dify, couvrant les quatre types de plugins : outils, modèles, sources de données et extensions.

Qu'est-ce que dify-skills ?

Ce guide de compétence (SKILL) pour le développement de plugins Dify fournit une documentation exhaustive pour les développeurs souhaitant étendre les capacités de la plateforme Dify. Il couvre en détail les quatre types de plugins : outils (Tool), modèles (Model), sources de données (Datasource) et extensions (Extension), en s'appuyant sur l'architecture innovante Beehive (ruche). La compétence explique comment installer l'environnement (Python 3.12+, uv, dify-cli), créer un premier projet de plugin, implémenter la logique métier en Python et déboguer localement avec Debug Runtime. Elle détaille les concepts fondamentaux comme les trois modes d'exécution (Local, Debug, Serverless) et leur sélection selon le cas d'usage, avec un tableau comparatif. Le guide propose des sections pratiques pour la migration d'API existantes vers des plugins, l'intégration OAuth 2.0, les tests unitaires et d'intégration, ainsi que le dépannage des problèmes courants. Il inclut les meilleures pratiques d'organisation du code, d'optimisation des performances, de sécurité et d'expérience utilisateur, et se termine par des conseils de déploiement et d'exploitation, notamment pour le déploiement serverless sur AWS Lambda. Ce SKILL est conçu pour les développeurs qui maîtrisent Python et qui cherchent à intégrer des services tiers, créer des outils personnalisés ou étendre les fonctionnalités de Dify de manière professionnelle.

Compatible avec✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/SystemTce/dify-skills/tree/main/02-plugin

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Compétence Développement de Plugins Dify

Aperçu

Le système de plugins Dify utilise l'architecture innovante Beehive (Ruche), prend en charge trois modes d'exécution et propose quatre types de plugins, offrant aux développeurs de puissantes capacités d'extension. Cette compétence fournit un guide complet de développement de plugins, du débutant au niveau expert.

Cas d'Utilisation

Utilisez cette compétence lorsque vous avez besoin de :

  • Développer des plugins Dify : les quatre types : Outil, Modèle, Source de données, Extension
  • Intégrer des services tiers : Wrapper API, Autorisation OAuth
  • Implémenter des outils personnalisés : Étendre les capacités de l'IA
  • Étendre les fonctionnalités de la plateforme Dify : Déclencheurs, Stratégies d'Agent
  • Migrer des API existantes vers des plugins : Conversion d'API en plugin
  • Déboguer et optimiser les performances des plugins : Ajustement des performances et résolution de problèmes

Valeur Fondamentale

  • Architecture Beehive : Ordonnancement décentralisé, élection maître-esclave, auto-réparation
  • Prise en charge de plusieurs modes d'exécution : Local, Debug, Serverless
  • Chaîne d'outils complète : CLI dify, SDK Python, Runtime de débogage
  • Écosystème riche : 70+ plugins de modèle, 20+ plugins d'outil, 18+ plugins de source de données
  • Qualité de production : OAuth 2.0, Contrôle d'accès, Surveillance et traçage

Démarrage Rapide

1. Préparation de l'Environnement

# Installer Python 3.12+
python --version  # Assurez-vous >= 3.12

# Installer le gestionnaire de paquets uv (recommandé)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Installer la CLI dify
pip install dify-cli

# Vérifier l'installation
dify --version

2. Créer le Premier Plugin

# Initialiser un projet de plugin
dify plugin init

# Choisir le type de plugin
? Select plugin type: Tool
? Plugin name: my_first_tool
? Author: your_name
? Description: My first Dify tool plugin

# Entrer dans le répertoire du projet
cd my_first_tool

# Installer les dépendances
uv pip install -r requirements.txt

3. Implémenter la Logique du Plugin

Éditez tools/my_tool.py :

from typing import Any, Generator
from dify_plugin.entities.tool import ToolInvokeMessage
from dify_plugin import Tool


class MyTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        """
        Point d'entrée de l'appel de l'outil
        """
        # Récupérer les paramètres
        text = tool_parameters.get("text", "")

        # Logique de traitement
        result = f"Résultat du traitement : {text.upper()}"

        # Retourner le résultat
        yield self.create_text_message(result)

4. Débogage Local

# Démarrer le Runtime de Débogage
dify plugin run

# Tester le plugin dans l'interface Dify
# Accéder à http://localhost:5001

5. Empaquetage et Déploiement

# Empaqueter le plugin
dify plugin package

# Générer le fichier my_first_tool.difypkg
# Télécharger sur le Dify Marketplace ou un déploiement privé

Concepts Fondamentaux

Architecture Beehive

Le système de plugins Dify utilise l'architecture Beehive (Ruche), dont les caractéristiques principales sont :

  1. Ordonnancement Décentralisé : Chaque nœud du processus de garde gère les plugins localement de manière indépendante
  2. Élection Maître-Esclave : Élection automatique du nœud maître via un verrou distribué Redis
  3. Synchronisation d'État : L'état de tous les nœuds est stocké dans Redis, permettant un accès inter-nœuds
  4. Auto-Réparation : Réattribution automatique des plugins en cas de panne d'un nœud

Pour une description détaillée de l'architecture, veuillez vous référer à : types/architecture.md

Trois Modes d'Exécution

Mode d'ExécutionCas d'UtilisationMéthode de CommunicationAvantagesInconvénients
Runtime LocalDéveloppement local, déploiement à petite échelleSTDIN/STDOUTFaible latence, isolement des ressourcesUtilisation mémoire élevée, extensibilité limitée
Runtime de DébogageDébogage à distance, environnement de développementTCP Full-DuplexConviviale pour le développement, déploiement flexibleDépendance réseau, gestion d'état complexe
Runtime ServerlessEnvironnement de production à grande échelleHTTP/SSEMise à l'échelle automatique, optimisation des coûtsLatence de démarrage à froid, débogage complexe

Pour une comparaison détaillée, veuillez vous référer à : development/runtime-modes.md

Quatre Types de Plugins

1. Tool (Plugin d'Outil)

Outils pour étendre les capacités de l'IA, tels que la traduction, la recherche, le traitement de données, etc.

# Exemple : Google Traduction
type: plugin
plugins:
  tools:
    - provider/google_translate.yaml

Cas d'Utilisation :

  • Wrapper d'API (API REST → Outil)
  • Traitement de données (conversion de format, calcul)
  • Intégration de services externes (recherche, traduction)

2. Model (Plugin de Modèle)

Intégration de fournisseurs LLM, tels qu'Anthropic, OpenAI, Gemini, etc.

# Exemple : Anthropic Claude
type: plugin
plugins:
  models:
    - provider/anthropic.yaml

Cas d'Utilisation :

  • Intégration d'un nouveau fournisseur LLM
  • Configuration personnalisée du modèle
  • Prise en charge des modèles multimodaux

3. Datasource (Plugin de Source de Données)

Connexion aux systèmes de stockage, tels que S3, Google Drive, Notion, etc.

# Exemple : AWS S3
type: plugin
plugins:
  datasources:
    - provider/aws_s3.yaml

Cas d'Utilisation :

  • Intégration de stockage cloud
  • Connexion à des plateformes documentaires
  • Accès aux bases de données

4. Extension (Plugin d'Extension)

Extension des fonctionnalités de la plateforme, telle que l'intégration avec des plateformes tierces comme Slack, WeChat Work, etc.

# Exemple : Slack
type: plugin
plugins:
  extensions:
    - provider/slack.yaml

Cas d'Utilisation :

  • Intégration de plateformes tierces
  • Implémentation de déclencheurs
  • Stratégies d'agent personnalisées

Pour une description détaillée des types, veuillez vous référer à : types/


Structure du Projet

Structure standard d'un projet de plugin Dify :

my_plugin/
├── manifest.yaml           # Manifeste du plugin (obligatoire)
├── main.py                 # Point d'entrée (obligatoire)
├── requirements.txt        # Dépendances Python
├── pyproject.toml         # Configuration du projet
├── README.md              # Description du plugin
├── PRIVACY.md             # Politique de confidentialité (si OAuth requis)
├── .env.example           # Exemple de variables d'environnement
│
├── _assets/               # Fichiers de ressources
│   └── icon.svg          # Icône du plugin
│
├── provider/              # Configuration du fournisseur
│   ├── provider_name.yaml # Fichier de configuration du fournisseur
│   └── provider_name.py   # Implémentation du fournisseur
│
└── tools/                 # Implémentation des outils (Plugin Tool)
    ├── tool_name.yaml    # Fichier de configuration de l'outil
    └── tool_name.py      # Implémentation de l'outil

Description des Fichiers Principaux

manifest.yaml

Fichier de manifeste du plugin, définissant les informations et la configuration de base :

author: your_name
name: my_plugin
version: 0.0.1
type: plugin

description:
  en_US: Plugin description
  zh_Hans: Description du plugin

label:
  en_US: My Plugin
  zh_Hans: Mon plugin

icon: icon.svg

meta:
  version: 0.0.1
  arch:
    - amd64
    - arm64
  runner:
    language: python
    version: '3.12'
    entrypoint: main

plugins:
  tools:
    - provider/my_provider.yaml

resource:
  memory: 1048576  # 1 Mo = 1048576 octets
  permission:
    tool:
      enabled: true
    model:
      enabled: true
      llm: true

tags:
  - utilities

Pour une description détaillée de la configuration, veuillez vous référer à : development/manifest.md

main.py

Fichier d'entrée du plugin :

from dify_plugin import Plugin, DifyPluginEnv

# Créer une instance du plugin
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))

if __name__ == '__main__':
    # Démarrer le plugin
    plugin.run()

Guide de Développement

Développement d'un Plugin Tool

1. Créer le Fournisseur

Éditez provider/my_provider.yaml :

identity:
  author: your_name
  name: my_provider
  label:
    en_US: My Provider
    zh_Hans: Mon fournisseur
  description:
    en_US: Provider description
    zh_Hans: Description du fournisseur
  icon: icon.svg
  tags:
    - utilities

extra:
  python:
    source: provider/my_provider.py

tools:
  - tools/my_tool.yaml

Éditez provider/my_provider.py :

from typing import Any
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
from dify_plugin import ToolProvider
from tools.my_tool import MyTool


class MyProvider(ToolProvider):
    def _validate_credentials(self, credentials: dict[str, Any]) -> None:
        """
        Valider les identifiants (si nécessaire)
        """
        try:
            # Valider la clé API ou d'autres identifiants
            api_key = credentials.get("api_key")
            if not api_key:
                raise ToolProviderCredentialValidationError("La clé API est obligatoire")

            # Tester la validité des identifiants
            MyTool().invoke(
                tool_parameters={"text": "test"}
            )
        except Exception as e:
            raise ToolProviderCredentialValidationError(str(e))

2. Créer l'Outil

Éditez tools/my_tool.yaml :

identity:
  author: your_name
  name: my_tool
  label:
    en_US: My Tool
    zh_Hans: Mon outil

description:
  human:
    en_US: Tool description for humans
    zh_Hans: Description de l'outil pour les humains
  llm: Description de l'outil pour LLM

extra:
  python:
    source: tools/my_tool.py

parameters:
  - name: text
    type: string
    required: true
    label:
      en_US: Texte d'entrée
      zh_Hans: Texte d'entrée
    human_description:
      en_US: The text to process
      zh_Hans: Le texte à traiter
    llm_description: Le texte d'entrée à traiter
    form: llm

Éditez tools/my_tool.py :

from typing import Any, Generator
from dify_plugin.entities.tool import ToolInvokeMessage
from dify_plugin import Tool


class MyTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        """
        Point d'entrée de l'appel de l'outil

        Args:
            tool_parameters: Dictionnaire des paramètres de l'outil

        Yields:
            ToolInvokeMessage: Message d'appel de l'outil
        """
        # 1. Récupérer les paramètres
        text = tool_parameters.get("text", "")

        if not text:
            yield self.create_text_message("Erreur : le paramètre text est obligatoire")
            return

        try:
            # 2. Logique de traitement
            result = self._process_text(text)

            # 3. Retourner le résultat
            yield self.create_text_message(result)

        except Exception as e:
            yield self.create_text_message(f"Erreur : {str(e)}")

    def _process_text(self, text: str) -> str:
        """
        Logique spécifique de traitement du texte
        """
        return text.upper()

Pour un guide de développement détaillé, veuillez vous référer à : development/tool.md


Intégration OAuth 2.0

Aperçu du Flux OAuth

Dify prend en charge le flux d'autorisation complet OAuth 2.0 :

  1. Obtenir l'URL d'autorisation : L'utilisateur clique sur le bouton d'autorisation
  2. Autorisation de l'utilisateur : Redirection vers la page d'autorisation du service tiers
  3. Obtenir le code d'autorisation : Retour du code d'autorisation après autorisation de l'utilisateur
  4. Échanger le jeton d'accès : Utiliser le code d'autorisation pour échanger un jeton d'accès
  5. Rafraîchir le jeton : Utiliser le jeton de rafraîchissement pour obtenir un nouveau jeton d'accès lorsque celui-ci expire

Configuration du Schéma OAuth

Ajoutez la configuration OAuth dans provider/my_provider.yaml :

oauth_schema:
  client_schema:
    - name: client_id
      type: secret-input
      required: true
      label:
        en_US: ID Client
        zh_Hans: ID Client
      placeholder:
        en_US: Saisissez votre ID Client OAuth
        zh_Hans: Saisissez votre ID Client OAuth
      help:
        en_US: Obtenez votre ID client auprès du fournisseur de services
        zh_Hans: Obtenez votre ID client auprès du fournisseur de services
      url: https://console.example.com/credentials

    - name: client_secret
      type: secret-input
      required: true
      label:
        en_US: Secret Client
        zh_Hans: Secret Client
      placeholder:
        en_US: Saisissez votre Secret Client OAuth
        zh_Hans: Saisissez votre Secret Client OAuth

  credentials_schema:
    - name: access_token
      type: secret-input
      label:
        en_US: Jeton d'Accès
        zh_Hans: Jeton d'Accès

    - name: refresh_token
      type: secret-input
      label:
        en_US: Jeton de Rafraîchissement
        zh_Hans: Jeton de Rafraîchissement

Implémentation du Fournisseur OAuth

from typing import Any
from dify_plugin import ToolProvider
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
import requests


class MyOAuthProvider(ToolProvider):
    def _validate_credentials(self, credentials: dict[str, Any]) -> None:
        """
        Valider les identifiants OAuth
        """
        access_token = credentials.get("access_token")
        if not access_token:
            raise ToolProviderCredentialValidationError(
                "Le jeton d'accès est obligatoire"
            )

        # Tester la validité du jeton d'accès
        try:
            response = requests.get(
                "https://api.example.com/user",
                headers={"Authorization": f"Bearer {access_token}"}
            )
            response.raise_for_status()
        except Exception as e:
            raise ToolProviderCredentialValidationError(
                f"Jeton d'accès invalide : {str(e)}"
            )

Utilisation du Jeton OAuth

Utilisez le jeton OAuth dans un outil :

class MyOAuthTool(Tool):
    def _invoke(
        self, tool_parameters: dict[str, Any]
    ) -> Generator[ToolInvokeMessage, None, None]:
        # Récupérer les identifiants OAuth
        credentials = self.runtime.credentials
        access_token = credentials.get("access_token")

        # Appeler l'API
        response = requests.get(
            "https://api.example.com/data",
            headers={"Authorization": f"Bearer {access_token}"}
        )

        yield self.create_text_message(response.text)

Pour un guide complet d'intégration OAuth, veuillez vous référer à : development/oauth-integration.md


Tests et Débogage

Tests Unitaires

Écrivez des tests unitaires avec pytest :

# tests/test_my_tool.py
import pytest
from tools.my_tool import MyTool


def test_my_tool():
    tool = MyTool()
    result = list(tool.invoke(tool_parameters={"text": "bonjour"}))

    assert len(result) == 1
    assert "BONJOUR" in result[0].message

Exécutez les tests :

pytest tests/

Tests d'Intégration

Testez l'intégration du plugin avec le système Dify :

# tests/test_integration.py
def test_plugin_integration():
    # Tester l'installation du plugin
    # Tester l'appel de l'outil
    # Tester le flux OAuth
    pass

Débogage avec Debug Runtime

Démarrez le Debug Runtime pour le débogage à distance :

# Démarrer le Debug Runtime
dify plugin run --debug

# Tester dans l'interface Dify
# Voir les logs en temps réel et les messages d'erreur

Résolution des Problèmes Courants

Échec de Démarrage du Plugin

  • Vérifier la version de Python (nécessite 3.12+)
  • Vérifier l'installation des dépendances (requirements.txt)
  • Vérifier la configuration de manifest.yaml
  • Vérifier le chemin du fichier d'entrée (main.py)

Échec de Validation des Autorisations

  • Vérifier la configuration des credentials
  • Vérifier si le jeton OAuth a expiré
  • Vérifier si la clé API est valide
  • Vérifier les déclarations d'autorisation (resource.permission)

Erreurs d'Exécution

  • Ajuster le délai d'expiration (MAX_REQUEST_TIMEOUT)
  • Optimiser l'utilisation de la mémoire (resource.memory)
  • Vérifier la connexion réseau
  • Vérifier les autorisations d'appel inversé

Pour un guide de dépannage détaillé, veuillez vous référer à : testing/troubleshooting.md


Migration d'API vers Plugin

Stratégie de Migration

  1. Mode Wrapper API : Encapsuler une API REST en plugin Tool
  2. Mode Intégration SDK : Utiliser un SDK Python tiers
  3. Migration OAuth : Implémenter le flux d'autorisation OAuth 2.0
  4. Optimisation des Opérations par Lots : Utiliser des réponses en flux pour traiter de gros volumes de données

Étapes de Migration

  1. Analyser l'API Existante

    • Points de terminaison et paramètres de l'API
    • Méthode d'authentification (clé API / OAuth)
    • Format de réponse et gestion des erreurs
  2. Choisir le Type de Plugin

    • API REST → Plugin Tool
    • API LLM → Plugin Model
    • API de stockage → Plugin Datasource
  3. Créer le Projet de Plugin

    dify plugin init
    
  4. Implémenter l'Appel API

    import requests
    
    class APIWrapperTool(Tool):
        def _invoke(self, tool_parameters: dict[str, Any]):
            response = requests.post(
                "https://api.example.com/endpoint",
                json=tool_parameters,
                headers={"Authorization": f"Bearer {api_key}"}
            )
            yield self.create_text_message(response.text)
    
  5. Configurer l'Authentification

    • Clé API : Configurer credentials dans provider.yaml
    • OAuth : Configurer oauth_schema
  6. Ajouter la Gestion des Erreurs

    try:
        response = requests.post(...)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        yield self.create_text_message(f"Erreur API : {str(e)}")
    
  7. Écrire les Tests

    def test_api_wrapper():
        tool = APIWrapperTool()
        result = list(tool.invoke(tool_parameters={...}))
        assert result[0].message
    
  8. Empaqueter et Déployer

    dify plugin package
    

Cas Concrets

  • API REST → Tool : Google Traduction (sans authentification)
  • API OAuth → Tool : Google Contacts (OAuth 2.0)
  • API LLM → Model : Anthropic Claude (clé API)
  • API de stockage → Datasource : AWS S3 (Authentification IAM)

Pour un guide de migration détaillé, veuillez vous référer à : development/migration-guide.md


Bonnes Pratiques

Organisation du Code

  1. Responsabilité Unique : Chaque outil ne fait qu'une seule chose
  2. Gestion des Erreurs : Capturer toutes les exceptions et retourner des messages d'erreur conviviaux
  3. Validation des Paramètres : Valider tous les paramètres au début de _invoke
  4. Journalisation : Utiliser une journalisation structurée pour les opérations clés

Optimisation des Performances

  1. Réponses en Flux : Utiliser un générateur (Generator) pour les gros volumes de données
  2. Stratégie de Cache : Mettre en cache les données fréquemment consultées
  3. Traitement Asynchrone : Utiliser async/await pour les opérations I/O intensives
  4. Limites de Ressources : Configurer resource.memory de manière appropriée

Considérations de Sécurité

  1. Validation des Entrées : Valider toutes les entrées utilisateur
  2. Données Sensibles : Utiliser le type secret-input pour stocker les informations sensibles
  3. Contrôle d'Accès : Principe du moindre privilège, ne déclarer que les autorisations nécessaires
  4. Messages d'Erreur : Ne pas divulguer de données sensibles dans les messages d'erreur

Expérience Utilisateur

  1. Description Claire : Fournir des description et help détaillés
  2. Valeurs par Défaut Raisonnables : Fournir des valeurs par défaut raisonnables pour les paramètres
  3. Prise en Charge Multilingue : Prendre en charge au moins en_US et zh_Hans
  4. Erreurs Conviviales : Retourner des messages d'erreur compréhensibles par l'utilisateur

Déploiement et Exploitation

Choix du Mode d'Exécution

ScénarioMode RecommandéRaison
Développement localRuntime LocalFaible latence, débogage facile
Débogage à distanceRuntime de DébogageFlexible, prise en charge à distance
Production à petite échelleRuntime LocalSimple, faible coût
Production à grande échelleRuntime ServerlessMise à l'échelle automatique, haute disponibilité

Déploiement Serverless

Déploiement sur AWS Lambda :

# 1. Empaqueter le plugin
dify plugin package

# 2. Créer la fonction Lambda
aws lambda create-function \
  --function-name my-plugin \
  --runtime python3.12 \
  --handler main.handler \
  --zip-file fileb://my_plugin.difypkg

# 3. Configurer les variables d'environnement
aws lambda update-function-configuration \
  --function-name my-plugin \
  --environment Variables={MAX_REQUEST_TIMEOUT=120}

# 4. Configurer le point de terminaison API Gateway
aws apigateway create-rest-api --name my-plugin-api

Surveillance et Journalisation

import logging

logger = logging.getLogger(__name__)

class MonOutilLogger(Tool):
    def _invoke(self, tool_parameters: dict[str, Any]):
        logger.info(f"Début du traitement : {tool_parameters}")
        try:
            result = self._process(tool_parameters)
            logger.info(f"Traitement terminé : {result}")
            yield self.create_text_message(result)
        except Exception as e:
            logger.error(f"Erreur de traitement : {str(e)}")
            raise

Gestion des Versions

# Mettre à jour la version
dify plugin version bump minor

# Voir l'historique des versions
dify plugin version list

# Revenir à une version précédente
dify plugin version rollback 0.0.2

Références

Documentation Officielle

Références Architecture

Guides de Développement

Meilleures Pratiques

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

Skills associés