SKILL DE DESENVOLVIMENTO DE PLUGINS DIFY
Visão Geral
O sistema de plugins do Dify adota a arquitetura inovadora Beehive (Favo de Mel), suportando três modos de execução e oferecendo quatro tipos de plugins, fornecendo aos desenvolvedores poderosas capacidades de extensão. Este SKILL oferece um guia completo de desenvolvimento de plugins, do básico ao avançado.
Cenários de Uso
Use este SKILL quando precisar dos seguintes cenários:
- Desenvolver plugins Dify: Quatro tipos: Ferramenta, Modelo, Fonte de Dados, Extensão
- Integrar serviços de terceiros: Wrapper de API, autorização OAuth
- Implementar ferramentas personalizadas: Expandir capacidades de IA
- Estender funcionalidades da plataforma Dify: Gatilhos, estratégias de Agente
- Migrar APIs existentes para plugins: Conversão de API para plugin
- Depurar e otimizar o desempenho de plugins: Ajuste de desempenho e solução de problemas
Valor Principal
- Arquitetura Beehive: Escalonamento descentralizado, eleição líder-seguidor, autocura de falhas
- Suporte a múltiplos runtimes: Três modos: Local, Debug, Serverless
- Conjunto completo de ferramentas: CLI
dify, SDK Python, runtime de depuração - Ecossistema rico: Mais de 70 plugins de modelo, 20+ plugins de ferramenta, 18+ plugins de fonte de dados
- Qualidade de produção: OAuth 2.0, controle de permissão, monitoramento e rastreamento
Início Rápido
1. Preparação do Ambiente
# Instalar Python 3.12+
python --version # Garantir >= 3.12
# Instalar o gerenciador de pacotes uv (recomendado)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Instalar o CLI do Dify
pip install dify-cli
# Verificar a instalação
dify --version
2. Criar o Primeiro Plugin
# Inicializar o projeto do plugin
dify plugin init
# Selecionar o tipo de plugin
? Select plugin type: Tool
? Plugin name: my_first_tool
? Author: your_name
? Description: Meu primeiro plugin de ferramenta Dify
# Entrar no diretório do projeto
cd my_first_tool
# Instalar dependências
uv pip install -r requirements.txt
3. Implementar a Lógica do 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]:
"""
Ponto de entrada da chamada da ferramenta
"""
# Obter parâmetros
text = tool_parameters.get("text", "")
# Lógica de processamento
result = f"Resultado do processamento: {text.upper()}"
# Retornar resultado
yield self.create_text_message(result)
4. Depuração Local
# Iniciar o Debug Runtime
dify plugin run
# Testar o plugin na interface do Dify
# Acessar http://localhost:5001
5. Empacotar e Implantar
# Empacotar o plugin
dify plugin package
# Gera o arquivo my_first_tool.difypkg
# Fazer upload para o Dify Marketplace ou implantação privada
Conceitos Principais
Arquitetura Beehive
O sistema de plugins do Dify adota a arquitetura Beehive (Favo de Mel), com características principais:
- Escalonamento Descentralizado: Cada nó do processo daemon gerencia plugins locais de forma independente
- Eleição Líder-Seguidor: Usa bloqueio distribuído do Redis para eleição automática do nó líder
- Sincronização de Estado: O estado de todos os nós é armazenado no Redis, suportando acesso entre nós
- Autocura de Falhas: Quando um nó cai, os plugins são automaticamente redistribuídos
Para uma descrição detalhada da arquitetura, consulte: types/architecture.md
Três Modos de Runtime
| Modo de Runtime | Cenário de Uso | Método de Comunicação | Vantagens | Desvantagens |
|---|---|---|---|---|
| Local Runtime | Desenvolvimento local, implantação de pequena escala | STDIN/STDOUT | Baixa latência, isolamento de recursos | Alto consumo de memória, escalabilidade limitada |
| Debug Runtime | Depuração remota, ambiente de desenvolvimento | TCP full-duplex | Amigável para desenvolvimento, implantação flexível | Dependência de rede, gerenciamento de estado complexo |
| Serverless Runtime | Ambiente de produção em larga escala | HTTP/SSE | Escalonamento automático, otimização de custos | Latência de inicialização a frio, depuração complexa |
Para uma comparação detalhada, consulte: development/runtime-modes.md
Quatro Tipos de Plugins
1. Tool (Plugin de Ferramenta)
Ferramentas que expandem as capacidades de IA, como tradução, pesquisa, processamento de dados, etc.
# Exemplo: Google Translate
type: plugin
plugins:
tools:
- provider/google_translate.yaml
Cenários de Uso:
- Wrapper de API (REST API → Tool)
- Processamento de dados (conversão de formato, cálculos)
- Integração de serviços externos (pesquisa, tradução)
2. Model (Plugin de Modelo)
Conectar provedores de LLM, como Anthropic, OpenAI, Gemini, etc.
# Exemplo: Anthropic Claude
type: plugin
plugins:
models:
- provider/anthropic.yaml
Cenários de Uso:
- Conectar novos provedores de LLM
- Configuração personalizada de modelo
- Suporte a modelos multimodais
3. Datasource (Plugin de Fonte de Dados)
Conectar sistemas de armazenamento, como S3, Google Drive, Notion, etc.
# Exemplo: AWS S3
type: plugin
plugins:
datasources:
- provider/aws_s3.yaml
Cenários de Uso:
- Integração com armazenamento em nuvem
- Conexão com plataformas de documentos
- Acesso a bancos de dados
4. Extension (Plugin de Extensão)
Extensões de funcionalidades da plataforma, como integração com plataformas de terceiros (Slack, WeCom, etc.).
# Exemplo: Slack
type: plugin
plugins:
extensions:
- provider/slack.yaml
Cenários de Uso:
- Integração com plataformas de terceiros
- Implementação de gatilhos
- Estratégias personalizadas de Agente
Para descrições detalhadas dos tipos, consulte: types/
Estrutura do Projeto
Estrutura padrão de um projeto de plugin Dify:
my_plugin/
├── manifest.yaml # Manifesto do plugin (obrigatório)
├── main.py # Arquivo de entrada (obrigatório)
├── requirements.txt # Dependências Python
├── pyproject.toml # Configuração do projeto
├── README.md # Descrição do plugin
├── PRIVACY.md # Política de privacidade (se necessário OAuth)
├── .env.example # Exemplo de variáveis de ambiente
│
├── _assets/ # Arquivos de recursos
│ └── icon.svg # Ícone do plugin
│
├── provider/ # Configuração do provedor
│ ├── provider_name.yaml # Arquivo de configuração do provedor
│ └── provider_name.py # Implementação do provedor
│
└── tools/ # Implementação da ferramenta (Plugin Tool)
├── tool_name.yaml # Arquivo de configuração da ferramenta
└── tool_name.py # Implementação da ferramenta
Descrição dos Arquivos Principais
manifest.yaml
Arquivo de manifesto do plugin, definindo as informações básicas e configuração:
author: your_name
name: my_plugin
version: 0.0.1
type: plugin
description:
en_US: Plugin description
zh_Hans: 插件描述
label:
en_US: My Plugin
zh_Hans: 我的插件
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 configuração detalhada, consulte: development/manifest.md
main.py
Arquivo de entrada do plugin:
from dify_plugin import Plugin, DifyPluginEnv
# Criar instância do plugin
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))
if __name__ == '__main__':
# Iniciar o plugin
plugin.run()
Guia de Desenvolvimento
Desenvolvimento de Plugin Tool
1. Criar o Provider
Edite provider/my_provider.yaml:
identity:
author: your_name
name: my_provider
label:
en_US: My Provider
zh_Hans: 我的提供者
description:
en_US: Provider description
zh_Hans: 提供者描述
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 credenciais (se necessário)
"""
try:
# Validar chave de API ou outras credenciais
api_key = credentials.get("api_key")
if not api_key:
raise ToolProviderCredentialValidationError("API Key é obrigatória")
# Testar a validade das credenciais
MyTool().invoke(
tool_parameters={"text": "teste"}
)
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))
2. Criar a Tool
Edite tools/my_tool.yaml:
identity:
author: your_name
name: my_tool
label:
en_US: My Tool
zh_Hans: 我的工具
description:
human:
en_US: Tool description for humans
zh_Hans: 给人类看的工具描述
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: 输入文本
human_description:
en_US: The text to process
zh_Hans: 要处理的文本
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]:
"""
Ponto de entrada da chamada da ferramenta
Args:
tool_parameters: Dicionário de parâmetros da ferramenta
Yields:
ToolInvokeMessage: Mensagem de chamada da ferramenta
"""
# 1. Obter parâmetros
text = tool_parameters.get("text", "")
if not text:
yield self.create_text_message("Erro: parâmetro 'text' é obrigatório")
return
try:
# 2. Lógica de processamento
result = self._process_text(text)
# 3. Retornar resultado
yield self.create_text_message(result)
except Exception as e:
yield self.create_text_message(f"Erro: {str(e)}")
def _process_text(self, text: str) -> str:
"""
Lógica específica para processar o texto
"""
return text.upper()
Para um guia de desenvolvimento detalhado, consulte: development/tool.md
Integração OAuth 2.0
Visão Geral do Fluxo OAuth
O Dify suporta o fluxo de autorização OAuth 2.0 completo:
- Obter URL de Autorização: O usuário clica no botão de autorização
- Autorização do Usuário: Redireciona para a página de autorização do serviço de terceiros
- Obter Código de Autorização: Após a autorização do usuário, retorna o código de autorização
- Trocar por Token de Acesso: Usa o código de autorização para trocar por um token de acesso
- Atualizar Token: Quando o token de acesso expira, usa o token de atualização para obter um novo token
Configurar o Schema OAuth
Adicione a configuração OAuth em provider/my_provider.yaml:
oauth_schema:
client_schema:
- name: client_id
type: secret-input
required: true
label:
en_US: Client ID
zh_Hans: 客户端 ID
placeholder:
en_US: Enter your OAuth Client ID
zh_Hans: 输入您的 OAuth 客户端 ID
help:
en_US: Get your client ID from the service provider
zh_Hans: 从服务提供商获取客户端 ID
url: https://console.example.com/credentials
- name: client_secret
type: secret-input
required: true
label:
en_US: Client Secret
zh_Hans: 客户端密钥
placeholder:
en_US: Enter your OAuth Client Secret
zh_Hans: 输入您的 OAuth 客户端密钥
credentials_schema:
- name: access_token
type: secret-input
label:
en_US: Access Token
zh_Hans: 访问令牌
- name: refresh_token
type: secret-input
label:
en_US: Refresh Token
zh_Hans: 刷新令牌
Implementar um 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 credenciais OAuth
"""
access_token = credentials.get("access_token")
if not access_token:
raise ToolProviderCredentialValidationError(
"Token de acesso é obrigatório"
)
# Testar a validade do token de acesso
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 acesso inválido: {str(e)}"
)
Usar Token OAuth em uma Tool
Use o token OAuth dentro da Tool:
class MyOAuthTool(Tool):
def _invoke(
self, tool_parameters: dict[str, Any]
) -> Generator[ToolInvokeMessage, None, None]:
# Obter credenciais OAuth
credentials = self.runtime.credentials
access_token = credentials.get("access_token")
# Chamar a API
response = requests.get(
"https://api.example.com/data",
headers={"Authorization": f"Bearer {access_token}"}
)
yield self.create_text_message(response.text)
Para um guia completo de integração OAuth, consulte: development/oauth-integration.md
Testes e Depuração
Testes Unitários
Use pytest para escrever testes unitários:
# 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
Execute os testes:
pytest tests/
Testes de Integração
Teste a integração do plugin com o sistema Dify:
# tests/test_integration.py
def test_plugin_integration():
# Testar instalação do plugin
# Testar chamada da ferramenta
# Testar fluxo OAuth
pass
Depuração com Debug Runtime
Inicie o Debug Runtime para depuração remota:
# Iniciar o Debug Runtime
dify plugin run --debug
# Testar na interface do Dify
# Ver logs e mensagens de erro em tempo real
Solução de Problemas Comuns
Falha ao Iniciar o Plugin
- Verificar a versão do Python (precisa ser 3.12+)
- Verificar a instalação das dependências (
requirements.txt) - Verificar a configuração do
manifest.yaml - Verificar o caminho do arquivo de entrada (
main.py)
Falha na Validação de Permissão
- Verificar a configuração de
credentials - Verificar se o token OAuth expirou
- Verificar se a chave de API é válida
- Verificar a declaração de permissão (
resource.permission)
Erros em Tempo de Execução
- Ajustar o tempo limite (
MAX_REQUEST_TIMEOUT) - Otimizar o uso de memória (
resource.memory) - Verificar a conexão de rede
- Verificar a permissão de chamada reversa
Para um guia detalhado de solução de problemas, consulte: testing/troubleshooting.md
Migração de API para Plugin
Estratégia de Migração
- Modo Wrapper de API: Empacotar uma REST API como um plugin Tool
- Modo de Integração com SDK: Usar SDK Python de terceiros
- Migração OAuth: Implementar o fluxo de autorização OAuth 2.0
- Otimização de Operações em Lote: Usar respostas em streaming para processar grandes volumes de dados
Etapas da Migração
-
Analisar a API Existente
- Endpoints e parâmetros da API
- Método de autenticação (API Key / OAuth)
- Formato de resposta e tratamento de erros
-
Selecionar o Tipo de Plugin
- REST API → Plugin Tool
- API de LLM → Plugin Model
- API de Armazenamento → Plugin Datasource
-
Criar o Projeto do Plugin
dify plugin init -
Implementar a Chamada à 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 Autenticação
- Chave de API: Configurar
credentialsemprovider.yaml - OAuth: Configurar
oauth_schema
- Chave de API: Configurar
-
Adicionar Tratamento de Erros
try: response = requests.post(...) response.raise_for_status() except requests.exceptions.RequestException as e: yield self.create_text_message(f"Erro na API: {str(e)}") -
Escrever Testes
def test_api_wrapper(): tool = APIWrapperTool() result = list(tool.invoke(tool_parameters={...})) assert result[0].message -
Empacotar e Implantar
dify plugin package
Exemplos Práticos
- REST API → Tool: Google Translate (sem autenticação)
- API OAuth → Tool: Google Contacts (OAuth 2.0)
- API de LLM → Model: Anthropic Claude (Chave de API)
- API de Armazenamento → Datasource: AWS S3 (autenticação IAM)
Para um guia detalhado de migração, consulte: development/migration-guide.md
Melhores Práticas
Organização do Código
- Responsabilidade Única: Cada Tool faz apenas uma coisa
- Tratamento de Erros: Capture todas as exceções e retorne mensagens de erro amigáveis
- Validação de Parâmetros: Valide todos os parâmetros no início do
_invoke - Registro em Log: Use logs estruturados para registrar operações críticas
Otimização de Desempenho
- Respostas em Streaming: Use Generator para retornar grandes dados em streaming
- Estratégia de Cache: Armazene em cache dados acessados com frequência
- Processamento Assíncrono: Use
async/awaitpara operações intensivas de I/O - Limites de Recursos: Configure
resource.memoryadequadamente
Considerações de Segurança
- Validação de Entrada: Valide todas as entradas do usuário
- Dados Sensíveis: Use o tipo
secret-inputpara armazenar informações confidenciais - Controle de Permissão: Princípio do menor privilégio, declare apenas as permissões necessárias
- Mensagens de Erro: Não vaze dados sensíveis em mensagens de erro
Experiência do Usuário
- Descrições Claras: Forneça
descriptionehelpdetalhados - Valores Padrão Razoáveis: Forneça valores padrão adequados para os parâmetros
- Suporte a Múltiplos Idiomas: Suporte pelo menos
en_USezh_Hans - Erros Amigáveis: Retorne mensagens de erro compreensíveis para o usuário
Implantação e Operação
Escolha do Modo de Runtime
| Cenário | Modo Recomendado | Motivo |
|---|---|---|
| Desenvolvimento local | Local Runtime | Baixa latência, fácil depuração |
| Depuração remota | Debug Runtime | Flexível, suporta remoto |
| Produção de pequena escala | Local Runtime | Simples, baixo custo |
| Produção em larga escala | Serverless Runtime | Escalonamento automático, alta disponibilidade |
Implantação Serverless
Implantação no AWS Lambda:
# 1. Empacotar o plugin
dify plugin package
# 2. Criar função Lambda
aws lambda create-function \
--function-name my-plugin \
--runtime python3.12 \
--handler main.handler \
--zip-file fileb://my_plugin.difypkg
# 3. Configurar variáveis de ambiente
aws lambda update-function-configuration \
--function-name my-plugin \
--environment Variab
…
[truncado para tradução]