我让AI自己学习了Dify源码和172个DSL,它现在会自动写工作流了
前两天有个朋友找我吐槽,说他在Dify上搭一个NL2SQL的工作流,光是拖节点、连线、调参数就折腾了一下午。
我说你这还算快的,我之前搭一个带数据库插件的多轮对话流程,光是搞明白tool节点的依赖配置就花了两天。
然后我突然想到一个问题:既然这些工作流本质上就是YAML,能不能让AI直接帮我写?
听起来很合理对吧?但实际试过之后你会发现,让AI裸写Dify DSL,跟让一个不懂语法的人写Python差不多——看起来像那么回事,但导入就报错。

为什么AI裸写DSL不靠谱
我做了一个实验。让Claude、GPT分别生成一个简单的工作流YAML,然后导入Dify。
结果:全部失败。
原因五花八门:version字段用了数字而不是字符串、node的type写法不对、edge的sourceType和实际节点不匹配、变量引用语法写成了Python格式……
这些问题单独看都不大,但合在一起就是一个「看起来对但跑不起来」的烂摊子。
后来我仔细想了想,这其实不怪AI。Dify的DSL规范没有一个完整的公开文档,很多细节藏在源码里。你让AI去猜这些规范,它当然只能靠「看起来合理」来编。
“这就像让一个外国人写中文——他认识几千个字,但写出来的句子总觉得哪里不对。
决定系统研究一下
既然AI不知道规范,那我就把规范整理出来给它。
我做了一件可能有点疯狂的事:把GitHub上能找到的Dify公开DSL文件全部下载下来研究。
三个仓库,172个可以解析的YML文件:
BannyLon/DifyAIA:38个 svcvit/Awesome-Dify-Workflow:45个 wwwzhouhui/dify-for-dsl:89个
然后我又去翻了Dify的官方源码——dsl_version.py、app_dsl_service.py、workflow/types.ts、node registry……
说实话,翻源码的过程挺痛苦的。Dify的代码组织方式跟文档描述有不少出入,很多规范是「代码里这么写,文档里没提」的状态。
但翻完之后,我终于搞清楚了几件关键的事:
第一,版本号是字符串不是数字。 你写 version: 0.6.0 会被当成浮点数,必须写 version: "0.6.0"。
第二,节点有两层type。 外层是 type: custom,真正的节点类型在 data.type 里面。这个设计反直觉,但源码就是这么规定的。
第三,变量引用有两种语法。 在prompt里用 {{#node_id.field#}},在selector里用 [node_id, field]。用错了不会报错,但运行时拿不到值。
第四,分支节点的handle必须和case ID精确匹配。 if-else是 true/false,question-classifier是分类ID。handle写错了,线连不上,但界面不会告诉你哪里错了。
这些坑,172个真实文件里踩过一遍,源码里验证了一遍。

从「研究」到「技能」
研究完了,然后呢?
直接写一篇博客把这些规范记下来?有用,但不够。因为每次写DSL的时候还是要人去查、去对照。
更好的方式是:把这些知识打包成一个「技能」,让AI编程助手自己学会。
这就是 dify-workflow-dsl-skill 这个项目做的事情。
它不是一个应用,不是一个库,而是一个 AI Agent Skill——一套结构化的知识体系,教AI编程助手怎么正确地生成、修改、审查Dify工作流DSL。
你装上这个skill之后,只需要用自然语言描述你想要什么:
「帮我创建一个Dify高级对话工作流。用户上传PDF,提取文本,用Qwen总结,把总结插入PostgreSQL,插入成功后回答用户。」
AI就会按照规范生成一个可以直接导入Dify的YAML文件。
它是怎么工作的
这个skill的核心设计思路是:给AI规则,而不是给AI工具。
什么意思?市面上大部分AI工具集成方案是给AI一堆API让它调用——创建节点API、连线API、配置API。但DSL生成不是这种「逐步操作」的任务,它更像是「写一篇结构极其严格的文档」。
所以skill的架构是这样的:
SKILL.md(核心指令,约135行):定义了7步工作流程——理清需求→选择版本→画草图→连线→加依赖→处理未知插件→验证。AI每次生成DSL都会走这7步。
**references/**(按需加载的参考资料):
dsl-structure.md:顶层YAML结构、边、handle、变量 node-schemas.md:每种节点类型的完整schema(553行) database-tools.md:PostgreSQL插件的两种模式 plugin-marketplace-tools.md:插件工具的「可靠性阶梯」 real-world-yml-study.md:172个真实文件的分析 complete-examples.md:4个可直接导入的完整示例
这种「核心短指令 + 按需加载参考资料」的设计,让AI的上下文窗口不会被撑爆。它只在需要的时候才去读详细的schema和示例。
一个我花了很多时间搞清楚的东西:插件工具的可靠性阶梯
Dify的插件生态是它最有吸引力的部分之一,但也是DSL生成中最不可控的环节。
因为插件的schema没有统一的公开注册表。你不知道一个插件需要哪些参数、参数是什么类型、有没有必填项。
为了解决这个问题,我设计了一个「可靠性阶梯」:
最高可靠: 用户自己导出的DSL里有这个tool节点。直接拿来用,100%准确。
高可靠: 用户给了插件的GitHub链接或包名。可以推断出plugin_id和基本结构。
中等可靠: 用户给了插件名称。可以尝试从marketplace推断,但可能不准。
最低可靠: 用户只说了「我要用XX工具」。只能生成一个占位节点,需要用户自己补全参数。
这个设计的核心理念是:诚实。 告诉AI什么时候可以保证正确,什么时候只能尽量猜测。比起生成一个「看起来对但导入报错」的文件,不如明确告诉用户哪些地方需要确认。
安全性不能只靠自觉
工作流里最容易出问题的是什么?
不是结构错误——那些导入时就能发现。真正危险的是SQL注入和数据泄露。
所以skill里内置了安全规则:
SQL必须使用参数化绑定( $arg0,$arg1),禁止字符串拼接检测危险关键词:DROP、DELETE、TRUNCATE、GRANT、EXEC 检测尾部逗号(会导致SQL语法错误) 数据库凭证必须通过环境变量传入,不能硬编码
这些规则不是建议,是强制的。AI生成的SQL如果有这些问题,validator脚本会直接报错。
验证器:最后一道防线
skill自带一个335行的Python验证脚本,能在用户导入Dify之前检查出大部分问题:
YAML解析是否正确 version字符串格式 图的边引用是否有效(source和target必须存在) 节点类型一致性 LLM节点的model和prompt模板 代码节点的main函数定义 Tool节点的必填字段 变量引用是否指向真实节点 重复的节点ID
这个验证器不是万能的——它不能检查业务逻辑是否正确——但它能拦住80%的「导入就报错」的问题。
多平台支持
这个skill不是只给某一个AI助手用的。它支持:
Codex(OpenAI) Claude Code(Anthropic) OpenClaw Hermes Agent
通过一个install.sh脚本,一行命令就能装到对应的平台。每个平台的知识目录结构不同,安装脚本会自动处理。
我从这件事学到了什么
回头看这个项目,有几个体会想分享:
1. AI不是万能的,但给对了知识它就能万能。
AI裸写DSL不行,不是因为AI笨,是因为它没见过规范。172个真实文件 + 源码分析 + 验证器,这套知识体系一给,AI立刻就能写出正确的DSL。
这说明什么?说明AI的能力瓶颈往往不在模型本身,而在我们给它的知识质量。
2. 「技能」比「工具」更适合AI。
给AI一堆API让它调用,它会按部就班地执行,但不会思考。给AI一套规则和知识体系,它会根据具体情况灵活应变。
DSL生成这种「规则密集型」任务,技能模式比工具模式效率高得多。
3. 诚实比完美更重要。
插件工具的可靠性阶梯,本质上是在教AI说「我不确定」。在AI应用中,「不确定但假装确定」是最危险的行为。明确告诉用户哪些是保证正确的、哪些是猜测的,才是真正负责任的做法。
4. 研究真实数据比读文档有用。
Dify的官方文档对DSL规范的描述是不完整的。但172个真实文件里包含了所有你能遇到的模式和坑。
这不只是Dify的问题。很多开源项目的文档都跟不上代码的变化。去看真实的使用案例,比读文档有效十倍。
写在最后
dify-workflow-dsl-skill 现在已经开源了,大家感兴趣可以去github上搜索使用
它不完美——Dify还在快速迭代,0.6.0的规范可能很快就会变;插件生态还在发展,很多插件的schema还是未知的。
但它证明了一件事:把领域知识系统化地打包给AI,效果远好于让AI自己猜。
如果你也在用Dify搭工作流,如果你也受够了拖节点调参数的重复劳动,可以试试让AI帮你写DSL。
前提是,你得先教会它。

夜雨聆风