Dify 开源体验
Dify 开源体验
Feature contribution
随着部门深入使用 dify,逐渐遇到了一些卡点问题,因此我也顺便看了下 Dify 社区的贡献指南,想着给社区提供一些我们这边的思路。
目前来说是做了两个 feature:
- 支持复制节点到迭代、循环节点内部
- 工作流发布为工具支持结构化数据输出
这两个 feature 都能显著提升平台使用体验。
第一个 feature 在开发工作流的过程中,一般我们是先搭直线的流程,再通过迭代节点等来进行流程的优化,此时如果要将许多节点一次性复制到迭代节点内部,就会特别方便,在以往只能重新再迭代节点内部再重搭一次流程。这个 feature 已经被合并到主分支且在 1.9.0 正式上线了。
第二个 feature 针对工作流发布为工具这一功能做了优化,这个功能是当下 dify 构建工作流中逻辑复用十分重要的一环,低代码平台中类比实际写代码中抽离公共函数的行为就是将工作流发布为工具,可以将一些功能单独发布为工具便于复用和降低耦合度。但当前 dify 平台针对这种工作流工具,为了通用性考虑,输出变量只放到了三个公共变量中,后续节点使用时需要手动解析 json 数据,从通用数据中解析出自己想要的某些数据,可以理解 dify 当初的设计是出于通用性,但确实在大批量使用工作流工具时会非常繁琐。其实我们是知道工作流的输入数据和输出数据的,因此就可以解析出这个工具具体输出的属性,后续节点就可以直接取到这些属性,不需要额外的代码去解析了。这个 feature 实打实地解决了我们内部使用 dify 的一大痛点,看 issue 和 pr 的反馈,也是有不少人认可的,目前这个 feature 仍在 review 阶段,不久后应该会正式合入主分支并上线。
社区氛围
这两个功能做下来,我大概也对 dify 这个项目的贡献有所了解了,之前提到每个项目的社区团队工作方式都不太一致,dify 这个项目的社区团队估计是人手不足的原因,我看 issue 和 pr 数一直居高不下,这也就导致了虽然团队已经很努力在处理和审阅,还是赶不上社区贡献的速度。我的第二个 feature 基本在过了一个月之后才被 review 到,这其中如果有一些问题需要改动,整体时间又会继续被拉长。总体而言,dify 这个项目会更多地关注 bugfix 类的 issue,而 feature 类的 issue 相对处理会比较谨慎和缓慢,同时针对 feature 类的 issue 建议是先与社区进行探讨再开发,否则容易会做无用功,这个也是当前许多开源项目针对 feature 的态度。新参加开源的朋友可以优先从 bugifx 开始下手,这样可以得到较快速度的响应,不至于说一直阻塞在某个阶段得不到正反馈,会影响自己的热情 🤣。
gemini code review & github action
在对比这个项目和之前的另一个 vite 相关的开源项目时,我发现社区都很喜欢使用 github action 来做一些 CI/CD 的工作,同时也确实感受到了 github action 的强大之处。得益于在同一套体系下,github action 能很好地和代码仓库融合,在指定的时机触发指定的操作,看起来就像是融为一体一样的丝滑。
在 dify 中,值得提的一点是它利用 github action,在提交 pr 的时候会自动对本次修改的代码,使用 gemini 来进行一次 code review,总体来说我觉得效果还是很不错的,有代码写法相关的优化建议,也能找出来一些明显错误,同时给出对应的修改建议,懒的话甚至可以一键采纳并 commit,用起来十分的丝滑。
在使用过后,我都在想是否能在公司内部去使用 AI 结合 gitlab 进行代码 review,因为 review 很大的两个卡点都能被 AI 解决:第一是人手不足,第二是每个项目都需要有 B 岗来了解,如果不了解项目对代码 review 就只能看一些通用的逻辑,业务逻辑需要去重新学习和理解。AI 的优势就体现出来了,它可以将整个代码库进行 embedding,来作为它 review 的上下文,然后它也是一个任劳任怨的人力,这两个最大的卡点都能被 AI 完美地解决,剩下的就是优化 prompt 和评测模型能力了。这个可以作为后续部门内部推进的目标之一。
项目技术相关
Flask & ORM
dify 这个项目的后端使用的是 python + flask,很典型的开源项目框架选型。python 的 web 项目主打的是一个快速上手和轻便,同时性能也过得去。这也是我第一次接触 python web 项目,总体来说和 nodejs 体验差不多,但整体感觉还是会正式不少,对比了一下两者,ORM 这个方面给我留下了挺深刻的印象。
nodejs 和 python 的 ORM 总体来说会做得更全面一点,它将数据库表的操作整体与代码进行映射,不单负责查数,还负责了数据库表的创建与修改,是一个「全包型」的思路。而企业级项目常用的 java web 框架使用的 mybatis 之类的库,它就仅负责数据的查询与实体类映射,数据库表的相关操作还是需要用户自己去编写 SQL,这并不是 java 做不到,在 java 中也有对应的库能实现,为什么有这种差异,更多是两者的设计思路不一样。nodejs 和 python 这边反映的是一种高度集成的路径,而 java 这边更倾向于让专业的工具各司其职。
回到 flask ORM 这边,它通过执行命令自动分析 Model 实体类来创建对应的 migrate 代码,同时支持快速的 upgrade 和 downgrade,也能处理不同版本之间差异时的 merge,给我还是留下了十分深刻的印象,太久没接触后端开发,发现现在的 ORM 框架能力做得确实很完善了,个人项目,还有需要快速迭代的开源项目,使用这类框架确实能大大提升开发效率。
单元测试 & AI 生成测试用例
在写完一个新的功能之后,自然是需要补充一些新的单元测试。python 这边使用的是 pytest 这个测试框架,本质上写单元测试都是执行一些逻辑,然后通过断言来判断是否正确。
在不太了解框架用法和 python 菜鸡的双重 buff 叠加下,我选择了使用 cursor 来自动生成测试用例。使用了如下 prompt:
查看我的 git 历史,针对我这次 workflow as tool 的改动,在 test_tool.py 中添加对应的单元测试
不得不说 AI 在生成测试用例这块还是很好用的,它能根据上下文找出我们的改动内容,同时学习项目中单测的写法,基本上帮助我写了 90%的单测代码,我需要做的就是 review 一遍,将它有些理解错的地方加以改正,总体来说效果还是很不错的,后续也可以多考虑使用 AI 来写单元测试。
前端 auto i18n
在做需求的时候,涉及到要添加一些新的文案,这块我研究了一下 dify 的 i18n 结构,dify 使用了 github action 来自动触发 i18n 的翻译,翻译逻辑写在一个 node 脚本中,通过解析 ast 和调用 bing 来进行多语言翻译,因此项目中只需要写清楚英文的文案,在每个大版本发布的时候,github action 就会自动触发并将未翻译的 i18n key 进行翻译,并自动提交 pr,以实现前端侧的自动 i18n。
这个思路和我之前写的 vue i18n translate 整套方案本质上差不多,它这里也有使用 typescript 的 ast 解析来规避一些不需要翻译的内容,它的方案约等于一个黑名单,我则是使用 ast-grep 来找出需要翻译的内容,我的方案类似一个白名单。翻译这块,我是使用了大模型来进行翻译,而 dify 应该是基于稳定性和效率考量,使用的是 bing 翻译。
Docker Compose
Docker 这个东西挺久之前就了解过和使用过了,它本质上就是一套完整的环境,能快速地将一个环境打包成一个镜像,方便迁移与快速使用。
而 Docker Compose 是一个配套的工具,在实际开发中,数据库是一个镜像,代码服务是一个镜像,还有其他的组件分别也是不同的镜像,如果需要每个单独去启动和配置是非常繁琐的。Docker compose 就是这样的一个工具,用于定义和运行多容器 Docker 应用的工具。核心其实就是一个 docker-compose.yml 文件,在里面定义好,其他人拿到这个配置文件之后就可以一键拉取镜像,一键将容器都运行起来。它也不是完美的,这工具只能运行在一台主机上,不具备生产所需的高可用和弹性。
这个时候可以提一嘴 Kubernetes,k8s 的存在就是专注于管理跨多台主机的大规模容器化应用,它具有完善的自我修复、自动扩缩容、滚动更新等生产级的功能。看 AI 回答的结果里提到了,k8s 早期是使用 docker 作为底层的容器运行时,在新版本转为使用更轻量的 containerd 和 cri-o,但 k8s 仍然支持运行 docker 构建的容器,containerd 只是一个运行时,本身也是 docker 引擎的一部分。
