dshkit

「一切皆插件」:DeepSeek Harness 背后的 Cordis 架构

插件内核这个说法在 dsh 里到底意味着什么——bundle 是可分发的配置行、dsh-base 这层地基、插件怎么解析和安装,以及为什么连 UI 都能换掉。

更新于 2026-08-133 min
一句话结论

dsh 里每一项 agent 能力都由插件提供——模型、工具、skills、会话、沙箱、存储、循环、调度和 UI。插件以 bundle 形式分发,bundle 是配置行加它挂载的代码,而 bundle 插入的任何东西都仍然能被上面的层 patch。bundle 先从 dsh 安装目录解析,再从 profile 自己的 node_modules。

「一切皆插件」这种话通常是营销词。在 DeepSeek Harness 里,它更接近对启动过程的字面描述,而由此推出的 结论值得搞清楚——它同时解释了这个 harness 的灵活性和它的锋利之处。

这句话的准确含义

插件提供每一项 agent 能力:模型、工具、skills、会话、沙箱、存储、循环、调度、UI。Cordis 的服务与 事件是这些插件互相触达的方式。

结论是:不存在一个「你只能围着它配置」的特权内核。harness 启动时组装出一串配置行,而每一行都来自某个 插件。所以下面这条命令才是有意义的,而不是调试用的花招:

dsh --profile web --dump-config

它打印整个运行中的系统,而其中每一行都是 patch 能命中的目标。

bundle:分发单位

你通常不是装单个插件,而是叠一个 bundle——Cordis 配置行及其挂载代码的分发格式。

这个定义里带着一条值得单独拎出来的保证:bundle 插入的任何东西,仍然能被它上面的层 patch。bundle 是起始位置,永远不是封死的盒子。

预览版自带三个:

Bundle提供
dsh-base模型适配器、工具、持久化、沙箱与审批策略、设置、凭证、遥测
dsh-web-app浏览器能力,即网页 UI
dsh-headless单次执行,无服务端

dsh-base 是一切的地基,其余是组装:web 是 base 加 web app,headless 是 base 加 headless。 两个自带 profile 的全部差别就这一点。

为什么这让 UI 可替换

如果浏览器 UI 是以 bundle 的形式到来、而不是就等于程序本身,那替换它就是一次配置改动。沙箱策略、 存储层、审批闸门同理——每一个都是 dsh-base 插入的一行,每一个都能被上面的 patch 层替换。

这才是这套架构真正的回报,也是为什么「harness」这个词比「app」更准确。harness 是你套在模型外面的 那副挽具;DeepSeek 押的注是:你应该能重新拴上其中任何一部分,而不需要 fork。

装 out-of-tree 插件

第三方插件装进 profile 自己的 node_modules

dsh plugin --profile web add some-cordis-plugin

子命令把参数直接转发给 pnpm,所以 pnpm 全套词汇可用——addremoveupdate、版本号、workspace 协议。

当一个名字可能指向两样东西时,解析顺序就重要了:bundle 先从 dsh 安装目录找,再从 profile 自己的 node_modules。配合 patch 层,你拿到两个互相独立的杠杆——要么按名字遮盖一个包,要么不动包、 只覆盖它插入的具体那几行。

因为插件是按 profile 隔离的,两个 profile 可以各持互不兼容的插件集而互不干扰。这也是并行跑「实验配置」 和「你真正依赖的配置」的正确方式:克隆一份 profile,把有风险的插件装进克隆体,按名字启动你想要的那个。

patch 一个插件的行

patch 按标识符命中某一行,要么整行替换配置、要么插入新行。层的顺序是固定的——profile 列出的每个 bundle、profile 的 cordis.patch.yml$DSH_HOME/cordis.patch.yml、最后 --patch

实操上永远是同样三步:

  1. dsh --profile web --dump-config,找到你要改的那一行的标识符
  2. 在 profile 的 cordis.patch.yml 里写一个命中该标识符的 patch
  3. --dump-config 一次,确认组装结果就是你要的

跳过第三步,就是人们坚信「配置系统坏了」而其实只是某个更高的层赢了的由来。

代价在哪

灵活不是白来的。

每个插件都是一个会移动的 API 面。 这是 v0.1 开发者预览版,维护者明说核心插件和 API 会持续演进。 你针对某一行的具体形状写的插件,等于你已经同意去维护它。

调试是「组装形状」的。 行为出乎意料时,问题很少是「这段代码干了什么」,通常是「哪一层设了这个」。 这和多数工具需要的调试直觉不一样,而 --dump-config--dump-default-config 的 diff 就是答案。

没有东西拦着你组装出一个不自洽的系统。 一个允许你替换审批策略的内核,也会允许你把它替换成「一律 放行」。patch 沙箱之前,先读懂你在 patch 什么。

常见问题

网页 UI 真的是插件吗?

是。浏览器能力来自叠在 dsh-base 上的 dsh-web-app bundle。headless profile 只是换成叠 dsh-headless,得到无服务端的单次执行。

怎么装第三方插件?

dsh plugin --profile <名字> <pnpm 参数>,它转发给 pnpm,装进该 profile 自己的 node_modules。

本地插件能覆盖自带的吗?

bundle 先从 dsh 安装目录解析、再从 profile 的 node_modules;而 bundle 之上的 patch 层可以替换它插入的任何一行。覆盖自带行为是设计好的路径,不是奇技淫巧。

接着看