You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
12 KiB
12 KiB
PLAN6 — 对标 Dify 无代码发布架构:差距分析与升级路线
一、核心结论
我们的流发布逻辑与 Dify 的底层思路高度一致(配置即数据 + 动态引擎),但在 7 个关键维度存在显著差距,需要补齐才能真正实现"无代码秒级发布,即刻可用"。
已对齐的架构思路
| Dify 核心思路 | 我们的实现 | 对齐度 |
|---|---|---|
| 配置即数据:前端生成 JSON,存入数据库 | ✅ FlowEditor 生成 nodes+edges JSON,存入 FlowDefinition.definition_json |
完全对齐 |
| 零部署:发布 = 数据库状态变更,不启动新服务 | ✅ publish 仅修改 status 字段,执行时动态加载 JSON | 完全对齐 |
| 动态编排引擎:解析 JSON → 执行 | ✅ FlowEngine 解析 JSON → 构建图 → traverse 执行 |
基本对齐 |
| DAG 拓扑排序执行 | ✅ _build_graph() + traverse() 支持条件分支和循环 |
基本对齐 |
| 多种节点类型 | ✅ 9 种节点:trigger/llm/tool/mcp/condition/rag/output/loop/code | 基本对齐 |
| 双渠道发布 | ✅ 企微 + Web 双渠道发布状态管理 | 额外优势 |
存在差距的关键维度
| # | 维度 | 差距等级 | 影响 |
|---|---|---|---|
| 1 | 版本快照 / 发布不可变 | 🔴 严重 | 发布后编辑直接影响线上服务 |
| 2 | 流式输出 (SSE) | 🔴 严重 | 长流程用户体验极差,无法实时看到结果 |
| 3 | 统一 API 网关 + App API Key | 🟠 高 | 无法被外部系统调用,无法做 API 市场 |
| 4 | 工具 Schema 标准化 | 🟠 高 | 无法运行时扩展工具,无参数校验 |
| 5 | Flow 节点 Memory | 🟠 高 | LLM 节点无上下文记忆,无法多轮对话 |
| 6 | 变量类型系统 | 🟡 中 | 复杂业务逻辑难以表达 |
| 7 | 执行监控与可观测性 | 🟡 中 | 无法追溯执行版本,缺少 token/延迟指标 |
二、逐维度详细对比
1. 版本快照 / 发布不可变(🔴 严重)
Dify 的做法:
- 点击"发布"时,将当前草稿 JSON 创建一份版本快照(snapshot),存入独立的
workflow_versions表 FlowDefinition有published_version字段,指向当前生效的版本- 执行引擎加载的是
published_version对应的 JSON,而非草稿 - 编辑草稿不影响已发布版本,回滚只需切换
published_version指针
我们的现状:
FlowDefinition只有version计数器(int),没有published_version字段- 发布仅修改
status="published",不创建快照 - 编辑草稿直接修改
definition_json,已发布的服务立即受影响 FlowExecution不记录执行时的版本号,无法追溯
需要补齐:
新增模型:FlowVersion
- id: UUID
- flow_id: FK → FlowDefinition
- version: int
- definition_json: JSON(快照)
- created_by: UUID
- created_at: datetime
修改模型:FlowDefinition
- 新增 published_version_id: FK → FlowVersion(nullable)
- 新增 draft_version: int(草稿版本号)
发布逻辑改造:
- publish → 创建 FlowVersion 快照 → 设置 published_version_id
- execute → 加载 published_version.definition_json(而非草稿)
- 编辑 → 只修改草稿,不影响 published_version
- 回滚 → 切换 published_version_id 指针
2. 流式输出 SSE(🔴 严重)
Dify 的做法:
- 统一 API 支持
response_mode: "streaming",返回 SSE 事件流 - 事件类型:
workflow_started→node_started→node_finished→workflow_finished - LLM 节点支持 token-by-token 实时推送(
text_chunk事件) - 前端通过 EventSource 实时渲染
我们的现状:
FlowEngine.execute()返回最终Msg,无中间状态LLMNodeAgent虽然配置了stream=True,但model(prompt)等待完整响应- WebSocket 端点仅 echo,未与 Flow 引擎集成
- 没有 SSE 端点
需要补齐:
新增 SSE 端点:GET /api/chat/stream/{flow_id}
- 接收 query 参数:message, session_id
- 返回 text/event-stream
- 事件格式:
event: node_started
data: {"node_id": "xxx", "node_type": "llm", "label": "生成摘要"}
event: text_chunk
data: {"node_id": "xxx", "content": "根据"}
event: node_finished
data: {"node_id": "xxx", "output": "..."}
event: workflow_finished
data: {"output": "最终结果"}
FlowEngine 改造:
- execute() 接受可选的 callback: Callable[[str, dict], None]
- 每个节点执行前后调用 callback("node_started"/"node_finished", data)
- LLMNodeAgent.reply() 改为 async generator,yield token
3. 统一 API 网关 + App API Key(🟠 高)
Dify 的做法:
- 每个 App 有独立的 API Key(
app-xxxxxxxx) - 统一入口:
POST /v1/chat-messages(对话型)、POST /v1/workflows/run(工作流型) - 请求格式标准化:
{inputs: {}, query: "", response_mode: "blocking|streaming", user: "user-id"} - 无需用户登录,API Key 即认证
我们的现状:
- 所有 API 依赖 JWT 用户认证,无 App-level API Key
- 执行分散在
/api/flow/definitions/{id}/execute和/api/chat/message/{id} - 无法被外部系统(如企微回调、第三方应用)直接调用
需要补齐:
新增模型:FlowApiKey
- id: UUID
- flow_id: FK → FlowDefinition
- key_hash: str(sha256)
- key_prefix: str(前8位,用于展示)
- name: str
- created_by: UUID
- created_at: datetime
- last_used_at: datetime(nullable)
新增统一网关端点:
POST /v1/chat-messages → 对话型 Flow(自动找 trigger → llm → output 路径)
POST /v1/workflows/run → 工作流型 Flow(完整 DAG 执行)
认证方式:
Header: Authorization: Bearer app-xxxxxxxx
→ 查 FlowApiKey 表 → 获取 flow_id → 加载 published_version → 执行
4. 工具 Schema 标准化(🟠 高)
Dify 的做法:
- 所有工具(内置/自定义 API/MCP)统一转换为 OpenAI Function Calling 的 JSON Schema
- Schema 包含:name, description, parameters(JSON Schema 格式,含 type/enum/description)
- 注入 LLM 时,工具 Schema 作为
tools参数传入 - 用户可在前端自定义 API 工具(填 URL、Method、参数结构)
我们的现状:
ToolNodeAgent._TOOL_REGISTRY硬编码 12 个工具函数- 工具函数只有 Python 签名,无结构化 Schema 描述
tool_params: dict = {}无校验- 无法运行时扩展工具
需要补齐:
工具 Schema 标准化格式:
{
"name": "send_notification",
"description": "发送企业微信通知给指定用户",
"parameters": {
"type": "object",
"properties": {
"to_user": {"type": "string", "description": "接收人用户ID"},
"message": {"type": "string", "description": "消息内容"}
},
"required": ["to_user", "message"]
}
}
改造 ToolNodeAgent:
- _TOOL_REGISTRY 改为 _TOOL_SCHEMA_REGISTRY: dict[str, dict]
- 每个工具注册时同时注册 Schema
- 调用前基于 Schema 校验 tool_params
- LLM 调用时将 Schema 作为 tools 参数传入
新增自定义 API 工具:
- 用户可填入 OpenAPI/Swagger URL
- 系统自动解析为标准 Schema 并注册
- 执行时通过 httpx 调用
5. Flow 节点 Memory(🟠 高)
Dify 的做法:
- 每个 App 有独立的对话记忆(窗口记忆/摘要记忆)
- 记忆在多次调用间持久化(Redis/数据库)
- LLM 节点自动注入历史对话上下文
我们的现状:
UserIsolatedMemory存在但未在 Flow 节点中使用- Flow 中的 LLM 节点每次调用都是无状态的
ChatMessage表存储了历史消息,但 Flow 执行时不读取
需要补齐:
FlowEngine 改造:
- execute() 接受 session_id 参数
- 创建 FlowSessionMemory(session_id, user_id)
- LLM 节点执行前注入历史消息
新增 FlowSessionMemory:
- 基于 ChatMessage 表持久化
- 按session_id + user_id 隔离
- 支持窗口大小配置(最近 N 条)
- 支持摘要模式(超过窗口时调用 LLM 生成摘要)
6. 变量类型系统(🟡 中)
Dify 的做法:
- 完整的变量面板:输入变量、环境变量、会话变量、上游节点变量
- 变量类型:string/number/array/object/file
- 支持 Jinja2 模板、类型转换、默认值
- "变量聚合"节点:汇聚并行分支输出
- "迭代"节点:对列表逐项处理
我们的现状:
- 仅有
{{node_id.output}}和{{trigger.field}}模板 - 所有值都是 str,无类型系统
- 无并行汇聚、无迭代节点
需要补齐:
变量系统升级:
- 节点输出增加类型标注(string/number/array/object)
- 模板解析支持类型转换和默认值
- 新增"变量聚合"节点(ParallelMergeNode)
- Loop 节点支持迭代数组模式
- 输入变量面板(Flow 级别的入参定义)
7. 执行监控与可观测性(🟡 中)
Dify 的做法:
- FlowExecution 记录执行时的版本号
- 统计 token 用量、延迟、费用
- 执行日志可按 App/时间/状态筛选
- 失败重试机制
我们的现状:
FlowExecution不记录版本号- 无 token/延迟统计
- 无失败重试
需要补齐:
FlowExecution 增加字段:
- version: int(执行时的版本号)
- token_usage: JSON(prompt_tokens, completion_tokens, total_tokens)
- latency_ms: int
- error_message: str(nullable)
执行引擎改造:
- 记录每个节点的 token 用量和耗时
- 汇总到 FlowExecution
- 失败节点支持重试配置
三、升级路线图
Phase 1 — 发布安全基础(P0,1-2周)
| 任务 | 改动范围 |
|---|---|
| 新增 FlowVersion 模型 + 迁移 | models, database |
| FlowDefinition 增加 published_version_id | models, schemas |
| 发布逻辑改造:创建快照 | flow_engine/router.py |
| 执行逻辑改造:加载 published_version | flow_engine/engine.py, chat/router.py |
| FlowExecution 记录版本号 | models, flow_engine/router.py |
Phase 2 — 用户体验核心(P0,2-3周)
| 任务 | 改动范围 |
|---|---|
| SSE 流式输出端点 | chat/router.py(新增) |
| FlowEngine callback 机制 | flow_engine/engine.py |
| LLMNodeAgent async generator 改造 | flow_engine/engine.py |
| 前端 EventSource 集成 | FlowChat.vue(新增) |
| Flow 节点 Memory 集成 | flow_engine/engine.py, 新增 FlowSessionMemory |
Phase 3 — 服务化能力(P1,2-3周)
| 任务 | 改动范围 |
|---|---|
| FlowApiKey 模型 + CRUD | models, schemas, 新增 router |
统一 API 网关 /v1/chat-messages, /v1/workflows/run |
新增 gateway router |
| API Key 认证中间件 | middleware |
| 工具 Schema 标准化 | tools/*.py, ToolNodeAgent |
| 自定义 API 工具(OpenAPI 导入) | 新增 custom_tool 模块 |
Phase 4 — 高级能力(P2,2-3周)
| 任务 | 改动范围 |
|---|---|
| 变量类型系统 | schemas, engine.py |
| 变量聚合节点 | 新增 ParallelMergeNodeAgent |
| Loop 迭代数组模式 | LoopNodeAgent |
| 执行监控指标 | FlowExecution, engine.py |
| 工具认证改造(去掉硬编码) | tools/*.py |
四、架构哲学对齐度总结
| Dify 架构哲学 | 我们的现状 | 对齐度 |
|---|---|---|
| 数据驱动:复杂 AI 逻辑抽象为可配置参数 | ✅ 已实现。9 种节点类型,每种有独立 config | 90% |
| 统一 Runner:一套引擎解析千种 JSON 组合 | ⚠️ 部分实现。引擎存在但缺少流式/Memory/版本快照 | 60% |
| 插件化架构:Tool/Model 实现高度抽象接口 | ❌ 未实现。工具硬编码,无标准 Schema,无自动发现 | 20% |
核心差距一句话总结:我们的"配置即数据"和"零部署"思路与 Dify 完全一致,但缺少"发布不可变"(版本快照)、"实时反馈"(SSE 流式)、"开放接入"(统一网关+API Key)和"插件化工具"(标准 Schema)四大关键能力,导致无法真正实现"无代码秒级发布,即刻可用"的完整体验。
补齐 Phase 1 + Phase 2 后,即可达到 Dify 约 80% 的核心能力。