在 AI Agent的浪潮中,大多数人还停留在“写出完美的提示词”阶段。但如果你曾深度使用过那些所谓的“助理”,你很快会遇到第一代系统的瓶颈:它们是静态的。你喂给它越多信息,它的上下文就越混乱;你教给它越多规矩,它就变得越束手束脚。 在构建 BBot 的早期阶段,设计哲学深受传统实践的影响。当时的架构通过多层解耦、严谨的数据库模式以及针对特定平台(如 Telegram)的深度绑定,力求在我们这些所谓的人类开发者眼中呈现出一种整洁的秩序感。 然而,随着对自治代理(Autonomous Agents)理解的深入,这种「为人类审美服务」的工程化设计逐渐显现出其局限性。 OpenAI 的工程师 ...
在理想状态下,CRDT 保证了所有副本的强最终一致性。但在现实当中,数据一致性并不等同于数据有效性。 这句话要怎么理解呢: 一致性:所有客户端最终都看到了相同的状态(比如都看到了 ID 为 A 的单元格存在于 Map 中但不在 Order 中)。 有效性:这个状态在业务逻辑上是合法的(单元格如果存在,就必须在 Order 中有一席之地,否则它就是孤儿单元格)。 我在设计 Notebook 的时候额外引入了一套完整的体系,包含 Reconciliation、Validation 以及 Auto-Stale 机制。我们的目标是构...
协同从来不是独角戏,它需要服务端的支撑。在 Notebook 的架构中,服务端扮演的角色与传统的 CRDT 应用截然不同。 在构建 Y.js 后端时,最直观的方案通常是:在服务端(Node.js)运行一个 Y.js 实例,接收所有客户端的 Update,在内存中合并成 Y.Doc,然后定时将文档序列化写入数据库。 这种“全知全能”的服务端虽然逻辑简单,但存在致命缺陷:技术栈锁定 Y.js 是 JS 库。如果后端基础设施是 Go/Java,引入 V8 引擎或重写 CRDT 逻辑的成本极高,同时,因为各种原因我们也并不打算使用 Yjs 的 Rust port。 所以,我在构建 ...
在上一篇文章中,我们构建了一个基于 "Map-Reduce" 理念的健壮 CRDT Schema。然而,拥有一个完美的数据模型只是第一步。在前端工程中,真正的挑战在于:如何将这个基于 Mutation(突变)和事件驱动的 Y.js 数据源,高效、合规且优雅地投影到基于 Immutability(不可变性)和 Render Cycle(渲染周期)的 React 组件树中。 如果处理不当,不仅会导致代码中充斥着难以维护的 useEffect 胶水代码,还会引发严重的性能问题(如全量重渲染)甚至无限循环。本文将详细阐述我基于 Jotai 原子化状态管理库构建的 **"Atoms Pro...
Writing with Gemini TL;DR; Schema 设计并非只是简单的 CRUD 映射,而应该基于 CRDT 特性对业务逻辑进行深度抽象: Map-Reduce 结构:利用 Map 确立数据主权,利用 Array 定义视图投影。 读写分离:将用户输入的“因”(Source)与系统生成的“果”(Output)在物理存储上隔离。 软删除:通过状态标记代替物理销毁,保障并发安全性。 这一坚固的数据底层,为上层的 React 渲染、历史记录管理以及协同冲突解决提供了可预测的、确定性的基础。 序言 在现...
以下是我的个人的拙见,我接触 CRDT 的时间其实只有短短的几个月,在这几个月期间也一直在思考如何绑定好 Yjs,但是,似乎这个答案并没有一个固定的结论。不断尝试尝试,而到今天,我觉得我的想法大约就是如此了 TL;DR; 在构建协作应用时,我们试图将 CRDT 协作协议层(Yjs)与 UI 状态层(Valtio Proxy)通过“隐式双向绑定”强行融合。这种看似优雅的抽象,最终在生产环境中制造了难以捉摸的“幽灵写入”(Phantom Writes)。而这些由 UI 自动产生的幽灵写入,一旦进入 CRDT 的更新流,就会被视为合法且具有因果顺序的操作,最终导致了持久化的数据破坏。 ...
本文由 AI 辅助编写,阅读时请注意勘误 为什么要重构?问题的起源 作为一个音频处理应用,WindsynthRecorder 最初采用了最直观的设计:一个简单的插件处理链。音频从输入端流入,依次经过每个插件处理,最后输出。这种设计在早期工作得很好,但随着用户需求的增长,问题开始暴露: 用户想要的功能: 并行处理多个音频流 侧链压缩(需要额外的音频输入) 发送/返回效果器(需要分支和合并) 实时的插件重排序 现有架构的限制: 只能串联处理,无法实现并行或分支 基于数组索引的插件管理,重排序时容易出错 同步的插件加载会阻塞 UI -...
ClartifyFile 是最近一直在开发的一个自用的软件,主要是作为管理文件的存在,这个软件以后有机会再详细讲述吧 在开发 ClarityFile 这个桌面应用的过程中,快捷键管理一直是一个让我头疼的问题。从最初的简单需求到现在的统一管理系统,这个功能经历了多次重构和演进(Refactor with Augment Code)。今天想和大家分享一下这个系统的演化历程,以及我们为什么最终选择了 zustand 作为状态管理方案。 第一阶段:原始的事件监听 最开始,快捷键实现非常简单粗暴: `tsx // 早期的实现方式 function ProjectListPage()...
最近购入了一台 iPhone 15 Pro Max,借着最新推出的 Action Button,心情感慨万分,用一段时间稍微了解过后,我做了一个具有极高自由度的 shortcut 系列,你可以执行各不相同的54种操作,我愿称之为:Smart Device Orientation 系列 Shortcuts 普通且寻常 最普通的,便是在一个捷径里面只做一种类型的操作,没有其他选择了 这是大多数人所知道、了解到的,这种方式的优点就在于它非常稳定,稳定在无论如何执行的都是这个操作。但缺点便是无论如何都只能执行这一套操作 虽然通过「菜单选取」可以实现执行别的...
这是 《如何开发 Mog》 系列的第一篇章,不过对于这个项目的结构我可能就不会怎么讲了,可能就稍微略过了,整体下来可能这个系列比较混乱,是开发的过程中就捎带写下罢了 如何新增配置 在 Mog v1 的时候,ConfigService 已经被抽离为一个 Library,你可以前往 libs/config 里看到有关这个服务的所有信息 你可以进入 apps/configs-service 查看服务的文件 ::: banner {warning} 在 Mog Stage 5 之前,ConfigService 依旧是一个 Library,但是在 Stage 6 中...