从商业化工具开始的探索
很久以前,我曾经试图用一个工具整合各种需求,即所谓「All in One」,结果却是让工具内部变得臃肿和笨重,后来还是逐渐放弃了。
现在,我做笔记用的是 Obsidian 和 Notion,任务管理用滴答清单,剪藏管理用 Cubox(都是少数派商店里面的好货)。这样将需求拆解到不同工具之后,很多复杂脚本被现成功能取代,工作确实简单了一些。但相应的代价则是需要在工具之间跳转,而它们的协作缺乏了一些「灵性」。
针对这种问题,市场上出现了许多基于 API 的自动化平台,试图让用户以较低门槛打通不同应用。这其中的行业领先者包括 Zapier 和 IFTTT 等,都是少数派读者耳熟能详的,在少数派上也有不少关的深度教程,例如:
经过检索,我发现在 AI 兴起之后,很多这类服务都快速添加了调用 OpenAI API 的功能。但是它们有一个共同的缺点(或者是我自己的缺点……),就是太贵了。可以对比一下此类产品的价格:
产品 | 价格 |
---|---|
Zapier | 免费用户每月 100 次任务。最低升级价格 $20/月,含 750 次任务 |
IFTTT | 免费用户可保存 3 个自动化(Applets)。含有 AI 功能的升级方案升级 $5/月 |
集简云 | 免费用户每月 500 次执行。升级一年 ¥1990,每月可执行 1500 次 |
HiFlow(腾讯轻联) | 免费用户每月 1000 次执行。升级一年 ¥980,每月 3000 次 |
原则上,我是非常支持为互联网企业的创新功能付费的,但是日常用户的需求并没有强烈到能支撑这种价格。特别是 Zapier,已经像是「轻奢品」的范畴了。
本文中,我将介绍自己如何搭建开源、可自建的自动化工具 n8n,并演示几个真实用例。在此基础上,我将对用自动化工具辅助工作的未来提出一些展望,以及就个人如何跟进这新的一轮「产业革命」提出些小小看法。
在经历一系列摸索之后,我最终找到了一个可用且免费的替代品——n8n。
n8n 是一个开源的自动化控制台。它具有设计简洁的图形界面,可以非常清晰地展示数据在各种服务之间流动的过程。对于入门用户,n8n 提供了丰富的模板,也有活跃的社区支持。

n8n 提供官方托管服务,定价也不便宜。但得益于开源属性,可以比较方便地在自己的 NAS 或 VPS 上部署,从而不需要任何额外开销。
用 Docker Compose 安装 n8n
n8n 的安装方式有多种选择,我选择的是 Docker Compose 方案,这也是一种比较容易上手的方案。(下面的步骤假定读者掌握基本的终端操作,且已经安装好 Docker。)
[ 编注:我们之前会员文章介绍过的 YunoHost 也可以快速安装 n8n。]
首先,获得 n8n 项目代码,并找到其中写好的 Docker Compose 配置:
# clone n8n source code
git clone https://github.com/n8n-io/n8n.git
# go to docker-compose directory
cd n8n/docker/compose/withPostgres
这个目录下有四个文件:
.env
: (必选)打开后根据提示编辑其中的三处用户名和密码。前两组用于数据库,最后一组用于浏览器登录使用。docker-compose.yml
:(可选)打开编辑 n8n 相关设置,如果有域名,这里可以绑定域名,在services.n8n.environment
部分添加- N8N_HOST="[domain name or IP]"
即可;如果有更换端口的需求也可以自行更改。README.md
、init-data.sh
:维持原样不动。
之后执行:
docker-compose up -d
即可成功部署。
此时,访问 [服务器域名 or IP]:5678
时,即可使用刚刚在 .env
中编辑的最后一组登录密码进入管理页面。
n8n 的基本使用

n8n 的管理页面非常简洁,左侧分别为:
- Workflows:创建和管理自动化流程
- Templates:社区已有的一些模板,可以直接查找使用
- Credentials:管理第三方服务的登录验证信息
- All executions:已经执行过的日志记录
在 Workflows 页面选择 Add Workflow,就可以创建新的工作流程了。
不过,在创建我们的工作流之前,需要简单介绍 Workflow 中最重要的两个元素——触发器和节点。
触发器(trigger)是一个 Workflow 中的起点,设定的条件满足后,就会执行后续的流程。一个 Workflow 中可以有多个触发器。
新建一个 Workflow 之后,第一步就会要求添加一个「起点」,这个起点就是触发器。

触发器的类型有如下几种:

- On app event:由第三方应用中的事件触发。
- On a schedule:定时触发。
- On webhook call:通过 webhook 触发,即在其他应用中向 n8n 发送 HTTP 请求 触发。
- Manually:手动点击按钮触发。
- When called by another workflow:通过其他 Workflow 的调用触发。
- 其他场景:针对文件变更、报错等特殊场景。
触发器的后续步骤都是节点(node),即根据流程需要依次执行的指令。

节点的类型非常多样,大家可以自己根据 n8n 的文档(可以通过每个节点设置中的 Docs 标签,或者一些待填项目右侧的问号按钮访问)摸索。我这里只简单介绍本文主要用到的,也是最灵活、最通用的两个节点。
首先,HTTP Request 节点用于发送请求,设置内容是很标准的方法、URL、鉴权方式和请求内容等。这里有个很方便的 Import cURL 按钮。因为很多 API 文档里都会提供 cURL 命令格式的示例,浏览器开发者工具也支持直接复制 cURL 命令格式的请求,用这个按钮就可以自动将其参数填写到对应的设置项中,不用自己一一手动操作了。

其次是 Execute Command 节点,可以直接执行 Shell Script,是我最常用的节点。

除此之外,n8n 也内置了丰富的控制流节点(如分支和循环)、第三方应用节点等,这与商业化服务类似,不再赘述。
实例演示:从滴答清单到 Notion
下面进入正题:我是如何将滴答清单和 Notion 通过 n8n 结合的。
作为一个本土软件,滴答清单在海外为主的自动化平台中受支持比较少,n8n 也没有专门支持。好消息是,滴答清单的 API 比较开放,理论上可以纯靠发送 HTTP 请求实现各项功能。坏消息是,滴答清单官方 API 文档显然有些过时了,跟着操作无法正常读取信息和任务列表。
为此,我想到一个取巧的办法:在 Github 上搜索 Dida365 和 API,抄抄别人的作业。这一搜果然有收获,通过阅读别人的代码,我发现先通过用户名和密码登录,获取 Cookies,就可以登录并操作网页版滴答清单,实现任务的搜索和编辑了。
定期获取 Cookies
首先我设置了一个专门用于登录的 Workflow。由于登录一次之后,Cookie 可以保存一段时间,所以我们可以利用这种机制减少登录频率,减少被认为是不合理使用的风险。

这里,第一个节点是定时触发器,每天早上 8 点会触发这个工作流,刷新一次 Cookies 并存储下来,供后续其他 Workflow 使用。

上图中,0 8 * * *
是 Crontab 格式表达的「每天八点」。(你可以从 Crontab guru 这个网站学习和编写 Crontab 表达式。)
接下来添加一个 HTTP 节点用于登录。

API 和 header 的信息按照上图进行设置。用到的部分固定参数如下(来源于从浏览器开发者工具测试并导出请求):
- URL:
https://api.dida365.com/api/v2/user/signon?wc=true&remember=true
- authority:
api.dida365.com
- referer:
https://dida365.com/webapp/
- origin:
https://dida365.com
然后打开 Send Body,在其中设置内容类型为 JSON。添加两个名称分别为 username
和 password
的参数,值分别为滴答清单的用户名(手机号码或者邮箱)和密码。

设置完成之后就可以进行一些简单的测试了。
n8n 中的每一个节点都有 Execute node 按钮,点击可以单独执行这个节点进行调试。

测试结果可以用表格或者 JSON 的形式输出。

上图中,我们看到节点成功获取了登录 token。
那么,如何让其他的 Workflow 使用这里的 token 呢?这里就需要使用 n8n 特殊的设计:Execute Command 节点,这也是它比其他很多服务更灵活强大之处。
本质上,Execute Command 的功能是在 n8n 的运行环境(这里是我们的 Docker 容器)中运行给定的 Shell 脚本。这里的 Shell 脚本可以直接访问运行环境的各个目录,例如 Linux 的通用临时文件路径 /tmp
。我们可以将各种变量写入 /tmp
目录的文件中,从而作为「全局变量」在各个 Workflow 中进行使用。
为此,我新建一个叫做 store token 的 Execute Command 节点,串接在之前的 Dida login 节点之后。打开其设置,将 Command 设置项右侧的类型从 Fixed 改为 Expression(区别在于是否支持使用变量),然后填入如下命令:
echo {{ $json.token }} > /tmp/token.txt

这里,{{ $json.token }}
是 n8n 嵌入数据等变量的格式,指从(输入节点的)JSON 输出中提取 token
键的值(完整语法可以参考文档)。不过,大多数时候并不需要手动输入,只要将之前测试所得结果中的所需字段直接拖拽到输入框里就行了。
这样就将 token 存入了 /tmp/token.txt
文件中。其他 Workflow 需要使用的时候,使用 Execute Command 节点去读取该文件的内容就可以访问了。
连接 Notion
接下来就是登录并连接到 Notion。这部分稍微复杂一些,设置好后的总览如下(个别脚本在名称里有一些 typo,是我在调试 Workflow 的时候心情烦躁导致的,大家见谅)。

n8n 内置了 Notion 节点,只要绑定自己的 Notion 账户就能使用。为此,打开自己 Notion 账户的 My integrations 页面,添加新的 integration(可以根据自己的需求编辑一个较窄的权限范围,提高安全性),然后复制所得的 token。

之后不要忘记在自己需要编辑的 Notion 页面中添加这个新 integration:

(更详细的步骤参见官方文档。)
回到 n8n,在 Notion 节点中选择 Create New Credential,粘贴上述 token。

此后,n8n 就可以自动化的完成创建页面和编辑页面等一系列操作了。以下是我的各个步骤配置示例,读者可以参照并结合自身需求修改使用。
(一)创建 Notion 页面节点
这里,我创建了一个新页面,并添加了一个 Daily Report 的 H1 级别标题。

(二)存储页面 ID
这里,我效仿之前步骤中的思路,将 Notion 的页面 ID 存储下来,方便后续调用。
echo {{ $json.id }} > /tmp/lastid.txt

(三)获取滴答清单 token
这里,我用 cat
命令获取了之前滴答清单步骤记录下在 /tmp
目录中的 token 信息。

(四)获取当日任务列表
这里,我从滴答清单中获取了当日任务列表,其中的查询范围是用 n8n 的内置时间变量组合成的 ISO 8601 格式。

- URL:
https://api.dida365.com/api/v2/project/all/completed
- from:
{{ $now.minus({days:1}).setZone('Asia/Shanghai').toISO().slice(0, 11).replace(/-/g, "-").replace("T", " ") + "00:00:00"}}
- to:
{{ $now.minus({days:1}).setZone('Asia/Shanghai').toISO().slice(0, 11).replace(/-/g, "-").replace("T", " ") + "23:59:59"}}
- limit:
50
Header 部分需要将之前取到的 token 写入 cookie 中,用于鉴权,配置方式如下。这里,用到了 $node["节点名"]
表达式,获取特定节点的输出(请无视这里的 typo)。

(五)Split in Batch 节点
这个节点可以将刚刚获取的一串数据依次送入下一个节点。Batch Size 输入 1,每次只向 Notion 页面中写入一个任务的信息。

(六)获取 Notion 页面 ID
将刚刚的 Notion 页面 id 取回:
cat /tmp/lastid.txt

(七)任务信息写入 Notion 页面

这里使用了多个节点的信息,拖动输入不太方便了,而且有些 bug,建议手动编辑:
- Block:
{{ $node["Fetch Last ID"].json.stdout }}
- Task Text:
{{ $node["Split In Batches"].json.title }}
页面串接好并启用之后,每天的 8 点,我在上班的时候就能看到我前一天的任务日报了。
用 OpenAI 创建更多可能性
在研究过程中,我无意中发现了 OpenAI 也有专门的节点:

于是,我尝试了在刚刚的任务流程上再分出一支,可以让 OpenAI 帮我写一个总结,再写回 Notion 中:

不过,实际用下来,AI 在这里的娱乐性大于实用性:我对于 OpenAI 给出的「日报」并不是特别有兴趣。但是,这里也让我看到了更多的自动化可能性,即将 AI 和自己的工作流程进行深度绑定,实现以前从未想过的自动工作流。n8n 社区上已经有一些模板,例如用 AI 将自己的邮箱变成一个智能客服。更多的使用方法还有待挖掘和思考。
n8n 的优劣总结
应当指出,上文用 n8n 实现的所有工作流程,都是可以通过直接写脚本完成的。对于调用 API 而言,一个 curl 命令基本就够了。但是,比起传统的脚本编辑,n8n 的优势也不能忽视:
- 便于编辑:通过图形化、模块化的编辑环境,可以更直观、方便地规划功能、串联步骤;可以独立执行每一个节点并相应调试查看输出。
- 便于使用:可以通过内置功能管理密钥、全局变量等信息,无需明文传递或另行存放。
- 便于管理:可以随时开关节点或整个工作流。
- 便于共享:可以导出 json 文件或创建模板分享给他人。
从这个角度看,n8n 之于脚本,就有点像 Jupyter 之于 Python;相比于功能增加,其意义更多在于提供了一个直观、易用的编辑和运行环境。
相比市面上已有的其他工具,n8n 强大的拓展性和自定义能力也是独树一帜的。如上文所示,可以使用 Shell 命令写入文件达到全局变量的效果;实际上,你还可以在 n8n 的 Docker 环境中安装 Python 库、NPM 包和更多其他命令行工具,增添更多功能。
n8n 目前还不够成熟。首先,我在使用中遇到了很多 bug,例如 OAth2 通过了验证但是无法访问数据,Notion 编辑的时候偶尔会找不到 Block ID,Webhook 触发器可能会失效。此外,用户体验也并不是非常完善,例如节点不能复制到其他的 Workflow,不能批量选中节点进行复制。
缺点很多,但是社区的大家也在共同努力。和其他的 API 自动化工具相比,n8n 在价格和功能上都已经实现了双重碾压。n8n 不嫌弃我穷,我也不会嫌弃他 bug 多呀。
延伸讨论
最后,我想对生产力工具的设计取舍做一些延伸讨论。
一个工具怎样才算「优秀」,能够得到推广乃至出圈?经验表明,这种工具的设计考量往往会超越工具本身,更深入地分析对「场景」和「客户群体」。
人都是有惯性的。若是要替换已有的工作流程中的某些环节,大部分人一定会自然地权衡成本和产出。只有新工具带来的效率提升明显大于学习和使用成本,大家才会主动学习、坚持使用。
这里做一个简单的分析,分别基于老工具和新工具对一些任务进行工时的评估。如果「新工具工时 + 学习成本 < 老工具工时」,就说明「简单的学习可以带来巨大的效率」。

首先分析一些正面案例,例如分别为文档和表格处理带来了便利的 Markdown 和 Excel。这些工具虽然也有进阶的使用方法,但是入门成本相对低廉,并且直接带来了巨大的效率提升,所以在写作、办公等非专业技术群体中的采用率也比较高。
相比之下,git、LaTeX、Obsidian 这些工具的长期收益有目共睹,但学习成本相对较高。我个人而言,会努力学习掌握这些工具;但它们不被更主流多数所接受,也是可以理解的。
还有一些工具,例如早期版本的 Notion、flomo 等,能力上限虽然不是特别高,但足够「无痛」和「易得」,是「小而美」的精致产品。这种工具有简单的出发点和简单的设计,可以凭借极低的学习成本吸引用户。在此基础上,可以通过迭代和开放接口拓展功能和生态,发展成叫好又叫座的效率利器。
因此,我认为一个「好」的效率工具应该从两个重要维度来构建:
- 降低学习成本:方法包括简化设计、提供详细的手册文档、植入已有工作环境等;
- 提高效率加成:方法包括定制设计,找准切入点,开放自动化能力等。
以此分析目前比较火的 GPT 类产品:它的上手成本不高,无非是对话打字,因此吸引很多普通用户尝鲜;但用于实际工作比较麻烦,需要经过粘贴输入——思考 prompt——调试优化 prompt——复制输出等一系列步骤,因此对于大多数人还是显得麻烦。人们在短暂热情之后,接着回归习惯的旧路径也很正常。
我自己虽然深度使用 AI 相关工具,但目前还不认为 AI 能完全取代我的工作,对效率上的提升也并没有达到我的预期。更具体地说,AI 工具目前不具备效率工具需要的稳定性和严谨性。但是在一些需要泛用性和灵活度的地方,AI 还是非常有价值的。
我认为,在自己的工作中,知识储备是根基,各种效率工具是树干和树枝,新生的 AI 工具则像是飞来的是外来者。我们可以让 AI 工具在 n8n 这样的树枝上「筑巢」,栖息于原本的系统之上,为工作流注入新的活力和生机。