deerflow-code/offline-backend-20260512/backend/docs/WORKFLOW_STUDIO_BACKEND_DEV_ZH.md
2026-09-07 18:24:55 +08:00

51 KiB
Raw Blame History

工作流编排与流式执行后端开发方案

文档状态:开发基线方案
适用项目:offline-backend-20260512/backend
对接前端:Coze Studio 独立工作流页面 frontend/apps/coze-studio/src/workflow-standalone/
更新时间:2026-08-29
阶段 0 状态:已完成 — 协议代码 packages/harness/deerflow/workflows/;文档见 WORKFLOW_SCHEMA_V1_ZH.md / WORKFLOW_SSE_V1_ZH.md / WORKFLOW_OPENAPI_DRAFT_V1.yaml / adr/0001-workflow-studio-runtime.md;契约测试 tests/test_workflow_schemas.py
阶段 1 状态:已完成 — 定义/版本持久化、草稿乐观锁、validate/publish、节点目录、Coze canvas/save/create/node_template 最小适配;路由 /api/workflows* + /api/workflow_api*;测试 tests/test_workflow_definitions.py(尚不执行运行)
阶段 2 状态:已完成 — run/node_run/event/artifact 表 + 迁移 20260828_02;幂等启动、租约调度、重启恢复、持久事件日志、SSE 回放/追尾。编排内核改为自建 DAG 调度器,不再编译成 LangGraph(理由见 adr/0001 阶段 2 修订)
阶段 3 状态:已完成 — start/output/transform/condition/merge + 安全表达式引擎;http 节点 SSRF 默认拒内网;sql_read 只读策略 + 数据源登记(密钥加密、只写不读,迁移 20260828_03);code 节点加固子进程执行器(默认关闭)
阶段 4 状态:已完成 — agent / skill 节点走 DeerFlow lead agent,模型增量与工具步骤映射为 node.output.delta / node.tool.*
阶段 5 状态:已完成 — human_input 暂停 + 一次性 resume token、子工作流(深度上限 3)、显式循环与 max_loop_iterations / max_steps 上限
阶段 6 状态:已完成 — iframe 票据(origin 白名单 + 60s 一次性 + frameAncestors)、按 owner/admin 的运行与数据源鉴权、每用户并发运行上限、结构化审计日志、事件/运行保留期配置与后台清理作业(WorkflowRetentionCleaner,每小时扫一次)、失败运行 POST /retry(复制已完成节点从失败点续跑,新 run 标 retry_of_run_id)、SSE Last-Event-ID 优先于 after。制品落盘文件仍跟随现有 sandbox/artifact 生命周期,不做工作流专属文件回收。多实例租约竞争 + SSE 重连有单机并发测试(test_two_dispatchers_only_one_claims_a_run / test_sse_reconnect_storm_is_ordered_and_complete),不是外部分布式压测。
会话规划补充(2026-08-31) — 普通对话先由独立内置智能体 workflow-planner(工作流总控)读取用户可见业务智能体目录、理解意图并选择角色,返回 2–3 条候选策略;它与 roundtable-coordinator 完全隔离,只做规划,不调用工具、不执行研究或正式运行。运行时强制 disable_tools=True 与 thinking_enabled=False,因此只产生一次轻量规划模型调用。模型仅能挑选已验证的 agentId 与既定策略,服务端才负责构造和校验可编辑 DAG;控制器不可用时显式报错,绝不退回关键词/静态模板。POST /api/workflows/{workflow_id}/planning-sessions/stream 复用 DeerFlow 控制器的真实流式回调,按目录读取、总控解析、角色选择、候选图组装、校验和完成依次发 SSE 里程碑,最后才发送候选会话;连接建立即写出一个真实的「已接收」传输里程碑,并以 SSE comment 保活/跨越代理缓冲阈值,comment 不会进入业务进度或持久化事件。前端默认收起该步骤条,只展示最新阶段,不能以本地定时器伪造进度。 审计整改(2026-08-29)状态:功能健壮性项已完成 — 按 WORKFLOW_STUDIO_BACKEND_REMEDIATION_ZH.md「0. 整改决策记录」:①人工恢复原子化(resume_with_payload 单条件更新 + set_awaiting_input 一次写入 checkpoint);②草稿保存 CAS 条件更新(409 带 currentRevision)+ 发布版本号计数器 workflow_definitions.next_version_number;③事件 seq 计数器 workflow_runs.next_event_seq(同事务取号,冲突自愈重试),事件落库失败丢弃不发布(删除负序号幽灵事件);④输入/输出完整 JSON Schema 校验(workflows/schema_validation.py,路由 400 + 节点错误均带字段路径);⑤测试纳入 Git(.gitignore 白名单)+ 新增 SQL 并发回归 tests/test_workflow_concurrency.py。迁移 20260828_04_workflow_counter_columns.py 增加两个计数器列(存量库由启动列同步自动补齐)。P0-01/02(内网可信环境,不实施)、P1-04/05(安全隔离,暂缓)见整改文档决策记录。
运行时测试:tests/test_workflow_engine.py(引擎、表达式、节点、安全策略)+ tests/test_workflow_runs.py(HTTP 生命周期、SSE、暂停恢复、租约回收、数据源、票据)+ tests/test_workflow_concurrency.py(整改并发回归:内存 + 真实 SQLite)

1. 目标与结论

本次建设的目标不是把 Coze Studio 或 ChatDev 2.0 整体并入 DeerFlow,而是在 DeerFlow 后端中增加一套可持久化、可恢复、可审计的工作流运行时,并让 Coze Studio 的工作流画布成为它的编辑器。

首期需要支持下面这类业务链:

开始/表单输入
  → SQL 只读查询 / HTTP 接口 / 数据采集智能体 / 技能
  → 数据清洗与整理智能体
  → 报告撰写智能体
  → 审核智能体
  → 条件分支(通过 / 退回修改)
  → 输出格式校验
  → Markdown、Word 或其他制品

最终技术选择:

  1. 画布与节点配置 UI 复用 Coze Studio,但不复用其完整后端协议和内置试运行系统。
  2. 工作流执行内核建设在 DeerFlow 中,编译为 LangGraph 图;智能体、技能、沙箱、模型、制品均复用 DeerFlow 的现有能力。
  3. ChatDev 2.0 仅作为 DAG、并行、循环、动态图和会话执行语义的参考,不整体搬入其运行时。
  4. 执行过程采用“数据库持久事件日志 + SSE 实时推送”。前端断线后使用 Last-Event-ID 或 after_seq 补放,不依赖内存中的单次连接。
  5. SQL 节点只允许服务器端已登记的数据源,并强制只读账号、语句检查、超时、行数/字节上限、表白名单和审计。
  6. 代码节点必须运行在 DeerFlow 沙箱中,不能照搬 ChatDev 的宿主机 subprocess.run。

2. 范围与非目标

2.1 首期范围

  • 工作流草稿、发布版本、复制、归档和权限校验。
  • 画布 JSON 的保存、校验、发布和不可变版本快照。
  • 节点:开始、输出、智能体、技能、HTTP、SQL 只读、代码、模板/转换、条件、合并、人工介入、子工作流、受限循环。
  • 同一层无依赖节点并行执行。
  • 运行创建、后台执行、取消、失败重试、人工介入后恢复。
  • 流式返回节点状态、模型输出增量、工具步骤、制品和终态。
  • 运行历史、事件重放、节点输入/输出审计和错误定位。
  • Coze 画布所需的最小兼容接口。
  • iframe 场景的短时票据、来源校验和权限隔离。

2.2 首期非目标

  • 不复制 Coze Studio 全部 Bot、插件市场、数据库产品和发布渠道。
  • 不实现 Coze 全量 workflow_api、试运行、Trace 和调试协议。
  • 不把 ChatDev 的消息类、模型提供商、WebSocket 服务或 SQLite 存储直接接入 DeerFlow。
  • 不允许用户把数据库密码、Bearer Token 等密钥写进画布 JSON。
  • 不允许 SQL 节点执行写语句、DDL、多语句或存储过程。
  • 不允许代码节点在 Gateway 宿主机直接启动任意进程。
  • 首期不承诺任意环图;循环必须是显式循环节点,并带次数、时长和成本上限。

3. 总体架构

Coze workflow-standalone(iframe)
          │
          │ HTTPS + Bearer/短时 iframe ticket
          ▼
FastAPI Gateway /api/workflows/*
  ├─ 定义、版本、资源目录、数据源 API
  ├─ 运行、取消、恢复、历史 API
  └─ SSE:持久事件补放 + 实时事件追尾
          │
          ▼
WorkflowApplicationService(app 层组合)
  ├─ WorkflowStore / RunStore / EventStore
  ├─ Dispatcher(扫描、抢占、租约、恢复)
  └─ Executor(后台任务)
          │
          ▼
deerflow.workflows(harness 层)
  ├─ Schema + Validator
  ├─ Safe expression resolver
  ├─ Node registry
  ├─ LangGraph compiler
  └─ Node executors
       ├─ DeerFlow agent
       ├─ DeerFlow skill/agent
       ├─ HTTP policy client
       ├─ read-only SQL
       └─ DeerFlow sandbox

必须继续遵守当前仓库的分层约束:

  • packages/harness/deerflow/** 可以定义通用工作流模型、编译器和节点执行协议。
  • packages/harness/deerflow/** 不得导入 app.*。
  • FastAPI、鉴权、app.state、数据库 Store 组合、后台 dispatcher/executor 启停放在 app/**。
  • 工作流智能体节点通过依赖注入使用现有 agent/runtime 能力,不新建另一套模型和工具体系。

4. 为什么不直接集成 ChatDev 后端

ChatDev 与本项目虽然同为 Python,但运行时边界不同。

对比项 DeerFlow ChatDev 2.0 处理方式
图运行时 LangGraph + DeerFlow middleware 自建 DAG executor 保留 DeerFlow,参考 ChatDev 调度语义
智能体 Lead Agent、定制 Agent、工具、MCP、技能 ChatDev 自有 Agent runtime 只调用 DeerFlow Agent
流式协议 已有 run/event/stream 基础设施 WebSocket 为主 建立 DeerFlow SSE 工作流协议
沙箱 DeerFlow Sandbox 抽象 Python executor 可直接 subprocess 禁止搬入 subprocess,实现 SandboxNode
持久化 项目统一 SQLAlchemy/数据库 自有 SQLite/存储服务 使用 DeerFlow persistence 层
技能 SKILL.md 指令包,由智能体加载 skills manager 也偏指令加载 明确区分 agent_skill 与 callable_skill
数据库节点 需要新增 未提供通用业务库查询节点 自己实现严格只读 SQL 节点

直接整包移植会产生两套图状态、两套消息协议、两套模型调用、两套会话和两套错误恢复。后续每增加一个 DeerFlow 能力都需要做两边适配,短期看似快,长期成本反而更高。

ChatDev 适合参考的源码路径见第 15 节。

5. 核心领域模型

5.1 定义、草稿与发布版本

建议采用“工作流元数据 + 可变草稿 + 不可变发布版本”的模型:

  • workflow_definitions
    • id
    • name
    • description
    • owner_id
    • status: draft | active | archived
    • draft_revision: 乐观锁版本号
    • draft_graph_json: 当前画布草稿
    • created_at / updated_at
  • workflow_versions
    • id
    • workflow_id
    • version_number
    • graph_json: 发布时完整不可变快照
    • graph_hash: 规范化 JSON 的 SHA-256
    • input_schema / output_schema
    • published_by / published_at
    • change_note

运行必须绑定 workflow_version_id。运行开始后,即使用户继续编辑草稿,已有运行也不能改变。

5.2 运行、节点运行和事件

  • workflow_runs
    • id
    • workflow_id / workflow_version_id
    • status: queued | running | awaiting_input | completed | failed | cancel_requested | cancelled
    • owner_id
    • idempotency_key
    • input_json
    • output_json
    • error_json
    • context_json: 非敏感运行上下文
    • lease_owner / lease_until / heartbeat_at
    • attempt / max_attempts
    • version: CAS 乐观锁字段
    • started_at / finished_at / created_at / updated_at
  • workflow_node_runs
    • id
    • run_id
    • node_id / node_type
    • status
    • attempt
    • input_snapshot / output_snapshot
    • error_json
    • started_at / finished_at
    • parent_node_run_id: 循环、子工作流或重试层级
  • workflow_run_events
    • run_id
    • seq: 每个 run 内严格递增,唯一键 (run_id, seq)
    • event_type
    • node_id / node_run_id
    • payload_json
    • created_at

事件日志是前端重建执行过程的事实来源;workflow_runs 和 workflow_node_runs 是便于列表查询的当前状态投影。

5.3 数据源与凭据

  • workflow_data_sources
    • id / name / kind
    • owner_scope: 用户、组织或全局
    • connection_config: 主机、端口、库名、SSL 等非密钥字段
    • credential_ref: 指向服务端密钥存储,不存明文
    • allowed_schemas / allowed_tables
    • statement_timeout_ms / max_rows / max_bytes
    • enabled
    • created_by / created_at / updated_at

画布只保存 data_source_id。前端永远拿不到数据库密码,运行事件也不能回传连接串或认证头。

HTTP 接口资源使用同一张表:kind=http 时,base_url 和 allowed_methods 是可展示的非密钥元数据;请求头仍加密放在 credential blob,列表、详情、资源目录和运行事件均不得回显。创建时至少提供一个允许方法,地址只接受不含账户密码、查询参数或片段的 http(s) URL。迁移:20260829_01_workflow_http_source_metadata.py。

5.4 iframe 短时票据

如 Coze 页面与 DeerFlow 不同域,新增短时、一次性的嵌入票据:

  • workflow_embed_tickets
    • ticket_hash
    • user_id
    • workflow_id
    • allowed_actions
    • allowed_origin
    • expires_at
    • consumed_at

只保存票据哈希。父页面请求票据后通过 postMessage 交给 iframe,iframe 再兑换短期访问令牌。不得把正式 JWT、数据库密钥或 API 密钥放在 iframe URL 查询参数中。

6. 画布 JSON 与运行数据契约

6.1 推荐的标准图结构

Coze 画布 DTO 进入 Gateway 后要转换成内部标准结构,运行时不得直接依赖 Coze 私有字段:

{
  "schemaVersion": "1.0",
  "id": "wf_report_001",
  "name": "专题报告生成",
  "inputSchema": {
    "type": "object",
    "required": ["topic"],
    "properties": {
      "topic": { "type": "string" },
      "taskId": { "type": "string" }
    }
  },
  "outputSchema": {
    "type": "object",
    "required": ["reportMarkdown"],
    "properties": {
      "reportMarkdown": { "type": "string" },
      "artifacts": { "type": "array" }
    }
  },
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "name": "开始",
      "config": {}
    },
    {
      "id": "sql_1",
      "type": "sql_read",
      "name": "查询业务数据",
      "config": {
        "dataSourceId": "ds_001",
        "statement": "SELECT id, title FROM report_source WHERE task_id = :task_id",
        "parameters": {
          "task_id": "{{ inputs.taskId }}"
        },
        "maxRows": 1000
      }
    }
  ],
  "edges": [
    { "id": "e1", "source": "start_1", "target": "sql_1" }
  ],
  "settings": {
    "runTimeoutSeconds": 1800,
    "nodeTimeoutSeconds": 300,
    "maxSteps": 200,
    "maxLoopIterations": 5,
    "maxParallelism": 4
  }
}

6.2 统一节点结果

所有节点统一返回 NodeResult,避免节点之间直接传递某个 LLM SDK 的对象:

{
  "data": {},
  "messages": [],
  "artifacts": [
    {
      "artifactId": "artifact_01",
      "name": "专题报告.md",
      "mimeType": "text/markdown",
      "path": "/mnt/data/专题报告.md"
    }
  ],
  "metadata": {
    "rowCount": 25,
    "model": "configured-model-name"
  },
  "warnings": []
}

大文本、二进制文件和超大查询结果不直接塞进事件或 output_json,而是保存为 artifact,再传引用和有上限的预览。

6.3 安全表达式

支持以下只读引用:

  • {{ inputs.topic }}
  • {{ nodes.sql_1.data.rows }}
  • {{ nodes.agent_1.data.answer }}
  • {{ run.id }}

实现要求:

  • 使用受限 JSON Path/JMESPath/自研字段访问器;禁止 Python eval、JavaScript 执行和任意属性反射。
  • 发布时解析全部表达式,检查引用节点是否在当前节点上游。
  • 条件节点只支持白名单运算符:相等、包含、数值比较、空值、布尔组合。
  • 模板渲染默认 HTML/文本转义;HTTP 和 SQL 参数分别走参数绑定,不能字符串拼接。
  • 运行时记录“引用不存在”和“类型不匹配”的结构化错误。

7. 节点类型与实现边界

7.1 开始节点 start

  • 按工作流 inputSchema 校验调用参数。
  • 注入用户、运行 ID、时间等安全上下文。
  • 不注入访问令牌、数据库密码等密钥。

7.2 输出节点 output

  • 从上游结果中映射最终字段。
  • 按 outputSchema 做 JSON Schema 校验。
  • 校验失败时工作流失败,错误中返回字段路径和期望类型。
  • 可选“LLM 修复格式”必须是明确配置,并保留原始结果与修复记录;首期建议默认关闭。

7.3 智能体节点 agent

配置建议:

{
  "agentId": "agent_xxx",
  "promptTemplate": "根据以下数据撰写报告:{{ nodes.merge_1.data }}",
  "responseMode": "text|json",
  "responseSchema": {},
  "threadMode": "isolated_per_node|shared_run_thread",
  "timeoutSeconds": 600
}

实现原则:

  • 通过现有 make_lead_agent / 定制 Agent 配置加载机制执行。
  • 不复制模型 provider、MCP、工具、memory 或 middleware。
  • 每个 node run 使用稳定的 child thread 或命名空间,保证重试不把半次输出混入下一次。
  • 将模型文字增量转成 node.output.delta;工具调用转成 node.tool.started/finished。
  • 不向工作流事件写入模型隐藏思维链;只记录可展示的回答、状态和工具摘要。
  • 节点取消要传播到 agent run 和沙箱任务。

7.4 技能节点 skill

现有 DeerFlow 技能主要是 SKILL.md 指令包,并不是每个技能都具有可直接调用的 Python 函数。因此首期要区分两种模式:

  1. agent_skill:选择一个 DeerFlow 智能体和技能列表,由智能体加载指定技能完成任务。可立即落地。
  2. callable_skill:技能必须显式声明入口、输入 JSON Schema、输出 JSON Schema、权限和超时。此模式需要新增技能 manifest 后再开放。

不能把“技能文件存在”直接等同于“可以当函数节点执行”。

7.5 HTTP 节点 http

  • 方法白名单:GET/POST/PUT/PATCH/DELETE,生产环境可按角色收紧。
  • URL 模板和请求体可引用上游数据。
  • 认证使用服务端 credential 引用,画布不保存密钥。
  • 支持 JSON、文本和有限大小的文件响应。
  • 默认禁止重定向;如允许,每一跳都重新执行安全检查。
  • 阻止 loopback、link-local、内网保留地址、云元数据地址和 DNS rebinding。
  • 配置域名白名单、连接/读取/总超时、最大响应字节数。
  • 日志和事件对 Authorization、Cookie、API Key 和配置的敏感字段脱敏。
  • 返回非 2xx 时按节点策略决定失败、重试或进入错误分支。

7.6 SQL 只读节点 sql_read

这是新增能力,不能把 DeerFlow 自身业务数据库连接直接暴露给节点。

强制策略:

  1. 数据库必须由管理员在服务端登记。
  2. 使用数据库原生只读账号;账号不拥有 INSERT/UPDATE/DELETE/DDL/EXECUTE 权限。
  3. 应用层再做 SQL AST 检查,只允许一个只读查询语句。
  4. 参数全部使用驱动绑定变量,不做字符串替换。
  5. 禁止多语句、注释逃逸、锁表/锁行、写入型 CTE、SELECT ... INTO、文件读写、危险函数和存储过程。
  6. 设置 statement timeout、连接超时、最大行数、最大字段长度和最大总字节数。
  7. 数据源配置可限制 schema、表和列。
  8. 结果中按策略遮蔽敏感列;审计记录操作者、数据源、规范化 SQL hash、参数名、行数、耗时和状态,不记录密钥。
  9. 发布校验时可做 EXPLAIN 或语法预检,但不能在保存画布时自动执行用户 SQL。
  10. 生产环境建议从只读副本查询,避免报表工作流影响主业务库。

首期驱动建议只做项目实际使用的 MySQL 和/或 PostgreSQL,不要一开始抽象所有数据库。

7.7 代码节点 code

  • 使用 deerflow.sandbox 抽象创建隔离执行环境。
  • 输入通过 JSON 文件或 stdin 传入,输出必须符合约定 JSON。
  • 设置 CPU、内存、磁盘、进程数、网络和执行时长上限。
  • 默认禁网;如业务需要访问网络,按域名能力授权。
  • 代码、依赖声明和运行镜像版本进入发布版本快照或可追溯引用。
  • 输出文件登记为 artifact。
  • 禁止调用 ChatDev python_executor.py 中的宿主机 subprocess.run 方案。

7.8 模板/转换节点 transform

  • 负责字段映射、数组过滤、模板渲染、Markdown 拼装。
  • 优先提供声明式操作,减少为了简单数据整理而启动智能体或代码沙箱。
  • 操作符与函数采用白名单。

7.9 条件和合并节点

  • condition:根据安全表达式选择一个或多个具名出口。
  • merge:支持 all、first_success、any_success 等明确策略。
  • 并行分支写入独立命名空间,合并节点使用确定性 reducer,不能依赖任务完成先后顺序。

7.10 人工介入节点 human_input

  • 发出 run.awaiting_input,持久化表单 schema、提示和可执行动作。
  • 将 run 状态原子更新为 awaiting_input,释放 worker 租约。
  • resume API 必须校验 run 当前状态、用户权限和输入 schema。
  • 同一个 resume_token 只消费一次,重复提交幂等返回当前状态。

7.11 子工作流与循环

  • 子工作流绑定一个已发布的不可变版本。
  • 记录 parent run/node run,事件中保留层级路径。
  • 防止直接或间接递归依赖。
  • 循环只能通过显式 loop 节点,必须配置最大次数;同时受全局 maxSteps、超时和预算限制。

8. 编译与执行流程

8.1 发布时校验

发布必须完成:

  1. JSON Schema 和内部 DTO 校验。
  2. 节点 ID、边 ID 唯一性。
  3. 开始/输出节点数量和可达性检查。
  4. 普通边拓扑检查;环只能存在于受控 loop 结构。
  5. 节点输入引用必须来自上游。
  6. 条件出口与边名称一致。
  7. Agent、Skill、数据源、子工作流版本存在且调用者有权限。
  8. 资源限制在系统上限内。
  9. 输出映射能够生成声明的 output schema。
  10. 规范化后生成 graph_hash,创建不可变版本。

8.2 LangGraph 编译

内部编译器将标准节点转换成 StateGraph:

  • WorkflowState 保存 inputs、各节点 NodeResult、运行控制字段和 artifact 引用。
  • NodeRegistry 根据 node.type 返回 executor factory。
  • 条件节点编译为 conditional edges。
  • 无依赖分支由 LangGraph 并行调度。
  • 合并字段必须注册确定性 reducer。
  • interrupt 用于 human_input,恢复时从持久 checkpoint 继续。

编译结果可按 graph_hash 做有界缓存;缓存对象不能包含用户级密钥或运行态数据。

8.3 后台运行状态机

queued
  → running
      → awaiting_input → queued/running
      → completed
      → failed
      → cancel_requested → cancelled

实现参考 roundtable job 的成熟模式:

  • 创建运行时用 idempotency_key 去重。
  • dispatcher 只抢占租约过期或 queued 的任务。
  • worker 定期 heartbeat 延长租约。
  • 所有状态变更使用版本字段/CAS,防止多个实例重复完成。
  • cancel 先设置 cancel_requested,worker 在安全点确认后写 cancelled。
  • Gateway 重启后扫描 queued 和租约过期的 running 任务。
  • 非幂等 HTTP 节点默认不自动重试;节点必须声明重试策略和幂等性。

9. SSE 流式协议

9.1 原则

  1. 先持久化,后发布:用户可见事件先写 workflow_run_events,提交成功后再推送到 live bridge。
  2. 事件严格有序:同一 run 的 seq 单调递增。
  3. 可重放:断线后从最后一个 seq 继续。
  4. 增量事件有上限:高频 token 可在 30–100ms 窗口内合并,避免一 token 一条数据库记录。
  5. 终态明确:completed/failed/cancelled 后停止重连。
  6. 不泄密:事件中不得出现凭据、完整认证头、数据库连接串和隐藏思维链。

9.2 端点

GET /api/workflows/runs/{run_id}/stream?after_seq=128
Accept: text/event-stream
Authorization: Bearer ...
Last-Event-ID: 128

服务端游标优先级建议:

  1. 合法的 Last-Event-ID
  2. after_seq
  3. 0

连接流程:

  1. 校验 run 访问权限。
  2. 从数据库按 seq > cursor 分页补放。
  3. 订阅 live bridge。
  4. 再查一次数据库关闭“补放到订阅”之间的竞态窗口。
  5. 实时追尾;发现 seq 跳号时回数据库补齐。
  6. 无事件时每 15–25 秒发送 heartbeat/comment。
  7. 收到终态且数据库已补齐后关闭连接。

9.3 帧格式

id: 42
event: node.output.delta
data: {"schemaVersion":"1.0","runId":"run_01","workflowId":"wf_01","versionId":"wv_03","seq":42,"nodeId":"agent_writer","nodeRunId":"nr_09","timestamp":"2026-08-26T10:00:00+08:00","data":{"channel":"answer","delta":"第一段内容"}}

通用 envelope:

{
  "schemaVersion": "1.0",
  "runId": "run_01",
  "workflowId": "wf_01",
  "versionId": "wv_03",
  "seq": 42,
  "nodeId": "agent_writer",
  "nodeRunId": "nr_09",
  "timestamp": "2026-08-26T10:00:00+08:00",
  "data": {}
}

9.4 事件清单

事件 关键数据 前端用途
run.created input 摘要、version 创建历史记录
run.queued queue 信息 显示排队
run.started startedAt 运行计时
node.queued node 信息 画布等待态
node.started attempt、输入摘要 高亮节点、创建步骤卡
node.progress phase、message、percent 进度条/说明
node.output.delta channel、delta 流式文本
node.tool.started toolCallId、name、input 摘要 工具步骤进行中
node.tool.finished toolCallId、status、output 摘要 完成工具步骤
artifact.created artifact 元数据 文件卡和预览
node.completed output 摘要、duration 节点完成
node.failed error code、message、retryable 节点失败
run.awaiting_input formSchema、actions、resumeToken 人工介入卡片
run.resumed action 恢复时间线
run.cancel_requested requestedBy 取消中
run.cancelled finishedAt 终态
run.completed output、artifacts 终态与结果
run.failed error、failedNodeId 终态与定位

heartbeat 建议使用 SSE comment : heartbeat,不写入数据库,也不进入前端业务 reducer。

9.5 事件粒度与存储控制

  • 模型输出增量按时间窗口或字符数批量落库,例如 50ms/1KB 合并一次。
  • 工具输入输出只存有界摘要;完整文件写 artifact。
  • SQL 结果默认只在事件里放列名、行数和前 N 行预览;完整结果按节点设置进入运行快照或 artifact。
  • 单事件 payload 设置字节上限;超限时写 {truncated: true, artifactId: ...}。
  • 事件保留周期应配置化;终态 run 可异步压缩快照,但在保留期内不能破坏 seq 重放。

10. HTTP API 设计

10.1 工作流定义

GET    /api/workflows
POST   /api/workflows
GET    /api/workflows/{workflow_id}
PATCH  /api/workflows/{workflow_id}
DELETE /api/workflows/{workflow_id}             # 软删除/归档
PUT    /api/workflows/{workflow_id}/draft        # draft_revision 乐观锁
POST   /api/workflows/{workflow_id}/validate
POST   /api/workflows/{workflow_id}/publish
POST   /api/workflows/{workflow_id}/copy
GET    /api/workflows/{workflow_id}/versions
GET    /api/workflows/{workflow_id}/versions/{version_id}

PUT draft 请求必须包含 expectedRevision,冲突返回 409 和服务端当前 revision,前端提示刷新或另存副本。

10.2 节点资源目录

GET /api/workflows/node-types
GET /api/workflows/resources/agents
GET /api/workflows/resources/skills
GET /api/workflows/resources/data-sources
GET /api/workflows/resources/subworkflows

资源目录返回工作流节点需要的精简 DTO,不直接暴露后端内部对象。

10.3 数据源

GET    /api/workflows/data-sources
POST   /api/workflows/data-sources
GET    /api/workflows/data-sources/{id}
PUT    /api/workflows/data-sources/{id}
DELETE /api/workflows/data-sources/{id}
POST   /api/workflows/data-sources/{id}/introspect
POST   /api/workflows/data-sources/{id}/validate-query

introspect 只返回白名单内 schema/table/column 元数据,不返回样例敏感数据。

HTTP 接口资源的创建体使用 kind=http、baseUrl、allowedMethods 和可选 headers;headers 是只写字段,服务端加密后不会出现在响应。资源目录 GET /api/workflows/resources/data-sources 返回前端所需的 dataSourceId、baseUrl、allowedMethods、description 等精简字段。

10.4 运行

POST /api/workflows/{workflow_id}/runs
GET  /api/workflows/{workflow_id}/runs
GET  /api/workflows/runs/{run_id}
GET  /api/workflows/runs/{run_id}/events?after_seq=0&limit=500
GET  /api/workflows/runs/{run_id}/stream
POST /api/workflows/runs/{run_id}/cancel
POST /api/workflows/runs/{run_id}/resume
POST /api/workflows/runs/{run_id}/retry
GET  /api/workflows/runs/{run_id}/artifacts

启动示例:

{
  "versionId": "wv_03",
  "inputs": { "topic": "市场分析", "taskId": "123" },
  "idempotencyKey": "client-generated-uuid",
  "executionMode": "normal"
}

10.5 Coze 最小兼容层

独立页面当前画布仍可能调用 Coze 生成 API。建议建立薄适配路由,而不是让内部 service 使用 Coze DTO:

POST /api/workflow_api/canvas
POST /api/workflow_api/save
POST /api/workflow_api/create
POST /api/workflow_api/node_template_list

兼容层职责只有:

  • Coze request/response DTO 与内部 draft DTO 互转。
  • 返回节点模板和图标元数据。
  • 调用内部 workflow service。

Coze 自带的 test-run、trace、workflow debug 接口首期不实现;前端关闭内置测试运行入口,改用第 10.4 节的运行 API。

10.6 iframe 会话

POST /api/workflow-embed/tickets
POST /api/workflow-embed/tickets/exchange
  • 创建票据需 DeerFlow 正常登录。
  • ticket 绑定 workflow_id + user_id + origin + permissions,有效期建议 60 秒。
  • exchange 一次后即失效,返回短期访问令牌和用户/工作流精简信息。
  • 响应带 Cache-Control: no-store。

11. 安全、权限与审计

11.1 权限

工作流至少区分:

  • view:查看定义和运行。
  • edit:修改草稿。
  • publish:发布不可变版本。
  • run:启动运行。
  • manage_data_source:登记或修改数据源。
  • view_sensitive_output:查看未脱敏的节点输出。

所有列表、详情、SSE、artifact 下载和 resume/cancel API 都必须重新校验权限,不能因为知道 run ID 就可访问。

11.2 凭据处理

  • 数据源、HTTP 认证和第三方 Token 使用服务端 credential reference。
  • 画布和版本快照仅保存引用 ID。
  • 进入日志、异常、SSE 和 node snapshot 前统一 redaction。
  • 发布者必须有权引用相应 credential;运行者是否可使用由策略决定。
  • credential 轮换不修改已发布图,但要记录实际使用的 credential version/audit id。

11.3 审计

记录:

  • 草稿保存、发布、归档、权限变更。
  • 运行创建、取消、恢复、重试。
  • 数据源测试与 SQL 执行摘要。
  • HTTP 目标域名、状态码和耗时。
  • 人工介入提交者和动作。
  • artifact 创建、下载和删除。

审计中保存 hash/摘要而不是密钥和完整敏感数据。

11.4 资源上限

系统级上限必须覆盖画布配置:

  • 每用户并发 run 数。
  • 单 run 最大时长、步骤数、循环次数、并行节点数。
  • 单节点重试次数。
  • LLM token/费用预算。
  • HTTP/SQL 响应大小。
  • 单 run artifact 数量与总大小。

12. 失败、重试、取消和恢复

12.1 错误结构

统一错误:

{
  "code": "WORKFLOW_SQL_POLICY_DENIED",
  "message": "SQL 节点只允许单条只读查询",
  "retryable": false,
  "nodeId": "sql_1",
  "details": {
    "rule": "single_read_statement"
  }
}

用户可见 message 不包含堆栈、SQL 密码、完整响应体或内部路径;完整异常进入受控服务端日志。

12.2 重试

  • 智能体节点:仅对明确的临时网络/限流错误重试,沿用稳定 node run lineage。
  • SQL 只读:连接临时失败可有限重试;语法/权限错误不重试。
  • HTTP:GET/HEAD 可按策略重试;POST 默认不重试,除非配置幂等键。
  • 代码:资源不足或代码错误默认不重试。
  • 工作流级 retry:POST /api/workflows/runs/{run_id}/retry 仅接受 failed 运行。新 run 复制已完成节点输出并从失败节点续跑;没有任何可回放 checkpoint 时则整图重跑,并标记 retry_of_run_id。

12.3 取消

  • API 原子设置 cancel_requested 并发事件。
  • worker 在节点边界、模型流、HTTP、SQL、沙箱等待点检查取消令牌。
  • 尽力取消外部操作;无法中止的请求完成后也不能再提交后续节点结果。
  • 终态只允许一次,不能出现 completed 后又 cancelled。

12.4 服务重启

  • 事件已持久化,因此 SSE 可恢复。
  • dispatcher 根据租约扫描未完成任务。
  • awaiting_input 不占 worker。
  • 对可能产生外部副作用的节点,恢复前检查幂等记录;状态不确定时标记人工处理,不能盲目重放。

13. 可观测性

日志统一带:

  • workflow_id
  • workflow_version_id
  • run_id
  • node_id
  • node_run_id
  • user_id
  • trace_id

建议指标:

  • queued/running/awaiting_input 数量。
  • run 和节点成功率、P50/P95/P99 耗时。
  • SSE 活跃连接、重连次数、补放事件数、游标落后量。
  • dispatcher 抢占、租约过期、重复执行阻止次数。
  • 各类节点错误率。
  • SQL 行数/超时、HTTP 状态码、sandbox 超时。
  • LLM token 与费用。

14. DeerFlow 现有代码参考路径

以下路径相对于 offline-backend-20260512/backend/。

14.1 运行与流式事件

路径 参考内容 复用方式
packages/harness/deerflow/runtime/runs/manager.py run 生命周期、去重、取消、持久化组合 复用模式,不把 thread run 数据模型硬套到 workflow run
packages/harness/deerflow/runtime/runs/worker.py agent.astream、流模式、结束/异常处理 智能体节点适配时参考
packages/harness/deerflow/runtime/runs/schemas.py run DTO 参考命名和序列化
packages/harness/deerflow/runtime/runs/store/base.py store 接口边界 为 workflow store 建立同风格接口
packages/harness/deerflow/runtime/stream_bridge/base.py 发布/订阅协议 可复用接口思想
packages/harness/deerflow/runtime/stream_bridge/memory.py 内存 replay、heartbeat/end sentinel 作为 live bridge;不能代替 DB 事件日志
packages/harness/deerflow/runtime/events/store/base.py 事件 store 抽象 工作流事件仓库参考
packages/harness/deerflow/runtime/events/store/db.py DB 批量事件写入、按 seq 读取 优先抽取可复用机制或照此实现 workflow event store
packages/harness/deerflow/runtime/journal.py 事件 journal 参考批量与刷新策略
app/gateway/routers/thread_runs.py run/SSE Gateway 写法 参考鉴权、响应头、断连处理
docs/STREAMING.md 当前流协议约定 新协议必须兼容仓库通用规则

14.2 后台任务与租约

路径 参考内容
app/gateway/routers/roundtable_jobs.py start/get/stream/resume/cancel API
app/gateway/roundtable_job_executor.py 后台执行、状态投影、恢复
app/gateway/roundtable_job_dispatcher.py 扫描、唤醒、租约
packages/harness/deerflow/persistence/roundtable_jobs/model.py job 表和状态字段
packages/harness/deerflow/persistence/roundtable_jobs/sql.py claim、heartbeat、CAS、取消

应复用租约和状态机经验,但不要继续采用“前端轮询完整 job snapshot”作为工作流主流协议;工作流使用增量事件 SSE。

14.3 智能体、技能、沙箱与制品

路径 参考内容
packages/harness/deerflow/agents/lead_agent/agent.py make_lead_agent 与 middleware 组装
packages/harness/deerflow/config/agents_config.py 定制 Agent 配置加载
app/gateway/routers/agents.py 智能体资源列表与权限
app/gateway/routers/skills.py 技能列表/读取 API
packages/harness/deerflow/skills/storage/local_skill_storage.py 技能存储模型
packages/harness/deerflow/tools/builtins/skill_tools.py Agent 如何查看/加载技能
packages/harness/deerflow/sandbox/sandbox.py 沙箱能力接口
packages/harness/deerflow/sandbox/tools.py 沙箱工具调用
packages/harness/deerflow/sandbox/middleware.py Agent 与沙箱生命周期
packages/harness/deerflow/sandbox/local/local_sandbox.py 本地沙箱实现及风险边界
app/gateway/routers/artifacts.py artifact 查询/读取 API

14.4 Gateway 和持久化接线

路径 参考内容
app/gateway/deps.py app.state 初始化 store/service/runtime
app/gateway/app.py router 注册、生命周期、CORS
packages/harness/deerflow/persistence/models.py ORM model 汇总导入
packages/harness/deerflow/persistence/engine.py 数据库 session/engine
packages/harness/deerflow/persistence/types.py MySQL/SQLite 可移植 JSON、LongText、时间类型
tests/test_harness_boundary.py harness → app 导入防火墙

14.5 iframe 参考但不要直接复用

路径 可参考 不可照搬原因
app/gateway/routers/public_embed.py session 映射、嵌入接口形态 public embed 偏匿名/公开读取,不满足工作流编辑与执行权限
packages/harness/deerflow/persistence/embed_sessions/model.py 嵌入 session 表结构 工作流需要一次性票据、origin 和 actions 绑定
packages/harness/deerflow/persistence/embed_sessions/sql.py session store 写法 需新增独立安全模型

15. ChatDev 2.0 参考与明确不复用的路径

以下路径相对于 F:/react01/chatDev/。

15.1 可参考

路径 参考点
workflow/topology_builder.py 从配置构建拓扑
workflow/graph.py 图对象职责
workflow/graph_context.py 图运行上下文
workflow/graph_manager.py 图生命周期管理
workflow/cycle_manager.py 显式循环控制
workflow/subgraph_loader.py 子图加载
workflow/executor/dag_executor.py DAG 调度语义
workflow/executor/parallel_executor.py 并行分支
workflow/executor/cycle_executor.py 循环执行
workflow/executor/dynamic_edge_executor.py 动态边选择
workflow/executor/resource_manager.py 并发资源控制
workflow/runtime/execution_strategy.py 执行策略抽象
workflow/runtime/runtime_builder.py runtime 组装
workflow/runtime/runtime_context.py 运行上下文
entity/configs/graph.py 图配置 schema
entity/configs/node/ 节点配置拆分方式
entity/configs/edge/ 边配置拆分方式
server/services/workflow_run_service.py run service 边界
server/services/session_execution.py 会话执行编排
server/routes/execute.py 异步执行 API 形态
server/routes/execute_sync.py 同步执行边界;本项目不建议面向长任务开放
server/routes/websocket.py 实时消息类型参考;传输改为 SSE

15.2 不复用

路径 原因
runtime/node/executor/python_executor.py 直接宿主机 subprocess,无法满足本项目沙箱边界
server/services/websocket_executor.py 本项目统一 SSE,避免并存两套重连协议
server/services/websocket_manager.py 同上
server/services/workflow_storage.py 使用 ChatDev 自身存储模型,会与 DeerFlow persistence 重叠
runtime/node/agent/skills/manager.py 只说明技能加载,不等于通用可调用技能节点
ChatDev 模型 provider、消息对象、Agent runtime 与 DeerFlow middleware/MCP/skill/memory 重复

16. 建议新增和修改的后端代码路径

以下均相对于 offline-backend-20260512/backend/。路径是开发拆分基线;实现时可在不破坏分层的前提下微调文件名。

16.1 harness:通用工作流内核

packages/harness/deerflow/workflows/
├── __init__.py
├── schemas.py                    # 图、节点、边、NodeResult、运行参数 DTO
├── state.py                      # WorkflowState 与确定性 reducer
├── errors.py                     # 稳定错误码和异常类型
├── expressions.py                # 安全变量引用与模板求值
├── validator.py                  # 发布前结构/引用/资源限制校验
├── registry.py                   # NodeRegistry 与 executor factory
├── compiler.py                   # 标准图 → LangGraph StateGraph
├── events.py                     # 事件类型、envelope、EventSink 协议
├── context.py                    # RunContext、取消令牌、依赖接口
├── nodes/
│   ├── __init__.py
│   ├── base.py                   # NodeExecutor 协议
│   ├── start.py
│   ├── output.py
│   ├── agent.py
│   ├── skill.py
│   ├── http.py
│   ├── sql_read.py
│   ├── code.py
│   ├── transform.py
│   ├── condition.py
│   ├── merge.py
│   ├── human_input.py
│   └── subworkflow.py
├── security/
│   ├── __init__.py
│   ├── http_policy.py            # SSRF、域名、重定向、响应大小
│   ├── sql_policy.py             # AST、只读规则、表白名单
│   └── redaction.py              # 事件/日志脱敏
└── execution/
    ├── __init__.py
    ├── service.py                # 单 run 执行用例
    ├── checkpoint.py             # interrupt/resume checkpoint 适配
    └── limits.py                 # 超时、步骤、循环、预算

16.2 persistence:定义、运行、事件和数据源

packages/harness/deerflow/persistence/workflows/
├── __init__.py
├── model.py                      # definition/version ORM
├── base.py                       # repository 协议
└── sql.py                        # SQLAlchemy 实现

packages/harness/deerflow/persistence/workflow_runs/
├── __init__.py
├── model.py                      # run/node_run ORM
├── base.py
└── sql.py                        # claim/lease/CAS/idempotency

packages/harness/deerflow/persistence/workflow_events/
├── __init__.py
├── model.py
├── base.py
└── sql.py                        # append/list/max_seq/批量写入

packages/harness/deerflow/persistence/workflow_data_sources/
├── __init__.py
├── model.py
├── base.py
└── sql.py

packages/harness/deerflow/persistence/workflow_embed/
├── __init__.py
├── model.py
├── base.py
└── sql.py

需要修改:

  • packages/harness/deerflow/persistence/models.py:汇总新 ORM model,确保 create_all 和迁移发现。
  • packages/harness/deerflow/persistence/types.py:仅在现有 portable 类型不足时扩展,禁止模型直接使用仅某一数据库支持的类型。
  • alembic/versions/<revision>_add_workflow_studio_tables.py:正式迁移。
  • 仓库现有 MySQL 增量脚本目录:按当前约定补齐等价 DDL,不能只依赖 create_all。

16.3 app:FastAPI、后台任务和资源适配

app/gateway/routers/workflows.py                 # 定义/草稿/发布/版本
app/gateway/routers/workflow_runs.py             # start/get/events/SSE/cancel/resume
app/gateway/routers/workflow_resources.py        # agents/skills/subworkflows/node-types
app/gateway/routers/workflow_data_sources.py     # 数据源管理/测试/元数据
app/gateway/routers/workflow_embed.py            # iframe ticket/exchange
app/gateway/routers/workflows_coze_compat.py      # 最小 Coze DTO 兼容层

app/gateway/workflow_executor.py                 # app 依赖注入后调用 harness runtime
app/gateway/workflow_dispatcher.py               # scan/claim/lease/wakeup/shutdown
app/gateway/workflow_event_hub.py                # 单进程实时 fan-out;DB 仍为事实来源
app/gateway/workflow_dependencies.py             # Agent/Sandbox/HTTP/SQL adapter 组合

需要修改:

  • app/gateway/deps.py:创建 repositories、event hub、executor、dispatcher,放入 app.state。
  • app/gateway/app.py:注册 routers,生命周期中启动/停止 dispatcher。
  • config.yaml:增加工作流运行上限、SSE、数据源和 iframe origin 配置;密钥继续使用环境变量/凭据引用。
  • packages/harness/deerflow/config/:如需强类型配置,在此增加 workflow_config.py,不要让 harness 读取 app.state。

16.4 测试文件

tests/test_workflow_schemas.py
tests/test_workflow_validator.py
tests/test_workflow_expressions.py
tests/test_workflow_compiler.py
tests/test_workflow_runtime.py
tests/test_workflow_parallel_merge.py
tests/test_workflow_loop_limits.py
tests/test_workflow_agent_node.py
tests/test_workflow_skill_node.py
tests/test_workflow_http_policy.py
tests/test_workflow_sql_policy.py
tests/test_workflow_code_sandbox.py
tests/test_workflow_run_repository.py
tests/test_workflow_event_repository.py
tests/test_workflow_stream.py
tests/test_workflow_stream_replay.py
tests/test_workflow_cancel_resume.py
tests/test_workflow_dispatcher.py
tests/test_workflow_embed_auth.py
tests/test_workflow_coze_compat.py
tests/test_workflow_migrations.py

tests/test_harness_boundary.py 必须继续通过。

17. 分阶段开发计划

阶段 0:协议冻结与样例图(2–3 人日)

  • 冻结内部 graph schema、NodeResult、错误码和 SSE envelope v1。
  • 建立“专题报告生成”标准样例图及每类节点最小样例。
  • 确认 MySQL/PostgreSQL 首期支持范围、凭据存储方式和 iframe 部署域名。
  • 用 ADR 记录“Coze 只负责画布、ChatDev 只参考、LangGraph 为执行内核”。

交付:schema 文档、事件表、样例 JSON、接口 OpenAPI 草案。

阶段 1:定义、版本与 Coze 保存兼容(5–8 人日)

  • 新建 workflow definition/version repository 和迁移。
  • 实现草稿 revision 乐观锁、validate、publish。
  • 实现节点目录和 Coze canvas/save/node_template 最小适配。
  • 前端可以真实加载、编辑、保存、发布工作流,但尚不执行。

阶段 2:运行骨架与持久 SSE(7–10 人日)

  • 新建 run/node_run/event 表。
  • 实现 run start/get/list/cancel 和 idempotency。
  • 建立 PersistingEventSink、event hub 和 SSE replay/tail。
  • 实现 dispatcher 租约、重启恢复和空图/start→output 运行。
  • 先完成事件顺序、断线重连、终态一致性测试。

阶段 3:基础数据处理节点(7–10 人日)

  • start/output/transform/condition/merge。
  • HTTP 节点及 SSRF/大小/超时策略。
  • SQL 数据源管理、元数据和只读查询节点。
  • code 节点接 DeerFlow sandbox。
  • 完成并行、错误分支和 artifact 引用。

阶段 4:智能体、技能和流式工具步骤(7–12 人日)

  • AgentNode 接定制 DeerFlow Agent。
  • agent_skill 模式。
  • 模型 delta、工具 started/finished、artifact 事件映射。
  • JSON 输出 schema、超时、取消和有限重试。
  • 以“采集→整理→撰写→审核”跑通端到端。

阶段 5:人工介入、子工作流和受控循环(5–8 人日)

  • awaiting_input/resume 与一次性 resume token。
  • 子工作流版本绑定和层级事件。
  • 显式循环、max iteration/steps/time/budget。
  • 审核不通过退回撰写节点的业务用例。

阶段 6:iframe 安全与生产加固(5–8 人日)

  • ticket/exchange、strict origin、CSP frame-ancestors。
  • 权限、审计、限流、配额、凭据脱敏。
  • 多 Gateway 实例、租约竞争、数据库短暂失败、SSE 大量重连压测。
  • 事件保留、清理和 artifact 生命周期。

阶段 6 已落地:WorkflowRetentionCleaner 消费 workflows.retention.*;POST /api/workflows/runs/{run_id}/retry;SSE Last-Event-ID;单机租约竞争与 SSE 重连风暴测试。制品文件仍走 sandbox/artifact,不另做工作流专属文件回收。

阶段 7:试点与扩展(持续)

  • 选择 1–2 个报告业务真实试点。
  • 根据执行数据增加 callable skill manifest、更多数据库驱动或专用业务节点。
  • 暂不满足稳定性前,不开放任意用户自建外网 HTTP 和数据库数据源。

18. 端到端报告工作流验收样例

建议以如下图作为首个验收基线:

开始(topic, taskId, dateRange)
  ├─ SQL:查询内部结构化数据
  ├─ HTTP:调用只读业务接口
  └─ Agent:使用检索技能搜集外部材料
          ↓
Merge:合并材料并保留来源
          ↓
Agent:数据整理与事实去重(JSON Schema 输出)
          ↓
Agent:撰写 Markdown 报告
          ↓
Agent:审核,输出 {passed, issues, revisedAdvice}
          ↓
Condition
  ├─ passed=true  → Output + Word/Markdown artifact
  └─ passed=false → Writer(最多回退 2 次)

验收必须覆盖:

  • 用户点击运行后 1 秒内看到 run.created/queued 或明确排队状态。
  • 节点开始、模型文字、工具步骤和 artifact 实时可见。
  • 刷新 iframe 后能从数据库恢复完整时间线并继续追尾。
  • 网络中断后无重复文字、无丢步骤、无跨 run 串流。
  • SQL 写语句、多语句和越权表被发布校验或运行策略拒绝。
  • HTTP 内网探测和云元数据地址被拒绝。
  • 代码超时后沙箱任务终止,Gateway 不受影响。
  • 审核退回次数达到上限时明确失败,不形成无限循环。
  • 取消后不再启动新节点。
  • 最终输出符合 JSON Schema,报告 artifact 可下载。

19. Definition of Done

一个阶段只有同时满足以下条件才算完成:

  • API、数据库迁移、配置和权限实现齐全。
  • 单元、repository、router、流重放和端到端测试通过。
  • 多实例/重启场景不会重复提交终态或丢事件。
  • 所有用户可见事件均可重放且不包含密钥和隐藏思维链。
  • 新代码通过 Ruff、类型检查和 test_harness_boundary.py。
  • 更新后端 README.md、CLAUDE.md/相关架构说明和 OpenAPI 示例。
  • 前后端基于同一个事件 schema fixture 做契约测试。

20. 实施时优先顺序

建议严格按下面顺序推进:

  1. 先冻结标准图和事件协议。
  2. 再做持久化、运行状态机和断线重放。
  3. 先接 start/output/transform,确认基础链路可靠。
  4. 再加 SQL、HTTP、Sandbox 等高风险节点。
  5. 最后接 Agent/Skill、人工介入、循环和复杂分支。

这样 Coze 画布、DeerFlow 后端和 iframe 时间线不会各自形成一套难以兼容的临时协议。