微内核设计的 Harness
以 LLM loop 为内核,所有上下文工程能力(prompt、记忆、技能、权限、会话、规划……)以插件形式挂载。插件独立演进,只要不破协议,互不踩脚。
0. 验证代码
代码:https://github.com/daoyuly/mirco-kernal-nanobot
1. 设计动机
用 AI 编程时,多个任务/多个 agent 同时进行会带来三类冲突:
- 代码冲突:大家都在改同一段 prompt 模板、同一份记忆 schema、同一个 skill 文件。
- 语义冲突:A 团队希望”记忆”按 SRS 衰减,B 团队希望按时间窗口压缩——耦合在一起就互锁。
- 生命周期冲突:会话级状态、任务级状态、全局状态混在一个大上下文里,谁清谁不清说不清。
宏内核式 Harness(一个大 agent loop,所有能力硬编码在里面)是上面三类冲突的温床。
微内核的承诺:把冲突面缩小到一根”协议”上,其它一切并行演化。
2. 核心隐喻:操作系统微内核
| OS 微内核(Mach / L4 / MINIX) | LLM Harness |
|---|---|
| Kernel 只做 IPC + 调度 | 只保留 LLM loop(推理 + 工具调用 + 状态推进) |
| 文件系统、驱动、网络栈都是用户态服务 | Prompt、Memory、Skill、Permission、Session… 全是插件 |
| 通过稳定的 syscall ABI 通信 | 通过稳定的 Context Object 协议通信 |
| 内核越小越稳,性能用 IPC 优化补 | Loop 越薄越久不动,性能用 pipeline 调度补 |
判据:能不动 loop 就别动 loop。任何新能力的第一反应应当是”这能不能做成插件?”。
3. 架构总览
3.1 洋葱视图(抽象层级,由内而外)
1 | 意图理解 |
直觉:越靠内,协议越稳定、变更频率越低;越靠外,业务语义越重、迭代越频繁。
3.2 Pipeline 视图(一次请求的执行顺序)
洋葱只画了”依赖深度”,真正运行时是一条管道:
1 | 用户输入 |
关键:洋葱顺序≠pipeline 顺序。洋葱表达的是”抽象依赖”,pipeline 表达的是”时序执行”。两个视图都要存在,否则容易把”加载顺序”错当成”抽象层级”。
4. 内核:LLM Loop
内核只做最少且最稳的事:
1 | loop: |
内核不关心:
- prompt 长什么样
- 记忆从哪儿来
- 工具是不是允许调用
- 当前是哪个会话/哪个 agent
它只关心:收到一个合法的 Context Object,吐出一个合法的下一步。
这就是”微”的含义:内核可以一年不改一行,只要协议不变。
5. 协议契约:Context Object
整个微内核成败的 90% 在这一节。协议设计差,插件之间还是会隐式耦合。
5.1 Schema 草案
1 | type ContextObject = { |
5.2 协议设计规则
- 只增不改:新字段允许追加,旧字段语义冻结。破坏性变更走 v2。
- 每个字段属于唯一插件:写入权专属,读权开放。避免”两个插件都在写 memory”。
- 插件之间不直接通信:要协作就通过 Context Object,禁止 plugin-to-plugin 调用。
- 可序列化、可 diff:方便审计、回放、debug。
- 顺序无关性(理想情况):插件链顺序变化不应改变最终行为。做不到的地方要显式声明依赖。
6. 插件层详解
每个插件实现统一接口:
1 | interface Plugin { |
6.1 意图理解(Intent)
- 职责:把用户输入归类为 task type(写代码 / 解释 / 调试 / 闲聊 / …)
- 输出:
ctx.intent - 可插拔点:分类器可以是关键词、Embedding、小模型、LLM 本身
6.2 任务规划(Plan)
- 职责:把意图拆成可执行步骤
- 输出:
ctx.plan - 形态:ReAct / Plan-and-Execute / Tree-of-Thoughts —— 都是这一层的插件实现
6.3 任务交接(Handoff)
- 职责:检测是否需要切换 agent / 切换上下文窗口
- 形态:sub-agent 派发、worktree 切换、长任务断点续传
6.4 持久化(Persistence)
- 职责:把会话、增量记忆、审计日志落盘
- 接口:
save(ctx)/load(session_id) - 可换:本地文件、SQLite、对象存储、向量库
6.5 会话管理(Session)
- 职责:多会话隔离 + 跨会话查找
- 关键:session 是 Context Object 的”宿主”,决定生命周期边界
6.6 权限控制(Permission)
- 职责:工具调用前的 capability 校验
- 形态:白名单、人审 prompt、speed-bump、敏感动作二次确认
- 位置:必须在 loop 的
dispatch处拦截,而不是在外层 pre-check
6.7 历史对话加载 / 压缩
- 两个插件,因为压缩策略和加载策略可以独立换:
- 加载:决定取多少、按什么排序
- 压缩:摘要、丢弃、向量化、滑动窗口
6.8 系统提示词(System Prompt)
- 职责:组装系统级 prompt 片段
- 关键:片段是有序列表,每片可签名(防止插件之间互相覆盖)
6.9 Skill 加载
- 职责:按意图召回可用 skill 的描述/触发条件,注入 prompt
- 机制:Skill 自身也是插件(数据 + 触发器 + 工具集合)
6.10 记忆加载(Memory)
- 三类:
- working:当前任务草稿
- episodic:过往会话的事件
- semantic:抽象后的知识(人物、偏好、项目事实)
- 可换:检索算法、SRS 衰减、重要性评分
6.11 压缩管理(Compaction)
- 职责:在拼装前做最终长度控制
- 策略:分段压缩、token 预算、关键字段保护
6.12 Prompt 结构化拼装
- 职责:把上面所有结果渲染成最终 messages
- 关键:这是离内核最近的一层,必须确定性、可 diff
7. 横切关注点
这些不属于某一层,但贯穿整个系统。
7.1 可观测性(Observability)
- 每个插件
apply前后打 trace - Context Object 可序列化 → 任何时刻都能回放
- 失败时能告诉你”是哪个插件把 ctx 改坏了”
7.2 热插拔与灰度
- 插件按 manifest 注册:
enabled / disabled / shadow(影子运行不影响输出) - 灰度通过 session_id 路由:10% 流量走新版 memory 插件
7.3 调度器(Scheduler)
- 真正决定执行顺序的不是洋葱,而是调度器
- 根据
dependsOn做拓扑排序 - 支持并行段:例如”记忆加载”和”Skill 加载”无依赖,可并行
7.4 预算与背压(Budget)
- 全局 token / 时间 / 工具调用次数预算
- 任一插件超预算 → 降级(不是失败):用更短摘要、跳过非关键插件
7.5 安全边界
- 权限插件是唯一可以阻断 loop 的插件
- 其它插件即使崩溃,应当 fail-soft(返回空贡献,记日志)
8. 执行生命周期(一次请求的旅程)
1 | 1. 用户:"帮我修 paper-learning 的 SRS bug" |
每一步都是一个 apply(ctx),每一步都可替换、可旁路、可灰度。
9. 与现有系统对比
| 系统 | 与本设计的关系 |
|---|---|
| Claude Code | 已经事实上微内核化:hooks、skills、subagents、settings 都是插件层;loop 本身很稳。可以视作本设计的实证存在。 |
| Cursor / Continue | 偏宏内核:prompt 模板和 IDE 集成耦合较紧,插件边界没那么清晰。 |
| LangChain / LangGraph | 提供了 graph 调度,但内核(agent loop)和插件(chain)边界模糊,组合容易”调色板化”。 |
| AutoGen / CrewAI | 多 agent 编排层做得重,但单 agent 内部仍是宏内核风格。 |
| OS 微内核(L4/seL4) | 直接灵感来源。值得学的是”IPC 协议先冻结,再谈插件”。 |
10. 失败模式与权衡
任何架构都要明说它在什么时候不好。
10.1 协议设计的脆弱性
- 协议错一次,所有插件返工。第一版尽量保守、留扩展位、版本化。
10.2 性能开销
- 插件链每加一层就是一次 ctx 拷贝/序列化
- 缓解:scheduler 并行段、关键路径上的插件做零拷贝(共享引用 + COW)
10.3 顺序敏感性
- “记忆先加载还是 skill 先加载?”会影响 token 预算分配
- 缓解:显式
dependsOn+ 调度器,而不是隐式数组顺序
10.4 调试更难还是更容易?
- 更容易的部分:每层可独立打 trace、回放 ctx
- 更难的部分:bug 可能在”插件 A 和 B 的交互边界”,而不是任一插件内
- 缓解:要求每个插件在 dev 模式下输出 diff(”我改了 ctx 的哪些字段”)
10.5 抽象税
- 简单场景下,微内核比”一段大 prompt + 一个 loop”显得过度工程
- 缓解:单文件最小实现 + 渐进式插件化。新项目可以从宏内核起步,按痛点拆插件。
11. 路线图(建议的最小可行版本)
v0.1:能跑的最小内核
- Context Object schema 定义
- 5 个核心插件:SysPrompt / History / Memory / Permission / PromptAssemble
- 一个串行调度器
- 一个文件持久化插件
v0.2:调度器升级
- 拓扑排序 + 并行段
- 插件 manifest + 启用/禁用
- 全链路 trace
v0.3:能力扩展
- Skill 插件机制
- Plan / Handoff 插件
- 灰度路由
v1.0:可被第三方扩展
- 插件 SDK
- 协议 v1 冻结
- 兼容性测试套
12. 开放问题
- 协议演化:如何避免 v1 → v2 时整个生态返工?是否引入 capability negotiation?
- 跨进程插件:是否允许某些重插件(如向量检索)跑在独立进程,通过 RPC 接入?这才是真·微内核。
- **插件之间的”准协作”**:例如 Memory 想知道 Plan 决定了什么。要不要引入只读 ctx 之外的事件总线?
- 多 agent 拓扑:handoff 之后新 agent 的 Context Object 是从零拼,还是继承?继承多少?
- 测试方法学:怎么对一个由 N 个插件组合而成的系统做端到端回归?快照测试 + 重放?
一句话总结
把 LLM loop 当成 CPU,把所有 Context 工程当成可热插拔的外设;先冻协议,再谈插件。