问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

独立、灵活、可扩展:Dify 插件机制的设计与实现

创作时间:
作者:
@小白创作中心

独立、灵活、可扩展:Dify 插件机制的设计与实现

引用
1
来源
1.
https://www.53ai.com/news/dify/2025031294206.html

Dify插件机制的推出,为AI系统带来了前所未有的灵活性和可扩展性。通过将可横向扩展的模块解耦并独立为运行时,Dify实现了模块的独立安装、卸载和运行,同时引入了插件市场和分享机制,极大地提升了用户体验。本文将深入探讨Dify插件机制的设计理念、用户价值和技术实现细节。

用户需求分析

在设计插件机制之前,Dify主要面临以下几个问题:

  1. 代码强耦合:在Dify中添加新模型和工具的过程非常繁琐,且会带来过多的工程依赖,导致工具和模型的版本管理问题。
  2. 用户需求无法闭环:某些需求,例如接入IM服务,必须在Dify之外再封装一层服务。
  3. 定制化模块固定性:例如,Dify的PDF解析器效果不理想,且RAG等定制化模块无法灵活调整。

针对这些问题,Dify决定实现一套统一的框架,拆分Dify的工具和模型,使它们可以独立安装并按需选择。同时,文档解析器、OCR等RAG相关功能也实现插件化,以满足不同的场景需求。对于Dify内无法闭环的场景,插件机制通过开放接口实现与外部系统的对接,比如支持对接IM平台的Outgoing Webhook。

解决方案

调试体验

在考虑如何实现插件机制之前,Dify首先思考了如何优化调试体验,尤其是针对开发者而言。理想的调试体验应该具备以下两个要求:

  1. 所见即所得:每次修改代码后,不需要安装过程,直接在Dify中生效。
  2. 本地调试:插件的代码需要在本地运行,以便能够通过断点等方式调试,查错过程更加便捷。

Dify参考了老牌调试器如GDB的设计,采用了调试器和运行时分离的方式:调试器等待运行时主动连接。一旦连接建立,本地插件就可以与Dify建立长连接,Dify会将其视为已安装插件,标记为调试模式。用户请求通过长连接转发给本地插件,插件的返回结果也通过长连接发送给Dify,从而实现了流畅的调试体验。

然而,这种设计面临一个问题:长连接是带状态的,而Dify目前的服务是无状态的。在Kubernetes集群中,负载均衡会将请求路由到不同的Dify Pod上。例如,Plugin 1连接到Dify 1,Plugin 2连接到Dify 2。当用户请求调用Plugin 1时,请求可能会被负载均衡路由到Dify 2,导致用户无法访问Plugin 1。因此,Dify需要在后续实现流量转发机制来解决这一问题。

Endpoint插件

Dify调研了许多现有的即时通讯(IM)工具和办公协作软件,并综合当前需求,明确了要解决的关键问题:如何让Dify接收来自这些平台的Webhook请求,并让插件能够处理这些HTTP请求。例如,使用Dify的App来处理用户消息。

为了解决这个问题,Dify设计了生成随机URL的机制,并将该URL与Discord等IM平台集成。这种方式避免了在每个插件中长期运行一个服务器的问题,因为Dify承担了HTTP请求转发的责任。Dify通过生成的URL来接收来自这些平台的Webhook请求,而插件则处理转发的请求。

解决了如何接收消息的问题后,紧接着是如何处理消息。设想正在开发一个Discord Bot,想让Dify的某个Chatflow来回复用户消息,代码可以是这样的:

class Webhook:
    def _invoke(self, r: Request) -> Response:
        message = r.json()['message']
        respose = invoke_app(app_id, message)
        return Response(response)

在这个插件中,需要能够调用Dify的App来处理请求,这样就可以实现Bot功能。此时,Dify v1.0.0中引出了一个重要概念:反向调用。

反向调用

反向调用是Dify插件机制中的重要概念,允许插件调用Dify内部的服务。例如,插件可以调用已经鉴权的模型、工具,或Dify的App。在以下几个场景中,反向调用发挥了重要作用:

  • LlamaIndex的实现:LlamaIndex实现了多种Agentic RAG策略,通过LLM对检索到的列表进行总结。在Dify中,它作为一个工具使用,用户只需配置模型参数和输入列表,工具即可安装卸载。
  • 模型作为工具:以前,OCR、ASR和TTS模型只能作为独立模型使用,无法灵活调用。现在,它们可以作为工具使用,例如将Gemini作为OCR工具,简化了操作流程。
  • OpenAI兼容API:通过Endpoint插件,Dify提供OpenAI兼容格式,插件可调用Dify的App,并返回统一格式的响应,支持不同模型如Claude或Gemini。
  • Agent插件化:如果支持反向调用工具,那么就可以实现Agent的插件化,自动接收参数执行操作并返回结果,并根据需求自定义Agent策略。

实现细节

首先,插件运行时的设计是需要解决的首要问题。最终,插件运行时到底是Docker容器、进程、虚拟机,还是Serverless运行时?在对Dify用户群体进行评估后,Dify决定实现四种完全不同的运行时,分别为:

  • 本地部署:面向中小型团队和个人开发者,部署需求相对较低,关注高可用性和大规模使用的需求较小。
  • SaaS服务:面向数十万用户,Dify需要考虑大量用户负载。
  • 企业版本:与SaaS类似,企业版本也要求高可用性,但企业用户需要更高的可控性、隐私保护和私有部署。
  • 远程调试:支持调试模式,也需考虑为其提供运行时支持。
本地部署

本地部署版本的实现注重“一键部署”和开箱即用。用户可以通过一句docker compose up -d命令运行整个Dify,并且安装插件时无需额外配置。在这种环境下,插件的运行时设计为一个子进程,由父进程管理所有生命周期控制,包括插件依赖包的安装,两者通过标准输入输出管道进行通信。在理论上,这种设计是可行的。

SaaS服务

考虑到大规模用户的需求,SaaS版本的设计采用类似Serverless的架构,能够根据使用量自动弹性伸缩,从而确保高并发、高资源利用率和高可用性。最终,Dify选择了AWS Lambda作为解决方案,AWS作为Dify的合作伙伴,已经支持现有SaaS业务,且Dify与Lambda使用网络进行通信,提供了一个非常合适的架构。

企业版本

考虑到企业客户在解决方案选择上的多样性,因此设计了一种可控、可信的运行时。这个版本可以为企业提供高度的可控性和隐私保护,支持企业内部私有部署。

远程调试

对于调试模式,Dify支持通过TCP网络长连接调试插件,并解决了有状态问题。采用类似etcd的设计,通过Redis HashMap管理插件的连接状态,确保插件的请求能够正确转发到相应的Pod。为了管理IP,设置了如下两项机制:

  • 集群需要维护一个IP池,Pod会将其IP加入池中。在生产环境中,一台机器可能有多个IP,并且位于多个子网,因此,Pod之间采用投票机制进行可达性测试,标记可用IP。
  • 集群需要有一个Master节点,定期检查Pod的存活情况,清理掉已退出的节点状态,确保集群的稳定性。

安全

系统安全

插件机制的安全性主要依赖于密码学中的签名,而不是类似Sandbox的强制性安全限制。Sandbox的限制非常严格,导致很多依赖包无法安装和使用,因为这些包可能会涉及未经许可的系统操作,严重影响插件使用体验。相较之下,插件是已经编写完成的代码包,在安装插件之前,人工审核能够为插件包打上“安全”标签,极大地降低风险。Dify采用了基于公钥密码学的签名策略:如果插件通过审核,将使用私钥对插件进行签名,标记为“已认证”,如果未通过审查,用户将看到“不安全”的提示。所有未签名的插件无法安装,除非用户手动更改设置。

隐私策略

所有插件均须明确声明其使用的权限、数据存储等隐私政策,尤其是涉及敏感数据的插件。对于简单的权限声明,插件开发者必须显式声明插件的功能权限,未声明的权限Dify会直接拒绝使用。而对于复杂的隐私政策,Dify要求开发者提供详细的隐私策略,并在Manifest中引用,所有上架Marketplace的插件都需要经过隐私策略审核。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号