HABILIDAD: Desarrollo de plugins de Dify
Descripción general
El sistema de plugins de Dify emplea la innovadora arquitectura Beehive (colmena), que soporta tres modos de ejecución y ofrece cuatro tipos de plugins, proporcionando a los desarrolladores una potente capacidad de extensión. Esta habilidad proporciona una guía completa para el desarrollo de plugins, desde el nivel básico hasta el avanzado.
Casos de uso
Utilice esta habilidad cuando necesite:
- Desarrollar plugins de Dify: cuatro tipos: herramientas, modelos, fuentes de datos y extensiones
- Integrar servicios de terceros: envoltorios de API, autorización OAuth
- Implementar herramientas personalizadas: extender las capacidades de IA
- Ampliar la funcionalidad de la plataforma Dify: disparadores, estrategias de agente
- Migrar API existentes a plugins: conversión de API a plugin
- Depurar y optimizar el rendimiento de plugins: ajuste de rendimiento y resolución de problemas
Valor principal
- Arquitectura Beehive: programación descentralizada, elección maestro-esclavo, autocuración de fallos
- Soporte de múltiples entornos de ejecución: modos Local, Debug y Serverless
- Conjunto de herramientas completo: CLI de dify, SDK de Python, entorno de ejecución de depuración
- Ecosistema rico: más de 70 plugins de modelo, más de 20 plugins de herramienta, más de 18 plugins de fuente de datos
- Calidad de producción: OAuth 2.0, control de permisos, monitoreo y seguimiento
Inicio rápido
1. Preparación del entorno
# Instalar Python 3.12+
python --version # Asegúrese de que sea >= 3.12
# Instalar el gestor de paquetes uv (recomendado)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Instalar dify CLI
pip install dify-cli
# Verificar la instalación
dify --version
2. Crear el primer plugin
# Inicializar el proyecto de plugin
dify plugin init
# Seleccionar el tipo de plugin
? Select plugin type: Tool
? Plugin name: my_first_tool
? Author: your_name
? Description: My first Dify tool plugin
# Entrar en el directorio del proyecto
cd my_first_tool
# Instalar dependencias
uv pip install -r requirements.txt
3. Implementar la lógica del plugin
Edite 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]:
"""
Punto de entrada de la invocación de la herramienta
"""
# Obtener parámetros
text = tool_parameters.get("text", "")
# Lógica de procesamiento
result = f"Resultado del procesamiento: {text.upper()}"
# Devolver resultado
yield self.create_text_message(result)
4. Depuración local
# Iniciar Debug Runtime
dify plugin run
# Probar el plugin en la interfaz de Dify
# Visitar http://localhost:5001
5. Empaquetado e implementación
# Empaquetar el plugin
dify plugin package
# Genera el archivo my_first_tool.difypkg
# Subir a Dify Marketplace o implementación privada
Conceptos principales
Arquitectura Beehive
El sistema de plugins de Dify emplea la arquitectura Beehive (colmena), con las siguientes características principales:
- Programación descentralizada: cada nodo del daemon gestiona los plugins locales de forma independiente
- Elección maestro-esclavo: utiliza bloqueos distribuidos de Redis para la elección automática del nodo maestro
- Sincronización de estado: el estado de todos los nodos se almacena en Redis, lo que permite el acceso entre nodos
- Autocuración de fallos: cuando un nodo falla, los plugins se reasignan automáticamente
Para obtener una descripción arquitectónica detallada, consulte: tipos/architecture.md
Tres modos de ejecución
| Modo de ejecución | Caso de uso | Método de comunicación | Ventajas | Desventajas |
|---|---|---|---|---|
| Local Runtime | Desarrollo local, implementación a pequeña escala | STDIN/STDOUT | Baja latencia, aislamiento de recursos | Alto uso de memoria, escalabilidad limitada |
| Debug Runtime | Depuración remota, entorno de desarrollo | TCP dúplex completo | Amigable para el desarrollo, implementación flexible | Dependencia de red, gestión de estado compleja |
| Serverless Runtime | Entornos de producción a gran escala | HTTP/SSE | Autoescalado, optimización de costos | Latencia de inicio en frío, depuración compleja |
Para una comparación detallada, consulte: desarrollo/modos-ejecucion.md
Cuatro tipos de plugins
1. Tool (Plugin de herramienta)
Herramientas que extienden las capacidades de IA, como traducción, búsqueda, procesamiento de datos, etc.
# Ejemplo: Google Translate
type: plugin
plugins:
tools:
- provider/google_translate.yaml
Casos de uso:
- Envoltorio de API (REST API → Tool)
- Procesamiento de datos (conversión de formatos, cálculos)
- Integración de servicios externos (búsqueda, traducción)
2. Model (Plugin de modelo)
Integra proveedores de LLM, como Anthropic, OpenAI, Gemini, etc.
# Ejemplo: Anthropic Claude
type: plugin
plugins:
models:
- provider/anthropic.yaml
Casos de uso:
- Integrar nuevos proveedores de LLM
- Configuración personalizada de modelos
- Soporte de modelos multimodales
3. Datasource (Plugin de fuente de datos)
Conecta sistemas de almacenamiento, como S3, Google Drive, Notion, etc.
# Ejemplo: AWS S3
type: plugin
plugins:
datasources:
- provider/aws_s3.yaml
Casos de uso:
- Integración de almacenamiento en la nube
- Conexión a plataformas de documentos
- Acceso a bases de datos
4. Extension (Plugin de extensión)
Extiende la funcionalidad de la plataforma, como la integración de Slack, WeChat empresarial, etc.
# Ejemplo: Slack
type: plugin
plugins:
extensions:
- provider/slack.yaml
Casos de uso:
- Integración de plataformas de terceros
- Implementación de disparadores
- Estrategias personalizadas de agente
Para obtener una descripción detallada de los tipos, consulte: tipos/
Estructura del proyecto
Estructura estándar de un proyecto de plugin de Dify:
my_plugin/
├── manifest.yaml # Manifiesto del plugin (requerido)
├── main.py # Archivo de entrada (requerido)
├── requirements.txt # Dependencias de Python
├── pyproject.toml # Configuración del proyecto
├── README.md # Descripción del plugin
├── PRIVACY.md # Política de privacidad (si requiere OAuth)
├── .env.example # Ejemplo de variables de entorno
│
├── _assets/ # Archivos de recursos
│ └── icon.svg # Icono del plugin
│
├── provider/ # Configuración del proveedor
│ ├── provider_name.yaml # Archivo de configuración del proveedor
│ └── provider_name.py # Implementación del proveedor
│
└── tools/ # Implementación de herramientas (Plugin Tool)
├── tool_name.yaml # Archivo de configuración de la herramienta
└── tool_name.py # Implementación de la herramienta
Descripción de archivos principales
manifest.yaml
Archivo de manifiesto del plugin, que define la información básica y la configuración del plugin:
author: your_name
name: my_plugin
version: 0.0.1
type: plugin
description:
en_US: Plugin description
zh_Hans: Descripción del plugin
label:
en_US: My Plugin
zh_Hans: Mi 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 # 1MB = 1048576 bytes
permission:
tool:
enabled: true
model:
enabled: true
llm: true
tags:
- utilities
Para obtener instrucciones de configuración detalladas, consulte: desarrollo/manifest.md
main.py
Archivo de entrada del plugin:
from dify_plugin import Plugin, DifyPluginEnv
# Crear instancia del plugin
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))
if __name__ == '__main__':
# Iniciar el plugin
plugin.run()
Guía de desarrollo
Desarrollo de plugins Tool
1. Crear el Provider
Edite provider/my_provider.yaml:
identity:
author: your_name
name: my_provider
label:
en_US: My Provider
zh_Hans: Mi Proveedor
description:
en_US: Provider description
zh_Hans: Descripción del proveedor
icon: icon.svg
tags:
- utilities
extra:
python:
source: provider/my_provider.py
tools:
- tools/my_tool.yaml
Edite 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:
"""
Validar credenciales (si es necesario)
"""
try:
# Validar API Key u otras credenciales
api_key = credentials.get("api_key")
if not api_key:
raise ToolProviderCredentialValidationError("API Key es requerida")
# Probar la validez de las credenciales
MyTool().invoke(
tool_parameters={"text": "test"}
)
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))
2. Crear la Tool
Edite tools/my_tool.yaml:
identity:
author: your_name
name: my_tool
label:
en_US: My Tool
zh_Hans: Mi Herramienta
description:
human:
en_US: Tool description for humans
zh_Hans: Descripción de la herramienta para humanos
llm: Tool description for LLM
extra:
python:
source: tools/my_tool.py
parameters:
- name: text
type: string
required: true
label:
en_US: Input Text
zh_Hans: Texto de entrada
human_description:
en_US: The text to process
zh_Hans: El texto a procesar
llm_description: The input text to be processed
form: llm
Edite 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]:
"""
Punto de entrada de la invocación de la herramienta
Args:
tool_parameters: Diccionario de parámetros de la herramienta
Yields:
ToolInvokeMessage: Mensaje de invocación de la herramienta
"""
# 1. Obtener parámetros
text = tool_parameters.get("text", "")
if not text:
yield self.create_text_message("Error: el parámetro text es requerido")
return
try:
# 2. Lógica de procesamiento
result = self._process_text(text)
# 3. Devolver resultado
yield self.create_text_message(result)
except Exception as e:
yield self.create_text_message(f"Error: {str(e)}")
def _process_text(self, text: str) -> str:
"""
Lógica específica para procesar texto
"""
return text.upper()
Para obtener una guía de desarrollo detallada, consulte: desarrollo/tool.md
Integración OAuth 2.0
Resumen del flujo OAuth
Dify soporta el flujo de autorización OAuth 2.0 completo:
- Obtener URL de autorización: el usuario hace clic en el botón de autorización
- Autorización del usuario: redirige a la página de autorización del servicio de terceros
- Obtener código de autorización: el usuario autoriza y devuelve un código de autorización
- Intercambiar por token de acceso: utiliza el código de autorización para intercambiar por un token de acceso
- Actualizar token: cuando el token de acceso caduca, utiliza el token de actualización para obtener uno nuevo
Configurar el esquema OAuth
Añada la configuración OAuth en provider/my_provider.yaml:
oauth_schema:
client_schema:
- name: client_id
type: secret-input
required: true
label:
en_US: Client ID
zh_Hans: ID de Cliente
placeholder:
en_US: Enter your OAuth Client ID
zh_Hans: Ingrese su ID de Cliente OAuth
help:
en_US: Get your client ID from the service provider
zh_Hans: Obtenga su ID de Cliente del proveedor de servicios
url: https://console.example.com/credentials
- name: client_secret
type: secret-input
required: true
label:
en_US: Client Secret
zh_Hans: Secreto de Cliente
placeholder:
en_US: Enter your OAuth Client Secret
zh_Hans: Ingrese su Secreto de Cliente OAuth
credentials_schema:
- name: access_token
type: secret-input
label:
en_US: Access Token
zh_Hans: Token de Acceso
- name: refresh_token
type: secret-input
label:
en_US: Refresh Token
zh_Hans: Token de Actualización
Implementar el Provider 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:
"""
Validar credenciales OAuth
"""
access_token = credentials.get("access_token")
if not access_token:
raise ToolProviderCredentialValidationError(
"El token de acceso es requerido"
)
# Probar la validez del token de acceso
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"Token de acceso inválido: {str(e)}"
)
Usar el token OAuth
Use el token OAuth en la herramienta:
class MyOAuthTool(Tool):
def _invoke(
self, tool_parameters: dict[str, Any]
) -> Generator[ToolInvokeMessage, None, None]:
# Obtener credenciales OAuth
credentials = self.runtime.credentials
access_token = credentials.get("access_token")
# Llamar a la API
response = requests.get(
"https://api.example.com/data",
headers={"Authorization": f"Bearer {access_token}"}
)
yield self.create_text_message(response.text)
Para obtener una guía completa de integración OAuth, consulte: desarrollo/integracion-oauth.md
Pruebas y depuración
Pruebas unitarias
Escriba pruebas unitarias con 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": "hello"}))
assert len(result) == 1
assert "HELLO" in result[0].message
Ejecute las pruebas:
pytest tests/
Pruebas de integración
Pruebe la integración del plugin con el sistema Dify:
# tests/test_integration.py
def test_plugin_integration():
# Probar la instalación del plugin
# Probar la invocación de la herramienta
# Probar el flujo OAuth
pass
Depuración con Debug Runtime
Inicie Debug Runtime para depuración remota:
# Iniciar Debug Runtime
dify plugin run --debug
# Probar en la interfaz de Dify
# Ver registros en tiempo real y mensajes de error
Solución de problemas comunes
El plugin no se inicia
- Verifique la versión de Python (se necesita 3.12+)
- Verifique la instalación de dependencias (
requirements.txt) - Verifique la configuración de
manifest.yaml - Verifique la ruta del archivo de entrada (
main.py)
Error de validación de permisos
- Verifique la configuración de
credentials - Verifique si el token OAuth ha caducado
- Verifique si la API Key es válida
- Verifique la declaración de permisos (
resource.permission)
Errores en tiempo de ejecución
- Ajuste el tiempo de espera (
MAX_REQUEST_TIMEOUT) - Optimice el uso de memoria (
resource.memory) - Verifique la conexión de red
- Verifique los permisos de invocación inversa
Para obtener una guía detallada de solución de problemas, consulte: pruebas/solucion-problemas.md
Migración de API a plugin
Estrategias de migración
- Modo envoltorio de API: empaquetar la API REST como un plugin Tool
- Modo integración SDK: utilizar SDK de Python de terceros
- Migración OAuth: implementar el flujo de autorización OAuth 2.0
- Optimización de operaciones por lotes: utilizar respuestas de streaming para manejar grandes volúmenes de datos
Pasos de migración
-
Analizar la API existente
- Endpoints y parámetros de la API
- Método de autenticación (API Key / OAuth)
- Formato de respuesta y manejo de errores
-
Seleccionar el tipo de plugin
- REST API → Plugin Tool
- LLM API → Plugin Model
- API de almacenamiento → Plugin Datasource
-
Crear el proyecto de plugin
dify plugin init -
Implementar la llamada a la 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) -
Configurar la autenticación
- API Key: configurar
credentialsenprovider.yaml - OAuth: configurar
oauth_schema
- API Key: configurar
-
Añadir manejo de errores
try: response = requests.post(...) response.raise_for_status() except requests.exceptions.RequestException as e: yield self.create_text_message(f"Error de API: {str(e)}") -
Escribir pruebas
def test_api_wrapper(): tool = APIWrapperTool() result = list(tool.invoke(tool_parameters={...})) assert result[0].message -
Empaquetar e implementar
dify plugin package
Casos prácticos
- REST API → Tool: Google Translate (sin autenticación)
- OAuth API → Tool: Google Contacts (OAuth 2.0)
- LLM API → Model: Anthropic Claude (API Key)
- API de almacenamiento → Datasource: AWS S3 (autenticación IAM)
Para obtener una guía de migración detallada, consulte: desarrollo/guia-migracion.md
Mejores prácticas
Organización del código
- Responsabilidad única: cada Tool debe hacer solo una cosa
- Manejo de errores: capturar todas las excepciones y devolver mensajes de error amigables
- Validación de parámetros: validar todos los parámetros al inicio de
_invoke - Registro de actividad: utilizar registros estructurados para registrar operaciones clave
Optimización del rendimiento
- Respuestas de streaming: utilizar Generator para devolver datos grandes de forma continua
- Estrategia de caché: almacenar en caché los datos a los que se accede con frecuencia
- Procesamiento asíncrono: utilizar async/await para operaciones intensivas de E/S
- Límites de recursos: configurar adecuadamente
resource.memory
Consideraciones de seguridad
- Validación de entrada: validar todas las entradas del usuario
- Datos sensibles: utilizar el tipo
secret-inputpara almacenar información sensible - Control de permisos: principio de mínimo privilegio, declarar solo los permisos necesarios
- Mensajes de error: no filtrar datos sensibles en los mensajes de error
Experiencia de usuario
- Descripciones claras: proporcionar
descriptionyhelpdetallados - Valores predeterminados razonables: proporcionar valores predeterminados adecuados para los parámetros
- Soporte multilingüe: al menos soportar
en_USyzh_Hans - Errores amigables: devolver mensajes de error que el usuario pueda entender
Implementación y operación
Selección del modo de ejecución
| Escenario | Modo recomendado | Razón |
|---|---|---|
| Desarrollo local | Local Runtime | Baja latencia, fácil depuración |
| Depuración remota | Debug Runtime | Flexible, compatible con remoto |
| Producción a pequeña escala | Local Runtime | Simple, bajo costo |
| Producción a gran escala | Serverless Runtime | Autoescalado, alta disponibilidad |
Implementación Serverless
Implementación en AWS Lambda:
# 1. Empaquetar el plugin
dify plugin package
# 2. Crear la función Lambda
aws lambda create-function \
--function-name my-plugin \
--runtime python3.12 \
--handler main.handler \
--zip-file fileb://my_plugin.difypkg
# 3. Configurar variables de entorno
aws lambda update-function-configuration \
--function-name my-plugin \
--environment Variables={...}
# 4. Probar la función
aws lambda invoke \
--function-name my-plugin \
--payload file://test_event.json \
response.json
Monitoreo y registro
- Registros estructurados: registrar todos los eventos clave en formato JSON
- Seguimiento de rendimiento: registrar tiempos de ejecución de herramientas
- Alertas: configurar alertas umbral para tiempos de espera
- Registros de auditoría: registrar todas las llamadas a herramientas para auditoría
Estrategia de versionado
- Versionado semántico: seguir el formato MAJOR.MINOR.PATCH
- Versión del manifiesto: mantener la consistencia con
manifest.yaml - Registro de cambios: mantener un registro detallado de cambios
- Retrocompatibilidad: garantizar la compatibilidad entre versiones menores