跳转到内容

Flowise 的插件化节点系统:动态发现、加载与 Feature Flag 禁用机制

学习目标

  • 理解 Flowise INode 接口规范:节点必须实现的属性与方法
  • 掌握节点的自动注册机制与分类体系
  • 了解 Feature Flag 禁用机制与社区节点管理

前置知识

本章为项目特定的工程实践。建议先阅读:


项目实践

INode 接口规范

每个 Flowise 节点必须实现 INode 接口:

interface INode {
label: string // 显示名称
name: string // 唯一标识(内部使用)
version: number // 节点版本号
type: string // 节点类型
icon: string // 图标路径
category: string // 分类(决定在画布中的分组)
description: string // 描述
baseClasses: string[] // 基类(决定可连接到哪些下游节点)
inputs?: INodeParams[] // 输入参数定义
outputs?: INodeOutput[] // 输出定义
init(nodeData, options): Promise<any> // 执行方法
}

节点分类体系

Flowise 在 packages/components/nodes/ 下按分类组织节点:

分类目录节点数说明
chatmodelsnodes/chatmodels/30+LLM 模型(OpenAI、Anthropic、Google 等)
toolsnodes/tools/40+工具(搜索、日历、邮件、代码执行等)
vectorstoresnodes/vectorstores/24向量数据库
documentloadersnodes/documentloaders/20+文档加载器
embeddingsnodes/embeddings/10+嵌入模型
memorynodes/memory/13记忆后端
retrieversnodes/retrievers/6+检索器
chainsnodes/chains/10+LLM 链
multiagentsnodes/multiagents/2Supervisor、Worker
agentflownodes/agentflow/12AgentFlow V2 节点
sequentialagentsnodes/sequentialagents/12Sequential Agent 节点
promptsnodes/prompts/5+提示词模板
outputparsersnodes/outputparsers/5+输出解析器
textsplittersnodes/textsplitters/4+文本分割器
cachenodes/cache/3+缓存后端
moderationnodes/moderation/2+内容审核

自动注册流程

节点示例

packages/components/nodes/chatmodels/ChatOpenAI/FlowiseChatOpenAI.ts
class ChatOpenAI_Flowise implements INode {
label = 'ChatOpenAI'
name = 'chatOpenAI'
version = 3.0
type = 'ChatOpenAI'
icon = 'openai.svg'
category = 'Chat Models'
description = 'OpenAI 的 GPT 系列模型'
baseClasses = ['BaseChatModel', 'ChatOpenAI']
inputs = [
{
label: 'Model Name',
name: 'modelName',
type: 'asyncOptions',
default: 'gpt-4o'
},
{
label: 'Temperature',
name: 'temperature',
type: 'number',
default: 0.9
},
// ...更多输入参数
]
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
// 初始化并返回 ChatOpenAI 实例
return new ChatOpenAI({
modelName: nodeData.inputs?.modelName,
temperature: nodeData.inputs?.temperature,
// ...
})
}
}
module.exports = { nodeClass: ChatOpenAI_Flowise }

节点间的连接规则

baseClasses 定义节点可以连接到哪些下游节点:

// LLM 节点的输出类型
baseClasses = ['BaseChatModel', 'ChatOpenAI']
// Agent 节点的输入要求
inputs = [
{
label: 'Model',
name: 'model',
type: 'BaseChatModel' // 只接受 BaseChatModel 类型的输出
}
]

Flowise 在画布中根据 baseClassestype 自动过滤可连接的节点。

Feature Flag 禁用机制

// 环境变量
DISABLED_NODES=nodeA,nodeB,nodeC
// 启动时检查
const disabled_nodes = process.env.DISABLED_NODES?.split(',') ?? []
const isDisabled = disabled_nodes.includes(newNodeInstance.name)
if (isDisabled) {
// 跳过注册
}

社区节点管理

const isCommunityNodesAllowed = appConfig.showCommunityNodes
const isAuthorPresent = newNodeInstance.author
if (!isCommunityNodesAllowed && isAuthorPresent) {
conditionTwo = false // 不注册社区节点
}

问题与规避

节点命名冲突

问题:两个节点使用相同的 name,后加载的会覆盖先加载的。

对策

  • 每个节点的 name 应该全局唯一
  • 遵循命名约定:chatOpenAIbufferMemory 等小驼峰
  • NodesPool 使用 Object.assign 合并节点,后加载的优先

依赖缺失导致加载失败

问题:节点依赖的 npm 包未安装,require(file) 抛出异常。

对策

  • 节点加载的 try/catch 捕获异常并记录日志,不阻止服务器启动
  • 在节点文档中明确列出依赖包
  • package.json 中声明 peerDependencies

baseClasses 不匹配

问题:上游节点的 baseClasses 与下游节点的 type 不匹配,画布中无法连接。

对策

  • 仔细设计节点的 baseClasses,确保与所有可连接的下游节点的 type 匹配
  • 参考已有节点的 baseClasses 定义
  • 使用更通用的基类(如 BaseChatModel)而非具体类名

设计取舍

文件扫描注册 vs 显式注册表

维度文件扫描显式注册表
新节点开发只需导出 nodeClass需要修改注册表文件
可发现性目录即注册表需要查找注册表
加载控制只能全量加载可按需加载
调试加载失败静默跳过显式错误

Flowise 选择文件扫描,因为:

  • 社区贡献者无需修改核心代码即可添加新节点
  • 目录结构自然反映节点分类
  • 配合 DISABLED_NODES 环境变量实现加载控制

宽泛的 baseClasses vs 精确的类型匹配

维度宽泛 baseClasses精确类型匹配
灵活性高(同类节点可互换)低(只能连接特定类型)
安全性低(可能连接到不兼容的节点)高(确保类型兼容)
用户体验友好(更多连接选项)严格(减少错误连接)

Flowise 选择宽泛的 baseClasses(如 BaseChatModel 而非 ChatOpenAI),让不同模型提供商的节点可以互相替换。


参考来源