はじめに
DifyはオープンソースのAIアプリ開発プラットフォームとして人気があります。
ネットワーク管理ソフトTWSNMP FC
の機能をAIから使ってもらうためにDifyのプラグインを開発しました。
このプラグインを開発した時に苦労したことを何かの役に立てばと思って紹介します。
Difyプラグインの開発
基本的な手順
公式のページに方法が詳しく書いてあります。
ツールタイプのプラグインを開発する方法は
に説明があります。
要約すると
のようになります。
開発環境
私は、ローカル環境でテストできるように
の環境で開発しました。
プラグイン開発のノウハウ
CLIを使ってプラグインプロジェクトを初期化
./dify plugin init
して自動生成されるソースコードやチュートリアルの説明にでてくるソースコードの中で、そのまま使わない方がよいポイントを紹介します。他の公式プラグインのソースコードを調べた内容です。
エラーの返し方
説明のページでは、
if not content:
raise Exception("公開するコンテンツは空にできません。")
のように例外でエラーを返すような書き方ですが、
if not content:
yield self.create_text_message("公開するコンテンツは空にできません。")
のようにLLM側へのテキストによる応答を返すほうがようさそうです。
ログの出力
# Import logging and custom handler
import logging
from dify_plugin.config.logger_format import plugin_logger_handler
# Set up logging with the custom handler
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(plugin_logger_handler)
のようにloggerを定義したら、
r = api.login(user,password)
if r:
logger.error("Can not login to TWSNMP FC")
yield self.create_text_message(f"Can not login to TWSNMP FC: {r}")
のように、ログを出力できます。infoやdebugも指定できます。
配列の応答を返す方法
例えば、nodesがノードを示すデータの配列だった場合
nodes = api.get("/api/nodes")
if not nodes:
logger.error("Failed to retrieve nodes from TWSNMP FC")
yield self.create_text_message("Failed to retrieve nodes from TWSNMP FC")
yield self.create_json_message(nodes)
のように配列を全部返すとうまくいきません。
nodes = api.get("/api/nodes")
if not nodes:
logger.error("Failed to retrieve nodes from TWSNMP FC")
yield self.create_text_message("Failed to retrieve nodes from TWSNMP FC")
for node in nodes:
yield self.create_json_message(node)
のように配列の要素を1件づつyieldで返すとうまくいきます。
多言語対応
自動生成される設定ファイルには
identity:
author: "twsnmp"
name: "test"
label:
en_US: "test"
zh_Hans: "test"
pt_BR: "test"
description:
en_US: "test"
zh_Hans: "test"
pt_BR: "test"
icon: "icon.svg"
tools:
- tools/test.yaml
extra:
python:
source: provider/test.py
のように中国語、ブラジルのポルトガル語が入っていますが、
消してen_USだけにしても問題ありませんでした。
ja_JPもいれてもよいです。
アイコンファイル
SVG形式になっていますがpngでも問題ないようです。
プライバシーポリシー
自動生成されるファイルは、
## Privacy
!!! Please fill in the privacy policy of the plugin.
のようになっています。
特に、プラグインがユーザー情報を収集するような動作をしなければ
# Privacy Policy
This tool is designed with privacy in mind and does not collect any user data. We are committed to maintaining your privacy and ensuring your data remains secure.
## Data Collection
- **No Personal Information**: We do not collect, store, or process any personal information.
- **No Usage Data**: We do not track or monitor how you use the tool.
- **No Analytics**: We do not implement any analytics or tracking mechanisms.
## Third-Party Services
This tool does not integrate with or utilize any third-party services that might collect user data.
## Changes to Privacy Policy
If there are any changes to our privacy practices, we will update this document accordingly.
## Contact Us
If you have any questions or concerns about this Privacy Policy, please contact us at
<連絡先メールアドレス>
でよいと思います。
GitHUBで自動公開
自動生成される.github/workflows/plugin-publish.yml
では、自動でプラグインのパッケージを作成しますが、プルリクエストを作成するような動作になっています。自分のリポジトリでtagをPUSHした時に自動リリースするGitHUBアクションは
name: release
on:
push:
tags:
- "v*"
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download CLI tool
run: |
mkdir -p $RUNNER_TEMP/bin
cd $RUNNER_TEMP/bin
wget https://github.com/langgenius/dify-plugin-daemon/releases/download/0.0.6/dify-plugin-linux-amd64
chmod +x dify-plugin-linux-amd64
echo "CLI tool location:"
pwd
ls -la dify-plugin-linux-amd64
- name: Get basic info from manifest
id: get_basic_info
run: |
PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2)
echo "Plugin name: $PLUGIN_NAME"
echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT
VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2)
echo "Plugin version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
# If the author's name is not your github username, you can change the author here
AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2)
echo "Plugin author: $AUTHOR"
echo "author=$AUTHOR" >> $GITHUB_OUTPUT
- name: Package Plugin
id: package
run: |
cd $GITHUB_WORKSPACE
PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
$RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME"
echo "Package result:"
ls -la "$PACKAGE_NAME"
echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT
echo "\nFull file path:"
pwd
echo "\nDirectory structure:"
tree || ls -R
- name: Release
uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
with:
files: ${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg
でいけます。
プラグインの署名
プラグインは署名していないので、Difyを
FORCE_VERIFYING_SIGNATURE=false
をつけて起動しないとGitHUBから配布したプラグインをインストールできませんでした。
今後、マーケットプレイスから公開する方法をしらべようと思います。