1. 知识管理工具的“不可能三角”:为什么我换到了 AFFiNE
过去几年,我几乎把市面上叫得上名字的知识管理工具都用了个遍。Notion、Confluence、语雀、飞书文档、Miro、Figma Whiteboard、Obsidian……每款工具都有自己擅长的一面,但也都有一个让人头疼的共同问题:文档是文档,白板是白板,数据库是数据库,它们被清楚地分割在不同的应用甚至不同的交互范式里。
做技术方案评审时,我需要在白板上画架构图、拉流程线,又要在文档里写背景、列数据;等方案定下来,还要把结论同步到团队知识库。这个过程中,资料要在三四个工具间来回搬运。更麻烦的是,白板里的架构图画完就“死”了——它无法和文档中的某一段内容联动,也无法直接引用数据库里的任务状态。时间一长,知识库就变成了一堆互相没有关联的静态文件。
后来我注意到AFFiNE这个开源的知识生产平台。它的核心思路很直接:把文档、白板、数据库这三种最常见的知识载体放进同一个编辑环境里,用块(Block)的方式自由嵌套和引用。也就是说,你可以在文档里直接嵌入一块白板,也可以在白板的卡片里引用一段文档内容,甚至可以把数据库视图插进白板节点中间。所有内容共用同一套数据模型,而不是靠复制粘贴维持表面上的“同步”。
这篇内容我会围绕 AFFiNE 的真实体验展开:它底层是怎么设计的、日常工作流怎么搭建、自托管部署怎么做、以及我在使用过程中踩过的坑。如果你正在纠结“用 Notion 还是 Miro 还是 Obsidian”,或者你所在团队有自建知识库的诉求,这篇应该能给你一个相对完整的参考。
顺便说明一下,我这里的体验基于 AFFiNE 的公开版本和开源仓库,版本迭代较快,具体界面上可能有细微差异,但核心逻辑是稳定一致的。
1.1 文档工具和白板工具的割裂,是真实痛点还是伪需求?
有人可能会说,文档和画图分开用不就行了?Word 配 Visio,Confluence 配 draw.io,不也活得好好的。
这么说有一定道理,但如果你的工作流里存在以下任意一种情况,割裂感就会非常明显:
- 架构图里的模块,需要对应到文档章节里的详细说明,改图时同步改文,两者很容易对不上
- 任务看板上的状态变化,需要手动更新到周报/项目文档里
- 会议白板上讨论出的结论,要重新誊写进文档才能归档
- 同一个知识条目,在文档视图看需要详细的文字描述,在管理视图看需要状态和负责人字段
这些问题本质上不是“换个更好的工具”能解决的,而是需要文档、白板、数据表在数据层面天然打通。AFFiNE 采用块模型,所有元素——不管是文本段落、标题、列表、数据库记录,还是白板上的图形节点——都是可以被嵌入、引用、聚合的块。这就让“白板上画完的东西直接变成文档内容”“数据库里的记录以卡片形式出现在白板上”这些操作变成了原生能力,而不是插件拼凑。
1.2 AFFiNE 的定位:文档即画布,画布即文档
AFFiNE 的英文全称拆开看其实是 Affine + Fine 的谐音,官方想表达的是一种“重新(A)定义 FINE”的意味?先不考究命名,单看产品定位就很清楚:它想做的不是又一个笔记软件,而是一个“知识生产平台”。
什么叫“知识生产平台”?我理解有两个层次:
第一层,是内容创建层面的融合。文档、白板、数据库不再是三种独立的文件类型,而是同一个页面里的三种视图。你可以从一张空白画布开始,先用白板把想法画出来;画的过程中觉得某块内容需要展开写,直接在节点上创建子文档;需要跟踪任务状态时,在旁边插入一个数据库表格视图。所有操作在同一个工作区内完成,不需要切换应用。
第二层,是开源生态层面的底座。AFFiNE 的代码完全开放在 GitHub 上,前端、后端、编辑器内核都是公开的。这意味着你的知识资产不绑定在任何一家商业公司的云服务上,你可以自托管一份完全属于自己的实例,也可以基于它的代码做二次开发,把知识系统嵌入到自己的业务产品中。这点对于有数据合规要求的企业、或者长期主义者来说,价值非常大。
2. 底层设计逻辑:离线优先、CRDT 协同和开源内核
AFFiNE 之所以能做到“文档和白板无缝融合”,是因为它的底层设计一开始就不是照着“网页版富文本编辑器”的思路做的。很多人第一次打开 AFFiNE,会下意识把它归类为“又一个 Notion 克隆”,但如果只是文档编辑器,它没必要把白板、数据库、电子书排布全部做成原生块。
这里有几个底层设计值得展开聊:本地优先的数据存储、基于 CRDT 的协同机制,以及完全开源的代码体系。搞懂这三个机制,你就知道它和传统在线文档在本质上的区别。
2.1 “本地优先”到底在解决什么问题
传统在线文档的工作模式是:所有内容都保存在服务器端,客户端只是一个“显示器”。你打开网页看到的每一段文字,都是从服务端拉下来的;你输入的每个字符,都要先上传到服务器,服务器返回确认后,再显示在屏幕上。
这种模式最大的隐患,是一旦服务器不可用或网络不稳定,你的工作流就中断了。哪怕只是暂时断网,你也只能盯着一个无法编辑的页面。更重要的是,你的数据模型和平台绑定——Notion 的数据存在 Notion 的服务器里,哪天服务商调整策略、涨价、或者关停,迁移成本非常高。
AFFiNE 走了另一条路——本地优先。
本地优先的核心思路是:数据默认保存在本地设备上,应用不管有没有网络都能正常工作。读取和写入都直接操作本地数据,速度极快;云端同步是一个后台行为,而不是编辑的前置条件。这跟本地代码仓库的工作方式很像——你本地有完整的代码库,push 到远端只是同步动作,不会因为你断网就不能写代码。
AFFiNE 在本地使用 SQLite 作为存储引擎,数据就在你的设备上;需要协作时,再通过服务端进行同步。对于个人用户来说,这意味着打开应用、创建文档、记录灵感,全程不依赖任何人的服务器;对于企业用户来说,这意味着所有内容可以留存在自己的内部环境里,规避数据出境和数据安防风险。
当然,本地优先也有代价:如果你同时用电脑和手机编辑,且两端的离线编辑存在冲突,就需要有机制来合并。这就引出了第二个核心技术——CRDT。
2.2 CRDT:多人同时编辑不冲突的底层机制
协同编辑的常规方案是 OT(Operational Transformation,操作转换),Google Docs 用的就是这类技术。OT 靠一套中心化服务器来排序和转换每个人的操作,逻辑复杂,每增加一种操作类型,转换算法就要跟着扩展。
AFFiNE 的实现选择了 CRDT(Conflict-free Replicated Data Type,无冲突复制数据类型),具体用的是 Yjs 框架。CRDT 的思路不太一样:它不是一个中心化服务器来仲裁操作,而是让每个客户端都保留完整的数据副本,每个人本地的修改都会产生一个带唯一标识的操作,这些操作通过网络同步给其他客户端,最终每个客户端收到的操作集合是完全一致的,最终合并出的状态也就完全一致。
用生活化的例子来解释:你在一张纸上写字,另一个人也在同一张纸上写字,传统模式是“你们互相等对方写完再写”;OT 模式是“有一个管理员在协调你们谁先谁后”;CRDT 模式是“你们同时在写,写出来的每个动作都带编号,最后把两个人的所有动作合在一起,不管合并顺序怎么变,结果都是同一句话”。所以哪怕两个人在完全离线状态下同时编辑同一个文档,等网络恢复了,CRDT 也能把两份文档合并成一个没有冲突的版本。
CRDT 对知识生产平台的意义在于,它让“文档里嵌白板、白板里嵌文档”这种复杂嵌套场景的协同变得可行。不同协作者可能同时在操作文档正文和白板节点,如果是传统 OT 模型,嵌套结构的操作转换会非常痛苦;CRDT 则天然支持多级嵌套结构的并发编辑,实现起来简单很多。
2.3 开源内核带来的确定性与生态价值
AFFiNE 的整个代码仓库在 GitHub 上公开,采用 MIT 协议(具体协议以仓库 LICENSE 为准)。这一点在很多技术选型讨论里被低估了。
对于普通用户,开源意味着“可审计”。你不用担心自己的笔记数据里被植入了什么不为人知的埋点或后门,因为代码是公开的,有技术能力的人可以自己看;即使自己看不懂,社区也会有人盯着。
对于团队和企业,开源意味着“可自托管”和“可二次开发”。AFFiNE 官方提供了完整的自托管方案,你可以把服务部署在自己的服务器上,数据存储在自己的存储里。如果需要对接内部系统的权限体系、或者扩展特定功能,你可以基于它的代码做定制,而不是等厂商发版。这跟很多企业选择自建 GitLab、自建 Jira 的逻辑是一致的——核心知识资产必须掌握在自己手里。
对于开发者群体,开源还意味着“可参与”。AFFiNE 的社区贡献渠道非常透明,Issue 列表、Roadmap、开发文档都是公开的。你可以在上面提需求、报 bug、提交 PR。我见过不少人在业余时间为它做本地化翻译、写插件、设计主题,这种社区生态带来的工具演进速度,是任何闭源产品都给不了的。
3. 工作区实操:从空白页到一套可用的知识体系
机制讲再多,最终还是要落到“我打开这个工具能干嘛”。这一节我会从实际操作的角度,带你把 AFFiNE 从零开始搭成一整套可以日常使用的知识系统。
完整流程我走下来大概是:建工作区 → 创建文档 → 在文档里插入白板 → 用数据库管理任务 → 用视图切换适应不同场景。整个过程不需要写代码,鼠标点按就能完成。
3.1 文档编辑体验:块级编辑器与斜杠菜单
AFFiNE 的文档编辑器和 Notion 一样,采用块级编辑模型。你输入的每一段内容,不管是标题、段落、列表、引用、待办事项,还是一个代码块、图片、白板、数据库,都是一个独立的块(Block)。
常用操作:
- 输入
/呼出斜杠菜单,可以直接选择插入各种块类型 - 输入
#加空格创建标题,输入-加空格创建无序列表,输入1.加空格创建有序列表 - 选中文字后,会弹出浮动工具条,可以设置加粗、斜体、链接、提醒等属性
- 每个块左侧都有拖拽手柄,可以自由拖动排序、缩进嵌套;也可以把某个块拖到其他文档里,实现跨文档引用
块级模型的好处,在于它的“内容”不是一串不可拆分的 HTML 字符串,而是一棵结构化的数据树。这种结构化让后续嵌入白板、数据库、模板,都有了统一的数据基础。比如你可以在一个“任务”块上添加状态属性、负责人属性、截止日期属性,这些属性在数据库视图里就可以变成表格的一列,在需要的时候自动汇总。
3.2 白板实操:从零画一张架构图
AFFiNE 的白板是我觉得它最能“打”的部分。它不是独立的白板应用,而是作为文档里的一种块存在。你可以在任意文档中插入“白板”块,然后在这块无限画布上自由拖动画框、写文字、连线、插入文档卡片。
具体操作:
- 在文档中插入
/白板,或者直接输入/whiteboard,画布块就出现在文档里了 - 画布上双击,可以直接输入文本生成文字卡片
- 使用左侧工具栏,可以插入几何图形、连线、便签、图片、文档块
- 选中任意元素,右侧属性面板可以调整样式、层级、对齐方式
- 最关键的是:你可以通过“插入文档块”把其他文档作为一个节点拖到画布上,节点会显示文档的实时摘要;你也可以在文档里插入“白板块”的引用,这样白板内容就嵌在文档流中了
这个机制解决了一个我一直觉得非常别扭的问题:以前用 Miro 画架构图,画完了就完事了,图和方案文档是两套内容;现在在 AFFiNE 里,白板就是文档的一部分,文档也是白板的一部分。画完架构图直接在上面写注释,注释又能被其他文档引用,所有内容在同一个图里流转起来。
我用一个比较直观的场景说明:做一次系统重构方案时,我先在文档里写背景和目标,然后插入白板块,用形状画出服务模块的依赖关系;某个模块需要展开细节时,我双击模块节点,给它创建一个子文档,子文档自动关联到这个节点上;最后我插入一个数据库视图,把“重构任务”按状态列出来,拖拽卡片到白板上,变成任务看板。这个过程全程没有离开过一篇文章。
3.3 数据库视图组合:让“不会用数据库”的人也能用起来
很多非技术背景的人一听到“数据库”三个字就紧张。其实 AFFiNE 里的数据库,本质上就是一张可以自定义字段的表格,字段类型支持文本、数字、单选、多选、日期、人员、链接等,跟 Notion 的数据库体验非常接近。
你可以把一系列文档或任务放到数据库里,然后用不同视图观察它们。
比如我管理一个技术分享专栏:
- 表格视图:每个文档一行,字段包括分享主题、状态、主讲人、预定日期
- 看板视图:按“状态”分组,待准备/已审核/已分享,直接用鼠标拖拽文档卡片跨状态流转
- 文档视图:每张卡片展开后就是一篇独立文档,可以在里面写提纲、放资料链接
这个设计最大的价值,是视图只是同一批数据的不同观察角度,不存在“复制一份数据到看板里”的问题。你在看板里把任务拖到“已完成”,表格视图里的状态自动就变了,文档里的内容也跟着联动。
我自己的习惯是:每个项目建一个页面,页面顶部用文字写项目背景,中间插入白板画流程,下面放数据库管理任务清单。一个页面就是一套完整的项目作战室,不再需要在“文档系统”和“项目管理工具”之间来回切换。
4. 自托管部署与数据自主权
如果你个人使用,直接用官方提供的桌面客户端或网页版就够了;但如果你是团队使用、或者对数据敏感度比较高,那我强烈建议做一次自托管部署。这也是 AFFiNE 作为开源项目最吸引人的地方——你可以把自己的知识库完整地部署在自己的服务器上,不依赖任何第三方云服务。
4.1 用 Docker 拉起一个私有实例
AFFiNE 提供了一站式的 Docker 镜像,部署流程很标准。你只需要准备一台有公网 IP 的服务器(2核4G 起步,个人使用足够了),装好 Docker,然后执行下面的命令:
# 拉取 AFFiNE 官方镜像(以 GitHub 仓库 ghcr.io/toeverything/affine 为例) docker pull ghcr.io/toeverything/affine:stable # 启动容器,映射端口并挂载数据目录 docker run -d \ --name affine \ --restart always \ -p 3010:3000 \ -v /opt/affine_data:/app/data \ ghcr.io/toeverything/affine:stable说明一下几个配置项:
-p 3010:3000:把宿主机 3010 端口映射到容器内的 3000 端口,访问http://你的服务器IP:3010就能打开 AFFiNE 界面-v /opt/affine_data:/app/data:把容器内的数据目录挂载到宿主机上,这一步非常关键,否则重启容器数据就没了
启动完成后,用 Nginx 配置一个反向代理和 HTTPS 证书,就可以用域名访问。更完整的部署文档(包括 docker-compose 写法、环境变量配置、升级流程)在 AFFiNE 的开源仓库 README 里都有,部署前建议先通读一遍。
这里想多说一句:自托管不等于“不需要运维了”。镜像更新、磁盘备份、访问安全都要你操心。如果是个人或小团队用,压力不大;如果是公司层面的知识库,建议至少搭配一套监控和定期备份机制。这个投入换来的,是你的知识资产完全在自己的掌控范围内。
4.2 数据目录与备份恢复
自托管之后,最重要的就是备份。AFFiNE 自托管实例的数据都保存在挂载的数据目录里,包括文档内容、白板数据、数据库记录和用户账号信息。
我的备份策略是双保险:
- 全量目录备份:用 cron 每天凌晨把
/opt/affine_data打包压缩,传到对象存储或另一台机器上 - 数据库级备份:如果部署过程使用了内置数据库,建议同时导出 SQLite 或对应数据库的备份文件
恢复的流程也不复杂:把备份文件解压回原目录,然后重新启动容器即可。我建议在第一次部署完成后,就立刻做一次“备份-恢复”演练,确认备份文件确实可用。很多人辛辛苦苦做了备份,真到恢复的时候才发现文件损坏或路径不对,那就尴尬了。
4.3 多人协同时的“管理员责任”
如果你是团队自托管,你还需要承担“管理员”的角色。AFFiNE 支持添加协作者,多人可以同时编辑同一个文档或白板,协同能力基于前面说到的 CRDT 机制,整体非常流畅。但作为自托管管理员,你要额外注意:
- 用户账号管理:定期清理离职人员的账号权限
- 数据容量监控:白板和文档多了以后,磁盘占用会涨得比较快,做好容量规划
- 访问安全:建议通过反向代理启用 HTTPS,并为管理端设置强密码,有条件的话可以接入 OAuth/OIDC 认证
5. 实际使用中遇到的坑和解决思路
工具再好,落地使用时总会遇到一些文档里不会写的问题。这里分享几个我在实际使用 AFFiNE 过程中踩过、并且已经解决掉的坑,希望能帮你少走一些弯路。
5.1 导入 Markdown 后的格式重整问题
AFFiNE 支持从 Markdown 文件导入文档。我很早就把过去的笔记沉淀成了 Markdown 文件,所以第一次迁移时直接批量导入了一大堆.md文件。
导入之后发现一个问题:Markdown 里用#定义的标题层级,导入后会正确转成标题块,但代码块里如果包含特殊符号,偶尔会出现解析错位;还有一些表格类内容,导入后格式会丢失,需要手动重建。
解决思路是:批量导入前,先对 Markdown 文件做一次标准化处理。比如统一标题层级、清理无效 HTML 标签、确保代码块标记闭合。另外,AFFiNE 的导入功能也在持续完善中,如果你用的是最新版,体验会好很多。
5.2 白板节点太多导致编辑卡顿
白板是 AFFiNE 的强项,但它也有性能边界。我在一个白板上画了上百个节点、几十条连线之后,拖动画布时能明显感觉到卡顿。这是因为每个节点都是一个块,且持续参与 CRDT 的状态同步,节点越多,需要计算和渲染的数据量就越大。
我的解决套路是:
- 按主题拆分白板,不要把无限画布当成“无限堆积”的垃圾桶
- 不需要频繁编辑的历史方案,可以把它导成 PDF 或截图归档,然后从当前工作区移除
- 如果必须保留大量节点,建议关闭实时协作,减少同步带来的渲染压力
还有一个操作层面的技巧:引用文档块、而不是复制内容到白板。比如某个节点需要在白板上展示文档内容,直接引用该文档的链接,而不是把整篇内容贴进节点,性能会好很多,数据也统一。
5.3 同步状态不明确时,先查网络和版本
AFFiNE 的同步是后台自动完成的,但我在使用中遇到过“状态看起来没更新”的情况。排查下来的原因通常不是软件 bug,而是下面几个问题之一:
- 多个端使用了不同版本,导致本地数据结构差异;解决办法是把所有端升级到一致版本
- 网络被防火墙拦截了同步端口;如果你使用自托管实例,要确认客户端和服务端的同步端口是通的
- 本地离线编辑了大量内容,重新联网后,CRDT 合并需要时间,短时间看状态没有变化是正常的,等一会儿再刷新
如果你在自己的自托管实例上使用桌面客户端,这些点尤其值得注意。
5.4 中文字体与排版细节
AFFiNE 默认的字体和排版对中文的适配还算不错,但如果你对中文排版细节要求比较高,可能会觉得默认行距和字号偏大偏散。解决办法是修改编辑器样式,或者自己在设置里调小字体。如果是用 Electron 桌面端,可以在系统的自定义 CSS 里调整。官方主题体系正在完善中,后续应该会有更灵活的自定义能力。
6. 对“开源知识生产平台”这六个字的个人理解
说得更直接一点:在 AFFiNE 身上,我看到了一个“知识系统”应该有的样子——不是一堆功能块的随机堆叠,而是从底层数据模型上就为知识的生产和流动而设计。文档、白板、数据库这些概念,在传统工具里是割裂的应用边界,在 AFFiNE 里只是同一份数据的几种呈现方式。
这也引出了一个更深层的问题:我们到底需要什么样的知识管理工具?
我的观点是,知识管理工具不应该只是“记东西的地方”,它应该是“生产想法的车间”。文档负责组织文字论证,白板负责梳理结构和发散思维,数据库负责跟踪任务和状态。三者协同,才构成完整的知识生产闭环。AFFiNE 选择把这些能力做进同一个内核,而不是靠集成多个工具拼凑,这个方向是我个人非常认可的。
开源则是这个方向最坚实的底座。你不用担心它不被认可、被收购、或者停止维护。只要社区还在,你随时可以 fork 一份继续发展。你的知识资产永远属于你。
所以如果你目前正在为知识工具的选择发愁,我的建议是:先别急着大搬家,把 AFFiNE 装起来,试着用文档 + 白板 + 数据库的完整流程跑一个小项目,感受一下“在一个地方完成思考和输出”到底是什么体验。工具这东西,适不适合自己,实际用一次比看十篇评测都准。