# 工作流特性对比:agent-management vs Dify
> 对比目的:以 Dify `1.16.0` 开源参考实现(详见 `docs/dify-readme.md`)为坐标系,定位本仓库(agent-management)工作流引擎的能力边界、创新点与可借鉴的演进方向。
>
> 对比维度:节点类型与编排、调度与执行、信封化与校验、变量与输入解析、智能体集成、画布编辑器、HITL、可观测、外部 API、生态扩展。
>
> 信息来源:
> - 本仓库需求与设计:`prompt.md`、`docs/workflow-*.md`、`docs/context-passing-architecture.md`、`docs/external-workflow-api-spec.md`、`docs/hermes-*.md`
> - 本仓库实现:`backend/src/main/java/com/agent/management/engine/**`
> - Dify 实现:`dify/api/core/workflow/**`、`dify/dify-agent/src/**`、`dify/dify-agent-runtime/**`
---
## 0. 结论速览
| 维度 | 量化对比 |
|---|---|
| 本仓库独有特性 | **21 项**(详见 §2) |
| Dify 独有特性 | **21 项**(详见 §3) |
| 实现方法差异 | **15 项**(详见 §4) |
| 设计哲学 | **本仓库**:单体 + 强一致 envelope + 引擎层统一治理(适合企业内部可控场景)
**Dify**:微服务 + 插件化生态 + 多形态应用(适合多租户 SaaS / 开源社区) |
---
## 1. 总体定位差异
| 维度 | agent-management | Dify |
|---|---|---|
| 项目类型 | 企业内部 AI 编码助手平台 | 开源 LLMOSS(LLM Operating System / Stack) |
| 后端实现 | Java 17 + Spring Boot 单体 | Python + Flask + Celery + 多服务编排 |
| 节点类型 | 硬编码 8 种 | 内置 + 插件扩展(plugin_daemon) |
| 应用形态 | Workflow 一种 | Workflow / Chat / AdvancedChat / Completion / AgentChat 五种 |
| 部署形态 | 单 JAR + MySQL + Redis | 11 个 docker-compose 服务(含 Plugin Daemon / Agent Backend / Local Sandbox 等) |
| Agent 引擎 | Hermes Bridge(Python 子进程)+ Spring AI ChatClient | CotAgentRunner / FunctionCallAgentRunner / dify-agent(pydantic-ai) |
| 沙箱实现 | Python 三层 monkey-patch(路径白名单) | Go Landlock LSM + tmux + sanitize-pty |
**核心差异**:本仓库追求**轻量、强一致、企业内部可控**;Dify 追求**生态、可扩展、多形态覆盖**。
---
## 2. 本仓库具备而 Dify 没有的功能
### 2.1 工作流引擎层
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 1 | **统一 envelope 全节点强制** | 所有节点(LLM / Agent / SmartAction / Hermes* / Knowledge / Condition / UserInput / Output)严格产出 `{status, message, data}` 三段式结构,多余字段丢弃;Dify 仅 Agent v2 节点强制 declared outputs,其他节点"尽力推断" | `engine/NodeOutputEnvelope.java`、`docs/workflow-node-output-envelope.md` 2.6 |
| 2 | **统一 failStrategy(abort/skip)** | 引擎层 `WorkflowLevelExecutor` 提供节点级 `failStrategy` 配置;Dify 没有此配置,失败处理散落各节点内部(Agent v2 有 OutputFailureOrchestrator,但仅限该节点) | `engine/WorkflowLevelExecutor.java`、`docs/workflow-node-output-envelope.md` 2.10 |
| 3 | **Dataflow 调度 + SKIPPED 状态** | 从 BSP(层同步)改造为 Dataflow:节点完成即触发后继(基于 `pendingInputs: Map` 入度计数),不被同层慢节点阻塞;条件分支未选路径自动标记 `SKIPPED`;Dify 的 `NodeOutputStatus` 枚举无 `SKIPPED` 状态(只有 PENDING/RUNNING/READY/TYPE_CHECK_FAILED/OUTPUT_CHECK_FAILED/NOT_PRODUCED/FAILED) | `docs/workflow-dataflow-execution-plan.md`、`dify/api/services/workflow/node_output_inspector_service.py:84-103` |
| 4 | **节点级 abort 取消在飞节点** | `abortFlag`(AtomicBoolean)+ `inFlightFutures` Map,失败时 CAS 设置并 `cancel(true)` 所有在飞节点;Dify 节点失败后是否取消兄弟节点由 GraphEngine 图级策略决定,Dify 侧不可见也无显式 API | `engine/WorkflowLevelExecutor.java` 阶段 3 |
| 5 | **envelope 失败自动升级** | `result.status == SUCCESS && envelope.isFailure()` 时引擎自动升级为 `NodeExecutionResult.failed`,按 failStrategy 处理;失败 envelope 仍写入上下文供下游感知 | `docs/hermes-error-detection-plan.md` 方案 D |
### 2.2 节点输入与变量系统
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 6 | **四级模糊匹配 fallback** | 节点输入解析按拓扑逆序遍历可达前驱,依次尝试:①精确同名 → ②模糊同名(忽略 `-` `_` 和大小写)→ ③JSON 嵌套精确同名 → ④JSON 嵌套模糊同名;Dify 通过 `variable_pool` 直接寻址,无模糊匹配 | `docs/workflow-variable-scope-design.md` 4.3、`dify/api/core/workflow/variable_pool_initializer.py` |
| 7 | **envelope.data 穿透取值** | 四级匹配全部穿透 envelope.data 内部取值,不再读扁平 Map 顶层;Dify 没有这种 envelope-aware 的输入解析 | `docs/workflow-node-output-envelope.md` 2.9 |
| 8 | **NodeWorkspace 仅含可达前驱** | 节点开始执行前构建工作区,仅包含**可达前驱**(反向 BFS 计算)的输出,避免无关变量污染;Dify 通过共享 variable_pool,无显式工作区隔离 | `docs/workflow-variable-scope-design.md` 2.1 |
| 9 | **前驱变量删除后自动回退关联** | 边变化导致前驱不再是可达前驱时,节点 inputs/output fields 的显式 mapping 自动回退为「自动推断」(autoMapped=true);Dify 通过手动 variable selector 重新选择,无自动回退 | `docs/workflow-variable-scope-design.md` 3.2 |
| 10 | **运行工作目录 + `.agentignore`** | 每次运行分配 `/workflow-runs/{workflowId}/{runId}/`,所有节点共享;`.agentignore` 排除 `.hermes/`、`*.log`、`*.tmp` 等;可打包下载 zip;Dify 有 Local Sandbox 沙箱但没有 `.agentignore` 机制 | `docs/external-workflow-api-spec.md` 3.5 |
### 2.3 LLM 结构化输出与重试
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 11 | **错误回注 prompt 的自我修正重试** | `StructuredOutputHelper.extractWithRetry` 校验失败时把 `lastError`(如"缺少 required 字段 xxx")注入 prompt 让 LLM 自我修正;Dify 没有这种"错误回注"的统一机制 | `engine/StructuredOutputHelper.java`、`docs/workflow-node-output-envelope.md` 2.2 |
| 12 | **三级 JSON 提取容错** | ①直接 JSON 解析 → ②` ```json ` 代码块提取 → ③首尾 `{}` 子串提取;适配 LLM 不稳定输出;Dify 通过 litellm + json-repair 0.60 在底层处理 | `engine/StructuredOutputHelper.java` |
| 13 | **类型静默自动转换** | 声明 number + 字符串数字 → 静默转换;boolean + "true"/"1"/"yes" → true;array/object + JSON 文本 → 解析;Dify 类型校验在 OutputTypeChecker 但更严格,无静默转换 | `engine/OutputValidator.java`、`dify/api/core/workflow/nodes/agent_v2/output_type_checker.py` |
| 14 | **双循环重试(计划中)** | 外层 runtime retry(重新完整推理,默认 2 次)+ 内层 format retry(仅重组 JSON,不重跑业务,默认 2 次);内层耗尽升级为外层;Dify 无此分层 | `docs/workflow-envelope-strict-validation-plan.md` 阶段 3 |
| 15 | **节点级 retry 配置覆盖全局** | `RetryPolicy.fromNodeData` 解析节点 `data.maxRetries` / `retryOn*`,覆盖 `application.yml` 默认值;Dify Agent v2 的重试在节点内部硬编码(OutputFailureOrchestrator) | `engine/RetryPolicy.java` |
### 2.4 智能体与 Hermes 集成
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 16 | **Hermes Bridge(Python 子进程)** | `HermesProcessManager` 启动 Python bridge 子进程,注入 `HERMES_BRIDGE_BASE_URL/API_KEY/MODEL` 等环境变量,通过 SSE 通信(思考流 / 工具调用 / 最终结果);Dify Agent v2 通过独立 FastAPI 服务(pydantic-ai),架构不同 | `engine/hermes/HermesProcessManager.java`、`backend/hermes-bridge/hermes_bridge.py` |
| 17 | **Hermes Error Pattern 错误检测** | 内置错误模式数据模型(`HermesErrorPattern`)+ Java Client 嗅探(`parseSseResponse` 在 done 分支后 substring 匹配)+ 前端管理页(`/hermes-errors`);内置"访问量过大"、"无效的 api"等中文模式;Dify 没有 LLM 错误响应的模式化识别 | `service/impl/HermesErrorPatternServiceImpl.java`、`docs/hermes-error-detection-plan.md` |
| 18 | **三层 monkey-patch 沙箱** | `sandbox_patch.py` 对 hermes-agent 的 `_resolve_path_for_task`(路径白名单)、`_resolve_base_dir`(相对路径锚定)、`_git_root`(阻断外层项目根注入)打补丁;通过 `_SESSION_CWD` contextvar 线程隔离;Dify 沙箱是 Go Landlock LSM + tmux(更底层但与 Hermes 无关) | `backend/hermes-bridge/sandbox_patch.py`、`docs/hermes-sandbox.md` |
| 19 | **默认模型实时路由** | `AiModelService.getDefaultModel` 实时查询,application.yml 切换默认模型后立即生效,不再回退到旧默认;模型管理可设置调用顺序 fallback;Dify 模型在节点级硬绑定,无统一默认路由 | `service/AiModelService.java` |
| 20 | **Skill 文件预同步(方案 A)** | `SkillFileSyncer.syncTo` 在每次工作流执行前将 `uploads/skills` 下所有 skill 复制到工作目录 `.hermes/skills`,不复制历史版本文件;Dify 插件化体系不同,无此同步需求 | `engine/SkillFileSyncer.java` |
| 21 | **技能生成(Skill 生成 Skill)** | 技能编辑页可选「该技能具备生成其他技能的能力」;技能生成菜单选择生成器技能 → 调 hermes-bridge → 在工作目录生成 → 复制到全局技能目录 → 跳转编辑页;Dify 无"工具生成工具"的概念 | `service/impl/SkillGenerationServiceImpl.java`、`prompt.md` 855-952 行 |
### 2.5 画布编辑器与运行时交互
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 22 | **字段「引入」双向关联** | 节点 inputs 从前驱 outputs 引入、节点 outputs 从后继 inputs 引入;输入节点输入变量从后继输入引入(业务输入语义);输出节点输出变量从前驱输出引入(业务输出语义);引入后自动填入变量名/中文名/类型/描述;Dify 通过 variable selector 单向引用,无"输出字段反向关联后继" | `frontend/src/utils/ioInference.js`、`prompt.md` 1188-1192 行 |
| 23 | **LLM 语义「自动关联」** | 点击「自动关联」按钮用 LLM 语义识别(非字符串匹配)哪些 Skill 的 SKILL.md 或智能操作工作流程中隐式调用了其他 Skill;识别结果以虚线框 + 虚线箭头画在画布上,技能节点位于虚线框中可拖动;Dify 无此"自动发现隐式依赖"能力 | `prompt.md` 357、776 行 |
| 24 | **模板变量动态识别(无碎片)** | 在 `{{}}` 中按顺序输入变量名时实时识别,区分「自动字段」(从 {{}} 识别)和「手动字段」(用户显式添加),避免中间变量碎片(a、ab、abc 三个变量);Dify 使用变量选择器 UI,无模板动态识别 | `prompt.md` 1195、1200 行 |
| 25 | **画布级变量/字段/节点名唯一性校验** | 节点内变量名不能重复、画布节点名不能重复,保存时拦截并列出具体节点与变量;Dify 通过 variable selector 引用,名称冲突由用户自行管理 | `prompt.md` 1265、1270 行 |
| 26 | **节点动态斥力** | 拖动节点后过近节点动态推开达到平衡(非生成时距离);Dify 用 ReactFlow + ELK.js 自动布局,无交互式斥力 | `prompt.md` 806-818 行 |
| 27 | **运行对话框变量导出/导入** | 导出已填入变量为 JSON 文件(命名 `工作流名称-节点名-输入变量.json`),强制选择保存位置;导入时填入对应表单;Dify 表单提交,无导入导出 | `prompt.md` 1276-1285 行 |
| 28 | **输入/输出节点变量标签颜色语义** | 输入节点变量蓝色(业务输入)、输出节点变量绿色(业务输出)、其他节点前置数据蓝/输出变量绿;Dify 节点端口样式统一 | `prompt.md` 1264 行 |
| 29 | **思考过程折叠 + 流式继续** | 运行记录中思考过程支持折叠,折叠后仍接收流式响应只是不显示,展开后可继续输出;Dify Trace 工具(Langfuse 等)有类似能力但非画布原生 | `prompt.md` 626 行 |
| 30 | **节点名称与类型双行显示** | 画布节点显示「节点名称 节点类型」,名称字体与类型字体区分;空时只显示节点类型;节点名称画布内唯一;Dify 节点显示样式不同 | `prompt.md` 66、156 行 |
### 2.6 工作流标识与外部 API
| # | 特性 | 关键行为 | 实现位置 |
|---|---|---|---|
| 31 | **kebab-case 唯一标识 + 中文 displayName 分离** | `name` 为 kebab-case(`^[a-z0-9]+(-[a-z0-9]+)*$`),URL 按 name 寻址;`displayName` 可任意字符(含中文);翻译只翻译 displayName 与正文,不破坏 name;Dify 工作流标识为 UUID | `service/WorkflowNameNormalizer.java`、`docs/workflow-crud-api.md` |
| 32 | **外部 API 三段式调用** | 创建运行(POST `/runs`)→ 启动(POST `/runs/{runId}/start`)→ 订阅(GET `/runs/{runId}/stream`);同步阻塞模式 `async=false` 直接 SSE;Dify 通过 Service API 单次调用,无"创建-启动-订阅"三段式 | `docs/external-workflow-api-spec.md` 3.1-3.2 |
| 33 | **断线重连 SSE(Last-Event-ID)** | 通过 `Last-Event-ID` 头部续传,事件缓存窗口默认 1000 条或运行结束保留 1 小时;Dify 通过 socket.io 自动重连,但 SSE 模式无 Last-Event-ID 续传 | `docs/external-workflow-api-spec.md` 5 |
| 34 | **工作目录 ZIP 打包下载** | `GET /runs/{runId}/workspace` 返回 zip(应用 `.agentignore`);Dify Agent 沙箱内文件通过 drive API 单文件上传/下载,无打包下载 | `docs/external-workflow-api-spec.md` 3.5 |
| 35 | **目录结构保留上传** | 通过 `X-Relative-Path` part header 保留目录结构,含 ZIP slip 防护;Dify 文件上传扁平化 | `docs/external-workflow-api-spec.md` |
---
## 3. 本仓库没有而 Dify 具备的能力
### 3.1 节点类型与编排
| # | 特性 | Dify 实现 | 本仓库状态 |
|---|---|---|---|
| 1 | **迭代节点(iteration)** | `core/workflow/nodes/iteration/` 支持数组迭代执行子图 | ❌ 不支持 |
| 2 | **显式并行节点 / 并行分支** | 通过 GraphEngine 线程池 + 并行边 | ⚠️ 仅同层并行(Dataflow 模式),无显式并行节点 |
| 3 | **问题分类器节点** | `question-classifier` 节点用 LLM 把输入分类到不同分支 | ❌ 可用条件分支节点近似但不能 LLM 自动分类 |
| 4 | **模板转换节点** | `template-transform` 节点专门做 Jinja2 渲染 | ❌ 无独立节点,模板渲染内嵌于各节点 |
| 5 | **参数提取器节点** | `parameter-extractor` 节点用 LLM 从自然语言提取结构化参数 | ❌ 无 |
| 6 | **变量聚合器节点** | `variable-aggregator` 节点把多个分支的变量合并 | ❌ 由 envelope 自动聚合,无显式节点 |
| 7 | **HTTP Request 节点** | 独立节点支持任意 HTTP 调用 | ❌ 由 SmartAction 节点近似但非通用 HTTP |
| 8 | **Code 节点(沙箱化代码执行)** | 独立 `dify-sandbox` 容器执行 Python / JS 代码 | ❌ 不支持任意代码执行 |
| 9 | **Knowledge Index 节点(索引而非检索)** | `core/workflow/nodes/knowledge_index/` 在工作流中增量索引文档 | ❌ 知识库索引在管理后台,非工作流节点 |
| 10 | **三种触发器节点(plugin / schedule / webhook)** | `trigger_plugin/`、`trigger_schedule/`、`trigger_webhook/` 支持事件驱动工作流 | ❌ 仅同步 API 触发 |
### 3.2 HITL 与执行控制
| # | 特性 | Dify 实现 | 本仓库状态 |
|---|---|---|---|
| 11 | **运行中 HITL 暂停-恢复** | `PauseStatePersistenceLayer` 全量序列化(generate_entity + graph_runtime_state + response_stream_filter_state + pause_reasons)+ 恢复重建;两条路径:独立 Human Input 节点 / Agent v2 内部 ask_human 延迟工具调用 | ❌ 仅支持运行前一次性收集 userInput |
| 12 | **Agent 内部 ask_human 延迟工具调用** | pydantic-ai external deferred tool,让 Agent 在执行中请求人工输入后继续原上下文 | ❌ 不支持 |
| 13 | **子工作流嵌套** | `_WorkflowChildEngineBuilder` 创建隔离的 child GraphEngine,复用父图 variable_pool | ❌ 工作流作为工具是外部 API 模式(通过 skill 调用),无内嵌子工作流 |
### 3.3 Agent 与 LLM 接入
| # | 特性 | Dify 实现 | 本仓库状态 |
|---|---|---|---|
| 14 | **ReAct(CoT)推理循环** | `CotAgentRunner` 实现 Thought/Action/Observation 文本协议 | ⚠️ 通过 Hermes Bridge 间接支持(hermes-agent 内部),但本仓库引擎不直接实现 |
| 15 | **Function Calling 推理循环** | `FunctionCallAgentRunner` 使用 LLM 原生 tool_calls | ⚠️ 同上 |
| 16 | **Agent v2 推理循环外包给 pydantic-ai** | 完全外包给独立 `dify-agent-backend` 服务 | ❌ Agent 在引擎内部执行 |
| 17 | **litellm 统一 LLM 接入** | 通过 litellm 1.83 收敛 100+ provider | ⚠️ 通过 Spring AI + 自定义 AiModelService,覆盖面窄 |
| 18 | **Plugin Daemon 插件化(模型 / 工具 / 节点)** | 所有 provider 外置为插件,第三方可贡献;28 种向量库 + 8 种 trace 后端 + 10 种对象存储 | ❌ 节点/模型/工具硬编码 |
### 3.4 多端协同与可观测
| # | 特性 | Dify 实现 | 本仓库状态 |
|---|---|---|---|
| 19 | **画布多人协同编辑** | loro-crdt 1.13 + python-socketio 实现工作流画布多人实时协同 | ❌ 单人编辑 |
| 20 | **OpenTelemetry 全链路追踪** | OTel distro + 五种 instrumentation(celery/flask/httpx/redis/sqlalchemy)+ B3 传播 | ❌ 仅节点级 logs,无 OTel |
| 21 | **8 种 Trace 后端插件化** | Langfuse / LangSmith / Phoenix / MLflow / Arize / Opik / Weave / 阿里云 / 腾讯云 | ❌ 无 trace 后端集成 |
| 22 | **MCP 客户端/服务端** | `core/mcp/` 内置 MCP 协议支持(auth / client / server / session) | ❌ 未涉及 |
| 23 | **Agent 沙箱化 Shell 工作区(tmux + Landlock)** | Go 实现的 `dify-agent-runtime`,通过 tmux 控制持久化 Shell,Landlock LSM 文件系统隔离,sanitize-pty ANSI 清洗 | ⚠️ Python monkey-patch 实现路径白名单,无 Landlock 级隔离 |
| 24 | **多语言 i18next(11 种语言)** | i18next 26 + react-i18next 17 + 11 种语言包 | ⚠️ 中文为主,仅 displayName 翻译 |
### 3.5 其他生态能力
| # | 特性 | Dify 实现 | 本仓库状态 |
|---|---|---|---|
| 25 | **五种应用形态** | Workflow / Chat / AdvancedChat / Completion / AgentChat | ⚠️ 仅 Workflow 一种 |
| 26 | **OpenAPI 自动生成(fastopenapi)** | `fastopenapi[flask]` 0.7.0 自动生成 OpenAPI 规范 | ⚠️ 通过 springdoc 生成(功能等价) |
| 27 | **结构化 output_type 契约(pydantic-ai)** | Agent v2 通过 pydantic-ai output_type 强制 JSON Schema 输出契约 | ⚠️ envelope 校验类似但基于 declared outputs 字段列表,非完整 JSON Schema |
| 28 | **多租户与 RBAC** | `core/rbac/` + tenant 隔离 + 套餐优先级(QueueDispatcherManager) | ⚠️ 单租户,无套餐优先级 |
| 29 | **Sentry / Amplitude 前端可观测** | Sentry 10.66 + Amplitude(含 session-replay) | ❌ 未涉及 |
| 30 | **流式工具调用(streaming tool call)** | `FunctionCallAgentRunner.stream_tool_call` 支持流式工具调用 | ⚠️ 通过 Hermes Bridge SSE 间接支持 |
---
## 4. 实现方法不同的能力
### 4.1 工作流引擎实现
| 维度 | agent-management | Dify |
|---|---|---|
| 语言 | Java 17 + Spring Boot | Python 3.12 + Flask + 外部 graphon 包 |
| 调度模型 | Dataflow(入度计数 `pendingInputs: Map`) | GraphEngine 线程池(min/max workers + scale up/down threshold) |
| 并发 | CompletableFuture + nodeExecutor 线程池 | graphon 内部线程池 |
| 失败取消 | `abortFlag`(AtomicBoolean)+ `inFlightFutures` Map,显式 cancel(true) | graphon 图级策略(Dify 侧不可见) |
| 文件位置 | `engine/WorkflowLevelExecutor.java` | `dify/api/core/workflow/workflow_entry.py:213-225` |
### 4.2 节点输出信封
| 维度 | agent-management | Dify |
|---|---|---|
| 强制范围 | 所有节点强制 `{status, message, data}` | 仅 Agent v2 节点 declared outputs 校验,其他节点"尽力推断" |
| 校验器 | `OutputValidator` 统一校验(required / typeMismatch + 静默自动转换) | `OutputTypeChecker`(Agent v2 专用)+ `NodeOutputInspectorService`(声明输出视图) |
| 失败处理 | envelope.isFailure() 自动升级为 NodeExecutionResult.failed | Agent v2 通过 `OutputFailureOrchestrator` 决策 RETRY/USE_DEFAULT/TAKE_FAIL_BRANCH/FAIL |
| 文件位置 | `engine/NodeOutputEnvelope.java`、`engine/OutputValidator.java` | `dify/api/core/workflow/nodes/agent_v2/output_failure_orchestrator.py` |
### 4.3 失败与重试策略
| 维度 | agent-management | Dify |
|---|---|---|
| 配置层级 | 引擎层 `failStrategy: abort/skip`(节点级) + 全局 `application.yml` retry 配置 + 节点级 retry 覆盖 | 无统一 failStrategy;Agent v2 节点内部 `OutputFailureOrchestrator` |
| 重试触发 | retryOnParseError / retryOnMissingRequired / retryOnTypeMismatch / retryOnKeyNameMismatch(计划中) | 由 OutputFailureOrchestrator 内部决策 |
| 重试方式 | 错误回注 prompt 自我修正;双循环(runtime retry + format retry,计划中) | 节点内部 RETRY 决策(重新调用 agent backend) |
| 文件位置 | `engine/RetryPolicy.java`、`engine/StructuredOutputHelper.java` | `dify/api/core/workflow/nodes/agent_v2/output_failure_orchestrator.py` |
### 4.4 Agent 推理循环
| 维度 | agent-management | Dify |
|---|---|---|
| 老版 Agent | `AgentExecutor` 直接 Spring AI ChatClient(无 ReAct 循环,单次调用) | `CotAgentRunner`(ReAct 文本协议)+ `FunctionCallAgentRunner`(FC) |
| 新版 Agent | `HermesAgentExecutor` 通过 Hermes Bridge Python 子进程(hermes-agent 内部实现推理循环) | Agent v2 通过 `dify-agent-backend`(pydantic-ai)服务 |
| 最大迭代 | 由 hermes-agent 控制(不在本仓库引擎层) | `min(max_iteration, 99) + 1` |
| 文件位置 | `engine/executor/HermesAgentExecutor.java` | `dify/api/core/agent/cot_agent_runner.py:80` |
### 4.5 结构化输出
| 维度 | agent-management | Dify |
|---|---|---|
| 触发条件 | 节点 `data.outputs` 非空即触发(不再要求 size > 1) | Agent v2 通过 pydantic-ai output_type 原生支持;其他节点 litellm + json-repair |
| 指令构造 | `StructuredOutputHelper.buildInstruction`(字段名+类型+描述追加 userPrompt) | pydantic-ai 内部根据 output_type 自动构造 |
| 容错 | 三级 JSON 提取(直接 / ```json``` / 首尾 `{}`) | json-repair 0.60 底层修复 |
| 文件位置 | `engine/StructuredOutputHelper.java` | `dify/api/core/workflow/nodes/agent_v2/agent_node.py:393-411` |
### 4.6 变量系统与输入解析
| 维度 | agent-management | Dify |
|---|---|---|
| 寻址方式 | 四级模糊匹配 fallback(精确 / 模糊 / JSON Path 精确 / JSON Path 模糊)+ 显式 mapping | variable_pool 直接寻址 + variable_prefixes 前缀解析 |
| 工作区 | NodeWorkspace(仅含可达前驱输出,反向 BFS) | 共享 variable_pool(无显式工作区隔离) |
| envelope 穿透 | 五级匹配全部穿透 envelope.data | 节点通过 variable selector 显式声明 |
| 模板渲染 | `{{varName}}`、`{{nodeId.varName}}`、`{{nodeId.var.path}}`;变量不存在保留占位符 | Jinja2 + variable_prefixes |
| 文件位置 | `engine/NodeInputResolver.java`、`engine/TemplateRenderer.java` | `dify/api/core/workflow/variable_pool_initializer.py`、`dify/api/core/workflow/variable_prefixes.py` |
### 4.7 HITL(人工介入)
| 维度 | agent-management | Dify |
|---|---|---|
| 入口 | userInput 节点(运行前一次性收集) | 独立 Human Input 节点 + Agent v2 ask_human 延迟工具 |
| 暂停机制 | ❌ 无运行中暂停 | `PauseRequestedEvent` + `PauseStatePersistenceLayer` 全量序列化 |
| 恢复机制 | ❌ 无 | 从 DB 加载 `WorkflowResumptionContext`,重建 GraphRuntimeState |
| 持久化 | ❌ 无 | generate_entity + graph_runtime_state + response_stream_filter_state + pause_reasons |
| 文件位置 | `engine/executor/UserInputExecutor.java` | `dify/api/core/app/layers/pause_state_persist_layer.py:77-177` |
### 4.8 沙箱实现
| 维度 | agent-management | Dify |
|---|---|---|
| 语言 | Python(hermes-bridge 内) | Go(dify-agent-runtime) |
| 隔离机制 | 三层 monkey-patch(路径白名单 + 相对路径锚定 + Git 根阻断)+ contextvar 线程隔离 | Linux Landlock LSM(内核级文件系统隔离)+ tmux(持久化 Shell)+ sanitize-pty(ANSI 清洗) |
| 隔离强度 | 应用层(依赖 Python 进程内约束) | 内核层(依赖 Linux LSM) |
| 状态持久化 | 工作目录 `/workflow-runs/{workflowId}/{runId}/` | SQLite(modernc.org/sqlite 纯 Go)记录 job 状态与退出码 |
| 文件位置 | `backend/hermes-bridge/sandbox_patch.py` | `dify/dify-agent-runtime/internal/landlock/`、`dify/dify-agent-runtime/internal/sanitize/` |
### 4.9 画布编辑器
| 维度 | agent-management | Dify |
|---|---|---|
| 框架 | Vue + vue-flow 风格画布 | React + ReactFlow 11.11 + ELK.js(图布局) |
| 协同 | ❌ 单人编辑 | loro-crdt 1.13 + python-socketio 多人实时协同 |
| 自动布局 | ❌ 手动 + 节点动态斥力(拖动后推开过近节点) | ELK.js 自动布局 |
| 字段关联 | 「引入」双向(input 从前驱 / output 从后继)+ LLM 语义「自动关联」(虚线框发现 Skill 隐式依赖) | variable selector 单向引用 |
| 文件位置 | `frontend/src/views/workflow/WorkflowEditor.vue`、`frontend/src/utils/ioInference.js` | `dify/web/features/workflow/` |
### 4.10 模型接入与默认路由
| 维度 | agent-management | Dify |
|---|---|---|
| 接入层 | Spring AI ChatClient + 自定义 AiModelService | litellm 1.83 统一收敛 100+ provider |
| 默认模型 | AiModelService.getDefaultModel 实时查询,application.yml 切换立即生效 | 节点级硬绑定,无统一默认路由 |
| Provider 管理 | 模型管理页设置调用顺序 + fallback | 通过 plugin_daemon 加载 provider 插件 |
| 文件位置 | `service/AiModelService.java` | `dify/api/core/model_manager.py`、`dify/api/core/provider_manager.py` |
### 4.11 持久化与执行历史
| 维度 | agent-management | Dify |
|---|---|---|
| 节点执行历史 | `WorkflowRunNode.logs`(thinking / tool_call / tool_result / info / error) | 节点执行记录 + OTel 全链路 trace |
| 上下文快照 | `NodeExecutionResult.contextSnapshot`(计划中,按节点持久化 variables) | 共享 variable_pool 状态(无显式 per-node snapshot,但 HITL 时全量序列化) |
| 调用链追踪 | 节点级 logs API:`GET /runs/{runId}/nodes/{nodeId}/logs` | OTel + 8 种 trace 后端(Langfuse / LangSmith / ...) |
| 文件位置 | `model/entity/WorkflowRunNode.java`、`docs/context-passing-architecture.md` Phase 2-3 | `dify/api/core/ops/ops_trace_manager.py` |
### 4.12 节点类型扩展机制
| 维度 | agent-management | Dify |
|---|---|---|
| 扩展方式 | 硬编码 `NodeTypeUtils` 枚举 + Executor 工厂 | plugin_daemon 加载第三方插件(节点 / 模型 / 工具) |
| 节点版本 | 无显式版本(通过 Executor 类区分 Hermes/非 Hermes) | 节点 `version()` 类方法显式版本(如 Agent v1 vs v2) |
| 动态注册 | ❌ 启动时静态注册 | ✅ 插件运行时注册 |
| 文件位置 | `engine/NodeTypeUtils.java`、`engine/executor/*Executor.java` | `dify/api/core/workflow/node_factory.py:279` |
### 4.13 国际化
| 维度 | agent-management | Dify |
|---|---|---|
| 范围 | 中文为主 + displayName 翻译(缓存到 JSON 文件或数据库,全文匹配调出) | i18next 26 + 11 种语言包 |
| 翻译策略 | 只翻译 displayName 与正文(含英文的段落即翻译),不翻译 name(避免 kebab-case 被破坏) | 完整 i18n 资源包切换 |
| 文件位置 | `prompt.md` 880-901 行 | `dify/web/i18n/`、`dify/web/i18n-config/` |
### 4.14 部署架构
| 维度 | agent-management | Dify |
|---|---|---|
| 后端服务数 | 1(Java 单体) | 5(api / worker / worker_beat / plugin_daemon / agent_backend) |
| 沙箱服务数 | 0(hermes-bridge 内嵌) | 2(dify-sandbox 代码沙箱 + dify-agent-local-sandbox Agent Shell) |
| 反向代理 | 可选(用户自决) | Nginx + SSRF Proxy(Squid)必需 |
| 必需基础设施 | MySQL/PostgreSQL + Redis + 向量库 | PostgreSQL/MySQL + Redis + 向量库 + Plugin Daemon + Agent Backend + Local Sandbox + Sandbox + SSRF Proxy + Nginx |
| 文件位置 | `backend/src/main/resources/application.yml.example` | `dify/docker/docker-compose.yaml` |
### 4.15 工作流标识与外部 API
| 维度 | agent-management | Dify |
|---|---|---|
| 工作流标识 | kebab-case `name`(URL 寻址)+ 中文 `displayName` 分离 | UUID |
| 外部调用模式 | 三段式(创建 → 启动 → 订阅)+ 同步阻塞模式 | 单次调用(Chat / Completion / Workflow 三类 API) |
| 输入形态 | 纯 JSON / JSON + 文件 / JSON + 目录(保留结构 + ZIP slip 防护) | JSON + 文件(扁平化) |
| 工作空间下载 | ZIP 打包(应用 `.agentignore`) | drive API 单文件上传/下载 |
| 文件位置 | `docs/external-workflow-api-spec.md` | `dify/api/controllers/service_api/` |
---
## 5. 综合对比表
### 5.1 能力覆盖矩阵
| 能力领域 | agent-management | Dify | 备注 |
|---|:---:|:---:|---|
| **DAG 调度** | ✅ Dataflow | ✅ GraphEngine | 实现方式不同(§4.1) |
| **同层并行** | ✅ Dataflow 模式 | ✅ GraphEngine 线程池 | 均支持 |
| **完成即触发后继** | ✅ 显式实现 | ⚠️ 推测支持(graphon 内部) | 本仓库可观察(§2.1 #3) |
| **SKIPPED 状态** | ✅ 条件分支未选路径 | ❌ 无此状态枚举 | 本仓库独有(§2.1 #3) |
| **统一 envelope** | ✅ 全节点强制 | ⚠️ 仅 Agent v2 | 本仓库更一致(§2.1 #1) |
| **统一 failStrategy** | ✅ abort/skip | ❌ 无统一配置 | 本仓库独有(§2.1 #2) |
| **条件分支** | ✅ condition 节点 | ✅ if-else 节点 | 均支持 |
| **迭代** | ❌ | ✅ iteration 节点 | Dify 独有(§3.1 #1) |
| **子工作流** | ❌ 内嵌 | ✅ child_engine_builder | Dify 独有(§3.2 #13) |
| **HITL 运行中暂停** | ❌ | ✅ PauseStatePersistenceLayer | Dify 独有(§3.2 #11) |
| **HTTP / Code 节点** | ❌ | ✅ 独立节点 | Dify 独有(§3.1 #7、#8) |
| **触发器(Webhook/Schedule)** | ❌ | ✅ 三种触发器 | Dify 独有(§3.1 #10) |
| **变量模糊匹配** | ✅ 四级 fallback | ❌ 直接寻址 | 本仓库独有(§2.2 #6) |
| **LLM 结构化输出** | ✅ extractWithRetry + 错误回注 | ✅ pydantic-ai output_type | 实现方式不同(§4.5) |
| **类型静默转换** | ✅ | ⚠️ 严格校验 | 本仓库更宽容(§2.3 #13) |
| **双循环重试** | ⚠️ 计划中 | ❌ | 本仓库规划中(§2.3 #14) |
| **ReAct / FC Agent** | ⚠️ Hermes Bridge 间接 | ✅ 原生实现 | Dify 更直接(§3.3 #14、#15) |
| **沙箱** | ✅ Python monkey-patch | ✅ Go Landlock + tmux | 实现方式不同(§4.8) |
| **多人协同画布** | ❌ | ✅ loro-crdt | Dify 独有(§3.4 #19) |
| **OTel 全链路追踪** | ❌ | ✅ + 8 种后端 | Dify 独有(§3.4 #20、#21) |
| **MCP 协议** | ❌ | ✅ 客户端 + 服务端 | Dify 独有(§3.4 #22) |
| **插件化扩展** | ❌ | ✅ plugin_daemon | Dify 独有(§3.3 #18) |
| **LLM 错误模式检测** | ✅ HermesErrorPattern | ❌ | 本仓库独有(§2.4 #17) |
| **LLM 自动关联** | ✅ 语义识别 Skill 依赖 | ❌ | 本仓库独有(§2.5 #23) |
| **模板变量动态识别** | ✅ 无碎片 | ❌ | 本仓库独有(§2.5 #24) |
| **变量导出/导入** | ✅ JSON 文件 | ❌ | 本仓库独有(§2.5 #27) |
| **默认模型实时路由** | ✅ | ❌ | 本仓库独有(§2.4 #19) |
| **工作目录 + `.agentignore`** | ✅ | ❌ | 本仓库独有(§2.2 #10) |
| **外部 API 三段式** | ✅ | ⚠️ 单次调用 | 本仓库更灵活(§4.15) |
### 5.2 设计哲学对比
| 维度 | agent-management | Dify |
|---|---|---|
| **核心目标** | 企业内部 AI 编码助手(Skill 驱动) | 开源 LLMOSS(多形态应用平台) |
| **一致性优先级** | 高(统一 envelope、统一 failStrategy) | 中(各节点分散处理) |
| **扩展性优先级** | 低(硬编码 8 种节点) | 高(插件化,第三方可贡献) |
| **学习曲线** | 低(节点少,强约束) | 高(节点多,配置灵活) |
| **部署复杂度** | 低(单体 JAR) | 高(11 个 docker 服务) |
| **生态丰富度** | 低(自有生态:Skill / Hermes) | 高(28 向量库 / 8 trace / 10 对象存储 / MCP) |
| **多租户** | ❌ | ✅ |
| **企业可控性** | 高(私有部署,全链路可见) | 中(开源 + 企业版分层) |
---
## 6. 演进建议
### 6.1 短期可借鉴(低成本高收益)
| 借鉴项 | 来源 | 价值 |
|---|---|---|
| **HITL 暂停-恢复机制** | `dify/api/core/app/layers/pause_state_persist_layer.py` | 让 userInput 节点支持运行中暂停,扩展交互场景 |
| **OTel 节点级追踪** | `dify/api/core/ops/ops_trace_manager.py` | 提升可观测性,便于性能调优 |
| **Langfuse 集成** | `dify/api/providers/trace/langfuse/` | 提供 LLM 调用全链路可视化 |
| **断线重连 SSE** | Dify socket.io 自动重连机制 | 已有 Last-Event-ID 续传,可进一步参考 socket.io 思路 |
| **节点版本机制** | Dify Agent v1 vs v2 的 `version()` 类方法 | 未来 Hermes/非 Hermes 节点演进时可显式版本化 |
### 6.2 中期可考虑(中等成本)
| 借鉴项 | 来源 | 价值 |
|---|---|---|
| **迭代节点** | `dify/api/core/workflow/nodes/iteration/` | 支持数组迭代处理(批量任务场景) |
| **子工作流嵌套** | `_WorkflowChildEngineBuilder` | 复用已有工作流作为子流程 |
| **HTTP Request 节点** | Dify http-request 节点 | 通用 HTTP 调用,替代 SmartAction 的部分场景 |
| **Code 节点(沙箱化)** | `dify-sandbox` 容器 | 支持任意代码执行,扩展工作流能力 |
| **触发器节点(Webhook)** | `trigger_webhook` 节点 | 事件驱动工作流,对接外部系统 |
| **多租户与 RBAC** | `dify/api/core/rbac/` | 企业级权限隔离 |
| **MCP 客户端集成** | `dify/api/core/mcp/` | 接入 MCP 生态,复用 MCP 工具 |
### 6.3 长期慎选(高成本,需重新定位)
| 借鉴项 | 来源 | 评估 |
|---|---|---|
| **Plugin Daemon 插件化** | `dify-plugin-daemon`(Go) | 显著增加架构复杂度,仅当需要第三方扩展生态时考虑 |
| **Landlock 沙箱** | `dify-agent-runtime/internal/landlock/` | 需 Linux 内核 5.13+,企业内部场景 monkey-patch 已够用 |
| **多人协同画布(loro-crdt)** | `dify/web/features/workflow/` | 需引入 CRDT 与 WebSocket,仅当多人协作是核心需求时考虑 |
| **多形态应用(Chat / Completion / AgentChat)** | `dify/api/core/app/apps/` | 与本仓库 Workflow 单形态定位冲突,需重新评估产品方向 |
| **litellm 统一 LLM 接入** | `dify/api/pyproject.toml` | Python 库,Java 生态可用 Spring AI 替代 |
| **Plugin 化向量库(28 种)** | `dify/api/providers/vdb/` | 仅当业务需要多向量库切换时考虑 |
### 6.4 应坚持的本仓库特色(不盲目学习 Dify)
| 特色 | 价值 |
|---|---|
| **统一 envelope 全节点强制** | 比 Dify"仅 Agent v2 强制"更一致,便于下游消费 |
| **统一 failStrategy(abort/skip)** | 比 Dify"散落各节点"更清晰,运维更可控 |
| **Dataflow + SKIPPED 状态机** | 完成即触发 + 条件分支可视化,比 Dify 的状态枚举更精细 |
| **四级模糊匹配 + envelope 穿透** | 容错性远超 Dify 的"直接寻址",降低用户心智负担 |
| **LLM 错误回注 prompt 自我修正** | Dify 没有此机制,是结构化输出的关键创新 |
| **Hermes Bridge + monkey-patch 沙箱** | 轻量级、无需多服务,适合企业内部场景 |
| **LLM 语义「自动关联」** | Dify 完全没有,是 Skill 工作流的独特创新 |
| **模板变量动态识别(无碎片)** | Dify 通过 variable selector 规避,体验不如本仓库 |
| **运行对话框变量导出/导入** | 实测对调试与复现非常有用,Dify 应该学 |
| **默认模型实时路由** | Dify 节点级硬绑定,本仓库更灵活 |
| **外部 API 三段式 + 工作目录下载** | 比 Dify 单次调用更适合长时间任务场景 |
| **kebab-case name + 中文 displayName 分离** | 比 Dify UUID 更友好,URL 可读性强 |
---
## 附录 A:本仓库工作流特性清单(按维度索引)
详见各设计文档:
- 节点类型与字段:`docs/workflow-node-fields.md`
- 调度引擎计划:`docs/workflow-scheduling-engine-plan.md`
- Dataflow 执行计划:`docs/workflow-dataflow-execution-plan.md`
- 节点输出信封:`docs/workflow-node-output-envelope.md`
- 信封严格校验:`docs/workflow-envelope-strict-validation-plan.md`
- 变量作用域:`docs/workflow-variable-scope-design.md`
- 上下文传递:`docs/context-passing-architecture.md`
- CRUD API:`docs/workflow-crud-api.md`
- 外部 API:`docs/external-workflow-api-spec.md`
- Hermes 沙箱:`docs/hermes-sandbox.md`
- Hermes 错误检测:`docs/hermes-error-detection-plan.md`
## 附录 B:Dify 参考索引
详见 `docs/dify-readme.md`:
- 技术栈:§2
- 必需依赖:§3
- 工作流编排调度:§4
- 多智能体协同探索(澄清:Dify 实际无此探索):§5
- 目录树说明:§6