给自己的 AI 助手做大重构:Go 微内核 + 35 个扩展,内核只干 6 件事
本文是《自制桌面 AI 助手》系列的第二篇。上一篇介绍的 0.4.x 版本是一个"单体"架构:所有功能都塞在一个 exe 里,改一个小功能就要整体重新编译发布。这半年我把它推倒重写了一遍,这篇讲讲 V2 的架构和踩过的坑。
为什么要重写:单体架构的三个死结
老版本用了几个月后,问题越来越明显:
- 内核越来越胖。文件读写、记忆、浏览器自动化、模型对接全在一个进程里,任何一处 panic 整个助手当场死掉。
- 改一处、发全套。只想给记忆检索加个参数,也得重新编译整个 2 万行的程序,还要考虑怎么把升级包安全地推给使用中的实例。
- AI 加功能没有安全边界。让 AI 自己给自己写功能(self-extend)时,一段错误代码就可能污染核心。
死结的本质:没有边界,就没有演进。
V2 架构:微内核 + 双形态扩展
新架构一句话:内核只保留 6 项职责,其余能力全部外置为扩展。
内核(约 3600 行 Go,13 个文件)只负责:
| 职责 | 说明 |
|---|---|
| 参数加载 | policy.json 四层配置覆盖 |
| 事件总线 | 扩展间通过事件解耦通信 |
| Journal | 会话日志落盘,崩溃后续跑 |
| 异常退避 | 扩展崩溃自动重启、指数退避 |
| 插件宿主 | 拉起/管理所有扩展进程 |
| 对话循环 | 模型 ↔ 工具的调度主循环 |
其他一切——模型提供者(GLM/DeepSeek/本地引擎)、文件工具、记忆库、看板、定时任务、UI 自动化、自检诊断——都是扩展,两种形态:
- sidecar exe:独立进程,崩溃不伤内核,内核自动拉活;
- c-shared DLL:轻量高频工具(如文件读写)走宿主进程,省一次进程往返。
目前 35 个扩展、约 130 个工具全部这样长在外面。协议是纯文本帧(manifest + stdin/stdout),版本纪律是只加不改不删,扩展乱升级也不会把内核搞挂。
几个值得说的设计
1. 扩展可以"接管"内核的决策点
V2 里有两个关键管道(pipe):
context.assemble:每轮对话前,记忆/技能/项目约定等多个扩展往上下文里注入内容,注入多少、怎么排序由配置决定,内核不管内容本身;tool.resolve:模型要调工具前,权限扩展和审计扩展可以否决这次调用(比如凭证扫描扩展拦下任何要外发 key 的命令)。
这就是把 Claude Code / Codex 的 hooks 机制搬进了插件体系,而且是内核级保证、无法绕过。
2. 自举升级:它会自己编译、自己换血
这是 V2 最"魔法"的部分:upgrade_apply工具会调 Go 工具链现场编译新版本扩展并热替换。升级内核本身时走"守卫换血"——分离脚本杀掉旧内核、换上新内核再拉起,如果新内核超时没确认存活就自动回滚到 .old 备份。整个产品可以自己给自己打补丁,全程不需要人肉替换 exe。
3. 多代理团队:扩展里长出了"组织"
agent 扩展支持派生后台子代理(researcher/coder/reviewer 等角色),子代理还能再派下层(限制层级)。配合看板扩展(kanban)和共享黑板(board),可以让一个"团队"并行推进几十张任务卡,主控只做验收。定时任务扩展还支持"闸门脚本":没活的时候轮询零成本,有活才真正唤醒。
4. 上下文治理三件套
长会话的通病是越聊越傻。V2 用三招对抗:
- 压缩扩展:超阈值时后台把旧消息交给模型摘要成要点,会话无限长而请求体有界;
- 上下文栈:像寄存器一样 push/pop 保存恢复现场,分支排查不丢主线;
- 记忆库:BM25 + 语义混合检索,长期记忆按需注入,注入参数(topK/minScore)可配置、可审计。
踩坑清单
- c-shared DLL 必须 CGO + MinGW,普通 go build 编不出来,构建脚本要内置 PATH 注入。
- 杀扩展进程前先验明正身:PID 会被系统回收,拿旧 pid 去 taskkill 可能误杀无关进程——先核对进程名再动手。
- 扩展配置有"内存态覆盖磁盘"的坑:某些缓存型扩展改完磁盘 meta 必须重启内核,否则退出时旧缓存会把磁盘改回去。
- 微内核的代价是调试链路变长:一次工具调用要跨 内核→扩展→内核 三个进程,没有全事件结构化审计日志(我们叫 audit 流水)根本没法排障,所以日志扩展是第一批实现的。
一点感受
重构前后最大的变化不是功能变多,而是改东西不再害怕:坏一个扩展,内核把它拉起来;升级失败,守卫自动回滚;想加能力,写个新扩展扔进目录就行。
"内核做小、生态做大"这条路,在操作系统领域被验证了五十年,放到个人 AI 助手上同样成立。
同系列上一篇文章见我主页。想交流架构细节的欢迎评论区留言。