跳转到内容

Flow JSON 契约与持久化协议

学习目标

  • 理解 Flow JSON 的结构和每个字段的契约含义
  • 掌握 Flow 的序列化(dump)和反序列化(load)流程
  • 了解加载时迁移策略:新字段自动兼容,缺失字段回退到默认值
  • 学会修改 Flow JSON 时不破坏已有保存的 Flow

前置知识


项目实践

1. Flow JSON 结构

Flow JSON 是 Langflow 中最重要的用户契约,由 Graph.dump() 方法生成:

{
"data": {
"nodes": [
{
"id": "ChatInput-abc123",
"type": "genericNode",
"data": {
"type": "ChatInput",
"node": {
"template": {
"input_value": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "你好"
}
},
"display_name": "Chat Input",
"description": "Receive chat message input.",
"icon": "message-square",
"edited": true
}
},
"position": { "x": 100, "y": 200 }
}
],
"edges": [
{
"source": "ChatInput-abc123",
"target": "ChatOpenAI-def456",
"sourceHandle": {
"id": "ChatInput-abc123",
"name": "message",
"output_types": ["Message"]
},
"targetHandle": {
"id": "ChatOpenAI-def456",
"fieldName": "input_value",
"type": "str",
"inputTypes": ["Message"]
}
}
]
},
"is_component": false,
"name": "My Flow",
"description": "..."
}

关键字段契约:

路径契约类型规则
nodes[*].data.type组件类型标识必须匹配注册的组件 name,否则加载失败
nodes[*].data.node.template[*]输入字段键名匹配组件的 Input.name
nodes[*].data.node.template[*].value输入值用户配置的实际值,加载时直接回填
edges[*].sourceHandle.name输出端口名匹配组件的 Output.name
edges[*].targetHandle.fieldName输入端口名匹配组件的 Input.name
edges[*].targetHandle.inputTypes类型兼容检查加载时验证输出类型是否与输入类型兼容

2. 序列化流程

3. 加载时迁移策略

Flow JSON 加载时的迁移策略基于宽容设计:

关键设计:

  • 新增字段:必须是 optional,带默认值 → 旧 Flow 加载时自动使用默认值
  • 删除字段:旧 Flow 中的值被忽略 → 不会崩溃,但用户配置丢失
  • 重命名字段:旧 Flow 中的键名在新组件中不存在 → 连线失效,这是回归
  • 类型收紧:旧 Flow 中传递的值类型不兼容新组件 → 加载失败,这是回归

4. Starter Projects 作为规范示例

src/backend/base/langflow/initial_setup/starter_projects/ 中的 JSON 文件是 Flow JSON 的规范示例:

  • 每个 Starter Project 引用真实组件的 name 和 type
  • 组件变更时,Starter Projects 必须更新并重新验证
  • CI 会在组件变更后自动检查 Starter Projects 是否仍可加载

为什么 Starter Projects 是契约的一部分:

  • 它们是用户首次接触 Langflow 时看到的模板
  • 它们验证了组件的向后兼容性:如果组件变更导致 Starter Project 无法加载,说明契约被破坏
  • 文档和教程中的截图和深链接指向这些文件

问题与规避

陷阱现象对策
组件重命名后 Starter Project 无法加载启动时报 “Component X not found”使用 legacy=True + replacement 保持旧名称可解析
新字段无默认值旧 Flow 加载时新字段为 undefined所有新字段必须有合理的默认值
导出时凭证泄露Flow JSON 中包含明文 API Key导出时自动将凭证替换为 Variable 引用
边的类型不兼容加载后连线显示为红色错误状态加载时验证边的类型兼容性,不兼容时标记警告但不崩溃

设计取舍

宽容加载 vs 严格校验:

维度宽容加载严格校验
用户体验旧 Flow 始终可加载不兼容时明确报错
隐性错误用户可能不知道某些配置已失效错误立即可见
迁移动力无强制力,用户可能长期运行在降级状态强迫用户更新 Flow
生产安全降级运行可能无感知崩溃可能导致服务中断

Langflow 选择宽容加载策略,核心原因是 Flow 是生产中的用户产物。宽容加载保证了即使组件发生变更,已有的 Flow 也不会突然停止工作。缺失字段回退到默认值,多余字段被忽略,只有在组件类型完全不存在时才报错。


参考来源

  • 源码:src/lfx/src/lfx/graph/graph/base.py — dump() / dumps() 方法
  • 契约文档:docs/agents/CONTRACTS.md — 契约 #7(Flow JSON schema)
  • Starter Projects:src/backend/base/langflow/initial_setup/starter_projects/