01 初认DSH
快速运行
运行deepseek harness 源码运行
1 | git clone https://github.com/deepseek-ai/deepseek-harness.git |

配置apiKey

常用路径解析
dsh运行时会在本机用户下的目录新建一个.dsh

| 路径 | 目的 | 应用场景 | 截图 |
|---|---|---|---|
| .dsh | Harness 主目录 | 处理配置,会话。插件注册等 | ![]() |
| .dsh/profiles/web | 以web模式启动的工作目录 | 插件挂载,依赖安装,cordis.patch.yml |
![]() |
| .dsh/sessions | 当前的会话日志 | ![]() |
|
| .dsh/.env | 环境变量配置 | ||
| .dsh/settings.yaml | 全局运行时设置(默认模型路由、权限预设等) | 配置模型,设置权限,主题设置等 | ![]() |
认识dsh cli
deepseek harness 的简称为dsh。 dsh cli则是这套harness的命令行入口,在本项目中是最顶层的命令行解析,也可以叫做 launcher入口(启动器)。由它给到launcher参数,launcher根据一套预设来组织启动,注入相应的依赖,插件以及执行顺序等。
整体概念搭建
dsh 基于 Cordis 微内核,所有功能均拆分为可插拔插件,通过事件总线协同完成 Agent 完整执行循环。Launcher 作为启动器,扫描发现插件,读取配置,参照插件注册表按依赖顺序实例化插件并启动内核;dsh CLI 作为入口,向 Launcher 指定配置与插件组合,最终编排为可运行的服务。
[!IMPORTANT] ❗ 重点
dsh 顶层命令行是整个项目的启动器,它的职责:
- 扫描目录,发现插件(本地插件 / 远程插件)
- 读取全局 + 用户自定义配置
- 按照插件依赖顺序实例化插件
- 启动 Cordis 微内核,把插件挂载到内核事件总线
- 拉起最终服务(web 服务 /cli 任务)

dsh cli 核心指令理解
名词解释
profile : 一套【命名好、独立隔离、可直接启动的插件组合配方】 ,保存在
$DSH_HOME/profiles/<profile名称>/目录里
| 命令 | 作用 | 截图 | 讲解 |
|---|---|---|---|
dsh --profile <名称> |
启动位于 $DSH_HOME/profiles/<名称> 的指定 profile。dsh根据这个的profile,得知并加载相应的Bundle、顺序以及patch文件按这份配方把插件树组装出来、拉起 Cordis 内核。 |
![]() |
官方内置了两套profile1. web dsh --profile web2. headless其中headless 主要服务于不想开界面,直接跑一个任务拿结果的任务,属于shell脚本,不开启端口,它会把命令行剩余部分,提交成一个普通用户消息,跑完把最后一段非空助手文本写到 stdout 退出。dsh --profile headless "把当前目录的测试跑一遍并汇总结果" |
dsh plugin --profile |
指定为某一个profile进行插件的管理事务 | plugin 把参数原样转发给 pnpm,在 profile 目录执行;只接受 pnpm 能识别的源(纯 git 源、link: 等)。 |
dsh plugin --profile web add <plugin插件名称> 为web 安装插件 dsh plugin --profile web remove <plugin插件名称> 为web移除插件 |
dsh --help |
查看启动器自己的帮助指南 | ![]() |
|
dsh --profile <profileName> --help |
查看profile该应用的帮助指南 | ![]() |
|
dsh <profileName> --dump-config |
查看带patch的配置以及组件树(叠加所有层之后的结果) | ![]() |
|
dsh <profileName> --dump-default-config |
查看内置默认配置(未叠加任何 patch) | ![]() |
最重要的规则:参数顺序
启动器只解析自己的 flag,从第一个无法识别的 token 开始,后面全部属于应用参数。
1 | # ✅ 正确:启动器参数在前,应用参数在后 |
认识DSH的配置逻辑
配置优先级以及理解
DSH 配置是分层叠加的:bundle 层 → profile 层 → 用户 patch 层,后者覆盖前者;运行时用户可改的东西在 settings.yaml。
其实所有的分层都是同一套配置的方式,但是意义不一样
bundle层是以 npm 包形式分发的预制能力包,每个 bundle 自带 patch,作为最底层基座(可以是官方 / 第三方写好的)
profile层是本机自定义的启动模板,它选定一组 bundle,同时 profile 自身可以附带一份专属 patch,用来对 bundle 的基础配置做修改
用户patch则提供了一个本机最高优先级的启动期补丁,在内核启动前合并,覆盖前面两层;即profile下的cordis.patch.yml。

1. bundle层
bundle 是 DSH 的标准化可分发能力包(npm 包) ,bundle 层就是 profile 里列出的所有 bundle,按顺序叠加出来的【底层默认配置基座】,是整套配置树的起点。它具体是npm包+dsh.bundle声明。如图




具体讲解:
- 读取当前 Profile 的清单,拿到
dsh.profile.bundles数组(bundle 加载顺序就是数组顺序,前面先加载,后面覆盖前面) - 调用 pnpm:检查包是否安装,缺失就自动安装;pnpm-lock 用来锁定版本
- 逐个遍历 bundle 数组:
- 在 node_modules/pnpm-workspace 找到该包的目录
- 读取包内
package.json - 判断是否含有
dsh.bundle字段,确认是合法 bundle - 读取
dsh.bundle.patch指向的 yaml 文件 - 将这份 patch 合并进全局 Cordis 配置树(下层,被后续 profile patch、全局 patch 覆盖)
[!IMPORTANT]
总的来说:
定义
Bundle就是 开发者写好、打包发布、多人共享的能力单元(可版本管理,npm 安装),是带 Cordis 配置补丁的 npm 能力包。,也是dsh配置体系的最底层基座。通常通过npm等方式安装。
执行逻辑
Launcher 读取 profile 里的 bundle 列表,借助 pnpm 安装并定位 node_modules / pnpm-workspace 下的依赖包;读取包内 package.json 中的
dsh.bundle标识,识别为 bundle 层,加载其指定的 patch 配置,依次合并进配置树。
当经历 bundle层之后,就相当于我们的工具箱里面加载了各种各样的工具,比如 螺丝刀、锤子、钳子….
2. profile/patch层
Profile 是本地目录模板,由它提供 bundle 清单;Launcher 先加载完清单内所有 bundle,再加载 profile 自带的 patch,在 bundle 合并结果之上做覆盖,构成 profile 层;profile 只存在本机,不作为 npm 包分发。换句话来说,我们的工具箱里面已经有了很多工具,现在我们要在这些工具里面挑选我们的工具组合(编写profile),用这些组合去解决问题。
对于launcher来说,
- CLI 指定
--profile xxx,Launcher 去$DSH_HOME/profiles/xxx/找到 profile 目录 - 读取 profile 目录里的
package.json,识别到dsh.profile,确认这是 profile - 取出
dsh.profile.bundles数组 → 进入 bundle 加载阶段(上一节的逻辑)⚠️ 注意顺序:profile 先提供 bundle 列表 → 加载全部 bundle 并合并
- Bundle 层全部加载完毕后,回到 profile 配置,读取
dsh.profile.patch指向的 yaml - 将这份 profile 的 patch 合并到当前配置树:覆盖 bundle 层里相同 key((用户patch层操作)

dsh web默认模板中patch为空。
1 | ~/.dsh/profiles/web/ |
3. setting.yml
setting.yml 位于 ~/.dsh 文件夹中,它与之前的不同的是,之前的是部署开发人员静态写好的配置文件,而settings.yml作用于启动后、运行时可改的配置(由 dsh-settings-file 热发布,用户可在 UI 改)。例如在设置那里配置的apiKey就会修改setting.yml










