DeepSeek Harness 03:插件树与组合层——Profile、Bundle 与能力接缝

DeepSeek Harness 03:插件树与组合层——Profile、Bundle 与能力接缝
Asaakii仅仅知道“一切皆插件”还不足以跑通一个真实的系统。当用户在终端键入启动命令时,系统必须确定地回答三个问题:
- 本次启动到底安装并激活了哪些插件?
- 当命令行参数、全局配置文件与内置策略发生冲突时,谁拥有最终裁决权?
- 当我们将系统底层的文件系统服务换成远程 Docker 沙箱时,终端、代码编辑器与语法分析器为何能自动且完整地迁移到沙箱中?
DeepSeek Harness 给出的答案是:产品形态绝不是一段写死的启动脚本,而是一棵在启动期由多层有序配置叠加渲染出来的插件树(Plugin Tree)。
一、从静态配置到动态插件树
在 DSH 中,官方提供的 Web 界面与 Headless 自动化任务并不是两个不同的内核分支,而是两份由不同组件组装出的“产品配方”。
flowchart TD Bundle["Bundle Patches (底层分发包)"] --> Profile["Profile Patch (产品级基础配方)"] Profile --> Home["Harness Home Patch (~/.dsh 全局配置)"] Home --> CLI["CLI Patch Overlays (命令行 --config 传参)"] CLI --> Launcher["Launcher Overlays (运行时附加选项/遥测)"] Launcher --> FinalTree["最终插件依赖树 (Resolved Plugin Tree)"] FinalTree --> Loader["Cordis Loader 激活并生成 Fiber 实例"]
这套流水线保证了系统在启动前就拥有一份完全确定的配置拓扑。通过在启动命令中加上 --dump-config 参数,你可以直接导出最终计算完成的插件树。这使得任何环境下的异常崩溃,都可以通过静态配置文件 100% 完整复现。
二、Bundle、Profile 与 Patch 的三层职责分工
为了避免配置文件膨胀失控,DSH 将配置拆解为三个职责明确的分层:
| 配置层次 | 核心设计职责 | 坚决禁止承担的越界行为 |
|---|---|---|
| Bundle | 分发一组经过严格版本兼容性测试的插件集合 | 决定特定机器或特定开发者的本地环境偏好 |
| Profile | 定义具体产品形态(如 Web、Headless 或定制 Coding Agent)的基准骨架 | 偷偷侵入或直接修改全局主机的环境参数 |
| Patch | 针对具体环境或临时实验,在指定层级做定向替换与增补 | 引入黑盒式的隐式深度合并逻辑 |
如果把这三层混在一个大而全的 YAML 文件里,虽然也能启动,但后续团队协作时将极其痛苦:你根本无法分辨某个变更到底应该跟随软件版本发布、跟随开发机生效,还是仅仅是一次临时的调试参数。
三、覆盖规则与“整段替换”陷阱
在当前 dsh-v0.1.0-rc.8 规范中,配置叠加的优先级严格遵从以下顺序(后出现的层级拥有绝对胜出权):
$$\text{Bundle} \longrightarrow \text{Profile} \longrightarrow \text{Harness Home} \longrightarrow \text{CLI Overlays} \longrightarrow \text{Launcher Options}$$
但在使用 Patch 覆盖时,有一个极其容易导致线上故障的底层机制:
[!WARNING]
覆盖规则是整段替换(Full Block Replacement),绝不做隐式深合并!
在 DSH 中,通过id覆盖某个插件配置时,系统会完整抹除旧配置块并替换为新配置块。如果你只想修改其中一个字段,但没有显式复述其他必要字段,原有字段将全部丢失。
例如以下错误示范:
1 | # 原始全局配置:设置了模型超时与重试次数 |
此外,DSH 在配置中提供了一个窄口径逃生通道 !!js,允许在受控节点直接执行 JavaScript 表达式引用动态变量。这个设计提升了配置表达力,但也意味着:任何外部传入的 Patch 文件都等同于可执行代码,必须像代码一样经过严格的代码审查(Code Review)与权限沙箱隔离,绝不能盲目加载不可信来源的配置文件。
四、能力接缝(Capability Seams):能力的传导骨架
插件树解决了“装了什么”,而能力接缝(Capability Seams)则解释了“为什么替换一个底层插件能够影响到所有相关上层能力”。
一个标准的能力接缝由三个角色形成闭环:
flowchart LR Def["1. Service Definition<br/>(稳定抽象契约,如 ctx.fs)"] Prov["2. Service Provider<br/>(具体提供者,如 DockerFsProvider)"] Cons["3. Consumers<br/>(消费者,如 BashTool, LSP, Editor)"] Prov -.->|实现契约| Def Cons -->|仅依赖契约| Def
- Service Definition(契约定义):明确规定能力的接口方法、参数结构与取消语义(例如
ctx.fs的readFile、writeFile)。 - Service Provider(能力提供者):负责将接口落地。在本地模式下是 Node.js 原生文件系统,在受限模式下则是隔离的远程容器沙箱。
- Consumer(能力消费者):系统内的上层工具,例如 Shell 执行器、代码编辑工具、LSP 语法服务器。
[!IMPORTANT]
可替换性的真伪检验:真正的能力替换,绝不是简单地把一个 npm 包替换成另一个包。只要任何一个 Consumer 绕过了接缝直接import 'fs'或调用原生系统进程,那么所谓的可插拔就只是表面文章。 只有当所有的 Consumer 都严格通过ctx.fs获取能力时,整个执行平面才能安全、完整地迁入沙箱。
五、官方预置的四种 Agent Preset
利用 Profile 的组合能力,DSH 原生提供了四种开箱即用的工作模式:
| 模式名称 | 预置配置标识 | 核心包含能力 | 适用业务场景 |
|---|---|---|---|
| Standard | standard |
文件编辑、Shell 执行、全局检索、Skills、主动规划 | 日常主力代码生成与调试场景 |
| PTC | code |
依托 TypeScript 编程动态串联工具,支持多步复合调用 | 涉及复杂拓扑、大量中间工具结果过滤的高级场景 |
| Minimal | minimal |
仅保留 bash 与 str_replace_editor 两个原子工具 |
基线评测(Benchmark)、最小权限隔离与调试 |
| Creative | cordis |
暴露完整的 Cordis 运行时反射接口与调试控制台 | 供开发者探索微内核机制与编写实验性插件 |
这四种模式的实现极为优雅:代码仓库中没有任何形如 if (mode === 'minimal') 的业务硬编码。所有的行为差异,完全是通过在 YAML 中装载不同的插件树来达成的。需要一套新的企业定制模式?只需要编写一份新 Profile YAML 即可。











