Dify Plugin 开发教程

1. 工具类基本结构

每个工具都需要继承 Tool 基类,并实现 _invoke 方法:

python 复制代码
from collections.abc import Generator
from typing import Any
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage

class ExampleTool(Tool):
    def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
        # 工具逻辑实现
        pass

2. 参数定义 (YAML 配置)

2.1 基本信息定义

yaml 复制代码
identity:
  name: "example_tool"  # 工具唯一标识
  author: "your_name"
  label:
    en_US: "Example Tool"
    zh_Hans: "示例工具"
description:
  human:
    en_US: "This is an example tool description."
    zh_Hans: "这是一个示例工具描述。"
  llm: "This tool is used for demonstration purposes."

2.2 参数字段定义

yaml 复制代码
parameters:
  - name: required_param
    type: string
    required: true
    label:
      en_US: Required Parameter
      zh_Hans: 必需参数
    human_description:
      en_US: "This is a required string parameter"
      zh_Hans: "这是一个必需的字符串参数"
    llm_description: "A required string parameter for the tool"
    form: llm

  - name: optional_param
    type: string
    required: false
    label:
      en_US: Optional Parameter
      zh_Hans: 可选参数
    human_description:
      en_US: "This is an optional parameter"
      zh_Hans: "这是一个可选参数"
    llm_description: "An optional parameter with default value"
    form: llm

  - name: number_param
    type: number
    required: false
    default: 100
    label:
      en_US: Number Parameter
      zh_Hans: 数字参数

  - name: boolean_param
    type: boolean
    required: false
    default: false
    label:
      en_US: Boolean Switch
      zh_Hans: 布尔开关

  - name: select_param
    type: select
    required: true
    options:
      - value: "option1"
        label:
          en_US: "Option One"
          zh_Hans: "选项一"
      - value: "option2"
        label:
          en_US: "Option Two"
          zh_Hans: "选项二"
    label:
      en_US: "Select Option"
      zh_Hans: "选择选项"

参数类型说明:

  • string: 字符串类型
  • number: 数字类型
  • boolean: 布尔类型
  • select: 下拉选择,需要配合 options 字段
  • file: 文件类型

3. 工具逻辑实现

3.1 参数获取和验证

python 复制代码
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
    try:
        # 获取必需参数
        required_param = tool_parameters.get('required_param')
        optional_param = tool_parameters.get('optional_param', 'default_value')
        number_param = tool_parameters.get('number_param', 100)
        boolean_param = tool_parameters.get('boolean_param', False)
        select_param = tool_parameters.get('select_param')

        # 验证必要参数
        if not required_param:
            raise ValueError("required_param 是必需的参数")

        # 参数类型转换和验证
        try:
            number_value = int(number_param)
        except (TypeError, ValueError):
            raise ValueError("number_param 必须是有效的数字")

        # 继续业务逻辑...

3.2 返回成功结果

使用 self.create_json_message() 返回结构化数据:

python 复制代码
# 返回成功结果
result_data = {
    "processed_items": 10,
    "status": "completed",
    "details": {"param1": required_param, "option": select_param}
}

yield self.create_json_message({
    "success": True,
    "message": "操作成功完成",
    "data": result_data
})

返回格式建议:

  • success: 操作是否成功 (boolean)
  • message: 人类可读的消息 (string)
  • data: 实际返回的数据 (any)

3.3 返回文本消息

如果需要返回纯文本:

python 复制代码
yield self.create_text_message("操作成功完成")

3.4 返回多条消息

可以多次使用 yield 返回多条消息:

python 复制代码
# 返回进度消息
yield self.create_text_message("开始处理数据...")

# 处理逻辑
processed_data = self.process_data(required_param)

# 返回最终结果
yield self.create_json_message({
    "success": True,
    "message": "数据处理完成",
    "data": processed_data
})

4. 异常处理

4.1 参数验证异常

python 复制代码
# 验证必要参数
if not required_param:
    raise ValueError("required_param 是必需的参数")

# 验证参数格式
if select_param not in ['option1', 'option2']:
    raise ValueError("select_param 必须是有效的选项")

4.2 业务逻辑异常

python 复制代码
try:
    # 业务逻辑
    result = self._complex_operation(required_param, number_param)
    
except SpecificException as e:
    # 处理特定异常
    raise Exception(f"业务操作失败: {str(e)}")
    
except Exception as e:
    # 处理其他异常
    raise Exception(f"处理过程中发生错误: {str(e)}")

4.3 统一异常处理

python 复制代码
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
    try:
        # 主要逻辑
        # ...
        
    except ValueError as e:
        # 参数错误
        raise Exception(f"参数错误: {str(e)}")
        
    except Exception as e:
        # 其他所有异常
        raise Exception(f"工具执行失败: {str(e)}")

5. 完整示例

5.1 简单数据处理工具

python 复制代码
from collections.abc import Generator
from typing import Any
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage

class DataProcessorTool(Tool):
    def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
        try:
            # 获取参数
            input_data = tool_parameters.get('input_data')
            operation = tool_parameters.get('operation', 'uppercase')
            repeat_times = tool_parameters.get('repeat_times', 1)
            
            # 参数验证
            if not input_data:
                raise ValueError("input_data 是必需的参数")
            
            if operation not in ['uppercase', 'lowercase', 'reverse']:
                raise ValueError("operation 必须是 uppercase、lowercase 或 reverse")
            
            # 业务逻辑
            result = self._process_data(input_data, operation, repeat_times)
            
            # 返回结果
            yield self.create_json_message({
                "success": True,
                "message": f"数据处理完成,操作类型: {operation}",
                "data": {
                    "original": input_data,
                    "processed": result,
                    "operation": operation,
                    "length": len(result)
                }
            })
            
        except Exception as e:
            raise Exception(f"数据处理工具执行失败: {str(e)}")
    
    def _process_data(self, data: str, operation: str, repeat_times: int) -> str:
        """处理数据的内部方法"""
        result = data
        
        if operation == 'uppercase':
            result = data.upper()
        elif operation == 'lowercase':
            result = data.lower()
        elif operation == 'reverse':
            result = data[::-1]
        
        return result * repeat_times

对应的 YAML 配置:

yaml 复制代码
identity:
  name: "data_processor"
  author: "developer"
  label:
    en_US: "Data Processor"
    zh_Hans: "数据处理器"
description:
  human:
    en_US: "Process text data with various operations."
    zh_Hans: "使用多种操作处理文本数据。"
  llm: "A tool for processing text data with operations like uppercase, lowercase, and reverse."
parameters:
  - name: input_data
    type: string
    required: true
    label:
      en_US: Input Data
      zh_Hans: 输入数据
    human_description:
      en_US: "The text data to process"
      zh_Hans: "要处理的文本数据"
    llm_description: "The input text data that will be processed"
    form: llm

  - name: operation
    type: select
    required: false
    default: "uppercase"
    options:
      - value: "uppercase"
        label:
          en_US: "Uppercase"
          zh_Hans: "大写"
      - value: "lowercase"
        label:
          en_US: "Lowercase"
          zh_Hans: "小写"
      - value: "reverse"
        label:
          en_US: "Reverse"
          zh_Hans: "反转"
    label:
      en_US: "Operation Type"
      zh_Hans: "操作类型"
    human_description:
      en_US: "The operation to perform on the data"
      zh_Hans: "对数据执行的操作类型"
    llm_description: "The operation type: uppercase, lowercase, or reverse"
    form: llm

  - name: repeat_times
    type: number
    required: false
    default: 1
    label:
      en_US: "Repeat Times"
      zh_Hans: "重复次数"
    human_description:
      en_US: "Number of times to repeat the processed result"
      zh_Hans: "重复处理结果的次数"
    llm_description: "How many times to repeat the processed result"
    form: llm
extra:
  python:
    source: tools/data_processor.py

5.2 API 调用工具示例

python 复制代码
import requests
from collections.abc import Generator
from typing import Any
from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage

class APICallTool(Tool):
    def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]:
        try:
            # 获取参数
            url = tool_parameters.get('api_url')
            method = tool_parameters.get('method', 'GET')
            headers = tool_parameters.get('headers', {})
            timeout = tool_parameters.get('timeout', 30)
            
            # 参数验证
            if not url:
                raise ValueError("api_url 是必需的参数")
            
            if method not in ['GET', 'POST', 'PUT', 'DELETE']:
                raise ValueError("method 必须是 GET、POST、PUT 或 DELETE")
            
            # 执行 API 调用
            response = self._call_api(url, method, headers, timeout)
            
            # 返回结果
            yield self.create_json_message({
                "success": True,
                "message": f"API 调用成功,状态码: {response.status_code}",
                "data": {
                    "status_code": response.status_code,
                    "headers": dict(response.headers),
                    "response": response.json() if response.content else None
                }
            })
            
        except requests.exceptions.RequestException as e:
            raise Exception(f"API 调用失败: {str(e)}")
        except Exception as e:
            raise Exception(f"API 工具执行失败: {str(e)}")
    
    def _call_api(self, url: str, method: str, headers: dict, timeout: int) -> requests.Response:
        """执行 API 调用的内部方法"""
        response = requests.request(
            method=method,
            url=url,
            headers=headers,
            timeout=timeout
        )
        response.raise_for_status()
        return response

6. 文件配置

extra 部分指定 Python 源文件位置:

yaml 复制代码
extra:
  python:
    source: tools/your_tool.py  # 相对于插件根目录的路径

7. 开发最佳实践

  1. 参数验证: 始终验证输入参数的有效性
  2. 错误处理: 提供清晰具体的错误消息
  3. 资源清理: 如果有资源需要清理,使用 try-finally 确保清理
  4. 类型安全: 进行适当的类型检查和转换
  5. 文档完整: 为所有参数提供完整的中英文文档
  6. 性能考虑: 避免在工具中进行耗时操作,必要时提供进度反馈

8. 测试建议

  • 测试正常流程和边界情况
  • 测试参数缺失和无效的情况
  • 测试异常处理流程
  • 验证返回格式是否符合预期

通过以上教程,您可以快速掌握 Dify Plugin 的开发方法,创建自己的工具插件。

相关推荐
海琴烟Sunshine3 小时前
leetcode 338. 比特位计数 python
python·算法·leetcode
呆萌很3 小时前
字典推导式练习题
python
闲人编程4 小时前
Python在云计算中的应用:AWS Lambda函数实战
服务器·python·云计算·aws·lambda·毕设·codecapsule
小兔崽子去哪了4 小时前
Python 数据分析环境搭建与工具使用指南
python
不惑_4 小时前
Java 使用 FileOutputStream 写 Excel 文件不落盘?
开发语言·python
IT小哥哥呀4 小时前
Python实用技巧:批量处理Excel数据并生成销售报表(含实战案例)
python·pandas·数据可视化·数据处理·报表生成·excel自动化·办公神器
烤奶要加冰5 小时前
PyCharm 社区版全平台安装指南
ide·windows·python·pycharm·mac
Siren_dream5 小时前
anaconda与pycharm
ide·python·pycharm
whale fall5 小时前
Windows下PyCharm如何激活python的虚拟环境
ide·python·pycharm