Skip to content

Feature: 节点间数据流

一句话目标

用户在下游节点触发 AI 生成时,系统自动收集所有上游节点的输出内容,按数据类型注入到生成请求的对应参数中。三个生成接口均支持文本、图片、视频三种输入类型,具体哪些输入生效由模型能力决定。

与画布系统的关系

连线的一切(创建、删除、渲染、持久化、验证、连接角色规则)均属于画布系统。数据流不管理连线,只通过 flowStore 的 edges 读取"谁连着谁",基于此收集上游节点数据。

行为约束

约束 1:数据收集时机

前置条件: 用户在下游节点点击生成 行为: 系统通过 flowStore.edges 找到所有以该节点为 target 的连线,读取对应 source 节点的输出 后置条件: 上游数据在生成请求发出前收集完毕,作为参数注入

约束 2:输出内容提取规则

上游类型提取字段说明
textresult(优先)或 content(回退)result 是 AI 生成结果,content 是用户编辑内容(HTML,需剥离标签);两者都是节点的"产出"
imageimageUrl当前展示的主图 URL
videovideoUrl当前视频 URL

不提取 prompt(那是生成指令,不是产出内容)

约束 3:上游输出注入下游参数的规则

收集到上游输出后,按数据类型注入到下游生成请求的对应参数:

  • 文本类输出 → 拼接到下游 prompt 前面(上游文本在前,用户 prompt 在后,空行分隔)
  • 图片类输出 → 注入下游 images[] 参数
  • 视频类输出 → 注入下游 videos[] 参数

三个生成接口(文本、图片、视频)均接受这三种输入参数。哪些输入实际生效由模型能力决定,数据流层只负责收集和注入,不判断兼容性。模型不支持的输入类型由后端忽略或返回错误。

约束 4:多上游合并策略

前置条件: 下游节点有多条入边 行为: 按连线创建时间顺序收集;同类型上游输出合并(文本拼接,图片追加到 images[],视频追加到 videos[]后置条件: 合并后的参数传递给 AI Service

约束 5:上游无输出时静默跳过

前置条件: 上游节点 status 为 idle 或输出字段为空 行为: 跳过该上游,不报错、不阻塞 后置条件: 下游正常生成,仅携带有输出的上游数据

约束 6:全量注入,不判断兼容性

前置条件: 上游输出已收集 行为: 全量注入到请求参数中,不判断模型是否支持该输入类型 后置条件: 由后端根据模型能力决定如何处理不支持的输入(忽略或报错)

兼容性的前置提示属于 model-capabilitiesedge-system AC-11 的职责。

约束 7:上游数据为只读快照

前置条件: 收集上游数据时 行为: 读取上游节点当前时刻的输出值,不建立响应式绑定 后置条件: 上游后续变更不影响已发出的生成请求

约束 8:prompt 拼接规则

前置条件: 存在上游文本输出且用户有自身 prompt 行为: 上游文本在前,用户 prompt 在后,以空行分隔 后置条件: 拼接后的完整文本作为 prompt 参数发送

格式:

{上游文本1}
{上游文本2}

{用户prompt}

仅上游文本或仅用户 prompt 时不拼接,直接使用有值的部分。

约束 9:自身媒体与上游媒体合并

前置条件: 下游节点自身有媒体(如 ImageNode 已上传图片、VideoNode 已截帧) 行为: 自身媒体与上游同类型媒体合并(去重),自身在前、上游在后 后置条件: 合并后的列表作为 images[]videos[] 参数发送

Acceptance Criteria

收集层(约束 1、2)

  • [x] AC-01:下游节点生成时,自动通过 edges 收集所有上游节点的输出内容
  • [x] AC-02:文本节点输出提取 result(优先)或 content(回退),HTML 标签剥离为纯文本
  • [x] AC-03:图片节点输出提取 imageUrl
  • [x] AC-04:视频节点输出提取 videoUrl

注入层 — 文本类(约束 3、8)

  • [x] AC-05:上游文本拼接到下游 prompt 前面,空行分隔用户 prompt
  • [x] AC-06:仅有上游文本无用户 prompt 时,prompt 为上游文本本身
  • [x] AC-07:仅有用户 prompt 无上游文本时,prompt 不变

注入层 — 图片类(约束 3、9)

  • [x] AC-08:上游图片注入 TextNode 的 images[] 参数
  • [x] AC-09:上游图片注入 ImageNode 的 images[] 参数,与自身图片合并去重
  • [x] AC-10:上游图片注入 VideoNode 的 images[] 参数

注入层 — 视频类(约束 3)

  • [x] AC-11:上游视频注入 TextNode 的 videos[] 参数
  • [x] AC-12:上游视频注入 ImageNode 的 videos[] 参数
  • [x] AC-13:上游视频注入 VideoNode 的 videos[] 参数

合并与边界(约束 4、5、7)

  • [x] AC-14:多上游节点的输出按连线创建顺序合并
  • [x] AC-15:上游节点无输出时静默跳过,不阻塞下游
  • [x] AC-16:收集的上游数据为只读快照,不建立响应式绑定

BDD Scenarios

gherkin
Feature: 节点间数据流

  # AC-01, AC-02, AC-05
  Scenario: 文本节点输出拼接到下游 prompt
    Given 文本节点 A 已生成内容 "一只可爱的猫"
    And A 连线到图片节点 B
    And B 的用户 prompt 为 "添加翅膀"
    When 用户在 B 中点击生成
    Then B 的生成请求 prompt 为 "一只可爱的猫\n\n添加翅膀"

  # AC-02 回退路径
  Scenario: 文本节点无 result 时回退到 content(HTML 剥离)
    Given 文本节点 A 未触发过生成
    And A 的编辑器内容为 "<p>手动输入的描述</p>"
    And A 连线到图片节点 B
    When 用户在 B 中点击生成
    Then B 的 prompt 中包含纯文本 "手动输入的描述"

  # AC-06
  Scenario: 仅有上游文本无用户 prompt
    Given 文本节点 A 已生成 "赛博朋克城市"
    And A 连线到图片节点 B
    And B 的用户 prompt 为空
    When 用户在 B 中点击生成
    Then B 的生成请求 prompt 为 "赛博朋克城市"

  # AC-07
  Scenario: 无上游文本仅有用户 prompt
    Given 图片节点 A 已生成图片(无文本输出)
    And A 连线到图片节点 B
    And B 的用户 prompt 为 "变成油画风格"
    When 用户在 B 中点击生成
    Then B 的 prompt 为 "变成油画风格"(不拼接)

  # AC-08
  Scenario: 图片节点输出注入文本节点
    Given 图片节点 A 已生成图片
    And A 连线到文本节点 B
    When 用户在 B 中点击生成
    Then B 的生成请求 images 参数包含 A 的 imageUrl

  # AC-09
  Scenario: 图片节点输出注入图片节点(合并去重)
    Given 图片节点 A 已生成图片 url-1
    And 图片节点 B 自身已上传图片 url-1
    And A 连线到 B
    When 用户在 B 中点击生成
    Then B 的 images 参数为 ["url-1"](去重后)

  # AC-10
  Scenario: 图片节点输出注入视频节点
    Given 图片节点 A 已生成图片
    And A 连线到视频节点 B
    When 用户在 B 中点击生成
    Then B 的生成请求 images 参数包含 A 的 imageUrl

  # AC-11
  Scenario: 视频节点输出注入文本节点
    Given 视频节点 A 已生成视频
    And A 连线到文本节点 B
    When 用户在 B 中点击生成
    Then B 的生成请求 videos 参数包含 A 的 videoUrl

  # AC-14
  Scenario: 多上游按连线顺序合并
    Given 文本节点 A 已生成 "一只猫"
    And 文本节点 C 已生成 "在花园里"
    And A 先连线到图片节点 B,C 后连线到 B
    When 用户在 B 中点击生成
    Then B 的 prompt 中 "一只猫""在花园里" 之前

  # AC-05, AC-09 组合
  Scenario: 混合类型上游分别注入对应参数
    Given 文本节点 A 已生成 "赛博朋克风格"
    And 图片节点 C 已生成图片
    And A 和 C 均连线到图片节点 B
    And B 的用户 prompt 为 "添加霓虹灯"
    When 用户在 B 中点击生成
    Then B 的 prompt 为 "赛博朋克风格\n\n添加霓虹灯"
    And B 的 images 参数包含 C 的 imageUrl

  # AC-15
  Scenario: 上游无输出时静默跳过
    Given 文本节点 A 处于 idle 状态(无 result 且 content 为空)
    And A 连线到图片节点 B
    When 用户在 B 中输入 prompt 并点击生成
    Then B 正常发起生成请求,prompt 仅为用户输入

TDD 单元测试要点

收集层(collectUpstreamOutputs,测试文件 test/unit/collectUpstream.test.ts):

  • [x] 给定 edges 和 nodes,正确找到指定节点的所有上游节点
  • [x] 文本节点:result 有值时提取 result,为空时回退到 content
  • [x] 文本节点:HTML 内容剥离标签,空 HTML 视为无输出
  • [x] 图片节点:提取 imageUrl
  • [x] 视频节点:提取 videoUrl
  • [x] 上游无输出时返回空,不报错
  • [x] 多上游按 edge 创建顺序排列

prompt 拼接函数(buildPrompt,测试文件 test/unit/collectUpstream.test.ts):

  • [x] 有上游文本 + 有用户 prompt → 上游在前、空行分隔、用户 prompt 在后
  • [x] 有上游文本 + 无用户 prompt → 仅上游文本
  • [x] 无上游文本 + 有用户 prompt → 仅用户 prompt
  • [x] 多段上游文本按顺序换行拼接

注入层(各节点 onGenerate):

  • [x] TextNode 注入 images[]videos[]
  • [x] ImageNode 注入 images[](自身+上游去重)和 videos[]
  • [x] VideoNode 注入 images[]videos[]
  • [x] 三种节点都执行 prompt 拼接
  • [x] 无有效上游时参数不受影响

Out of Scope

  • 实时数据流(上游变更自动触发下游重新生成)
  • 条件分支(根据上游内容决定下游行为)
  • 上游输出的版本选择(多 variations 时选择哪一个 — 当前取主图/主结果)
  • 模型能力查询与兼容性判断 — 属于 model-capabilities
  • 连线兼容性警告 UI — 属于 edge-system AC-11/AC-12
  • 输入数量截断(images/videos 超出模型 maxCount 时的处理)— 属于模型能力层职责
  • context 独立字段方案 — 当前采用 prompt 拼接,待后端支持后可切换