Skip to content

Chain Parser 开发设计文档

1. 概述

ChainParser 是 Tinyflow AI 工作流编排框架中的工作流定义解析器,负责将 JSON 格式的可视化工作流(由 Tinyflow 前端流程图工具生成)转换为可执行的 ChainDefinition 对象。它采用插件化架构,支持灵活扩展新的节点类型,实现了可视化编排 → 代码执行的关键桥梁。

本文档深入解析 ChainParser架构设计、解析流程、扩展机制与最佳实践,帮助开发者构建可定制、可维护的工作流解析体系。

2. 核心设计原则

2.1 插件化节点解析(Pluggable Node Parsing)

  • 每种节点类型(如 llmNodehttpNode)由独立的 NodeParser 实现
  • 通过 Map<String, NodeParser<?>> 动态注册/替换解析器
  • 优势:解耦核心解析逻辑与节点实现,便于扩展

2.2 分层解析(Layered Parsing)

  1. 基础属性解析BaseNodeParser):
  • ID、名称、描述
  • 输入/输出参数(parameters / outputDefs
  • 执行策略(循环、重试)
  • 节点条件(condition
  1. 节点特有逻辑doParse):
  • 由具体 NodeParser 实现(如 LlmNodeParser 解析 llmIdprompt

3. 架构组成

3.1 核心组件

组件职责
ChainParser主解析器,协调节点/边解析
NodeParser<T>节点解析接口,泛型约束返回类型
BaseNodeParser<T>基础解析器,实现通用属性解析
DefaultNodeParsers内置节点解析器注册中心

4. 解析流程详解

4.1 入口方法

java
public ChainDefinition parse(String jsonString) {
    JSONObject root = JSON.parseObject(jsonString);
    return parse(root, root.getJSONArray("nodes"), root.getJSONArray("edges"), null);
}

4.2 节点解析

  1. 类型识别:从 nodeObject.type 获取节点类型
  2. 解析器查找nodeParserMap.get(type)
  3. 通用属性解析BaseNodeParser.parse):
  • 基础信息(ID、名称、描述)
  • 参数(parameters / outputDefs
  • 执行策略(循环、重试)
  • 条件(JsCodeCondition
  1. 特有属性解析doParse):由子类实现

4.3 边解析

  • edgeObject 提取 source/target
  • 解析 data.conditionJsCodeCondition
  • 子流程支持:过滤父节点到子流程入口的边(避免重复)

4.4 参数模型

Parameter 支持丰富元数据,便于前端渲染表单:

字段用途
formType表单控件类型(input/select/textarea)
formLabel字段标签
formPlaceholder占位符
enums枚举选项(下拉框)
contentType内容类型(text/json/image)
children嵌套参数(用于复杂对象)

5. 扩展机制

5.1 自定义节点解析器

步骤 1:实现 NodeParser

java
public class CustomNodeParser extends BaseNodeParser<CustomNode> {
    @Override
    protected CustomNode doParse(JSONObject node, JSONObject data, JSONObject chain) {
        CustomNode node = new CustomNode();
        // 解析特有属性
        node.setApiEndpoint(data.getString("apiEndpoint"));
        node.setAuthKey(data.getString("authKey"));
        return node;
    }
}

步骤 2:注册解析器

java
// 方式1:构建时注册
ChainParser parser = ChainParser.builder()
    .addParser("customNode", new CustomNodeParser())
    .build();

// 方式2:动态注册
parser.addNodeParser("customNode", new CustomNodeParser());

5.2 覆盖默认解析器

java
// 替换内置 llmNode 解析器
ChainParser parser = ChainParser.builder()
    .addParser("llmNode", new MyEnhancedLlmNodeParser())
    .build();

5.3 禁用默认解析器

java
// 仅使用自定义解析器
ChainParser parser = ChainParser.builder()
    .withDefaultParsers(false)
    .addParser("myNode", new MyNodeParser())
    .build();

6. 内置节点解析器

DefaultNodeParsers 提供以下开箱即用的解析器:

节点类型解析器用途
llmNodeLlmNodeParser大语言模型调用
httpNodeHttpNodeParserHTTP API 调用
codeNodeCodeNodeParser脚本执行(Groovy/JS)
knowledgeNodeKnowledgeNodeParser知识库检索
templateNodeTemplateNodeParser字符串模板处理
searchEngineNodeSearchEngineNodeParser搜索引擎查询
confirmNodeConfirmNodeParser人工确认节点
loopNodeLoopNodeParser循环控制
startNode/endNodeStartNodeParser/EndNodeParser流程起止

💡 扩展建议:通过 DefaultNodeParsers.registerDefaultNodeParser() 全局注册新解析器

7. 最佳实践

7.1 解析器设计

继承 BaseNodeParser:复用通用属性解析逻辑
doParse 专注特有属性:避免重复解析 ID、参数等
空值安全:对 JSON 字段做 hasText() / null 检查

7.2 JSON Schema 设计

前端生成的 JSON 应遵循约定结构:

json
{
  "nodes": [
    {
      "id": "llm-1",
      "type": "llmNode",
      "label": "调用大模型",
      "data": {
        "llmId": "gpt-4o",
        "userPrompt": "你好,{{name}}!",
        "parameters": [
          { "name": "name", "required": true, "formType": "input" }
        ],
        "outputDefs": [
          { "name": "response", "dataType": "String" }
        ],
        "retryEnable": true,
        "maxRetryCount": 3
      }
    }
  ],
  "edges": [
    {
      "id": "e1",
      "source": "start",
      "target": "llm-1",
      "data": {
        "condition": "input.age > 18"
      }
    }
  ]
}

8. 高级特性

8.1 子流程支持

通过 parentId 字段实现嵌套工作流:

java
// 仅解析顶层节点(parentNode == null)
if ((parentNode == null && StringUtil.noText(nodeObject.getString("parentId")))
    || (parentNode != null && parentNode.getString("id").equals(nodeObject.getString("parentId")))) {
    // 解析节点
}

8.2 条件表达式

  • 边/节点条件使用 JsCodeCondition
  • 支持 JavaScript 表达式(如 "input.score > 90"
  • 运行时通过 ScriptEngine 执行

8.3 表单元数据

参数中的 form* 字段支持前端动态生成配置表单:

java
Parameter param = new Parameter();
param.setFormType("select");
param.setEnums(JSONArray.of("option1", "option2"));
// 前端可渲染为下拉框

9. 自定义实现示例

9.1 数据库查询节点

java
public class SqlNode extends BaseNode {
    private String dataSource;
    private String sqlTemplate;
    // getters/setters
}

public class SqlNodeParser extends BaseNodeParser<SqlNode> {
    @Override
    protected SqlNode doParse(JSONObject node, JSONObject data, JSONObject chain) {
        SqlNode sqlNode = new SqlNode();
        sqlNode.setDataSource(data.getString("dataSource"));
        sqlNode.setSqlTemplate(data.getString("sqlTemplate"));
        return sqlNode;
    }
}

// 注册
ChainParser parser = ChainParser.builder()
    .addParser("sqlNode", new SqlNodeParser())
    .build();

9.2 解析 JSON

json
{
  "type": "sqlNode",
  "data": {
    "dataSource": "user-db",
    "sqlTemplate": "SELECT * FROM users WHERE name = '{{input.name}}'",
    "parameters": [{"name": "name", "required": true}]
  }
}

10. 总结

ChainParser 是 Tinyflow 工作流引擎的可视化编排入口,通过插件化、分层解析的设计,实现了灵活扩展、结构清晰、前后端协同的工作流定义解析能力。开发者可基于其构建从简单自动化到复杂智能体协作的各类可视化 AI 应用。