llm-to-agent/docs/architecture.md
2026-07-23 17:49:50 +08:00

7.6 KiB
Raw Blame History

架构总览

定位

本项目是纯个人使用、本地优先的开发助手与电脑管家。完整功能范围保持不变,但源码只围绕两个长期边界演化:Kernel 撑起系统,Extensions 增加能力。

架构不追求套用通用框架的模块名。一个概念是否进入 Kernel只看它是不是所有能力都必须遵守的稳定运行规则其余需求默认通过 Extension 实现。

系统拓扑与源码架构

系统拓扑描述进程如何连接:

Supervisor ──启动/切换/回退──▶ Runtime
                                ▲
                                │
                    CLI / Web / Desktop

Runtime 内部的源码架构只有:

Kernel ◀──── Extensions

Supervisor、Runtime 入口和三个产品入口是部署位置,不是叠在 Kernel 上方的业务架构层。

Kernel

Kernel 负责让系统可靠地运行:

  • 启动、停止以及 Extension 生命周期;
  • Extension 注册、能力查找和运行事件;
  • Space、Conversation、Message 与 Run 的稳定语义;
  • Agent 主执行循环、流式输出、取消和错误边界;
  • 本地状态、持久化一致性和资源所有权;
  • Tool 等副作用能力不可绕过的权限与记录边界;
  • 产品输入提交和 Run 事件订阅的统一运行接口。

Kernel 可以认识本项目真正不可缺少的概念,不为了保持“微内核纯度”拆出 Application、Host 或 Client 等中间层。

正常增加产品能力时不修改 Kernel。只有多个 Extension 都缺少同一种通用机制,或某项规则必须由系统统一强制执行时,才扩展 Kernel 的公共接口。

Extensions

Extension 负责让系统具备具体能力例如模型、Workspace、Shell、Git、计划、多 Agent、记忆、浏览器、自动化、界面和系统控制。

Extension 不需要声明自己属于 Adapter、Tool、Hook、Behavior 或 Profile。一个完整能力可以同时注册可调用实现、订阅事件、维护数据并管理资源。

最小契约只有生命周期:

interface Extension {
  readonly id: string;
  setup(context: ExtensionSetupContext): void | Promise<void>;
  start?(context: ExtensionRuntimeContext): void | Promise<void>;
  stop?(context: ExtensionRuntimeContext): void | Promise<void>;
}
  • setup 只注册能力和事件处理器,不开启外部资源;所有 Extension 完成 setup 后才进入 start
  • start 开启终端、网络连接、后台任务等运行资源。
  • stop 按安装的逆序关闭资源。

Extension 对象只是安装入口。Kernel 在运行时真正调用的是 Extension 注册的能力;只需响应过程的 Extension 则订阅 Kernel 事件。事实事件只能由拥有该事实的 Kernel 流程发布ExtensionContext 不提供发布 Kernel 事件的权限。

公共扩展与产品线私有扩展

Extensions 按使用范围组织:

extensions/
├── shared/       # 三条产品线可复用的能力
├── cli/          # CLI 私有输入、展示和终端交互
├── web/          # Web 私有协议、路由和页面
└── desktop/      # Desktop 私有原生集成

公共扩展不认识具体产品界面。产品线私有扩展可以使用 Kernel 和公共能力,但 CLI、Web、Desktop 私有扩展之间不能直接依赖;不再只属于一条产品线的代码应提升到 shared/,不要求三个产品全部使用。

“公共”与“私有”只是源码归属和装配规则。Kernel 不认识这些分类,也不包含 cli | web | desktop 分支。

产品装配

每条产品线只有一份扩展清单:

products/
├── shared.ts
├── cli.ts
├── web.ts
└── desktop.ts

启动入口先安装公共扩展,再安装当前启用产品的私有扩展。装配清单不承载业务逻辑,也不形成新的架构层。

单个 Runtime 可以同时装配三条产品线的接入扩展也可以在某种安装形态中只启用其中一部分。无论启用哪些产品Kernel 和公共数据始终只有一套。

系统拓扑图中的 CLI、Web、Desktop 表示用户实际接触的产品入口。产品私有 Extension 运行在适合自己的位置Web Extension 可以直接在 Runtime 中开启服务CLI 与 Desktop 可以包含 Runtime 侧接入能力和进程外的轻量启动器。启动器只负责拉起或连接 Runtime、转发输入输出不保存 Agent 状态,也不复制 Kernel。CLI 启动器退出时Runtime 中的 Kernel 与已提交 Run 继续运行。

产品入口需要使用的 Kernel 接口不只包含聊天 Run还包括三类基础操作

  • 创建、读取和修改 Space、Conversation、配置、扩展及审批等产品状态
  • 提交、查询、取消和继续 Run
  • 按连接或 Run 重新订阅实时事件。

这些是同一套运行接口,不要求再建立独立 Client 架构层。具体采用本地 IPC、HTTP、SSE 或其他传输方式,由相应产品 Extension 决定。

首版工作流

第一版先跑通同一条端到端主链路:

产品私有扩展接收输入
        ↓
Kernel 创建 Run 并保存用户消息
        ↓
Kernel 调用模型 Extension
        ↓
模型返回文本增量或 Tool 请求
        ↓
Kernel 按需调用 Tool Extension并将结果继续交给模型
        ↓
Kernel 保存最终消息和 Run 状态
        ↓
产品私有扩展订阅 Run Event 并展示

CLI 私有 Extension 与轻量启动器把 Run Event 渲染到终端Web 转换为网络响应和事件流Desktop 转换为 IPC、窗口或原生通知。产品差异只存在于链路两端中间的 Run、模型、Tool、记忆和计划能力全部复用。

能力与事件

  • 能力是 Kernel 或其他 Extension 需要主动调用并取得结果的实现例如模型生成、Tool 执行或记忆检索。
  • 事件是已经发生的运行事实,例如 Run 开始、文本增量、Tool 完成和 Run 结束。所有监听器相互隔离;监听失败进入诊断记录,不反向改变已经发生的事实或主流程结果。

需要阻止、修改或返回结果的逻辑不能伪装成普通事件监听;真实需求出现时,由 Kernel 提供明确的调用能力或受控执行点。

Extension 的持久化数据统一通过 Kernel Store 写入各自命名空间。Extension 可以拥有自己的数据结构和外部资源,但不能绕过 Kernel 的数据目录、生命周期、权限和清理规则;模型连接、浏览器进程等运行资源在 start/stop 中管理。

依赖规则

main → products → extensions → kernel

shared extensions  → kernel
CLI extensions     → kernel + shared capabilities
Web extensions     → kernel + shared capabilities
Desktop extensions → kernel + shared capabilities

Kernel ✕ 具体 Extension
CLI ✕ Web ✕ Desktop 私有实现

图中的依赖表示源码 import。Extension 之间需要协作时,通过 Kernel 注册和取得公开能力,不直接反向引用另一个 Extension 的内部实现。

目录不是边界本身。判断架构是否成立的标准是:新增具体能力通常只需增加或修改 Extension而 Kernel 不需要知道它的名字和产品归属。

Supervisor 与自进化

Supervisor 位于当前 Runtime 版本之外,只负责启动、版本切换、健康检查和失败回退。它在 System Evolution 发布闭环出现时实现;此前可由普通启动脚本承担。

Agent 可以在隔离 worktree 中修改 Kernel 或 Extensions、运行测试并展示 Diff。具体功能优先通过 Extension 生长,但 Kernel 并非不可修改;涉及新的全局运行规则时,仍可在验证和回退保护下演化 Kernel。