Dify 插件開發 SKILL
概述
Dify 插件系統採用創新的 Beehive(蜂巢)架構,支援三種執行時期模式,提供四種插件類型,為開發者提供強大的擴充能力。本 SKILL 提供從入門到精通的完整插件開發指南。
適用場景
當你需要以下場景時使用本 SKILL:
- 開發 Dify 插件:工具、模型、資料來源、擴充四種類型
- 整合第三方服務:API 包裝、OAuth 授權
- 實作自訂工具:擴充 AI 能力
- 擴充 Dify 平台功能:觸發器、Agent 策略
- 將現有 API 遷移為插件:API 到插件的轉換
- 除錯和最佳化插件效能:效能調校和問題排查
核心價值
- Beehive 架構:去中心化排程、主從選舉、故障自癒
- 多執行時期支援:Local、Debug、Serverless 三種模式
- 完整工具鏈: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
三種執行時期模式
| 執行時期模式 | 適用場景 | 通訊方式 | 優勢 | 劣勢 |
|---|---|---|---|---|
| Local Runtime | 本地開發、小規模部署 | STDIN/STDOUT | 低延遲、資源隔離 | 記憶體佔用高、擴充性有限 |
| Debug Runtime | 遠端除錯、開發環境 | TCP 全雙工 | 開發友善、靈活部署 | 網路依賴、狀態管理複雜 |
| Serverless Runtime | 大規模生產環境 | HTTP/SSE | 自動擴充、成本最佳化 | 冷啟動延遲、除錯複雜 |
詳細對比請參考:development/runtime-modes.md
四種插件類型
1. Tool(工具插件)
擴充 AI 能力的工具,如翻譯、搜尋、資料處理等。
# 範例:Google Translate
type: plugin
plugins:
tools:
- provider/google_translate.yaml
使用場景:
- API 包裝(REST API → Tool)
- 資料處理(格式轉換、計算)
- 外部服務整合(搜尋、翻譯)
2. Model(模型插件)
接入 LLM 提供商,如 Anthropic、OpenAI、Gemini 等。
# 範例: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 Schema
在 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 權杖
在 Tool 中使用 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 只做一件事
- 錯誤處理:捕獲所有例外並回傳友善錯誤資訊
- 參數驗證:在
_invoke開始時驗證所有參數 - 日誌記錄:使用結構化日誌記錄關鍵操作
效能最佳化
- 串流回應:對於大資料使用 Generator 串流回傳
- 快取策略:快取頻繁存取的資料
- 非同步處理:使用 async/await 處理 I/O 密集型操作
- 資源限制:合理配置
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={
REDIS_URL=redis://...
}
# 4. 設定 API Gateway 觸發器
aws api-gateway create-rest-api \
--name my-plugin-api
監控和日誌
- Prometheus 指標:監控插件效能
- 結構化日誌:使用 JSON 格式輸出日誌
- 錯誤追蹤:整合 Sentry 等錯誤追蹤服務
- 效能分析:使用 OpenTelemetry 進行分散式追蹤
生態系統
Marketplace
Dify 插件可發布到官方 Marketplace:
# 發布插件
dify plugin publish
# 需要通過審核
# 支援版本管理
社群貢獻
- 貢獻指南:CONTRIBUTING.md
- 開發路線圖:ROADMAP.md
- 回報問題:GitHub Issues
參考資源
官方文檔
工具和 SDK
- dify-cli:命令行工具
- dify-plugin:Python SDK
- 除錯執行時期
社群資源
本 SKILL 基於 Dify 插件開發文檔和實踐經驗整理,持續更新中。