EAC-Desktop三层架构完全解析:Tauri原生壳、Node sidecar与dsh内核如何分工协作
【免费下载链接】EAC-DesktopEmbracing All Creation (Desktop) — Dedicated to the Harmonious Coexistence of Hundreds of DSH Plugins / 揽尽万象(桌面版) —— 致力于让数百个DSH插件和谐共存项目地址: https://gitcode.com/gh_mirrors/de/EAC-Desktop
EAC-Desktop(Embracing All Creation,揽尽万象)是一个致力于让数百个 DSH 插件和谐共存的开源桌面工作台。它最独特的地方,正是这篇文章要拆开的三层架构:**Tauri 原生壳(L1)**负责窗口与桌面集成,**Node sidecar(L2)**负责运行编排与插件治理,**dsh 内核(L3)**负责 Agent 执行与 Web 界面——三层各司其职、互不越界。本文将带你完整看懂这个分工设计,不需要你具备 Rust 或 Node.js 经验,只要对"桌面应用是怎么跑起来的"感兴趣就能读懂。
为什么桌面应用要做"三层架构"?
一个常见的困惑是:桌面应用用一个框架(比如 Electron 或 Tauri)从头包到尾不就行了吗?
EAC-Desktop 的设计者给出的答案是:桌面能力和 AI 内核的演进速度完全不同。窗口、托盘、单实例锁这些"桌面集成"需求变化很慢,但 Agent 内核、插件生态的变化极快。如果把两者焊死在一个进程里,任何一层出问题都会连累全局——典型症状就是"一个插件崩溃,整个应用白屏"。
因此 EAC-Desktop 用一份架构决策记录(ADR)明确划定了三条永不混淆的边界:
| 层次 | 一句话职责 | 技术实现 |
|---|---|---|
| L1 桌面集成层 | 窗口 / 托盘 / 单实例 / 退出策略 | Rust(Tauri),可替换 |
| L2 业务服务层 | 进程编排 / 环境初始化 / 插件治理 | Node.js sidecar,壳无关 |
| L3 内核层 | Agent 执行 / 对话 / 工具 / Web UI | 官方 dsh 内核,零修改 |
完整的设计背景可以阅读 0002-壳层边界声明与分层架构.md。这份文档里有一句关键结论:原壳层中约 60% 是"与桌面框架零耦合的 Node 业务逻辑",只有约 35% 是"真·桌面集成"——前者原封不动搬进了 L2 sidecar,后者才用 Rust 重写。这正是"三层"的由来。
L1 层:Tauri 原生壳——只管"像桌面应用"
L1 是用户双击安装包后第一个接触到的部分。它的职责被刻意收窄到极小:窗口、托盘、单实例、退出策略和原生集成,代码入口是 main.rs。
从启动序列能看出 L1 的角色定位(main.rs 头部注释写得很直白):
- 拉起 sidecar 子进程,建立 stdio JSON-RPC 通道,并绑定本地回环端口;
- 主窗口先显示加载页("即起即见",不用干等内核启动);
- 通过
boot.start让 sidecar 去拉起 dsh 内核; - 内核就绪后,主窗口导航到真实 Web UI;内核异常则显示恢复页。
可以看到,Rust 壳从头到尾没有碰任何业务逻辑。它像一个"总机接线员":来自页面的请求,属于窗口控制的(最小化、拖拽标题栏)就地拦截处理,属于业务编排的一律转发给 sidecar。这种"壳层不承包业务"的纪律,是 L1 层最值得学习的点——它保证了未来想换壳(比如换别的原生框架),L2、L3 一行代码都不用动。
L2 层:Node sidecar——三层中技术含量最高的"大脑"
如果说 L1 是脸面,L2 就是大脑。server.ts 是 sidecar 的入口,它启动后按严格顺序挂载一组桌面服务模块(lib/desktop/ 目录):
environment(环境隔离)→ platform(平台适配)→ profile(配置档案) → runtime-patches(运行时补丁)→ guard-box(插件保护) → companion-sync(配套插件同步)→ plugin-ops(插件启停) → boot-server(内核进程编排)L2 承担了三件"脏活累活":
- 环境初始化。读取用户配置、准备插件目录之前,必须先建立隔离的运行环境(下一节详述);
- 进程编排。由 boot-server.ts 启动 dsh 内核进程,监听服务就绪,内核挂掉时走恢复链而不是静默失败;
- 插件治理。guard-box.ts 提供插件快照、体检与回滚入口,plugin-ops.ts 管理启停,让"数百个插件"不至于演变成一场灾难。
L2 还有一个关键设计:它是"壳无关"的。同一份 Node 代码既能被旧 Electron 壳驱动,也能被新 Tauri 壳驱动——sidecar 只认 stdio JSON-RPC 协议帧,不关心外面是谁。
L3 层:dsh 内核——"绝对不动区"与真正的 AI 能力
L3 是官方@deepseek-ai/dsh内核加 Cordis 插件树,负责 Agent 执行、对话、工具调用和整个 Web 界面。它被称为"绝对不动区":壳层对内核一行代码都不修改,扩展能力一律通过插件契约(host/client 注入点)接入。
你在界面上看到的一切"智能"——会话列表、模型选择、文件变更、权限确认——都是 L3 的 Web UI 渲染出来的。L1 的窗口只是它的一副"屏幕边框"。这也是为什么插件生态能长到几百个规模:插件挂在内核的插件树上,崩溃治理由 L2 的保护中心兜底,而内核本身始终保持干净。
三层如何通信:两条通道各司其职
三层之间的对话走两条互相独立的通道,这是很多架构文章里容易忽略的细节:
| 通道 | 连接 | 协议 | 用途 |
|---|---|---|---|
| stdio JSON-RPC | Rust 壳 ↔ Node sidecar | 行分隔 JSON 帧 | 业务方法调用(boot.*、profile.*、files.*) |
| 回环 WebSocket | Web 页面 ↔ Rust 壳 ↔ sidecar | WS JSON-RPC | 页面桥window.dshDesktop(窗口控制、boot 事件) |
两条通道的纪律都是:stdout 只走协议帧,一切日志走 stderr(见 server.ts 的注释)。协议与诊断分离,意味着日志打多了也不会把通信协议"冲花",这是长连接服务稳定性的基本功。页面侧的桥实现见 bridge.ts,它对内核页面暴露的接口面经过严格收敛——只保留官方契约加窗口控制,壳层自造的扩展面全部剥除。
隐藏的地基:DPX 环境隔离层
三层之外还有一个贯穿全局的地基:DPX 环境隔离(environment.ts + dsh-dpx)。
问题背景是:如果 EAC 直接复用系统里旧的.dsh目录,老版本的插件和依赖会被新内核继续读取,实测后果是插件加载失败和白屏。EAC 的解法很干脆——每个发布通道(beta / rc)拥有独立的数据根目录,内核、插件、缓存全部装在自己的"沙箱"里,互不污染。
更关键的是它的失败策略:fail closed。环境初始化失败时 sidecar 会直接退场并记录错误,走恢复链,绝不悄悄回退到宿主旧目录——因为"在错误的数据根里假装成功"才是最难排查的故障来源。设计细节见 0004-EAC安装环境隔离.md。
总结:一张表看懂 EAC-Desktop 三层分工
| 问题 | 谁来回答 | 入口文件 |
|---|---|---|
| 窗口为什么能最小化/拖动? | L1 Rust 壳拦截win.*方法 | main.rs |
| 内核进程怎么启动、挂了怎么恢复? | L2 sidecar 进程编排 | boot-server.ts |
| 插件太多怎么治理? | L2 保护中心快照/体检/回滚 | guard-box.ts |
| 数据会不会被旧版本污染? | DPX 通道隔离,fail closed | environment.ts |
| 对话、工具执行、插件能力在哪? | L3 dsh 内核(零修改) | package.json |
这套架构给普通用户带来的实际好处是:内核可以激进迭代而不影响桌面体验,桌面集成可以按平台优化而不触碰 AI 内核,插件装多了也有保护中心兜底。三层边界看似增加了工程复杂度,实际上是把复杂性关进了明确的笼子里——这正是 EAC-Desktop 能让"数百个 DSH 插件和谐共存"的根本原因。
【免费下载链接】EAC-DesktopEmbracing All Creation (Desktop) — Dedicated to the Harmonious Coexistence of Hundreds of DSH Plugins / 揽尽万象(桌面版) —— 致力于让数百个DSH插件和谐共存项目地址: https://gitcode.com/gh_mirrors/de/EAC-Desktop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考