Dify 插件开发全流程指南
在 AI 应用快速落地的今天,越来越多企业不再满足于“只聊天”的大模型能力。他们需要的是能真正执行任务、调用系统、连接现实世界工具的智能体(Agent)。而 Dify 正是这样一个平台 —— 它不仅支持 Prompt 工程与 RAG 构建,更通过插件机制打通了 AI 与外部系统的最后一公里。
想象一下:用户一句话:“帮我查下上海今天的天气,然后发个飞书提醒我带伞。”
如果 AI 只能回答“上海今天26℃,晴”,那只是信息搬运工;
但如果它能自动调用天气 API、再触发飞书机器人发送通知,这才叫真正的智能代理。
这背后的核心,就是Dify 的插件系统。开发者可以通过编写轻量级 Python 服务,让 AI Agent 获得“动手能力”。本文不走概念铺陈的老路,而是带你从零开始,亲手打造一个可被工作流调用的真实插件,并完整经历调试、集成、打包全过程。
我们先来理清一个关键认知:Dify 插件本质上是一个运行在本地或远程的 HTTP 服务,遵循特定协议响应/invoke请求。它不需要复杂的部署架构,也不依赖 Kubernetes 或微服务框架 —— 一个 Flask 应用 + 几个配置文件就够了。
要启动开发,首先确保你的环境满足基础要求。Dify 插件目前基于 Python 开发,且强烈推荐使用 Python 3.12 或更高版本。原因在于其底层依赖大量异步处理逻辑,低版本可能因语法不兼容导致运行失败。
验证方式很简单:
python --version输出应为Python 3.12.x或以上。如果你使用conda管理环境,建议创建独立空间避免依赖冲突:
conda create -n dify-plugin python=3.12 conda activate dify-plugin当然,你也可以用venv:
python -m venv .venv source .venv/bin/activate # Linux/macOS # 或 .venv\Scripts\activate # Windows激活后,所有后续安装都将隔离在这个环境中。
接下来是核心工具链:dify-plugin-daemon。这是 Dify 官方提供的 CLI 工具,负责项目初始化、本地运行和打包发布。前往 GitHub Releases 页面下载对应系统的二进制文件:
👉 Releases · langgenius/dify-plugin-daemon
例如 macOS 用户可下载dify-plugin-daemon-darwin-amd64,重命名为dify并加入系统 PATH。Windows 用户则需将其所在目录添加到环境变量中,以便全局调用。
验证是否成功:
dify --help若能看到命令列表,说明 CLI 已就位。
准备好之后,执行初始化命令:
dify plugin init进入交互式引导:
? Plugin name: my-first-plugin ? Author: Zhang San ? Description: A simple plugin to test Dify integration ? Language: Python ? Permissions: ◉ Read system info ◉ Access network ◉ Execute shell commands ◉ Read environment variables这里填写基本信息即可。权限选项会影响用户在使用插件时看到的授权提示,按需勾选。完成后,脚手架自动生成如下结构:
my-first-plugin/ ├── __init__.py ├── manifest.yml ├── schema.yml ├── main.py ├── .env.example └── requirements.txt四个关键文件需要重点关注:
manifest.yml:插件元信息,如名称、版本、作者、服务地址等。schema.yml:定义对外暴露的功能接口,包括参数和返回值格式。main.py:主程序入口,实现具体的业务逻辑。.env.example:环境变量模板,用于安全配置敏感信息。
我们先看.env文件。复制模板并编辑:
cp .env.example .env内容如下:
PLUGIN_HOST=http://localhost:5001 PLUGIN_API_KEY=sk-abc123def456ghi789PLUGIN_HOST指明插件监听地址,本地开发通常设为http://localhost:5001;PLUGIN_API_KEY是通信密钥,必须与 Dify 实例中的设置一致,否则会因鉴权失败无法连接。
⚠️ 注意:
.env属于敏感文件,务必加入.gitignore,切勿提交至代码仓库。
对应的manifest.yml中也包含相同字段:
name: my-first-plugin version: 0.1.0 description: A simple plugin to test Dify integration author: Zhang San host: http://localhost:5001 api_key: sk-abc123def456ghi789这两处必须保持同步,否则会出现“注册成功但调用失败”的诡异问题。
现在进入核心设计环节:如何定义插件功能?
以“获取天气”为例,在schema.yml中声明一个函数:
functions: - name: get_weather description: 获取指定城市的当前天气情况 parameters: type: object properties: city: type: string description: 城市名称,如 Beijing, Shanghai required: - city returns: type: object properties: temperature: type: number description: 当前温度(摄氏度) condition: type: string description: 天气状况,如 Sunny, Cloudy这段 YAML 将决定该功能在 Dify 工作流中的表现形式 —— 用户拖入节点后,会看到清晰的参数输入框和类型提示。这也是为什么建议你在描述中写得尽量具体:它是给最终使用者看的文档。
接着来到main.py,这里是真正干活的地方。默认模板使用 Flask 构建服务:
from flask import Flask, request, jsonify import os app = Flask(__name__) @app.route('/invoke', methods=['POST']) def invoke(): data = request.json function = data.get('function') inputs = data.get('inputs') if function == 'get_weather': city = inputs.get('city') if not city: return jsonify({ "error": { "type": "invalid_parameter", "message": "City parameter is required." } }), 400 # 这里可以接入真实 API,比如高德天气 return jsonify({ "result": { "temperature": 26, "condition": "Sunny" } }) return jsonify({"error": "Unknown function"}), 400 if __name__ == '__main__': app.run(host='0.0.0.0', port=5001)注意两点:
- 所有请求都走
/invoke接口,通过function字段区分调用哪个功能; - 返回结果必须包裹在
"result"键下,错误则用"error"结构化返回。
这种约定式设计降低了平台解析成本,也提升了跨语言插件的兼容性。
开发过程中,推荐使用 PyCharm 提升效率。导入项目后,记得将解释器切换为你创建的虚拟环境路径,例如:
~/miniconda3/envs/dify-plugin/bin/python然后安装依赖(如有):
pip install -r requirements.txt运行main.py启动服务,访问http://localhost:5001即可确认服务正常。
此时,回到 Dify 控制台 —— 假设你已通过 Docker 或 SaaS 版本部署好实例。
进入【开发者】→【插件】→【本地插件】,点击「添加本地插件」:
- 名称:My First Plugin
- URL:
http://host.docker.internal:5001(适用于 Mac/Win Docker Desktop) - API Key:
sk-abc123def456ghi789
💡 如果你在 Linux 上运行 Docker,需替换为宿主机网关 IP,如
http://172.17.0.1:5001
点击「测试连接」,出现“连接成功”表示注册完成。刷新插件市场,你会在「本地插件」分类下看到自己的作品。
接下来,验证它能否真正参与工作流。
新建一个空白工作流,点击「+ 添加节点」,在工具箱中找到你的插件,拖入画布。配置如下:
- 函数选择:
get_weather - 输入城市:
Shanghai
此时节点会显示输出结构预览,方便下游使用。
为了体现 AI 的整合能力,再添加一个 LLM 节点,输入提示词:
根据以下天气信息生成一段友好的提醒: 城市:{{start.nodes.plugin_1.outputs.result.city}} 温度:{{start.nodes.plugin_1.outputs.result.temperature}}℃ 天气状况:{{start.nodes.plugin_1.outputs.result.condition}} 请给出穿衣建议。注意这里的变量引用语法 —— Dify 使用双花括号提取上游节点输出。只要数据结构匹配,就能无缝传递。
点击「运行」,观察输出:
“上海当前气温 26℃,天气晴朗。适合穿短袖衬衫或T恤,注意防晒。”
成功!这意味着插件已被正确调用,且结果顺利流入大模型进行语义加工。
当你对功能满意后,就可以打包共享了。
执行命令:
dify plugin package ./my-first-plugin输出:
📦 Packaging plugin... ✔ Plugin packaged successfully! 📁 Output: dist/my-first-plugin-0.1.0.zip这个 ZIP 包含全部代码、配置和元数据,可用于离线分发或上传至私有插件市场。
在其他 Dify 实例中,只需进入【插件】→【上传插件】,选择该文件即可安装。无需重新配置网络或权限,开箱即用。
在整个开发过程中,有几个经验值得强调:
- 版本管理要用语义化规范(如 0.1.0 → 0.2.0),便于团队协作追踪变更;
- 敏感信息绝不硬编码,统一通过
.env注入,生产环境可通过 Secret Manager 替代; - 接口文档要清晰,尤其是
schema.yml中的 description 字段,直接影响用户体验; - 异常处理要结构化,返回标准 error 对象,帮助平台做统一错误提示;
- 做好单元测试,特别是参数校验和边界条件,避免因输入异常导致服务崩溃。
举个例子,当城市为空时,不要返回裸字符串错误,而应使用如下格式:
{ "error": { "type": "invalid_parameter", "message": "City parameter is required." } }这样 Dify 平台才能识别并友好展示错误信息。
最后想说的是,Dify 的真正价值不在于“可视化编排”本身,而在于它把复杂的技术栈封装成了普通人也能操作的模块。而插件机制,则是打开这座黑箱的钥匙 —— 让开发者既能享受低代码便利,又不失对系统深度控制的能力。
无论是对接 CRM 查询客户订单,还是调用企业微信推送审批通知,甚至控制 IoT 设备开关灯光,都可以通过一个简单的插件实现。
下一步你可以尝试:
- 封装一个真实的第三方 API,比如微信模板消息或阿里云短信;
- 结合 RAG 模块,构建“知识库查询 + 外部工具调用”双驱动 Agent;
- 参与 Dify GitHub 社区 贡献通用插件模板,帮助更多人快速上手。
Dify 不只是一个工具,它是通往 AGI 时代的工程跳板。而你写的每一个插件,都是为未来智能体生态添砖加瓦。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考