拆 n8n 的引擎Node.js Vue3 400 节点拖拽比写代码灵活是怎么做到的【免费下载链接】n8nFair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400 integrations.项目地址: https://gitcode.com/GitHub_Trending/n8/n8n把工作流自动化做成拖拖拽拽就行这个口号喊了很多年但大多数低代码产品拖到复杂场景就崩要么编排能力撑不住分支和循环要么一旦碰到表达式、自定义代码就立刻露怯。n8n 是少数把这两头都做扎实的开源项目——画布上拖的是节点节点背后跑的是 TypeScript 引擎用户写{{ $json.title }}时系统不只是在做字符串替换而是在隔离的 VM 里执行一套真正安全的表达式运行时。本文直接拆它的仓库源码看看拖拽比写代码灵活这句话在工程上到底是怎么落地的。架构骨架一份工作流两个执行语境n8n 的仓库是一个 pnpm monorepo关键不在包多而在边界划得清晰。前端画布在 packages/frontend/editor-ui后端执行在 packages/n8n/engine而两者共享的工作流心智模型被抽到了 packages/workflow/src/workflow.ts。编辑器的技术栈很直白Vue3 Pinia Vue Router vue-i18n见 packages/frontend/editor-ui/package.json画布本身基于vue-flow/core渲染节点与连线配合vuedraggable做拖拽。也就是说前端负责的是把工作流变成看得见摸得着的图。真正有意思的是Workflow这个类。它既不在浏览器里独占也不属于后端而是通过IS_FRONTEND这样的运行时标记packages/workflow/src/runtime-environment.ts做到前后端同构编辑器里做测试运行走的是同一套Workflow数据结构和同一套表达式求值逻辑生产环境执行用的还是它们。工作流存下来只是一段 JSON——节点数组加连接表——但Workflow构造函数会把这段 JSON 补全成可执行形态按节点类型补齐参数默认值、建立connectionsBySourceNode与connectionsByDestinationNode双向索引再实例化一个WorkflowExpression用于解析所有表达式。数据结构即契约画布上拖出来的图和引擎里跑起来的图是同一份数据。执行侧这两年做了大重构。老的WorkflowExecute被拆成以 step 为中心的异步引擎代码集中在 packages/n8n/engine/src/execution一次执行被切成queued → running → waiting → completed / failed / cancelled等状态见 packages/n8n/engine/src/execution/execution.types.ts每个节点的运行结果进入 step store由 step-ready / step-settled 两个 handler 驱动推进规划orchestration与执行step走两条独立队列避免步骤洪流饿死调度packages/n8n/engine/src/execution/step-worker.ts 注释里写得很明确。对循环的处理尤其体现工程深度画布上的循环在图论上就是一条回边back-edge引擎用 Tarjan 算法求强连通分量把每个回边目标推导成一个WorkflowLooppackages/n8n/engine/src/graph/loops.ts区分入口边、回边、出口边。更妙的是这个引擎被设计成可嵌入的独立 runtime——createEngineRuntime把数据库、准入策略、外部依赖全部作为适配器注入packages/n8n/engine/src/runtime/create-engine-runtime.ts这意味着同一套执行内核既能嵌进 n8n 主进程也能被其他宿主复用。节点即配置一份描述同时驱动 UI 与执行器n8n 现在内置的节点分布在 packages/nodes-base/nodes561 个节点文件和 packages/n8n/nodes-langchain/nodes139 个节点文件两处加上 1500 集成与 9000 模板README.md。数量多不难难的是多而不乱。每个节点的定义都遵循INodeTypeDescription接口packages/workflow/src/interfaces.ts 第 3121 行起version声明版本inputs/outputs声明连接口properties声明参数表单credentials声明凭据还有requestDefaults可以声明式地描述整个 REST API 调用。这意味着很多 HTTP 类节点根本不需要写一行执行逻辑——参数表单、请求构造、响应处理全部由DeclarativeRestApiSettings配置驱动。节点对引擎而言是描述即代码这是低代码平台能批量长出成百上千个节点而不失控的根本原因。版本化是另一个关键设计。节点类型用VersionedNodeType包裹例如 AI Agent 节点就同时维护着 V1、V2、V3 三套实现packages/n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts老工作流按各自声明的typeVersion继续跑旧逻辑新工作流默认用3.1。表达式求值在遇到节点时也是按getByNameAndVersion(node.type, node.typeVersion)精确定位packages/workflow/src/workflow.ts。向后兼容不是靠冻结旧版而是靠每个版本都有独立实现。值得一提的还有节点元数据里的codex字段——它给节点声明了别名、分类与builderHint构建提示。比如 AI Agent 节点声明了alias: [LangChain, Chat, ReAct, Tools]并给languageModel()、memory()、tool()这些子节点装配方法写了完整示例同一文件里可以看到trigger(...)、languageModel(...)、outputParser(...)组成的可复制代码模板。这套元数据既服务画布搜索也让 AI 辅助构建节点成了可能——节点先定义机器能读懂的自己然后编辑器、文档、甚至 LLM 都从同一份描述里取信息。表达式系统拖拽参数里藏着一门被沙箱化的语言拖拽的终点是参数。而参数里那些{{ ... }}表达式才是 n8n 灵活性的真正来源。用户在节点参数里可以写{{ $json.email }}、{{ $node[HTTP Request].json.id }}、{{ $(Other Node).item.json.title }}——这套语法由 packages/workflow/src/expression.ts 和WorkflowDataProxypackages/workflow/src/workflow-data-proxy.ts实现所有$json、$node、$parameter、$vars之类的数据根本质上是 Proxy 暴露出来的只读视图pairedItem机制还能从下游节点反向追溯到上游某条具体数据。但能写表达式不难让用户随便写还不被攻击才难。n8n 的做法是双层防线第一层是 AST 级清洗用n8n/tournament遍历语法树把constructor、__proto__、defineProperty、setPrototypeOf等危险访问路径在编译期拦掉packages/workflow/src/expression-sandboxing.ts第二层是把表达式真正放进isolated-vm的独立 isolate 里执行宿主只通过结构化克隆交换数据并施加内存与超时上限packages/n8n/expression-runtime/src/bridge/isolated-vm-bridge.ts。跨 isolate 的错误还会在宿主侧重建为类型化的ExpressionErrorpackages/workflow/src/expression.ts 的mapVmError。性能上还有一个被大多数文章忽略的细节n8n 为表达式做了一个原生快路径。绝大多数用户表达式只是取数据、拼字符串、做简单比较为此它在 packages/workflow/src/expressions/native-evaluation 里定义了一个闭子集语法——只有字面量、数据根访问、固定操作符、白名单字符串/数组方法、以及五个受控迭代器packages/workflow/src/expressions/native-evaluation/grammar.ts。命中子集的表达式不进 isolate直接在进程内由解释器求值结果用 LRU 缓存packages/workflow/src/expressions/native-evaluation/index.ts 缓存上限 1024 条、单表达式 1 万字符。这套能进子集走快路、进不去才进沙箱的分级策略让表达式求值既安全又足够快。AI 原生把 LangChain 编排装进画布节点n8n 的 AI 能力不是接个 OpenAI 节点那么简单它把整条 LangChain 编排链视觉化了。看 packages/n8n/nodes-langchain/nodes 的目录结构就能感受到agents、chains、llms、memory、tools、retrievers、vector_store、output_parser、document_loaders——这不是几个散装节点而是一套完整的 AI 原语库。核心是AI Agent 根节点模式。一个 AI Agent 节点n8n/n8n-nodes-langchain.agent作为主节点其余 AI 能力都以子节点形式插到它的输入口上languageModel(...)接模型OpenAI、Anthropic 或本地模型可平替切换memory(...)接记忆outputParser(...)接结构化输出而工具则来自tools目录下的 ToolCode、ToolHttpRequest、ToolVectorStore 等节点。一个可回退的 Agent 甚至支持双模型数组——第一个模型失败时自动切到第二个packages/n8n/nodes-langchain/nodes/agents/Agent/Agent.node.ts 的needsFallback配置。这套抽象最聪明的地方在于AI Agent 对引擎来说仍然只是一个节点。它同样有inputs/outputs、同样吃表达式参数、同样参与$json数据流。于是普通自动化与 AI 工作流可以无缝混排——前面是 Webhook 收数据中间过一个 Agent 节点做判断后面再走 HTTP 节点写回 CRM全程没有跨系统断层。社区情报里反复出现的400 节点、AI 原生、自托管这些卖点落到代码层面其实就是一句话AI 被降维成了图上的普通节点。结语拖拽比写代码灵活之所以在 n8n 这里不是营销话术是因为它把三件事做到了位其一用一份声明式节点描述同时驱动画布、执行器与文档让 400 节点可维护其二用AST 清洗 isolated-vm 闭子集快路径让表达式系统既强大又安全其三把 AI 编排折叠成普通节点让自动化与智能体在同一条数据流里共生。对想自建低代码/工作流平台的团队来说这套 monorepo 里的边界划分——workflow共享模型、engine独立执行内核、nodes-base声明式节点——本身就是一份可抄的作业。【免费下载链接】n8nFair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400 integrations.项目地址: https://gitcode.com/GitHub_Trending/n8/n8n创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考