Dify プラグイン開発 SKILL
概要
Dify プラグインシステムは、革新的な Beehive(ハイブ)アーキテクチャを採用しており、3つのランタイムモードと4種類のプラグインタイプをサポートし、開発者に強力な拡張機能を提供します。この SKILL は、初心者からエキスパートまで対応する完全なプラグイン開発ガイドです。
適用シーン
以下のようなシナリオでこの SKILL を使用します:
- Dify プラグインの開発:ツール、モデル、データソース、拡張の4タイプ
- サードパーティサービスとの統合:API ラッピング、OAuth 認証
- カスタムツールの実装:AI 機能の拡張
- Dify プラットフォーム機能の拡張:トリガー、Agent ポリシー
- 既存 API のプラグインへの移行:API からプラグインへの変換
- プラグインパフォーマンスのデバッグと最適化:パフォーマンスチューニングと問題解決
コアバリュー
- Beehive アーキテクチャ:分散スケジューリング、マスター選出、障害自己修復
- マルチランタイムサポート:Local、Debug、Serverless の3モード
- 完全なツールチェーン:dify CLI、Python SDK、デバッグランタイム
- 豊富なエコシステム:70+ のモデルプラグイン、20+ のツールプラグイン、18+ のデータソースプラグイン
- プロダクションレベルの品質:OAuth 2.0、アクセス制御、モニタリングトレース
クイックスタート
1. 環境準備
# Python 3.12+ のインストール
python --version # >= 3.12 を確認
# uv パッケージマネージャーのインストール(推奨)
curl -LsSf https://astral.sh/uv/install.sh | sh
# dify CLI のインストール
pip install dify-cli
# インストールの確認
dify --version
2. 最初のプラグインを作成
# プラグインプロジェクトの初期化
dify plugin init
# プラグインタイプの選択
? Select plugin type: Tool
? Plugin name: my_first_tool
? Author: your_name
? Description: My first Dify tool plugin
# プロジェクトディレクトリへ移動
cd my_first_tool
# 依存関係のインストール
uv pip install -r requirements.txt
3. プラグインロジックの実装
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]:
"""
ツール呼び出しエントリポイント
"""
# パラメータの取得
text = tool_parameters.get("text", "")
# 処理ロジック
result = f"処理結果: {text.upper()}"
# 結果を返す
yield self.create_text_message(result)
4. ローカルデバッグ
# Debug Runtime の起動
dify plugin run
# Dify 画面でプラグインをテスト
# http://localhost:5001 にアクセス
5. パッケージ化とデプロイ
# プラグインのパッケージ化
dify plugin package
# my_first_tool.difypkg ファイルが生成される
# Dify Marketplace またはプライベートデプロイにアップロード
コアコンセプト
Beehive アーキテクチャ
Dify プラグインシステムは Beehive(ハイブ)アーキテクチャを採用しており、その中核的特徴は以下の通りです:
- 分散スケジューリング:各デーモンプロセスノードがローカルプラグインを独立して管理
- マスター選出:Redis 分散ロックによる自動マスターノード選出
- 状態同期:全ノードの状態を Redis に保存し、ノード間アクセスをサポート
- 障害自己修復:ノードダウン時にプラグインを自動再割り当て
詳細なアーキテクチャ説明は types/architecture.md を参照してください。
3つのランタイムモード
| ランタイムモード | 適用シーン | 通信方式 | 利点 | 欠点 |
|---|---|---|---|---|
| Local Runtime | ローカル開発、小規模デプロイ | STDIN/STDOUT | 低レイテンシ、リソース分離 | メモリ消費大、拡張性に制限 |
| Debug Runtime | リモートデバッグ、開発環境 | TCP 全二重 | 開発フレンドリー、柔軟なデプロイ | ネットワーク依存、状態管理が複雑 |
| Serverless Runtime | 大規模本番環境 | HTTP/SSE | 自動スケーリング、コスト最適化 | コールドスタート遅延、デバッグが複雑 |
詳細な比較は development/runtime-modes.md を参照してください。
4種類のプラグインタイプ
1. Tool(ツールプラグイン)
翻訳、検索、データ処理など、AI の機能を拡張するツールです。
# 例:Google Translate
type: plugin
plugins:
tools:
- provider/google_translate.yaml
使用シーン:
- API ラッピング(REST API → Tool)
- データ処理(形式変換、計算)
- 外部サービス統合(検索、翻訳)
2. Model(モデルプラグイン)
Anthropic、OpenAI、Gemini などの LLM プロバイダーに接続します。
# 例:Anthropic Claude
type: plugin
plugins:
models:
- provider/anthropic.yaml
使用シーン:
- 新しい LLM プロバイダーへの接続
- カスタムモデル設定
- マルチモーダルモデルサポート
3. Datasource(データソースプラグイン)
S3、Google Drive、Notion などのストレージシステムに接続します。
# 例:AWS S3
type: plugin
plugins:
datasources:
- provider/aws_s3.yaml
使用シーン:
- クラウドストレージ統合
- ドキュメントプラットフォームへの接続
- データベースアクセス
4. Extension(拡張プラグイン)
Slack、企業微信などのサードパーティプラットフォーム統合など、プラットフォーム機能を拡張します。
# 例:Slack
type: plugin
plugins:
extensions:
- provider/slack.yaml
使用シーン:
- サードパーティプラットフォーム統合
- トリガーの実装
- カスタム Agent ポリシー
各タイプの詳細は types/ を参照してください。
プロジェクト構成
標準的な Dify プラグインプロジェクトの構成:
my_plugin/
├── manifest.yaml # プラグインマニフェスト(必須)
├── main.py # エントリファイル(必須)
├── requirements.txt # Python 依存関係
├── pyproject.toml # プロジェクト設定
├── README.md # プラグイン説明
├── PRIVACY.md # プライバシーポリシー(OAuth が必要な場合)
├── .env.example # 環境変数サンプル
│
├── _assets/ # リソースファイル
│ └── icon.svg # プラグインアイコン
│
├── provider/ # プロバイダー設定
│ ├── provider_name.yaml # プロバイダー設定ファイル
│ └── provider_name.py # プロバイダー実装
│
└── tools/ # ツール実装(Tool プラグイン)
├── tool_name.yaml # ツール設定ファイル
└── tool_name.py # ツール実装
コアファイルの説明
manifest.yaml
プラグインの基本情報と設定を定義するマニフェストファイル:
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
詳細設定は development/manifest.md を参照してください。
main.py
プラグインエントリファイル:
from dify_plugin import Plugin, DifyPluginEnv
# プラグインインスタンスの作成
plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120))
if __name__ == '__main__':
# プラグインの起動
plugin.run()
開発ガイド
Tool プラグイン開発
1. Provider の作成
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
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:
"""
資格情報の検証(必要な場合)
"""
try:
# API Key などの資格情報を検証
api_key = credentials.get("api_key")
if not api_key:
raise ToolProviderCredentialValidationError("API Key is required")
# 資格情報の有効性テスト
MyTool().invoke(
tool_parameters={"text": "test"}
)
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))
2. Tool の作成
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
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]:
"""
ツール呼び出しエントリポイント
Args:
tool_parameters: ツールパラメータの辞書
Yields:
ToolInvokeMessage: ツール呼び出しメッセージ
"""
# 1. パラメータの取得
text = tool_parameters.get("text", "")
if not text:
yield self.create_text_message("Error: text parameter is required")
return
try:
# 2. 処理ロジック
result = self._process_text(text)
# 3. 結果を返す
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:
"""
テキスト処理の具体的なロジック
"""
return text.upper()
詳細な開発ガイドは development/tool.md を参照してください。
OAuth 2.0 統合
OAuth フロー概要
Dify は完全な OAuth 2.0 認可フローをサポートしています:
- 認可 URL の取得:ユーザーが認可ボタンをクリック
- ユーザー認可:サードパーティサービスの認可ページにリダイレクト
- 認可コードの取得:ユーザー認可後に認可コードが返される
- アクセストークンの交換:認可コードを使用してアクセストークンを取得
- トークンのリフレッシュ:アクセストークン期限切れ時にリフレッシュトークンを使用して新しいトークンを取得
OAuth スキーマの設定
provider/my_provider.yaml に OAuth 設定を追加:
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: リフレッシュトークン
OAuth Provider の実装
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:
"""
OAuth 資格情報の検証
"""
access_token = credentials.get("access_token")
if not access_token:
raise ToolProviderCredentialValidationError(
"Access token is required"
)
# アクセストークンの有効性テスト
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"Invalid access token: {str(e)}"
)
OAuth トークンの使用
ツール内で OAuth トークンを使用:
class MyOAuthTool(Tool):
def _invoke(
self, tool_parameters: dict[str, Any]
) -> Generator[ToolInvokeMessage, None, None]:
# OAuth 資格情報を取得
credentials = self.runtime.credentials
access_token = credentials.get("access_token")
# API を呼び出す
response = requests.get(
"https://api.example.com/data",
headers={"Authorization": f"Bearer {access_token}"}
)
yield self.create_text_message(response.text)
完全な OAuth 統合ガイドは development/oauth-integration.md を参照してください。
テストとデバッグ
ユニットテスト
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
テストを実行:
pytest tests/
統合テスト
Dify システムとの統合テスト:
# tests/test_integration.py
def test_plugin_integration():
# プラグインのインストールテスト
# ツール呼び出しテスト
# OAuth フローテスト
pass
Debug Runtime デバッグ
Debug Runtime を起動してリモートデバッグ:
# Debug Runtime の起動
dify plugin run --debug
# Dify 画面でテスト
# リアルタイムログとエラー情報を確認
一般的な問題のトラブルシューティング
プラグイン起動失敗
- Python バージョンを確認(3.12+ が必要)
- 依存関係のインストールを確認(
requirements.txt) manifest.yamlの設定を確認- エントリファイルのパスを確認(
main.py)
権限検証失敗
credentialsの設定を確認- OAuth トークンの有効期限を確認
- API Key の有効性を確認
- 権限宣言を確認(
resource.permission)
ランタイムエラー
- タイムアウト時間を調整(
MAX_REQUEST_TIMEOUT) - メモリ使用量を最適化(
resource.memory) - ネットワーク接続を確認
- リバースコール権限を確認
詳細なトラブルシューティングガイドは testing/troubleshooting.md を参照してください。
API からプラグインへの移行
移行戦略
- API ラッピングパターン:REST API を Tool プラグインとしてラップ
- SDK 統合パターン:サードパーティ Python SDK の使用
- OAuth 移行:OAuth 2.0 認可フローの実装
- バッチ操作の最適化:ストリームレスポンスを使用した大規模データ処理
移行手順
-
既存 API の分析
- API エンドポイントとパラメータ
- 認証方式(API Key / OAuth)
- レスポンス形式とエラー処理
-
プラグインタイプの選択
- REST API → Tool プラグイン
- LLM API → Model プラグイン
- ストレージ API → Datasource プラグイン
-
プラグインプロジェクトの作成
dify plugin init -
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) -
認証の設定
- API Key:
provider.yamlでcredentialsを設定 - OAuth:
oauth_schemaを設定
- API Key:
-
エラー処理の追加
try: response = requests.post(...) response.raise_for_status() except requests.exceptions.RequestException as e: yield self.create_text_message(f"API Error: {str(e)}") -
テストの作成
def test_api_wrapper(): tool = APIWrapperTool() result = list(tool.invoke(tool_parameters={...})) assert result[0].message -
パッケージ化とデプロイ
dify plugin package
実際のケース
- REST API → Tool:Google Translate(認証なし)
- OAuth API → Tool:Google Contacts(OAuth 2.0)
- LLM API → Model:Anthropic Claude(API Key)
- ストレージ API → Datasource:AWS S3(IAM 認証)
詳細な移行ガイドは development/migration-guide.md を参照してください。
ベストプラクティス
コード構成
- 単一責任:各 Tool は1つのことだけを行う
- エラー処理:すべての例外をキャッチし、ユーザーフレンドリーなエラーメッセージを返す
- パラメータ検証:
_invokeの開始時にすべてのパラメータを検証 - ログ記録:構造化ログを使用して重要な操作を記録
パフォーマンス最適化
- ストリームレスポンス:大規模データには Generator を使用したストリーム返却
- キャッシュ戦略:頻繁にアクセスするデータをキャッシュ
- 非同期処理:I/O バウンドな操作には async/await を使用
- リソース制限:
resource.memoryを適切に設定
セキュリティ考慮事項
- 入力検証:すべてのユーザー入力を検証
- 機密データ:機密情報は
secret-inputタイプで保存 - アクセス制御:最小権限の原則に従い、必要な権限のみを宣言
- エラーメッセージ:エラーメッセージに機密データを含めない
ユーザーエクスペリエンス
- 明確な説明:詳細な
descriptionとhelpを提供 - 適切なデフォルト値:パラメータに適切なデフォルト値を設定
- 多言語サポート:少なくとも
en_USとzh_Hansをサポート - ユーザーフレンドリーなエラー:ユーザーが理解できるエラーメッセージを返す
デプロイと運用
ランタイムモードの選択
| シーン | 推奨モード | 理由 |
|---|---|---|
| ローカル開発 | Local Runtime | 低レイテンシ、デバッグ容易 |
| リモートデバッグ | Debug Runtime | 柔軟、リモートサポート |
| 小規模本番 | Local Runtime | シンプル、低コスト |
| 大規模本番 | Serverless Runtime | 自動スケーリング、高可用性 |
Serverless デプロイ
AWS Lambda へのデプロイ:
# 1. プラグインのパッケージ化
dify plugin package
# 2. Lambda 関数の作成
aws lambda create-function \
--function-name my-plugin \
--runtime python3.12 \
--handler main.handler \
--zip-file fileb://my_plugin.difypkg
# 3. 環境変数の設定
aws lambda update-function-configuration \
--function-name my-plugin \
--environment Variables={...}
# 4. API Gateway の設定
# 詳細は Serverless デプロイガイドを参照
監視とログ
-
ログ記録
import logging logger = logging.getLogger(__name__) logger.info("Tool invoked with parameters: %s", tool_parameters) -
メトリクス収集
- 呼び出し回数
- 応答時間
- エラー率
- メモリ使用量
-
アラート設定
- エラー率の閾値
- 応答時間の閾値
- リソース使用量の閾値
バージョン管理とアップデート
-
セマンティックバージョニング
- メジャー:互換性のない変更
- マイナー:後方互換性のある機能追加
- パッチ:バグ修正
-
更新手順
manifest.yamlのバージョン更新- 変更ログの記録
- テストの実行
- パッケージ化と再デプロイ
# プラグインの更新
dify plugin package --version 0.0.2
詳細なデプロイガイドは deployment/ を参照してください。
参考リンク
この SKILL は Dify プラグイン開発者向けの包括的なガイドです。開発サイクル全体を通して参照し、高品質なプラグインを効率的に開発してください。