Cordis:五个动作
论文第 5 章讲实现。Cordis 的核心库,说到底只给了组件五个动作:
| 动作 | 做什么 | 对应 |
|---|---|---|
| ctx.effect | 做一件事,当场交回执 | 04 回执 |
| ctx.set / ctx.get | 在总账上登记一个键 / 读一个键 | 05 插座 |
| ctx.isolate | 让一个名字在子环境里指向私有的一份 | 05 隔离 |
| ctx.intercept | 在读依赖的路上加一道规则 | 05 拦截 |
| ctx.use | 按一份说明书装上一个组件,得到一个 fiber | 07 一生 |
其中最要紧的是第一个。Cordis 里一切对语境的改动,都只走 ctx.effect 这一个入口 p.59:登记一个键是它,装上一个组件也是它。入口只有一个,回执就一张都漏不了。第 06 章说的「一扇门」,在代码里就是这一个函数。
声明式加载器和热重载不在核心里,是另外两个包,以组件的身份挂上去。
Koishi:四年,四千个插件
理论站不站得住,要看它在真实世界里跑得怎么样。论文拿 Koishi 当证据 p.69:
- 拆得干净:在控制台停用一个插件,它的改动当场撤回;开发时改完代码一保存,插件原地重载,系统其余部分的缓存和连接都还在 p.70。
- 接得稳:Koishi 的插件之间有真正的依赖网,适配器提供各个聊天平台,数据库驱动提供存储,功能插件声明依赖再去用。运行中换掉存储后端,只有依赖真的变了的插件才重新上岗;依赖不在的插件安静待命,不报错 p.70。
- 不挑环境:Koishi 的网页控制台本身是第二个独立的 Cordis 应用,跑在浏览器里 p.69。同一套模型,服务器上能用,浏览器里也能用。
这些插件出自几千个互不认识的作者。论文最看重的,正是「独立写成的代码之间,组合照样成立」。
dsh:墙上一排插座
dsh 的 55 个包,每个核心能力都占着一个固定的 ctx 键:ctx.llm 是模型适配器,ctx.tools 是工具注册表,ctx.sessions 是会话记录,ctx.agentLoop 是默认的思考循环,还有 ctx.fs、ctx.shell、ctx.sandbox 等等。
插件之间只认这些名字,不直接引用彼此的代码。所以「一切皆插件」不是口号:连 AI 的主循环,也只是插在 ctx.agentLoop 这个插座上的一个插件,和别的工具一样能被换掉。
Cordis 本身,被整个搬进了 dsh 仓库的 vendor 目录,连同加载器、热重载、配置校验等一共 9 个目录。dsh 不跟外部版本走,这颗心脏由它自己维护。

一个能力,三个角色
dsh 的文档把一个能力拆成三个角色,叫能力接缝:声明接口的、实现接口的、使用接口的。
换成图上的东西:墙上的插座是接口(一个 ctx 键),中间那个电源盒是提供者,亮着的灯是使用者。灯只认插座,不认电源盒。电源盒随便换,灯照样亮。
fs: local # 本机磁盘三层配方:档案、捆绑包、补丁
dsh 启动时组装哪些插件,由三层配置决定:
| 层 | 是什么 | 例子 |
|---|---|---|
| Profile 档案 | 一套命名的组合,决定启动什么 | dsh web 就是 dsh --profile web |
| Bundle 捆绑包 | 分发单位,包自己声明里面有什么 | dsh-base 是公共底层;dsh-web-app 往上加浏览器界面 |
| Patch 补丁 | 你自己的覆盖文件,按 id 替换或插入一行 | 在 cordis.patch.yml 里把 fs 换成沙箱 |
运行 dsh --profile web --dump-config,能打印出整棵启动树;打印出来的每一行,都能被你的补丁顶掉。这就是第 07 章「声明式配置」落到产品里的样子。
会话日志:唯一的事实
dsh 还有一个设计,和第 06 章的「一扇门」是同一个思路:模型看到的上下文,完全从持久化的会话日志推出来。规矩是「模型看得见的,一定已经记下了」,运行时会检查每一次模型请求都能从日志完整重建。
好处是只有一份真相:调试、从某一轮分叉出新会话、回放、换一个界面,全都从同一份日志出发。
这里还有两个时间单位值得知道。step 是一次模型请求,加上它引发的工具调用;turn 是从接下一条输入,到再没有欠着的事为止,可以包含零个或多个 step。一轮对话就是一串环节:开始、请求模型、执行工具、结束。每个环节都能挂监听器,加工后交给下游,或者直接拍板。拦截请求、改写工具调用,都在对应环节上挂一个就行。
借鉴之前,看清两件事
第一,dsh 还处在 developer preview,README 用大写字母警告会有破坏兼容的改动。借它的思路,别直接抄它的接口。
第二,论文讲的是 Cordis 的理论,dsh 是建在 Cordis 上的产品。本章关于 dsh 的内容来自它的 README 和架构文档,不是论文的结论。
能力做成插座:接口不变,提供者随便换,用的人只认名字。
请把这个项目里可替换的能力(文件读写、执行命令、调用模型、存储等)改造成「能力接缝」: 1. 每个能力定义一个接口,用一个固定的名字注册; 2. 使用方只按名字取接口,不直接 import 具体实现; 3. 实现作为提供者注册到这个名字上,切换实现只需要改一行配置; 4. 提供者被替换时,使用方自动重新接上; 5. 说明改造后,把文件系统换成沙箱需要改哪一行。
