自学教程

DeepSeek Harness 安装插件与配置加载顺序

DeepSeek Harness 的插件安装、配置加载是两套独立但联动的流程:插件安装是包管理动作,负责把插件代码下载、写入 Profile 清单;配置加载是内核启动时的组合解析动作,按固定分层顺序合并配置,后加载层覆盖前面层。绝大多数配置不生效、插件加载失败、参数覆盖异常问题,根源就是混淆了「安装流程」和「启动加载流程」。

一、插件安装:两种安装方式与清单变更

插件安装本质是修改对应 Profile 的 package.json 与 dsh.profile,分为Bundle组合包安装和独立外置插件安装。

1. CLI 命令安装(推荐)

# 向 web profile 安装插件/组合包
dsh plugin --profile web add dsh-auto-clean
# 卸载
dsh plugin --profile web remove dsh-auto-clean

执行安装时内部发生的动作:

  1. 包管理器下载插件包(npm包、本地路径、github仓库);
  2. 将包写入当前 Profile 的 package.json dependencies;
  3. 如果该包包含 dsh.bundle 声明,则自动追加到 dsh.profile 的 bundles 数组末尾;
  4. 普通无 bundle 声明的独立插件,仅安装依赖,不会自动加入 bundles 列表,需要手动在patch中注册。

重点:Bundle 会追加到 bundles 数组尾部,数组越靠后,配置优先级越高,天然实现后置覆盖前置。

2. 本地手动安装(开发调试)

直接在 profile 的 package.json 添加依赖,或者用 link: 挂载本地插件源码。

  • 有 dsh.bundle:手动在 dsh.profile 的 bundles 数组加入包名;
  • 无 bundle 的独立插件:仅添加依赖,需要在 cordis.patch.yml 手动声明插件实例。

区分:安装只是把代码放到环境,不等于自动加载插件;只有被 Profile 引用的 Bundle,或者在patch里显式注册的插件,内核才会在启动阶段加载。

二、内核启动:配置分层加载顺序(核心)

Harness 启动时,从空配置开始逐层叠加,后应用的层,相同配置项直接覆盖前面层,优先级由低到高如下:

  1. Bundle 层(最低优先级)
    按 dsh.profile 文件内 bundles 数组顺序依次加载每个 Bundle。
    读取每个 Bundle 内部 dsh.bundle 清单,加载Bundle自带插件与默认配置。

数组靠前先加载;数组靠后后加载,同配置会覆盖前面Bundle。

  1. Profile 本地补丁层
    读取当前Profile目录内 cordis.patch.yml,对上面所有Bundle的配置做局部覆盖。仅作用于当前Profile。
  2. 全局Home补丁层
    读取 $DSH_HOME/cordis.patch.yml,全局补丁,对本机所有Profile生效,优先级高于Profile本地补丁。
  3. 命令行 –patch 层
    启动命令传入的 --patch 参数,临时叠加配置,只在本次启动生效。
  4. 启动器内置补丁(最高优先级)
    框架启动器自动注入的内置配置(遥测开关、agent预设参数等),优先级最高,无法通过patch覆盖。

一句话优先级:Bundle 默认配置 < Profile补丁 < 全局Home补丁 < CLI –patch < 框架内置补丁

三、插件实例加载与激活顺序(Cordis内核)

配置合并完成后,进入插件实例化阶段,遵循依赖拓扑排序,不是简单按Bundle数组顺序执行。

  1. 内核扫描全部插件声明,构建插件依赖图(Definition / Provider / Consumer三角色依赖关系);
  2. 按依赖拓扑排序:被依赖的插件优先启动;
  3. 执行插件生命周期钩子:setup → 注册服务、事件、工具 → 激活;
  4. 依赖缺失的插件会延迟等待,超时则抛出加载失败;
  5. 热重载场景:修改Bundle/Profile/patch文件,内核重新执行整套配置合并+拓扑加载,无需完全重启进程。

注意:Bundle数组顺序决定配置合并顺序;插件之间的依赖关系决定实例激活顺序,二者不要混淆。

四、实战示例:安装插件后配置覆盖演示

假设 dsh.profile:

{
  "bundles": [
    "@deepseek-ai/dsh-base",
    "@deepseek-ai/dsh-web",
    "dsh-auto-clean"
  ]
}

加载流程:

  1. 加载 @deepseek-ai/dsh-base 基础Bundle,写入基础默认配置;
  2. 加载 @deepseek-ai/dsh-web,覆盖base中冲突配置;
  3. 加载 dsh-auto-clean(后安装的插件Bundle),覆盖web层冲突配置;
  4. 读取当前profile的 cordis.patch.yml,覆盖上面三层;
  5. 读取全局home补丁,继续覆盖;
  6. 解析命令行 --patch 参数;
  7. 内核做依赖拓扑排序,依次实例化插件。

五、调试加载顺序的工具

  1. dsh --dump-config:导出合并完成后的完整最终配置,查看每一项配置来自哪一层,是排查配置不生效最常用命令;
  2. 日志:启动日志会打印每层配置加载、插件注册、依赖等待信息;
  3. HMR热重载:开启后修改patch、profile、bundle清单,自动重新执行整套加载流程。

六、常见踩坑清单

  1. 安装插件后,插件不加载
    原因:插件包没有声明 dsh.bundle,安装仅写入package.json,没有加入bundles数组。
    解决:要么手动声明bundle,要么在patch中手动注册插件。
  2. 修改Bundle源码配置,重启不生效
    原因:Bundle包是版本固化,不要直接修改bundle源码;用户自定义修改统一写在patch层。
  3. 后面Bundle的配置无法覆盖前面Bundle
    原因:bundle数组顺序写反,需要把需要覆盖的Bundle放到数组后面。
  4. 全局patch覆盖了本地profile配置
    原因:全局home补丁优先级高于profile补丁,本机所有环境都会被影响,项目定制优先使用profile目录内patch。
  5. 插件安装成功,但启动报依赖缺失
    原因:包安装完成,但插件内部依赖的服务没有被加载,内核拓扑排序等待依赖超时。检查依赖对应的Bundle是否加入profile bundles列表。

七、最佳实践

  1. 通用能力封装为Bundle,安装时自动追加到bundles末尾,利用后置覆盖特性;
  2. 项目级配置修改,优先写当前Profile的 cordis.patch.yml,不改动Bundle包;
  3. 机器全局偏好,使用 $DSH_HOME/cordis.patch.yml;
  4. 临时调试参数,使用命令行 --patch,不写入文件;
  5. 新增Bundle一律放在bundles数组末尾,避免覆盖顺序混乱;
  6. 遇到配置异常,优先使用 dsh --dump-config 查看最终合并后的配置,定位配置来源层。

小结

插件安装是包管理动作,只负责下载代码、修改Profile清单;配置加载是内核启动时分层合并动作,遵循固定优先级,后层覆盖前层;插件实例激活顺序由依赖拓扑关系决定,而非Bundle数组顺序。理解这套顺序,就能快速定位插件加载失败、配置不生效、参数覆盖异常等绝大多数问题。

标签:

0 条笔记