
当下,低代码开发平台凭借其可视化构建与快速交付的能力,日益成为企业提升效率、降低开发门槛的核心工具。然而,目前市面上的大多数低代码平台都忽视了多人协同编辑这一关键能力,这已成为制约团队效能的突出短板。
在缺乏实时协同机制的环境中,开发者常常陷入“工作撞车”的尴尬局面:精心配置半天的组件,可能因同事的无意间的覆盖操作而在瞬间清零。这种频繁发生的版本冲突与数据覆盖,不仅带来极大的挫败感,更显著增加了团队沟通与版本管理成本。

跨职能协同已成为现代应用开发的常态。从产品、设计到开发、测试及业务人员,往往需在同一平台上紧密配合才能高效完成应用交付。然而,目前大多数低代码平台仍依赖于传统的“文件锁–上传–合并”机制规避冲突,无法实现真正意义上的实时协同。这种类似于“流水线轮流作业”的协作模式,严重制约了团队并行输出的能力,已成为提升交付效率的主要瓶颈。

如今用户已被 Google Docs、腾讯文档、Figma、Notion 等优秀协同工具“教育”并“惯坏”,他们对协同操作的体验预期已被提升至前所未有的高度。
用户期待的低代码协同体验应包括:
这些来自消费级协同工具的优秀体验重塑了用户的使用习惯,正不断推动低代码平台由传统的 “开发效率工具” 向真正的 “团队协作平台” 演进,也使高质量的多人在线协同从“加分项”转变为“必选项”。
如下图所示,是我们在基于AST的低代码项目中的协同实现效果:

在此前的文章中,我们曾深入介绍过基于 AST 的低代码平台的整体架构与实现原理。与传统低代码平台普遍基于私有 DSL 的方式不同,该平台依托源码级的 AST 驱动引擎,不依赖任何私有 DSL 或封闭协议,真正实现了“源码进、源码出”,具备实时出码与多场景源码适配能力。这种架构在为开发者提供高度灵活性和透明度的同时,也对多人实时协同提出了更高要求——如何在不破坏 AST 结构一致性的前提下,实现操作的同步与合并成为关键挑战。
本文将系统性地介绍我们如何在这样的技术基底上,构建一套兼顾实时性、一致性与丰富功能的多人协同操作引擎。从技术选型、架构设计到核心算法实现,分享我们在此过程中的探索路径与最终的成功实践。
实现协同编辑需解决两大核心问题:实时同步与冲突处理。很多人会联想到《王者荣耀》等 MOBA 游戏中使用的帧同步技术,但游戏同步是强制单时间线,而协同编辑允许多时间线并行,还需支持“回滚”等高阶操作,因此复杂度显著更高,具体挑战体现在:
当下协同的主流解决方案包括以下三类:
方案 | 说明 | 优点 | 缺点 |
|---|---|---|---|
❌ 悲观锁 | 同一时间只允许一位用户编辑 | 实现简单,保证强一致性 | 严重限制协作流畅性 |
❌ 自动合并 | 如Git机制 | 适用于异步场景,体验较好 | 对结构化数据冲突处理能力弱,合并复杂 |
✅ 协同算法 | 基于数学理论实现实时一致性 | 支持实时协同,保留操作意图 | 实现复杂,高度依赖数据结构 |
分布式系统一致性核心算法主要包括 OT(Operational Transformation) 与 CRDT(Conflict-free Replicated Data Type)。OT 是1989年提出的经典算法,而CRDT在2011年被系统化总结,代表了更现代的、天生去中心化的协同理论。
OT(操作转换)

CRDT(无冲突复制数据类型)

核心差异对比
特性 | OT (Operational Transformation) | CRDT (Conflict-free Replicated Data Type) |
|---|---|---|
提出时间 | 1989年 | 2011年(理论体系化) |
哲学 | 避免冲突(Avoidance) | 容忍冲突(Tolerance) |
架构 | 中心化,依赖服务器 | 去中心化,服务器仅中继 |
复杂度 | 算法复杂,转换规则难设计 | 数据结构复杂,设计门槛高 |
网络要求 | 需要稳定连接,对服务器性能要求高 | 支持离线编辑,恢复连接后自动同步 |
适用场景 | 文本协同 | 复杂结构、去中心化应用、物联网、边缘计算等 |
基于 JSON Patch 实现客户端冲突处理。Server 仅接受同一版本下的一个 ChangeSet,冲突由后提交的客户端单边处理。
客户端将PPT文档的XML数据转换为JSON格式进行操作,通过差分算法生成 ChangeSet 数据差集。例如,当客户端A、B基于同一版本v100生成 ChangeSet 时,若B的请求先到达,服务端将版本更新为v101并广播通知;A提交时因版本过期被拒绝,需在本地解决冲突后重新生成v101'提交。

该方案基于 JSON Patch 标准(定义了add、delete、replace、move、copy、test六种操作类型),仅同步差异内容而非全量数据,高效支持协同编辑、撤销/重做等操作,详见:https://jsonpatch.com/ 。
腾讯文档3.0升级为双边OT架构,采用 Mutation 原子指令集描述变更,服务端与客户端共同通过转换函数(T-function)实现高效冲突处理与离线支持。
数据模型升级:
核心改进:
冲突解决依托为各类 Mutation 开发的转换函数,例如状态 X 下操作 O₁、O₂ 满足:
X ← O₁ ← T(O₂, O₁) ≡ X ← O₂ ← T(O₁, O₂)使得前后端可自主实现操作还原、序列化与冲突解决,离线编辑亦不受阻塞。
Figma 未采用 OT 方案,主要因其在离线缓存等场景下易引发操作组合爆炸,复杂度高。虽然 CRDT 设计初衷为去中心化系统,会带来一定性能与内存开销,但 Figma 仍借鉴其思想,构建了中心化 CRDT 协同系统。
该系统将设计文件抽象为图形树,以对象属性为最小操作单元。
冲突处理采用 LWW(最后写入获胜) 策略:
例如某文本属性值为“B”,用户A改为“AB”,用户B改为“BC”,最终结果为“AB”或“BC”,取决于谁的修改最后送达服务端。此机制与多数协同表格应用一致,仅富文本协同需合并结果。

基于 AST 的低代码平台需处理结构化数据协同,其复杂性要求算法具备以下能力:
基于以下优势,CRDT成为理想选择:
CRDT 在处理非线性数据结构时展现出显著优势,成为 AST 低代码平台实现实时协同的首选方案。
在 CRDT 的两种实现模式中,选择 基于操作的模式(Op-based CRDT),主要基于以下考量:
• 基于状态(State-based)CRDT 的局限性
节点间需同步完整状态(如整个集合、计数器)。当 AST 结构复杂、文档体量较大时,完整状态的传输将占用大量带宽,同步延迟高,因此在实际生产环境中较少采用。
• 基于操作(Op-based)CRDT 的优势
仅需同步增量操作指令(如"创建组件"、"更新属性"),传输数据量极少。其核心设计要求是:所有操作必须满足交换律(Commutative),即改变操作顺序不影响最终结果。
基于操作的模式天然适合 AST 结构:操作粒度细、传输效率高,支持离线编辑与自动冲突解决,为低代码平台提供了高效可靠的协同基础。
为什么需要交换律?
由于网络延迟与不确定性,各副本接收操作的顺序可能不同。交换律保证了无论顺序如何,最终状态一致。这类似于数学中的加法:a + b 与 b + a 的结果相同。
在低代码平台的协同设计中,传统方案通常基于私有 Schema 协议,可通过 JSON Patch 等方式操作 JSON 数据还原用户操作。然而,在基于 AST 的低代码平台中,用户在画布中的交互(如拖拽、属性配置)涉及更复杂的结构化操作,直接使用 CRDT 原语难以完整描述。因此,我们需要将 UI 操作解构为一组定义良好的原子操作(Mutation),并使其满足交换律,作为 CRDT 同步的基本单元。
CRDT 特别适合此类场景,原因如下:
tid),避免因数组索引变动引发脏路径问题。因此,CRDT所同步的数据并非完整的AST树状态,而是细粒度的操作指令流。通过预定义原子操作并确保其满足交换律,我们可在分布式环境下实现操作序列的可靠同步与合并。对于无法规避的冲突(如并发修改同一属性),则采用附加元数据(时间戳、客户端 ID)的 LWW(最后写入获胜)策略解决,最终在各客户端重建出一致的 AST 状态。
最终,定义了以下 50 个原子操作,覆盖了低代码平台的各种交互场景:
类别 | 操作示例 |
|---|---|
视图操作 | AddRoute, AddFragment, AddModal, UpdatePage, UpdateFragment, UpdateModal, RemovePage, RemoveFragment, RemoveModal, RemoveViewFiles, UpdatePageSize |
视图节点相关操作 | DropNode, InsertNode, InsertBeforeNode, InsertAfterNode, UpdateAttribute, UpdateAttributes, ReplaceNode, RemoveNode, PasteNode, CloneNode |
依赖操作 | UpdateDependency, RemoveDependency |
store变量处理 | AddStoreFile, RemoveStoreFile, AddStoreState, RemoveStoreState, UpdateStoreVariable |
function函数处理 | AddGlobalFunctionFile, RemoveGlobalFunctionFile, AddGlobalFunction, UpdateGlobalFunction, RemoveGlobalFunction |
service服务函数处理 | AddServiceFile, AddServiceFunction, AddServiceFunctions, UpdateServiceFunction, RemoveServiceFunction, UpdateServiceBaseConfig |
插件处理 | AddPlugin, RemovePlugin, UpdatePluginParams, UpdatePluginState |
配置文件操作 | UpdateConfigFiled, GroupLayers, UngroupLayers |
文件操作 | AddFile, RemoveFile, RenameFile, UpdateCode |
这些原子操作共同构成了协同编辑的指令集,确保了操作的可序列化、可同步和最终一致性。
AST 操作天然可分区,大部分UI操作(修改不同组件的属性、在不同区域添加节点)本身就是针对树的不同分支,因此天然具有可交换性 A ⊕ B = B ⊕ A。
例如,两个用户同时操作一颗AST树,用户A更新button2组件的属性,用户B在根节点下创建button3组件:
UpdateProperty(id: "button2", property: "text", value: "Close")CreateComponent(parentId: "Page", component: { id: "button3", ... }, ...)无论操作依何种顺序执行,因两者通过 ID 定位、修改树的不同部分,最终 AST 状态一致。交换律保障了操作顺序不影响结果。
虽然基于操作的 CRDT 仅强制要求交换律,但结合律和幂等律能提供额外的健壮性保障:
结合律使系统能更灵活地处理批量到达的独立操作,操作分组合并不受顺序影响 (A ⊕ B) ⊕ C = A ⊕ (B ⊕ C)。
在 AST 协同中,结合律适用于修改不同对象或属性的独立操作。例如:
UpdateProperty(id: "comp1", key: "color", value: "red")UpdateProperty(id: "comp2", key: "text", value: "Hello")UpdateProperty(id: "comp3", key: "visible", value: false)无论按 (A⊕B)⊕C或 A⊕(B⊕C)的顺序合并,最终 AST 状态一致。结合律使系统能灵活处理批量到达的独立操作。
幂等律能有效应对网络重复消息、客户端重试等异常场景,同一操作多次应用效果与一次相同 A ⊕ A = A。
例如重复执行 UpdateProperty(id: "button2", key: "color", value: "blue"),无论执行次数,按钮颜色终为蓝色。再如重复执行 CreateComponent(parentId: "Page", component: { id: "button3", ... }, ...) 由于 id 的唯一性,导致重复 id 的组件插入失败。
幂等律能有效应对网络重复消息、客户端重试等异常场景,提升系统鲁棒性。
在基于操作的 CRDT 系统中,针对无法通过交换律解决的冲突(如并发修改同一属性),采用以下策略收敛:
• 最后写入获胜(LWW - Last Write Wins)
为每个操作分配全局唯一且单调递增的时间戳(或逻辑时钟)。当检测到针对同一属性的并发修改时,系统自动选择时间戳最大的操作作为最终结果。这是实现最简单、应用最广泛的冲突解决策略。
• 确定性操作转换
对于某些特定类型的操作,可以预定义转换规则。例如,当两个用户同时对同一数值属性进行"增加"和"减少"操作时,系统可以按照确定性的数学规则合并这些操作,而不是简单地选择最后写入的值。
• 操作依赖关系管理
通过维护操作间的依赖关系,确保存在逻辑顺序约束的操作能够被正确执行。例如,针对某个组件的删除操作应该优先于针对该组件的属性修改操作。
在基于 AST 且有中心服务的场景中,LWW 因其实现简单、决策明确成为最合适的选择,能够有效解决大多数属性级别的冲突情况。
设想一个符合逻辑的典型场景:多个操作乱序到达,包含重复传输,且存在需要中心化仲裁的属性冲突:
CreateComponent(parent: "Form", id: "Input1", type: "InputField") 在表单中创建一个输入框UpdateProperty(id: "SubmitBtn", key: "color", value: "blue", timestamp: 1001) 将按钮颜色改为blue(时间戳1001)UpdateProperty(id: "SubmitBtn", key: "color", value: "green", timestamp: 1002) 将同一按钮改为green(时间戳1002)假设操作到达顺序为:B → C → A' → A,系统的处理流程如下:
交换律确保了基础操作的可靠性,而LWW策略则提供了冲突的仲裁方案,二者结合为平台提供了完整的协同解决方案。
为满足低代码平台复杂场景下的实时协同需求,设计了清晰的三层架构,在保证功能完备性的同时,兼顾了性能与可扩展性:

在众多 CRDT 实现中,Yjs 以其成熟性和完整性脱颖而出。它是一个高性能的 CRDT 库,通过共享类型(Shared Types)(如 Y.Array、Y.Map)抽象数据结构,使得任何变更都能自动、无冲突地同步到所有对等节点。
Yjs 具备以下核心特性与优势:
在 AST 低代码项目中选择 Yjs 作为协同框架,主要基于以下原因:
Y.Array、Y.Map)、高效的二进制编码及 WebSocket 集成,显著降低开发复杂度;前面已经提到,系统将复杂的协同操作收敛为50种定义良好的原子操作(Mutation),用于描述对项目源码的所有变更。这些操作通过有限集合的排列组合,可精确还原任意操作后的源码状态。原子操作的设计遵循以下原则:
IOperateData格式持久化于 Y.Array中,作为协同唯一数据源。本地操作通过 addOpData方法序列化并 push 至该数组,由Yjs负责同步,利用数组有序性保证各客户端日志一致。commit记录,作为版本恢复与回溯的基准。为解决CRDT操作日志无限增长带来的性能瓶颈,系统采用操作日志(OpLog)与版本快照(Snapshot)相结合的混合持久化策略,并与Git版本管理系统深度集成:
操作日志(OpLog)
Y.Array中,形成有序操作流水,用于实时协同与增量同步版本快照(Snapshot)
type: commit记录作为检查点版本管理机制
系统以Git Commit ID作为数据一致性的黄金标准,实现精确的版本控制:
[V0]-[op1]-[op2]-[v1]-[op1]-[op2]-[v2]...协同恢复流程
新客户端加入或进行版本回退时执行:

系统采用Yjs库内置的YATA (Yet Another Transformation Approach) 冲突处理模型。该模型基于双向链表数据结构,将操作抽象为“插入”与“删除”两种类型,并通过以下核心机制确保所有客户端最终状态一致:
item.deleted = true)并记录到删除集合(DeleteSet)中。此机制确保了后续可能到达的、针对该节点的操作仍能正确定位到目标,从而彻底避免因节点缺失而导致的数据不一致性问题。性能考量与优化:

系统通过 Yjs 的 WebSocket 同步服务实现高效的状态同步,服务端作为无状态中间层,其核心职责包括:
AST 操作同步与 Delta 数据处理
系统利用 Delta 格式(一种基于 OT 算法设计的用于描述序列化数据结构变化的标准化格式,详见 Quill Delta https://quilljs.com/docs/delta/)来精确描述和传递操作变化。在 observe 回调中,通过解析 event.changes.delta 来识别多种操作场景,例如:
系统据此采取相应的同步策略(如版本回退+强制重做),并驱动UI更新。
Awareness 状态同步
除AST数据同步外,为提升多用户协作体验,系统基于 Yjs Awareness 协议实现了低延迟的元状态同步:
在多人协同编辑环境中,实现撤销(Undo)与重做(Redo)功能面临核心挑战:传统单机撤销模型通过回退全局操作队列实现状态还原,这会直接影响所有协作者,导致其他用户的操作被意外覆盖。
为解决这一难题,系统基于 Yjs UndoManager 构建了客户端粒度的撤销重做机制,其核心设计原则为:仅回退当前客户端自身发起的操作,避免干扰其他协作者。
具体实现机制:
trackedOrigins 选项为操作标记来源(使用客户端ID而非用户ID,以区分同一用户的多终端会话),精准隔离不同客户端的操作序列。该方案在保证协同数据最终一致性的前提下,为用户提供了符合直觉的独立撤销/重做体验,有效简化了复杂协同环境下的撤销/重做逻辑。
基于协同编辑场景的特殊性,从多个维度对系统进行了深度优化,具体包括以下方面:
通过操作批处理机制,将短时间内的高频操作在客户端进行合并,显著减少网络请求次数,降低服务端压力。同时采用操作差分与压缩算法,过滤连续重复的操作提交,仅同步有效变更内容,大幅减少网络传输数据量。在网络连接方面,实现智能重连机制,基于指数退避算法自动处理网络异常,保障协同连接的稳定性。
引入全局节点缓存索引,通过 Map结构以 tid为键缓存所有 AST 节点,将节点查询时间复杂度从 O(n) 优化至 O(1),极大提升了节点定位效率。同时建立分层更新机制,通过细粒度的依赖分析,确保每次操作仅触发最小范围的组件更新,避免不必要的计算开销。
实施差异化渲染策略,基于操作流分析精准识别变更范围,实现 UI 最小化 HMR。AST状态更新时,结合节流防抖机制仅同步变更文件列表,大幅降低内存占用与网络传输开销。
构建多重校验体系,在客户端同步时进行 Commit ID 与操作序列长度的双重验证,有效识别和防止状态分叉;客户端提交时比对代码仓库与协同记录的Git Commit ID,解决用户脱离协同系统提交git版本且未重新初始化低代码编辑器,在提交保存时导致的数据不一致问题。建立快速恢复机制,在服务端异常或网络中断后,能够基于最新版本快照和操作日志快速重建协同状态,确保数据一致性。

通过将CRDT协同算法与AST驱动的低代码平台深度集成,我们成功构建了一套高性能、高可用的多人实时协同编辑引擎。这一技术方案不仅彻底解决了传统低代码平台中的“工作撞车”问题,更在多个维度实现了突破性进展:
技术架构的革新性融合
用户体验的质的飞跃
工程实践的卓越表现
这项实践不仅证明CRDT在复杂结构化数据协同场景下的可行性,更为整个低代码行业提供了协同编辑的系统性解决方案。从“避免撞车”到“愉悦协同”,我们正在重新定义团队协作的开发体验与工作流,让低代码平台真正成为赋能团队创新的协作平台而非单兵作战工具。
展望未来,随着协同算法的持续优化和硬件能力的提升,我们相信实时协同将成为所有低代码平台的标配能力。而基于AST与CRDT的架构方案,无疑为这一演进方向提供了坚实的技术基石。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。