ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Dify 插件开发实验(10):自定义节点扩展——不改平台代码,插件如何补节点能力?

2026/8/22 11:50:37 拓冰建站 浏览量
Dify 插件开发实验(10):自定义节点扩展——不改平台代码,插件如何补节点能力? Dify 插件开发实验10自定义节点扩展——不改平台代码插件如何补节点能力Dify 实验系列 · 插件开发 10/12 | 实验编号DIFY-106-10基于 Dify 1.16.1 实测2026-081. 业务场景先讲一个我们实际遇到的场景。客服工单 SaaS 的工单编号有一套业务规则DTF-YYYYMMDD-序号序号每日从 001 递增跨天归零。比如今天第一张工单是DTF-20260805-001第二张是DTF-20260805-002明天又从DTF-20260806-001开始。这个编号是工单的对外门面——客户报修、财务对账、跨系统引用都靠它。我们第一次接这类需求时第一反应也是「编号嘛代码节点里写个计数器不就行了」。真正动手才发现——代码节点每次运行相互独立根本记不住「今天发到第几个号了」让 LLM 生成编号既可能重复也可能跑偏。我们最初想做「自定义工作流节点」插件实测 1.16.1 daemon 根本没有 extensions 节点类型——平台不支持只能找等效路径。这不是个例。任何业务系统都有自己的编号规则订单号、发票号、流水号、审批单号——「前缀 日期 当日自增序号」是最常见的形态而「跨运行有状态」恰恰是普通工作流节点最难满足的需求。2. 场景痛点这个流程的痛点在编号生成时体现得最直接代码节点无状态工作流代码节点每次运行相互独立记不住「今天已经发到第几个号了」序号永远从 001 开始。LLM 生成不可控让模型生成编号既可能编出重复号也可能格式跑偏——编号这种确定性数据不该交给概率。并发重复多个客服同时建单各自都拿到 001工单号撞车对账直接乱套。跨天不归零用固定键存计数第二天忘了重置序号一路涨下去规则就废了。本质上编号生成是「有状态 确定性」的需求——现有节点凑不出需要的是一个「拖入即用、跨运行有状态」的能力。3. 方案为什么先探边界再选等效路径选这个方案我们实际对比过先探平台边界目标本是「自定义工作流节点」extension 类型但实测 1.16.1 daemon 的 PluginExtensions 只有 tools / models / endpoints / agent_strategies / datasources / triggers 六类无 extensions 节点类型——平台当前不支持自定义节点插件非版本落后main 分支源码同样没有工具插件等效替代generate_ticket_no工具 KV 序列存储工作流工具节点调用——「拖入即用 跨运行有状态」两个诉求都能满足功能与自定义节点等价日期键天然跨天归零KV 键按日期设计ticket_seq_YYYYMMDD换键即重计不用显式判断日期变化。这篇文章我们就用它搭一个「工单编号生成器」工具插件dify106_10_ticket_no_toolgenerate_ticket_no KV 序列跑通「当日自增、跨天归零、跨运行有状态」的完整链路并实测平台边界给出结论。4. 整体架构【等效方案实测】开始date/prefix 可选工具节点 generate_ticket_no输出 ticket_noend工具内部读 KV ticket_seq_YYYYMMDD → seq1 → 写回 → 返回 {ticket_no, date, sequence}【预期方案平台不支持】工作流画布自定义节点「工单编号生成器」extension 类型出现在节点面板链路很清晰收日期/前缀 → 读当日 KV 计数 → 自增 → 写回 → 返回编号。关键设计是「日期键」——KV 键里带日期换键即重计跨天归零是天然行为不是额外逻辑。5. 模块设计5.1 工具参数声明tools/generate_ticket_no.yamldate 与 prefix 都是可选参数默认值在实现里兜底parameters:-name:datetype:stringrequired:falseform:llmllm_description:Date in YYYYMMDD format, e.g. 20260805, default today-name:prefixtype:stringrequired:falseform:llmllm_description:Ticket number prefix, 1-8 chars, default DTF5.2 日期键 参数校验tools/generate_ticket_no.py日期键换键即重计天然支持跨天归零DATE_PATTERNre.compile(r^\d{8}$)PREFIX_PATTERNre.compile(r^[A-Za-z0-9_-]{1,8}$)date_str(tool_parameters.get(date)or).strip()ordatetime.now(timezone.utc).strftime(%Y%m%d)prefix(tool_parameters.get(prefix)or).strip()orDTFifnotDATE_PATTERN.match(date_str):yieldself.create_text_message(err(param_invalid,date must be YYYYMMDD (e.g. 20260805)))returnkeyticket_seq_date_str# 日期键换键即归零天然跨天seqread_kv_seq(kv_url,key)# 读当日计数KV 持久化复用 106-05 模式seq1write_kv_seq(kv_url,key,seq,date_str)# 先查后写与 106-05 同款竞态语义yieldself.create_text_message(json.dumps({ticket_no:f{prefix}-{date_str}-{seq:03d},date:date_str,sequence:seq},ensure_asciiFalse))6. 运行验证验证项输入/场景预期结果注册安装工具插件工具目录出现 generate_ticket_no✅基本默认参数运行输出 DTF-20260810-001✅序列递增连续运行 3 次001/002/003✅跨天归零date20260806换键重计序号 001✅并发5 线程同日期序号不重复⚠️ 全 seq 1竞态窗口实测预期内生产 Redis INCR对照代码节点 vs 工具插件 6 维度差异表✅与代码节点对照结论6 维度差异表跨运行状态——代码节点无每次独立工具插件 KV 持久化 ✅复用性——代码节点每工作流复制粘贴工具插件一次安装全局可用 ✅可配置性——代码节点改代码工具插件参数凭证配置 ✅维护性——代码节点多处副本难同步工具插件单点更新 ✅开发成本——代码节点低但做不了有状态工具插件中插件流程已熟可测试性——代码节点无独立测试工具插件本地单测冒烟 ✅。有状态需求编号序列/计数/审批状态是代码节点盲区——工具插件KV 持久化是官方支持路径下的等效解法真·自定义节点面板新节点类型需等 Dify 支持节点扩展插件。7. 实战坑坑现象修复节点扩展不支持核心1.16.1 daemon PluginExtensions 无 extensions 类型仅六类插件main 分支源码同样无工具插件等效替代generate_ticket_no KV 序列等 Dify 升级支持节点扩展再实测节点接口不熟sdk 0.7.4 workflow_node 仅支持内置节点运行时parameter_extractor/question_classifier不写自定义节点按工具插件标准结构开发工作流用工具节点调用本地持久化失败节点/工具内写本地文件被沙箱拦截104-01 实测 code 沙箱禁写序列计数走 KV 外部存储复用 106-05 模式并发重复序号先查后写竞态5 线程并发全 seq 1生产用 Redis INCR 原子自增替代跨天不归零若用固定键需要显式判断日期变化才能归零日期键设计 ticket_seq_YYYYMMDD换键即重计天然跨天归零8. 实验文档及源码获取实验文档DIFY-106-10自定义工作流节点扩展.md插件安装包dify106_10_ticket_no_tool.signed.difypkg源码目录dify-106/dsl | dify-106/plugins文章聚焦核心配置与采坑点完整分步操作与代码节点对照实验记录见实验文档原文。下一篇Dify 插件开发实验11打包分发与离线安装——插件如何打包签名、分发与离线安装 你在这个实验的场景里踩过什么坑欢迎评论区分享你的实战经验。