ツールとは、Chatflow / Workflow / Agent タイプのアプリケーションから呼び出すことができるサードパーティサービスを指し、Difyアプリケーションの能力を強化するための完全なAPI実装機能を提供します。例えば、アプリケーションにオンライン検索や画像生成などの追加機能を追加します。

この記事では、「ツールプラグイン」 とは、ツールプロバイダーファイル、機能コードなどの構造を含む完全なプロジェクトを指します。1つのツールプロバイダーには複数のツール(個々のツール内で提供される追加機能と理解できます)を含めることができ、構造は以下の通りです。

- ツールプロバイダー
    - Tool A
    - Tool B

この記事では、Google Search を例に、ツールプラグインを迅速に開発する方法を紹介します。

事前準備

  • Difyプラグインスキャフォールドツール
  • Python環境、バージョン ≥ 3.12

プラグイン開発用のスキャフォールドツールの準備方法については、開発ツールの初期化を参照してください。初めてプラグインを開発する場合は、まずDifyプラグイン開発:Hello Worldガイドを読むことをお勧めします。

新規プロジェクトの作成

スキャフォールドコマンドラインツールを実行し、新しいDifyプラグインプロジェクトを作成します。

./dify-plugin-darwin-arm64 plugin init

このバイナリファイルを dify にリネームし、/usr/local/bin パスにコピーした場合、以下のコマンドを実行して新しいプラグインプロジェクトを作成できます。

dify plugin init

以下では、コマンドラインの例として dify を使用します。問題が発生した場合は、dify コマンドをコマンドラインツールの実際のパスに置き換えてください。

プラグインタイプとテンプレートの選択

スキャフォールドツール内のすべてのテンプレートは、完全なコードプロジェクトを提供しています。この記事の例では、Tool プラグインを選択します。

プラグイン開発に慣れている場合は、テンプレートを使用せずに、一般仕様のガイドラインを参照して、さまざまなタイプのプラグイン開発を完了できます。

プラグイン権限の設定

プラグインはDifyプラットフォームの権限も読み取る必要があり、このサンプルプラグインには以下の権限を付与します。

  • Tools
  • Apps
  • 永続ストレージStorageを有効にし、デフォルトサイズのストレージを割り当てる
  • Endpointの登録を許可する

ターミナル内で方向キーを使用して権限を選択し、「Tab」キーを使用して権限を付与します。

すべての権限項目にチェックを入れた後、Enterキーを押してプラグインの作成を完了します。システムは自動的にプラグインプロジェクトコードを生成します。

ツールプラグインの開発

1. ツールプロバイダーファイルの作成

ツールプロバイダーファイルはYAML形式のファイルで、ツールプラグインの基本設定エントリと理解でき、ツールに必要な認証情報を提供するために使用されます。

プラグインテンプレートプロジェクトの /provider パスに移動し、そこにあるyamlファイルを google.yaml にリネームします。この yaml ファイルには、ツールプロバイダーの情報(プロバイダー名、アイコン、作成者などの詳細)が含まれます。この情報はプラグインのインストール時に表示されます。

コード例

identity: # ツールプロバイダーの基本情報
    author: Your-name # 作成者
    name: google # 名称、一意であり、他のプロバイダーと重複することはできません
    label: # ラベル、フロントエンド表示用
        en_US: Google # 英語ラベル
        zh_Hans: Google # 中国語ラベル
    description: # 説明、フロントエンド表示用
        en_US: Google # 英語の説明
        zh_Hans: Google # 中国語の説明
    icon: icon.svg # ツールアイコン、_assetsフォルダに配置する必要があります
    tags: # タグ、フロントエンド表示用
        - search

このファイルパスが /tools ディレクトリに配置されるようにしてください。完全なパスは次のとおりです。

plugins:
    tools:
        - 'google.yaml'

google.yamlファイルは、プラグインプロジェクトにおける絶対パスを使用する必要があります。この例では、プロジェクトのルートディレクトリにあります。YAMLファイル内のidentityフィールドは次のように説明されます:identityには、作成者、名前、ラベル、説明、アイコンなど、ツールプロバイダーの基本情報が含まれます。

  • アイコンは添付リソースに属する必要があり、プロジェクトのルートディレクトリにある _assets フォルダに配置する必要があります。
  • タグは、ユーザーがカテゴリ別にプラグインをすばやく見つけるのに役立ちます。以下は現在サポートされているすべてのタグです。
class ToolLabelEnum(Enum):
  SEARCH = 'search'
  IMAGE = 'image'
  VIDEOS = 'videos'
  WEATHER = 'weather'
  FINANCE = 'finance'
  DESIGN = 'design'
  TRAVEL = 'travel'
  SOCIAL = 'social'
  NEWS = 'news'
  MEDICAL = 'medical'
  PRODUCTIVITY = 'productivity'
  EDUCATION = 'education'
  BUSINESS = 'business'
  ENTERTAINMENT = 'entertainment'
  UTILITIES = 'utilities'
  OTHER = 'other'

2. サードパーティサービス認証情報の補完

開発を容易にするため、サードパーティサービス SerpApi が提供する Google Search API を採用することを選択します。SerpApi は使用にあたって API Key の入力を要求するため、yaml ファイル内に credentials_for_provider フィールドを追加する必要があります。

完全なコードは以下の通りです。

identity:
    author: Dify
    name: google
    label:
        en_US: Google
        zh_Hans: Google
        pt_BR: Google
    description:
        en_US: Google
        zh_Hans: GoogleSearch
        pt_BR: Google
    icon: icon.svg
    tags:
        - search
credentials_for_provider: # credentials_for_provider フィールドを追加
    serpapi_api_key:
        type: secret-input
        required: true
        label:
            en_US: SerpApi API key
            zh_Hans: SerpApi APIキー
        placeholder:
            en_US: Please input your SerpApi API key
            zh_Hans: SerpApi APIキーを入力してください
        help:
            en_US: Get your SerpApi API key from SerpApi
            zh_Hans: SerpApiからSerpApi APIキーを取得します
        url: https://serpapi.com/manage-api-key
tools:
    - tools/google_search.yaml
extra:
    python:
        source: google.py
  • credentials_for_provider の子構造は、一般仕様の要件を満たす必要があります。
  • このプロバイダーにどのツールが含まれているかを指定する必要があります。この例では、tools/google_search.yaml ファイルのみが含まれています。
  • プロバイダーとして、基本情報を定義するだけでなく、そのコードロジックの一部を実装する必要があるため、その実装ロジックを指定する必要があります。この例では、機能のコードファイルを google.py に配置しましたが、一時的に実装せず、まず google_search のコードを作成します。

3. ツールyamlファイルの記入

1つのツールプラグインには複数のツール機能を含めることができ、各ツール機能には、ツール機能の基本情報、パラメータ、出力などを含む yaml ファイルで記述する必要があります。

引き続き GoogleSearch ツールを例に、/tools フォルダ内に新しい google_search.yaml ファイルを作成します。

identity:
    name: google_search
    author: Dify
    label:
        en_US: GoogleSearch
        zh_Hans: Google検索
        pt_BR: GoogleSearch
description:
    human:
        en_US: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query.
        zh_Hans: Google SERP検索を実行し、スニペットとウェブページを抽出するためのツールです。入力は検索クエリである必要があります。
        pt_BR: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query.
    llm: A tool for performing a Google SERP search and extracting snippets and webpages.Input should be a search query.
parameters:
    - name: query
      type: string
      required: true
      label:
          en_US: Query string
          zh_Hans: クエリ文
          pt_BR: Query string
      human_description:
          en_US: used for searching
          zh_Hans: ウェブコンテンツの検索に使用
          pt_BR: used for searching
      llm_description: key words for searching
      form: llm
extra:
    python:
        source: tools/google_search.py
  • identity には、ツールの基本情報(名前、作成者、ラベル、説明など)が含まれます。
  • parameters パラメータリスト
    • name (必須)パラメータ名、一意であり、他のパラメータと重複することはできません。
    • type (必須)パラメータタイプ。現在、string(文字列)、number(数値)、boolean(ブール値)、select(ドロップダウンリスト)、secret-input(暗号化入力フィールド)の5種類をサポートしています。機密情報にはsecret-inputタイプを使用してください。
    • label(必須)パラメータラベル、フロントエンド表示用。
    • form (必須)フォームタイプ。現在、llmformの2種類をサポートしています。
      • Agentアプリケーションでは、llm はLLMが自身で推論するパラメータを示し、form はこのツールを使用するために事前に設定できるパラメータを示します。
      • Workflowアプリケーションでは、llmform の両方をフロントエンドで入力する必要がありますが、llm のパラメータはツールノードの入力変数として機能します。
    • required 必須かどうか
      • llm モードでは、パラメータが必須の場合、Agentはこのパラメータを推論する必要があります。
      • form モードでは、パラメータが必須の場合、ユーザーは対話開始前にフロントエンドでこのパラメータを入力する必要があります。
    • options パラメータオプション
      • llm モードでは、DifyはすべてのオプションをLLMに渡し、LLMはこれらのオプションに基づいて推論できます。
      • form モードで typeselect の場合、フロントエンドはこれらのオプションを表示します。
    • default デフォルト値。
    • min 最小値、パラメータタイプが number の場合に設定できます。
    • max 最大値、パラメータタイプが number の場合に設定できます。
    • human_description フロントエンド表示用の説明、多言語対応。
    • placeholder フィールド入力ボックスのヒントテキスト。フォームタイプがformで、パラメータタイプがstringnumbersecret-inputの場合に設定でき、多言語対応です。
    • llm_description LLMに渡す説明。LLMがこのパラメータをよりよく理解できるように、ここにこのパラメータに関するできるだけ詳細な情報を記述してください。

4. ツールコードの準備

ツールの設定情報を入力した後、ツールの機能コードの作成を開始し、ツールの論理的な目的を実現できます。/toolsディレクトリにgoogle_search.pyを作成し、内容は以下の通りです。

from collections.abc import Generator
from typing import Any

import requests

from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage

SERP_API_URL = "https://serpapi.com/search"

class GoogleSearchTool(Tool):
    def _parse_response(self, response: dict) -> dict:
        result = {}
        if "knowledge_graph" in response:
            result["title"] = response["knowledge_graph"].get("title", "")
            result["description"] = response["knowledge_graph"].get("description", "")
        if "organic_results" in response:
            result["organic_results"] = [
                {
                    "title": item.get("title", ""),
                    "link": item.get("link", ""),
                    "snippet": item.get("snippet", ""),
                }
                for item in response["organic_results"]
            ]
        return result

    def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
        params = {
            "api_key": self.runtime.credentials["serpapi_api_key"],
            "q": tool_parameters["query"],
            "engine": "google",
            "google_domain": "google.com",
            "gl": "us",
            "hl": "en",
        }

        response = requests.get(url=SERP_API_URL, params=params, timeout=5)
        response.raise_for_status()
        valuable_res = self._parse_response(response.json())

        yield self.create_json_message(valuable_res)

この例の意味は、serpapi にリクエストを送信し、self.create_json_message を使用して json 形式のフォーマット済みデータを返すことです。返されるデータ型の詳細については、プラグインのリモートデバッグおよび永続ストレージKVのドキュメントを参照してください。

4. ツールプロバイダーコードの完成

最後に、認証情報検証ロジックを実装するためのプロバイダーの実装コードを作成する必要があります。認証情報検証が失敗した場合、ToolProviderCredentialValidationError例外がスローされます。検証が成功すると、google_searchツールサービスに正しくリクエストが送信されます。

/provider ディレクトリに google.py ファイルを作成し、コードの内容は以下の通りです。

from typing import Any

from dify_plugin import ToolProvider
from dify_plugin.errors.tool import ToolProviderCredentialValidationError
from tools.google_search import GoogleSearchTool

class GoogleProvider(ToolProvider):
    def _validate_credentials(self, credentials: dict[str, Any]) -> None:
        try:
            for _ in GoogleSearchTool.from_credentials(credentials).invoke(
                tool_parameters={"query": "test", "result_type": "link"},
            ):
                pass
        except Exception as e:
            raise ToolProviderCredentialValidationError(str(e))

プラグインのデバッグ

プラグインの開発が完了したら、次にプラグインが正常に動作するかをテストする必要があります。Difyは便利なリモートデバッグ方法を提供し、テスト環境でプラグイン機能を迅速に検証するのに役立ちます。

「プラグイン管理」ページに移動して、リモートサーバーアドレスとデバッグキーを取得します。

プラグインプロジェクトに戻り、.env.example ファイルをコピーして .env にリネームし、取得したリモートサーバーアドレスとデバッグキーなどの情報を入力します。

.env ファイル:

INSTALL_METHOD=remote
REMOTE_INSTALL_HOST=remote
REMOTE_INSTALL_PORT=5003
REMOTE_INSTALL_KEY=****-****-****-****-****

python -m main コマンドを実行してプラグインを起動します。プラグインページで、このプラグインがWorkspaceにインストールされていることが確認でき、チームの他のメンバーもこのプラグインにアクセスできます。

プラグインのパッケージ化(オプション)

プラグインが正常に動作することを確認した後、以下のコマンドラインツールを使用してプラグインをパッケージ化し、名前を付けることができます。実行後、現在のフォルダに google.difypkg ファイルが見つかります。これは最終的なプラグインパッケージです。

# ./google をプラグインプロジェクトの実際のパスに置き換えてください

dify plugin package ./google

おめでとうございます、これでツールタイププラグインの完全な開発、デバッグ、パッケージ化プロセスを完了しました!

プラグインの公開(オプション)

プラグインをDify Marketplaceに公開したい場合は、プラグインがDifyマーケットプレイスへの公開の仕様に従っていることを確認してください。審査に合格すると、コードはメインブランチにマージされ、自動的にDify Marketplaceに公開されます。

公開概要

さらに探る

クイックスタート:

プラグインインターフェースドキュメント:

次のステップ