n8n 的 AI 工作流导入 PDF 总中断?2.23.4 补上了 DOMMatrix 缺失这一环
n8n 是一个面向技术团队的低代码工作流自动化平台。
它把可视化拖拽编排与 400+ 集成、LangChain 原生 AI 能力结合在一起,
让开发者能快速搭建从数据提取到 LLM Agent 的完整管线。
6 月 5 日发布的 v2.23.4 虽然只是一次 patch 级别的小更新,
但修复的问题恰恰卡住了不少 AI 工作流的起点——PDF 文档加载。
问题出在 Node.js 缺失浏览器专有的 DOMMatrix 全局对象上。
n8n:拖拽编排 + 原生 AI,自部署工作流的标杆
n8n(读作 n-eight-n,源自 "nodemation") 是一款基于 fair-code 许可证的开源平台, 核心定位是给技术团队提供兼具代码灵活性与可视化效率的工作流引擎。 它与 Zapier/Make 这类纯 SaaS iPaaS 的最大区别在于: 代码层面支持 JavaScript/Python 片段与 npm 包, 部署层面提供 Docker 自托管与私有云, AI 层面原生集成了 LangChain 生态。
在技术实现上,n8n 的 monorepo 包含 cli(服务端)、
core(工作流运行时)、nodes-base(400+ 集成节点)、
@n8n/nodes-langchain(AI 子节点)等核心模块。
AI 工作流的典型结构是 Agent 节点连接 LLM Chat Model 与若干 Tool,
而 Tool 的数据来源之一就是文档加载器(Document Loader)。
用户可以把 PDF 合同、CSV 报表、Word 文档等上传到工作流,
经加载器处理后向量化存储,供 LLM 检索问答。
这个入口一旦断裂,后续的 Agent 对话就无数据可用。
痛点:给 AI 喂 PDF 时,Node.js 缺了一个浏览器 API
用 n8n 构建知识库问答或文档摘要工作流的用户, 最常用的节点就是 Default Data Loader。 选择 PDF 格式后,它会将 PDF 的每一页解析为独立的 LangChain Document 对象,然后送入向量库或直接作为 Agent 上下文。
然而在实际运行中,部分用户会遇到 PDF 解析静默失败或抛出异常。 原因不在 n8n 的逻辑,而在于其底层的 PDF 解析技术栈:
• n8n 的 PDF 加载器 N8nPdfLoader 基于 pdf-parse v2 实现
• pdf-parse v2 的核心依赖是 pdfjs-dist——Mozilla PDF.js 的 npm 发行版
• PDF.js 最初是为浏览器环境设计的,
它在渲染过程中依赖 DOMMatrix 这个浏览器 DOM API
来做坐标变换计算
问题来了:
Node.js 在 v20 之前完全没有 DOMMatrix 实现
(即使 v21+ 的全局 DOMMatrix 也是实验性的,
且行为与浏览器版本不完全一致)。
所以当 n8n 在 Node.js 运行时中调用 PDF 解析函数时,
pdfjs-dist 在初始化阶段就会因为找不到 DOMMatrix
而崩溃——一条 PDF 都读不出来。
对于一台工作流服务端,这等于 AI 数据管线在入站处直接断路。
更隐蔽的是,问题不是所有环境都必现:
如果用户用了低版本 pdf-parse 或其他 PDF 库可能绕过,
但一旦升级到 v2,踩坑概率很高。
能力:惰性 polyfill,一条 if 语句消除中断
n8n@2.23.4 的修复非常聚焦——只改动了一个文件
packages/@n8n/ai-utilities/src/utils/loaders/n8n-pdf-loader.ts,
新增的代码不足 5 行有效逻辑,
但效果却是从「跑不起来」到「无感运行」。
修复后的 PDF 加载器在 parse() 方法的开头
增加了惰性 polyfill 模式:
解析 PDF 之前的瞬间,检查 globalThis 上是否有 DOMMatrix
如果不存在 -> 动态导入 @thednp/dommatrix,挂到全局
如果存在 -> 跳过,不额外加载
继续执行 pdf-parse 的解析流程
这一做法的设计考量有三点:
按需加载不浪费。
@thednp/dommatrix 是一个轻量(约 3KB gzip)
的 DOMMatrix 纯 JS 实现,
只有在 DOMMatrix 未定义时才被动态引入。
对于已经在 Node.js v22+ 中内置了 DOMMatrix 的环境,
这条分支根本不走,零开销。
不影响下游消费方。
N8nPdfLoader 的输出与 LangChain 社区版的 PDFLoader 完全一致
——每页一个 Document 对象,包含 pageContent、
metadata.loc.pageNumber、metadata.pdf.* 等字段。
向量库、摘要链、检索逻辑都不需要做任何修改。
兼容新旧两种文本拆分模式。 n8n v1.1 版本的 Default Data Loader 提供了「Simple」模式 (内置 1000 字符/200 重叠的递归拆分), 不再强制要求用户额外连接 Text Splitter 子节点。 PDF 解析完成后,文档内容直接进入拆分环节, 整个管线无缝衔接。
原理:浏览器 API 在 Node.js 中的补丁模式
DOMMatrix 缺失引发崩溃,
本质上是一个经典问题的新案例:
当浏览器生态的库被复用到服务端时,
边界 API 的缺口怎么补。
pdfjs-dist 依赖 DOMMatrix 来做 PDF 页面中的坐标变换,
例如文字定位、矢量图形缩放、旋转矩阵计算。
在浏览器中,DOMMatrix 是 window 下的原生构造函数,
由浏览器引擎(如 Chrome 的 Blink)在 C++ 层实现,性能极好。
Node.js 并未内置这一 API——globalThis 上没有 DOMMatrix
——所以 pdfjs-dist 在调用 new DOMMatrix() 时会直接抛异常。
n8n 的选择是用 @thednp/dommatrix 来填补。
它不依赖任何 DOM 环境,纯粹用 JavaScript 实现了 DOMMatrix 规范
(包含 translate、rotate、scale、multiply 等方法),大小约 10KB。
更重要的是,它通过 Reflect.set(globalThis, 'DOMMatrix', DOMMatrix)
注入到全局作用域——pdfjs-dist 在库初始化时
通过 typeof DOMMatrix 判断可用性,
一旦发现全局有定义就会直接使用,
不需要改动 pdfjs-dist 的任何代码。
这种 全局 polyfill + 惰性加载 的组合并非 n8n 独创, 在服务端使用 Puppeteer、jsdom、Cloudflare Workers 等场景都很常见。 但 n8n 这次把它落到了自己的 AI 文档加载器上, 解决了一个直接影响用户体验的「纯后端问题」。 对于自部署 n8n 的用户而言,升级到 2.23.4 后, PDF 文档加载不会再因为 Node.js 环境差异而静默失败 ——无论跑在 Docker、K8s 还是裸机节点上,体验是一致的。
对于在 Node.js 上构建文档管线
(特别是涉及 PDF 解析)的开发者来说,
这个案例也提供了一个可复用的模式:
在调用 pdfjs-dist 或类似库之前,
先用 @thednp/dommatrix 打好补丁,
能规避未来因 Node.js 版本或运行环境变化带来的兼容隐患。
夜雨聆风