这一篇要解决的问题是:在前面一路跟着需求推进之后,怎样把已经出现的概念重新收束成一张清晰的 Runtime 心智图。为了把这件事讲清楚,我们会先回看 Context、Plugin、Service、Event、Lifecycle 和 inject 分别对应了什么问题,再把它们压缩回一个统一判断,最后说明它为什么和 Agent Runtime 如此相似。
1. 这一篇要解决的问题
前面几篇是按问题推进,这一篇则换一个角度,专门负责回收概念。也就是说,这里不会再继续增加新需求,而是把前面已经出现的结构重新整理成一张完整的 Runtime 心智图,让 Context、Plugin、Service、Event、Lifecycle 和 inject 彼此之间的关系重新变得清楚。
这一篇的主线可以先压缩成下面这条路径:
把前面的局部问题重新收束
↓
看清 Context、Plugin、Service 的分工
↓
把 Event 和 inject 放回生命周期主线
↓
重新得到 Runtime 的整体判断2. 这些概念分别对应什么问题
先从最常见的几个访问方式开始:
ctx.greeter
ctx.clock
ctx.farewell这说明 Context 可以理解为当前 Runtime 的能力视图,也就是“这个系统此刻有哪些能力可用”。而这些具体能力本身,就是 Service。它们并不是孤立对象,而是由某个 Plugin 安装到 Runtime 里的对外能力。
如果把三者关系压缩成一张最小图,大致就是:
Plugin
│
↓
Service
│
↓
Context接着看事件部分。App 通过:
ctx.emit('greet', 'Alex')发出通知,Logger 通过:
ctx.on('greet', ...)订阅通知,这对应的是模块之间的解耦通信,也就是 Event。但前面已经看到,Cordis 真正重要的并不只是“能发事件”,而是这些 listener 会跟着 Plugin 的生命周期一起被清理。于是 Event 最终又落回到了 Lifecycle。
最后是 inject。它的作用不是把一个对象简单传进去,而是把一条依赖关系正式告诉 Runtime,让 Runtime 能够根据依赖是否可用,自动决定相关能力是否应该激活、停用或重新恢复。
3. 为什么 Lifecycle 才是底层主线
如果把前面的推导再压一层,会发现几乎所有概念最后都会落到生命周期管理上。Plugin 有 install、running、dispose;Service 有 available、remove;Event listener 有 register、auto cleanup;依赖则有 available、unavailable、restored。也就是说,Cordis 真正关心的并不是“有没有这些对象”,而是“这些能力如何进入系统、在什么条件下可用、失效时如何退出,以及退出时谁负责清理残局”。
这也是为什么可以把 Cordis 的核心能力概括成一句话:
它不只是一个依赖注入容器,而是一个管理动态能力生命周期的 Runtime。
4. Vanilla 和 Cordis 真正的差异在哪里
把整条推导链放在一起看,差异会变得很清楚。在最开始只有一个 Greeter 的时候,Vanilla 更简单,Cordis 没有优势;加入事件以后,Vanilla 开始自己维护 listener 的注册和清理;加入动态依赖以后,Vanilla 开始出现手动同步;再加入第二个依赖方以后,胶水代码开始复制。
所以 Cordis 的价值并不是“Hello World 少写了几行”,恰恰相反,在最小例子里它通常会写得更多。它真正的价值在于:当系统中动态能力和依赖关系越来越多时,生命周期管理的边际成本不会跟着一起失控。
5. 为什么这和 Agent Runtime 很像
把前面的例子映射到 Agent Runtime,会更容易看出这些抽象的现实意义。原来的:
Clock
├── Greeter
└── Farewell可以换成:
Model
├── ResearchAgent
├── CodingAgent
├── Summarizer
└── Tools或者:
MCP Server
├── Search Tool
├── Browser Tool
└── Data Tool这些能力同样可能加载、失效、恢复、替换和卸载。于是系统就必须持续回答同一类问题:谁依赖谁,依赖还没准备好怎么办,依赖消失以后谁应该停掉,恢复以后谁应该重启,Plugin 创建出来的 listener、timer 和其他资源该由谁清理,同名 Service 冲突时又该如何处理。前面用 Greeter、Clock 和 Farewell 讲的,其实正是这类 Runtime 问题的最小版本。
6. 这一篇的结论
这一组文章从一个变量开始,经过多个实现、事件、资源清理、动态依赖和多个依赖方,最后才落到 Runtime。这条推导链真正想建立的认识始终只有一个:
Cordis 不是在解决“怎么调用一个 Service”,而是在解决“一个长期运行、能力会动态变化的系统,如何统一管理能力、依赖以及它们的生命周期”。
理解这一点以后,Context、Plugin、Service、Event、Lifecycle 和 inject 就不再只是几个零散 API,而会自然连成一套完整的 Runtime 设计。到这里,这一章的主线也就完整闭合了。