本页文字稿为音频的配套解读,内容取自小山学堂课程素材,属二次演绎版本。
文中行数、包数、插件数均为 2026-08-13 对源码做本地统计的结果,随版本演进可能变化。
读一篇产品的发布文,有两种常见的读法,两种都会出错。
第一种是把它当宣传稿略过。结果是错过真正的架构信号——发布文里往往藏着一个团队最想让别人记住的设计决策,那些话反而是最诚实的。
第二种是把它当设计文档全盘接受。结果是照着一句文案去仓库里找实现,找了半天发现这个名字只在 UI 层存在,源码里根本没有对应物。
这一集走第三条路:逐条对照。把发布文里说的四种模式、插件生态,一条条对到仓库里的具体文件,看它们到底叫什么、在哪一行。对照完会得到三句话:
把这一集讲的东西按"谁负责什么"拆开,得到这样一张地图。
| 层 | 位置 | 职责 | 变化频率 |
|---|---|---|---|
| 内核 | vendor 进仓库的 Cordis 框架 | 装载插件、卸载插件、把注册记为可逆副作用并在卸载时回滚 | 几乎不变 |
| 能力层 | packages/(49 个分组 / 219 个包) | 模型适配器、工具注册表、会话日志、agent loop 主循环等全部业务能力 | 高 |
| 组装层 | apps/cli/config/agent-presets/<mode>/ | preset.yml 管展示名与排序,agent.cordis.yml 是插件清单 | 高 |
| 生态层 | 树外(out-of-tree)npm 包 | 第三方插件,装进 profile,运行时挂载 | 最高 |
内核这一层的边界是这一集最值得记住的东西。Cordis 只做三件事:把插件装进共享上下文、把插件卸下来、把每次注册记成可逆的副作用。业务逻辑一行都没有。根 AGENTS.md 第 3 行用加粗英文写着"everything is a plugin"。
官方文档(docs/architecture.zh.md 第 11、13 行)的原话是:
Cordis 是 dsh 底层的框架:插件向共享上下文贡献服务、类型化事件和可逆的副作用。产品的每一部分都是插件,包括模型适配器、工具注册表、会话日志,以及 agent loop 本身,因此每一部分都可以从配置替换。
不存在需要打补丁的特权内核:扩展 dsh 的方式是把插件挂载到其他插件旁边,而各项注册都是副作用,会在其插件卸载时撤销。
"不存在需要打补丁的特权内核"不是修辞,是有代价的承诺。 要兑现它,内核必须小到只装得下装卸机制。这也意味着:一旦有人为了省事把某个业务能力塞回内核,这条承诺就开始漏水,而且短期内没人会发现——因为短期内没人会去替换那个能力。
四种模式各是 apps/cli/config/agent-presets/ 下的一个目录,目录里两个文件。切换模式 = 换一份清单重新组装,源码里没有任何模式分支。
| 模式 | 目录 | 清单行数 | 相对 standard 的差异 | 给谁用 |
|---|---|---|---|---|
| 标准 | standard/ | 251 | 基准,23 个插件全开(macOS 视角) | 日常写代码的人,默认档 |
| PTC(Code Mode) | code/ | 262 | standard 一行不动,末尾多挂 tool-presentation,mode: code | 跑多步长任务、嫌一次一往返太慢的人 |
| 极简 | minimal/ | 62 | 只剩 6 个插件,persona complete: true 锁死,无 compaction | 跑模型基准测试的人 |
| 创造 | cordis/ | 262 | standard 全套 + tool-cordis 工具集 + 组合写法 skill,persona 换版本 | 想让 Agent 造 Agent 的人 |
standard/agent.cordis.yml 全文。思路是先定义一个能力齐全的参照系,其余三个模式才有资格用一句话说清自己。code/agent.cordis.yml 第 259–262 行,第 3 行注释写明 standard 全量未动。效果是用 run_code 一次执行原本要 5 次往返的操作。改的只是工具的呈现方式,能力本身没变,所以差异只配拥有一行。minimal/agent.cordis.yml 全文 62 行,persona 见第 8–13 行。思路是把 harness 的变量排干净,剩下的表现就是模型本身。cordis/agent.cordis.yml 第 245–246 行,权限提醒见第 9–12 行。文件头注释提醒:把这个模式的会话当 shell 权限对待。思路是组装器自己也是插件,所以能开放给 Agent 用。插件数是 macOS 视角。仅 Windows 启用的 tool-pwsh 与两条 disabled 状态的委派行未计入,因此在 Windows 上数出来的数字会不一样。
能力层之上还有一层:官方仓库之外的插件,即 out-of-tree(树外)插件。
dsh plugin --profile <name> add <package> 把包装进某个 profile;dsh-plugin 话题标签,方便互相检索。出处:packages/bundle/README.zh.md 第 13 行;README.zh.md 第 40 行;docs/architecture.zh.md 第 13 行。
这里有一处容易被忽略的因果链值得单独说明:副作用可逆 → 可安全反复装卸 → 热切换模式成立。如果注册不是可逆的,那么装一次卸一次就会留下残留状态,模式切换只能靠重启进程来做,运行时可拔插这件事在事实上就不成立了。所以"可逆副作用"看起来只是卸载时的清理细节,实际上它是整套热插拔叙事的地基。
也因此,发布文里"邀请共建生态"这句话不是客套。装卸机制、profile、话题标签这套东西本来就是为第三方准备的,机制是现成的,缺的只是参与者。
code/preset.yml 第 1 行写着 name: PTC 模式,但目录叫 code,源码注释和文档里这套机制叫 Code Mode。全仓库找不到名为 PTC 的实现。
这件事本身不大,但它给了一个很好用的判断标准:
看到一个花哨的名字,先去仓库里搜一遍。搜得到就是机制,搜不到就是文案。
花三十秒能省掉后面一整场误会,也能避免把一句宣传语写进自己的设计文档。
同一个问题——想给 Agent 加一个新能力,需不需要动它的仓库源码?三家给出三种答案。
| 产品 | 答案 | 机制 | 换来的东西 |
|---|---|---|---|
| DeepSeek Harness | 不需要改仓库 | 能力是树外 npm 包,装进 profile,运行时挂载,卸载时副作用自动回滚 | 运行时可拔插、可替换、可审计 |
| Claude Code | 看情况 | 还原源码是一棵 TypeScript 单体源码树(入口 main.tsx),对外留 hooks / MCP / Skills 扩展口 | 产品迭代速度 |
| Grok Build | 需要改仓库 | 根 Cargo.toml 的 members 数组列 79 个 workspace 成员,按 crate 切分、编译期组合 | Rust 的类型与性能保证 |
三家没有绝对优劣,只是代价不同。若目标是"可替换、可审计的运行时",三家里只有 DeepSeek Harness 让第三方无需 fork 仓库就能替换深层能力。
评估一个 Agent 产品是否真的做到"一切皆插件",可以按这七条逐项打勾:
第 5 条是分水岭。很多产品做到第 2、3 条就宣称自己是插件化架构,但主循环仍然焊死在产品源码里——那意味着你换不掉这个 Agent 的思考方式。
再补一条关于可逆性的检查:插件卸载时,它注册的服务、事件监听、副作用是否全部撤销?如果卸载会留下残留状态,热切换模式就只能靠重启进程,运行时可拔插这件事实际上不成立。
agent.cordis.yml 文件行数。tool-pwsh 与两条 disabled 委派行。standard / code / minimal / cordis)或机制真名 Code Mode,避免使用 UI 展示名 PTC 与工程师对齐。微内核思想比这份代码老得多。操作系统课上的 Mach 与 L4、浏览器的扩展体系、VS Code 的插件生态,走的都是同一条路:变化快的能力放外圈,几乎不变的装卸机制放核心。
这么分层的好处经得起时间考验:官方把 agent loop 整个重写一遍,Cordis 的装卸逻辑一行不用动;换个语言把这套 harness 再写一遍,这个分层照样管用。
推论是:学这类项目时,记结构比记代码划算。代码只是这个思路的某一版实现,明年可能就变了;结构才是能带走、能迁移的东西。
判断什么该进内核,别问它重不重要,要问它变不变。会话日志很重要,但它会变;工具注册表很重要,它也会变;装卸机制看起来最不起眼,可它几乎不变。按变化频率分层比按重要性分层靠谱得多,因为重要性是主观的,变化频率是可以事后验证的。
standard 模式的存在意义不是"给大多数人用",而是"让其余组合能用一句话说清自己"。你在设计任何一组 SKU、套餐、配置档位时,都值得先造一个能力齐全的参照系。没有基准,别的组合就只能靠长篇描述说清自己,而长篇描述正是分歧的开始。
这套做法有个通行名字:配置即架构。想知道两个模式差在哪,diff 两份 YAML;想造新模式,复制目录改几行;出了问题,回滚清单就行。Kubernetes 用 YAML 声明集群,Docker 用 Dockerfile 声明镜像,同一个思路在不同层面反复出现。架构问题一旦降维成文本问题,就变得可以比较、可以回滚、可以进代码评审了。
在写设计文档之前,把文档里出现的产品名、模式名、特性名逐个在仓库里搜一遍。搜不到实现的名词一律标注为"UI 展示名",不要让它进入技术对齐的语境。这条习惯成本极低,收益极高。
把standard/agent.cordis.yml里id: compaction的整个 group(第 137–155 行)删掉,得到的会话和极简模式在上下文压力下的表现是否等价?再对照minimal/agent.cordis.yml的 persona 三个字段(第 8–13 行),说出除了压缩之外还差哪两点。
不等价。 除了没有 compaction 之外,至少还差两点:
complete: true 的一句话,别的插件想追加提示词也加不进去;standard 删掉 compaction 后,其余插件仍可继续贡献提示词。str_replace_editor;standard 删掉 compaction 后仍保有文件编辑、shell、检索、计划、子代理、工作流等全套工具。想明白这两点,四份清单就算真的读透了。
packages/ 里的插件;preset.yml 的展示名里,机制的真名叫 Code Mode;来源:xueai.miyang.cn(小山学堂 · 洛小山《学 AI 产品,从入门到精通》)
本内容改编自小山学堂课程素材,为二次演绎版本。