Dify 通过导入 DSL 文件创建 Workflow 过程及实现

本文使用 Dify v0.9.2 版本,主要介绍 Dify 通过导入 DSL(或 URL)文件创建(或导出)Workflow 的操作过程及源码分析实现过程。Dify通过导入DSL文件创建Workflow过程及实现:https://z0yrmerhgi8.feishu.cn/wiki/KVIWwrcPMiOdDhk4FngcHrlgnJc

一.导入 DSL 文件创建 Workflow 过程

1.导入操作过程

点击"导入 DSL 文件"后,会弹出"导入 DSL"框,如下所示:

可以选择从文件导入,也可以选择从 URL 导入,如下所示:
在这里插入图片描述

2.导入操作 API

通过浏览器 Network 可看到,本子调用为 http://localhost:5001/console/api/apps/import 接口,如下所示:

该接口具体返回结果(Preview),如下所示:

该接口具体返回结果(json),如下所示:

{"id": "24a1f8d6-aad0-4099-b724-0cdd15d39dde","name": "20240930_\u6a21\u578b\u7ade\u6280\u573a\uff08\u7b80\u5355\u5e76\u884c\uff09_v1","description": "20240930_\u6a21\u578b\u7ade\u6280\u573a\uff08\u7b80\u5355\u5e76\u884c\uff09_v1","mode": "advanced-chat","icon_type": null,"icon": "\ud83e\udd16","icon_background": "#FFEAD5","icon_url": null,"enable_site": true,"enable_api": true,"model_config": null,"workflow": {"id": "c9721caf-6d43-413d-8447-136b1ba8ede0","created_by": "12ab7619-6406-4df2-b2a4-c581e033d7fb","created_at": 1729144453,"updated_by": null,"updated_at": null},"site": {"access_token": "PZ63qIcMMjL3W1Aa","code": "PZ63qIcMMjL3W1Aa","title": "20240930_\u6a21\u578b\u7ade\u6280\u573a\uff08\u7b80\u5355\u5e76\u884c\uff09_v1","icon_type": null,"icon": "\ud83e\udd16","icon_background": "#FFEAD5","icon_url": null,"description": null,"default_language": "en-US","chat_color_theme": null,"chat_color_theme_inverted": false,"customize_domain": null,"copyright": null,"privacy_policy": null,"custom_disclaimer": null,"customize_token_strategy": "not_allow","prompt_public": false,"app_base_url": "http://127.0.0.1:3000","show_workflow_steps": true,"use_icon_as_answer_icon": false,"created_by": "12ab7619-6406-4df2-b2a4-c581e033d7fb","created_at": 1729144453,"updated_by": "12ab7619-6406-4df2-b2a4-c581e033d7fb","updated_at": 1729144453},"api_base_url": "http://127.0.0.1:5001/v1","use_icon_as_answer_icon": false,"created_by": "12ab7619-6406-4df2-b2a4-c581e033d7fb","created_at": 1729144453,"updated_by": "12ab7619-6406-4df2-b2a4-c581e033d7fb","updated_at": 1729144453,"deleted_tools": []
}

3.导出操作过程

因为导出 DSL 文件比较简单就不再详细介绍,主要实现为 api.add_resource(AppExportApi, "/apps/<uuid:app_id>/export"){"data": AppDslService.export_dsl(app_model=app_model, include_secret=args["include_secret"])}

二.导入 DSL 文件创建 Workflow 实现

0.整体实现流程

首先通过(伪)流程图方式分析"导入 DSL 文件"的函数调用流程,如下所示:

1.第 1 部分源码分析

主要是通过 DSL 文件导入,以及 URL 导入的路由,如下所示:

2.第 2 部分源码分析

最核心的是根据 AppMode 类型的不同,导入 DSL 文件,然后创建 App。如下所示:

# import dsl and create app
app_mode = AppMode.value_of(app_data.get("mode"))
if app_mode in {AppMode.ADVANCED_CHAT, AppMode.WORKFLOW}:app = cls._import_and_create_new_workflow_based_app(tenant_id=tenant_id,app_mode=app_mode,workflow_data=import_data.get("workflow"),account=account,name=name,description=description,icon_type=icon_type,icon=icon,icon_background=icon_background,use_icon_as_answer_icon=use_icon_as_answer_icon,)
elif app_mode in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.COMPLETION}:app = cls._import_and_create_new_model_config_based_app(tenant_id=tenant_id,app_mode=app_mode,model_config_data=import_data.get("model_config"),account=account,name=name,description=description,icon_type=icon_type,icon=icon,icon_background=icon_background,use_icon_as_answer_icon=use_icon_as_answer_icon,)

3.第 3 部分源码分析

针对 AppMode.ADVANCED_CHAT, AppMode.WORKFLOW 的 AppMode 类型,导入 DSL 文件,创建 App 过程。主要是创建 App,并且初始化草稿 Workflow,如下所示:

(1)创建 App

app = cls._create_app(tenant_id=tenant_id,app_mode=app_mode,account=account,name=name,description=description,icon_type=icon_type,icon=icon,icon_background=icon_background,use_icon_as_answer_icon=use_icon_as_answer_icon,
)

首先创建 app,然后在 apps 数据表中插入记录,如下所示:

当 app 创建时,发送 app_was_created 事件,如下所示:

具体 app_was_created 事件执行逻辑,如下所示:

这段代码是一个事件处理器,用于在应用程序创建时自动创建一个已安装的应用实例。具体功能如下:

  • 监听 app_was_created 事件,当新应用被创建时触发。
  • 通过事件的发送者(即新创建的应用)获取相关信息(如租户 ID 和应用 ID)。
  • 创建一个 InstalledApp 实例,包含应用的租户 ID、应用 ID 及应用拥有者的租户 ID。
  • 将该实例添加到数据库会话中,并提交更改,以保存新创建的已安装应用记录。

这段代码实现了在应用程序创建时,自动生成一个站点记录的功能。具体概述如下:

  • 监听 app_was_created 事件:当一个新的应用被创建时触发。
  • 获取发送者和账户信息:sender 是触发事件的应用,kwargs 用于获取传递的账户信息(如界面语言)。
  • 创建 Site 实例:使用发送者(应用)的信息创建一个站点记录,包含应用的 ID、名称、图标信息、语言设置、自定义令牌策略等。
  • 生成站点代码:调用 Site.generate_code(16) 生成 16 位长度的唯一代码。
  • 记录创建者和更新者:存储应用的创建者和更新者信息。
  • 保存到数据库:将创建的站点记录添加到数据库会话中,并提交保存,以确保站点信息被持久化。

(2)初始化草稿 Workflow(同步工作流)

draft_workflow = workflow_service.sync_draft_workflow(app_model=app,graph=workflow_data.get("graph", {}),features=workflow_data.get("../core/app/features", {}),unique_hash=None,account=account,environment_variables=environment_variables,conversation_variables=conversation_variables,
)  # 同步草稿工作流

在 sync_draft_workflow()方法中,判断 draft workflow 是否存在,若不存在则创建,若存在则更新,并保存到 workflows 数据表中。然后触发 app_draft_workflow_was_synced 事件,如下所示:

app_draft_workflow_was_synced 事件的具体执行逻辑,如下所示:

在这里插入图片描述

这段代码实现了在草稿工作流同步完成后,对工具节点的管理功能。具体功能概述如下:

  • 监听 app_draft_workflow_was_synced 事件:当草稿工作流同步完成时触发。
  • 获取应用和节点数据:sender 代表触发事件的应用,kwargs 中包含同步的草稿工作流节点数据。
  • 遍历节点:从同步的工作流中获取所有节点,逐个检查其类型。
  • 处理工具节点:如果节点类型为工具节点:尝试将节点数据转换为 ToolEntity 实例;使用工具实体的信息获取工具的运行时;创建一个 ToolParameterConfigurationManager 实例,用于管理该工具的参数配置;删除该工具的参数缓存,以确保使用最新的参数配置。
  • 异常处理:如果在处理过程中发生异常(如工具不存在),捕获并忽略该异常。

(3)初始化草稿 Workflow(发布工作流)

workflow_service.publish_workflow(app_model=app, account=account, draft_workflow=draft_workflow)  # 发布工作流

首先创建新的 workflow,记录到数据表 workflows 中。然后触发 app_published_workflow_was_updated 事件。如下所示:

app_published_workflow_was_updated 事件的具体执行逻辑,如下所示:

这段代码实现了在应用发布工作流更新时,对工作流中数据集的管理和同步功能。具体功能概述如下:

  • 监听 app_published_workflow_was_updated 事件:当应用发布的工作流被更新时触发。
  • 获取应用和工作流信息:sender 代表触发事件的应用,published_workflow 是更新后的工作流数据,并将其类型转换为 Workflow
  • 提取数据集 ID:通过 get_dataset_ids_from_workflow 函数,从更新后的工作流中提取与知识检索节点相关的数据集 ID,并返回一个包含数据集 ID 的集合。
  • 查询应用数据集关联:从数据库中查询该应用当前的 AppDatasetJoin 关联数据集。
  • 计算新增和移除的数据集 ID。如果应用没有任何关联数据集,则所有提取的 ID 为新增数据集;如果有现有的数据集关联,则计算出新增的数据集 ID(added_dataset_ids)和需要移除的数据集 ID(removed_dataset_ids)。
  • 更新数据库。对于需要移除的数据集 ID,从 AppDatasetJoin 中删除相应记录;对于需要添加的数据集 ID,创建新的 AppDatasetJoin 记录,并添加到数据库。
  • 提交更改:最终将所有数据集的变更(新增或删除)提交到数据库以完成更新。

4.第 4 部分源码分析

针对 AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.COMPLETION 的 AppMode 类型,导入 DSL 文件,创建 App 过程。如下所示:

(1)创建 App

app = cls._create_app(tenant_id=tenant_id,app_mode=app_mode,account=account,name=name,description=description,icon_type=icon_type,icon=icon,icon_background=icon_background,use_icon_as_answer_icon=use_icon_as_answer_icon,
)

首先创建 app,然后在 apps 数据表中插入记录。当 app 创建时,发送 app_was_created 事件。该部分代码逻辑和第 3 部分源码分析(创建 App)相同,就不再赘述。

(2)触发事件

app_model_config_was_updated.send(app, app_model_config=app_model_config)

触发 app_model_config_was_updated 事件,如下所示:

app_model_config_was_updated 事件的具体执行逻辑,如下所示:

这段代码的功能是在应用程序的模型配置更新时,根据新的模型配置同步与数据集的关联。具体功能概述如下:

  • 监听 app_model_config_was_updated 事件:当应用的模型配置更新时触发。
  • 获取应用和模型配置信息:sender 代表触发事件的应用,kwargs 中的 app_model_config 包含更新后的模型配置。
  • 提取数据集 ID:通过 get_dataset_ids_from_model_config 函数,从模型配置中提取与工具和数据集配置相关的 ID,包括代理模式中的工具以及数据集配置中的数据集,返回一个包含数据集 ID 的集合。
  • 查询现有的应用数据集关联:从数据库中查询该应用当前的 AppDatasetJoin 关联的数据集。
  • 计算新增和移除的数据集 ID。如果没有现有数据集关联,则所有提取的 ID 为新增数据集;如果有现有数据集关联,则计算出新增的数据集 ID(added_dataset_ids)和需要移除的数据集 ID(removed_dataset_ids)。
  • 更新数据库。对于需要移除的数据集 ID,从 AppDatasetJoin 表中删除相应的关联记录;对于需要添加的数据集 ID,创建新的 AppDatasetJoin 记录并添加到数据库。
  • 提交数据库会话:最终将所有对数据集关联的变更(新增或删除)提交到数据库。

三.删除 Workflow 过程

1.删除操作过程

(1)删除操作

因为 workflow 本质还是 app,所以删除 workflow 本质上还是删除 app,如下所示:

(2)调用接口

删除 workflow 调用接口为 http://localhost:5001/console/api/apps/3c32956e-96bd-4e19-9c47-fd06bb4c5890,如下所示:

(3)接口日志

在 PyCharm 控制台上可看到调用接口的日志,如下所示:

(4)任务日志

在 PyCharm 控制台上可看到执行异步任务(remove_app_and_related_data_task)的日志,如下所示:

2.删除操作实现

(1)任务执行逻辑

触发 remove_app_and_related_data_task 异步任务,具体执行逻辑如下所示:

(2)任务日志记录

执行异步任务(remove_app_and_related_data_task)的过程,本质上就是从相关数据表中删除 app 及相关数据,这个过程中产生的日志记录(日志级别为 INFO),如下所示:

[2024-10-18 13:46:30,516: INFO/MainProcess] Task tasks.remove_app_and_related_data_task.remove_app_and_related_data_task[e401ada0-bd53-4626-ac6d-fd69ba58f686] received
[2024-10-18 13:46:30,517: INFO/MainProcess] Start deleting app and related data: 7bdb51d6-f390-4b23-a59e-9cdbe2e93136:3c32956e-96bd-4e19-9c47-fd06bb4c5890
[2024-10-18 13:46:30,739: INFO/MainProcess] Deleted site cf995800-1808-4109-960c-f6246cbdb26f
[2024-10-18 13:46:30,758: INFO/MainProcess] Deleted installed app e125a5c8-b4a5-462d-bc9f-254abd1ab8eb
[2024-10-18 13:46:30,784: INFO/MainProcess] Deleted workflow 592fd414-204a-48aa-9ad5-7c1ac814d85d
[2024-10-18 13:46:30,789: INFO/MainProcess] Deleted workflow 782f46e7-4ee8-4064-9941-afcda22a6397
[2024-10-18 13:46:30,821: INFO/MainProcess] Deleted conversation variables for app 3c32956e-96bd-4e19-9c47-fd06bb4c5890
[2024-10-18 13:46:30,821: INFO/MainProcess] App and related data deleted: 3c32956e-96bd-4e19-9c47-fd06bb4c5890 latency: 0.30396559997461736
[2024-10-18 13:46:30,822: INFO/MainProcess] Task tasks.remove_app_and_related_data_task.remove_app_and_related_data_task[e401ada0-bd53-4626-ac6d-fd69ba58f686] succeeded in 0.3130000000819564s: None

(3)@shared_task 装饰器

@shared_task(queue="app_deletion", bind=True, max_retries=3) 代码是使用 Celery 定义一个共享任务的装饰器。定义了一个 Celery 任务,指定了其在处理应用删除操作时的队列、上下文绑定以及最大重试次数,便于实现异步任务管理和失败处理。具体含义和功能如下:

  • @shared_task:这是 Celery 的一个装饰器,用于将一个函数定义为可以被 Celery 调用的任务。它可在不同的模块中被共享和调用。
  • queue=“app_deletion”:指定任务将被发送到名为 app_deletion 的队列。这样可通过队列管理任务的执行,适用于需要异步处理的操作。队列包括 dataset、generation、mail、ops_trace 和 app_deletion。
  • bind=True:允许任务访问其上下文信息,特别是可以访问任务实例本身(通过 self 参数)。这对于任务重试、状态更新等操作很有用。
  • max_retries=3:定义任务最大重试次数。如果任务执行失败,Celery 会自动重新调度该任务,最多重试 3 次。如果超过这个次数,任务将标记为失败。

参考文献

[1] Dify 编排节点:https://docs.dify.ai/zh-hans/guides/workflow/orchestrate-node

[2] Dify通过导入DSL文件创建Workflow过程及实现:https://z0yrmerhgi8.feishu.cn/wiki/KVIWwrcPMiOdDhk4FngcHrlgnJc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/61002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录第46期 单调栈

这道题主要是单调栈的简单应用 class Solution { public:vector<int> dailyTemperatures(vector<int>& T) {vector<int> result(T.size(),0);stack<int> st;st.push(0);for(int i1;i<T.size();i){if(T[i]<T[st.top()]){st.push(i);}else{wh…

3步实现贪吃蛇

方法很简单&#xff0c;打开页面&#xff0c;复制&#xff0c;粘贴 一.整体思维架构 我们根据游戏的开始&#xff0c;运行&#xff0c;结束&#xff0c;将整个游戏划分成三个部分。在每个部分下面又划分出多个功能&#xff0c;接下来我们就根据模块一一实现功能。 二.Gamesta…

【linux012】文件操作命令篇 - more 命令

文章目录 more 命令1、基本用法2、常见选项3、交互式键盘命令4、举例5、注意事项 more 命令 more 是 Linux 中的一个分页查看命令&#xff0c;用于逐屏显示文件内容。它特别适合用于查看较长的文件&#xff0c;与 cat 不同&#xff0c;more 不会一次性输出所有内容&#xff0c…

机器学习笔记2 - 机器学习的一般流程

image.png 1、数据基本处理 数据集的划分 根据用途可将获取到的数据划分为训练集和测试集&#xff0c;有时还会有验证集。一般而言训练集用于训练模型&#xff0c;测试集用于测试模型的效果&#xff08;泛化误差&#xff09;。严格来讲&#xff0c;测试集的数据不能直接或间接&…

《C陷阱与缺陷》

文章目录 1、【词法陷阱】1.1 符号与组成符号间的关系1.1 与 1.3 y x/*p 与 y x/(*p)&#xff0c;a-1 与 a - 1 与 a -1, 老版本编译器的处理是不同的&#xff0c;严格的ANSI C则会报错1.4 十进制的 076&#xff0c;会被处理为八进制&#xff0c;ANSI C禁止这种用法&#x…

小白快速上手 labelme:新手图像标注详解教程

前言 本教程主要面向初次使用 labelme 的新手&#xff0c;详细介绍了如何在 Windows 上通过 Anaconda 创建和配置环境&#xff0c;并使用 labelme 进行图像标注。 1. 准备工作 在开始本教程之前&#xff0c;确保已经安装了 Anaconda。可以参考我之前的教程了解 Anaconda 的下…

脑机接口、嵌入式 AI 、工业级 MR、空间视频和下一代 XR 浏览器丨RTE2024 空间计算和新硬件专场回顾

这一轮硬件创新由 AI 引爆&#xff0c;或许最大受益者仍是 AI&#xff0c;因为只有硬件才能为 AI 直接获取最真实世界的数据。 在人工智能与硬件融合的新时代&#xff0c;实时互动技术正迎来前所未有的创新浪潮。从嵌入式系统到混合现实&#xff0c;从空间视频到脑机接口&…

【STM32】MPU6050简介

文章目录 MPU6050简介MPU6050关键块带有16位ADC和信号调理的三轴MEMS陀螺仪具有16位ADC和信号调理的三轴MEMS加速度计I2C串行通信接口 MPU6050对应的数据手册&#xff1a;MPU6050 陀螺仪加速度计 链接: https://pan.baidu.com/s/13nwEhGvsfxx0euR2hMHsyw?pwdv2i6 提取码: v2i6…

ISP——你可以从这里起步(二)

接上一篇&#xff0c;上一篇是原理篇&#xff0c;这一篇是实战篇&#xff0c;为了实现下面框图中的不完美ISP。 第一章 做一张RAW图自己用 不是所有的人都能获得raw图&#xff0c;即使获得了raw图也需要对应的sensor参数才能把它用起来&#xff0c;所以我找了一条野路子可以把…

Istio分布式链路监控搭建:Jaeger与Zipkin

分布式追踪定义 分布式追踪是一种用来跟踪分布式系统中请求的方法&#xff0c;它可以帮助用户更好地理解、控制和优化分布式系统。分布式追踪中用到了两个概念&#xff1a;TraceID 和 SpanID。 TraceID 是一个全局唯一的 ID&#xff0c;用来标识一个请求的追踪信息。一个请求…

【论文阅读】主动推理:作为感知行为的理论

文章目录 主动推理&#xff1a;作为感知行为的理论摘要1.引言2. 主动推理的概念和历史根源3. 主动推理的规范视角—以及它的发展历程 未完待续 主动推理&#xff1a;作为感知行为的理论 Active inference as a theory of sentient behavior 摘要 这篇文章综述了主动推理的历…

【MySQL】MySQL数据库入门:构建你的数据基石

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL初阶探索&#xff1a;构建数据库基础 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f985;数据库基础&#x1f400;什么是数据库&#x1f40f;主流数据库&#x1f986;MySQL数据库的基本…

6.584-Lab1:MapReduce

前置知识/概念 Raft 是一个基于“Leader”的协议&#xff0c;能够保证分布式网路的一致性。 RPC&#xff08;Remote Producer Call&#xff09; 参考链接1 参考链接2 Go中RPC的简单实现 Golang中regexp正则表达式的用法 https://gukaifeng.cn/posts/golang-zheng-ze-biao-…

抽象java入门1.5.3.1——类的进阶

前言&#xff1a;在研究神技代码Hello word的时候&#xff0c;发现了一个重大公式bug&#xff0c;在代码溯源中&#xff0c;我发现了一个奇怪的东西&#xff0c;就是OUT不是类中类&#xff08;不是常规类的写法&#xff09; 内容总结&#xff1a; 代码运行的顺序复习 正片开始…

人力资源招聘系统的革新之路:从传统到智能的转变

在全球化与数字化交织的今天&#xff0c;企业间的竞争日益激烈&#xff0c;而人才作为企业发展的核心驱动力&#xff0c;其重要性不言而喻。传统的人力资源招聘方式&#xff0c;如依赖纸质简历、人工筛选、面对面面试等&#xff0c;不仅效率低下&#xff0c;且难以精准匹配企业…

AXI DMA IP BUG踩坑记录

1. 问题描述 在突发的过程中总是一旦使用XAxiDma_SimpleTransfer函数就会出现AXI STREAM信号的READY信号先拉高4个数据(32位)的时钟后会迅速拉低,换句话说就是一旦PS端发起了XAxiDma_SimpleTransfer,AXI总线的READY信号就会拉高四个节拍,这样就会导致传输的数据出现问题。…

Vue2教程001:初识Vue

文章目录 1、初识Vue1.1、Vue2前言1.2、创建Vue实例1.3、插值表达式1.4 Vue响应式特性 1、初识Vue 1.1、Vue2前言 Vue是什么&#xff1f; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式框架。 Vue的两种使用方式&#xff1a; Vue核心包开发 场景&#xff1a;局部模块…

vscode vite+vue3项目启动调试

1、经常我们在普通的项目中&#xff0c;如果算法并不复杂&#xff0c;那么基本上console.log就可以搞定&#xff0c;当然也可以直接alert&#xff0c;打包的时候如果不去掉&#xff0c;还会在发版中上接弹出&#xff0c;给你个惊喜。 2、碰到了有些算法过程比较复杂的情况下&a…

Jdbc学习笔记(三)--PreparedStatement对象、sql攻击(安全问题)

目录 &#xff08;一&#xff09;使用PreparedStatement对象的原因&#xff1a; 使用Statement对象编写sql语句会遇到的问题 ​编辑 &#xff08;二&#xff09;sql攻击 1.什么是sql攻击 2.演示sql攻击 &#xff08;三&#xff09;防止SQL攻击 1.PreparedStatement是什么 …

后端分层解耦

引入 在上篇所举的例子中&#xff0c;我们将所有的代码均放在HelloControl方法之中&#xff0c;这样会导致代码的复用性、可读性较差&#xff0c;难以维护。因此我们需 三层架构 在之前的代码中&#xff0c;代码大体可以分为三部分&#xff1a;数据访问、数据逻辑处理、响应数…