跳过主要内容
全部文章
指南

DeepSeek Harness 的 Profile 与 Bundle 详解

DeepSeek Harness 的 profile 和 bundle 如何协同工作、它们在磁盘上放在哪、dsh.profile.bundles 如何自动同步,以及什么时候该维护多个 profile。

Profile(配置档案) 是你用 dsh --profile <name> 启动的一份可运行配置。Bundle(插件包) 是贡献这份配置一部分内容的 npm 包。每个 profile 本质上就是一份按顺序排列的 bundle 列表,加上你自己的覆盖层——理解这层拆分,是弄懂 DeepSeek-Harness(dsh)配置到底怎么运作的最快方式。

Bundle:一个包贡献了什么

Bundle 就是任何一个在 package.json 里声明了 dsh.bundle 字段、并指向一个 patch 文件的 npm 包:

{
  "name": "dsh-hello-plugin",
  "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}

这个 cordis.patch.yml 文件才是真正的负载——一份 YAML 文档,用来往 Cordis 插件树里插入或覆盖某些行(关于这个配置层的详细内容见 DeepSeek Harness 配置指南)。Bundle 本身只是打包方式:借助普通的 npm/pnpm 供应链来发布、管理版本、安装这份 patch。

并不是你装进某个 profile 的每个包都是 bundle。如果一个包的 package.json 里没有 dsh.bundle 字段,dsh plugin 依然会把它当作普通依赖装进去——当一个真正的插件依赖某个纯库时这很有用——但会打印警告,且不会为它激活任何配置。dsh.bundle 字段的存在与否,是区分"这是一个 dsh 插件"和"这只是某个 dsh 插件恰好需要的一个包"的唯一权威信号。

Profile:你到底在运行什么

Profile 就是一个目录:$DSH_HOME/profiles/<name>/(默认 $DSH_HOME~/.dsh)。里面有两个关键文件:

  • package.json——声明 dsh.profile.bundles,一个有序的 bundle 包名数组,加上这个 profile 自己的 npm 依赖(也就是那些已安装的 bundle 包本身)。
  • cordis.patch.yml——你为这个特定 profile 添加的个人覆盖层,叠加在各个 bundle 已经配置好的内容之上。
{
  "dsh": {
    "profile": {
      "bundles": ["@deepseek-ai/dsh-base", "dsh-hello-plugin"]
    }
  }
}

有两个 profile 名字是保留的,第一次使用时会自动用内置模板初始化:web(用 @deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app 初始化)和 headless@deepseek-ai/dsh-base + headless bundle)。文档明确写明 dsh webdsh --profile web 的硬编码别名,一次性无头任务则走 dsh --profile headless "任务文本"

其他任何名字的 profile,都必须先初始化才能启动——第一次执行 dsh --profile <name> add <包> 时,会先用基础 bundle @deepseek-ai/dsh-base 引导这个 profile,再把你要求安装的包装到上面。

dsh.profile.bundles 是如何保持同步的

你不需要手动编辑 bundle 列表。每一条 dsh plugin --profile <name> <pnpm 参数> 命令——addremoveupdatewhy——都会原样转发给 pnpm,执行完之后再重新核对该 profile 下实际安装的依赖。任何声明了 dsh.bundle 的已安装包,都会被自动同步进 bundle 列表;被移除的包会自动从列表里摘除。完整的安装命令走查以及 GitHub 来源插件(没有预编译 lib/、直接分发源码)会触发的 allowBuilds 提示,参见如何安装 DeepSeek-Harness 插件

# 往 web profile 里装一个插件
dsh plugin --profile web add github:owner/repo

# 查看生成后的 profile package.json
cat "$DSH_HOME/profiles/web/package.json"

层叠顺序:先 bundle,再你自己,最后是整机

dsh 为一个 profile 组装最终配置时,各层按以下顺序生效,后面的层按行 id 覆盖前面的层:

顺序作用范围
1各 bundle 的 patch,按 dsh.profile.bundles 列表顺序(base bundle 总是第一个)每个 profile 各自的、来自已安装包
2该 profile 自己的 cordis.patch.yml仅限当前 profile
3$DSH_HOME/cordis.patch.yml这台机器上的所有 profile
4命令行上的任意 --patch <path> 参数,按 argv 顺序仅限本次调用

注意第 3 层——机器级的 patch——排在 profile 自己的 patch 文件之上。你写进 $DSH_HOME/cordis.patch.yml 的设置,会覆盖某个具体 profile 自己配置的内容,这正是它存在的意义:这是放"无论启动哪个 profile 都想生效"的偏好设置的地方。这部分内容从"配置如何合并"的角度在 DeepSeek Harness 配置指南中有更详细的讨论,包括 patch 会整体替换目标行的 config、而不是深度合并这一点。

什么时候该维护多个 profile

因为模型提供商配置($DSH_HOME/settings.yaml.credentials.yaml)是所有 profile 共享的,而 bundle 及其 patch 是各 profile 独立的,维护多个 profile 的成本很低,而且在划分关注点时确实有用:

  • web——你日常用的那一个,装你真正依赖的插件:一个 UI 修复、一个通知插件,或者从开发与运行时分类里挑的什么东西。
  • 一个 minimal profile——dsh 内置了一个 minimal agent 预设(固定的系统提示词,只挂载 bashstr_replace_editor 两个工具),适合你想要最小化能力面、不想让任何第三方插件参与其中的场景。
  • 一个实验性 profile——用来试装还不完全信任的插件,与你日常用的 web profile 隔离开,这样一次装坏了也不会拖垮你依赖的那份配置。

在它们之间切换只需要改 --profile 参数,底层的 dsh 二进制本身不会有任何变化。

引导一个既不是 web 也不是 headless 的 profile

保留名字的这个快捷方式只适用于这两个名字。如果你在一个 profile 存在之前就试着启动它,dsh 不会悄悄替你造出一份完整的初始配置——它只会用基础 bundle @deepseek-ai/dsh-base 初始化这个 profile,别的什么都没有。你需要显式地把想要的其他东西加进去:

# 第一次使用 "experiment"——只用 @deepseek-ai/dsh-base 引导
dsh plugin --profile experiment add github:owner/some-plugin

# 现在它是一个可以启动的真实 profile 了
dsh --profile experiment

这是一个刻意为之的不对称设计:webheadless 是两个符合大多数人实际用法的、有主见的起点(一个浏览器 UI,或一个可脚本化的一次性任务执行器),而自定义名字的 profile 则尽可能地从"空"开始,这样它就不会悄悄积累你从未要求过的插件。如果你要为某个具体的、范围很窄的目的搭建一个 profile——比如一个 CI 执行器、一个精简过的审查 agent——正是这个行为保证了它不会悄悄继承和你 web profile 一样的默认配置。

FAQ

Bundle 之间可以互相依赖吗?

webheadless 这两个启动模板里,基础 bundle @deepseek-ai/dsh-base 在层叠顺序上总是排第一,其他 bundle 预期是在此基础上通过 patch 顺序叠加的。除此之外,dsh 官方文档(以及本站参考的事实资料)没有描述一套超出 dsh.profile.bundles 列表顺序之外的正式 bundle 间依赖图——目前应把"安装顺序"当作依赖机制来对待。

如果我手动删掉一个 profile 目录会怎样?

删掉 $DSH_HOME/profiles/<name>/ 会把这个 profile 彻底移除。webheadless 下次使用时会直接从默认模板重新引导;自定义名字的 profile 则需要重新执行一遍 dsh --profile <name> add <包> 才能重新初始化。

多个 profile 之间会共享插件吗,还是各自单独装一份?

每个 profile 都有自己独立的 node_modules 和自己的 bundle 列表——往 web 里装一个插件,不会让它在另一个 profile 里也可用。如果想让同一个插件在两个 profile 里都能用,需要在每个 profile 里分别安装一次。

dsh.profile.bundles 需要我手动编辑吗?

不需要——它设计上是根据你通过 dsh plugin add/remove 实际安装的内容自动派生出来的。手动编辑它有可能让它和 node_modules 的实际状态脱节;交给 CLI 在每次安装后的重新核对逻辑去维护会更准确。

下一步

理解了 profile 和 bundle 如何组合之后,DeepSeek Harness 配置指南会讲清楚 patch 到底是怎么合并的(整行替换而非深度合并),以及如何用 --dump-config 调试组合后的最终配置。如果你还没装过插件,可以先看如何安装 DeepSeek-Harness 插件,或者去开发与运行时分类以及完整插件目录逛逛——一个不错的起点是 oh-dsh,一个把 TUI、桌面端、Web UI 打包成一个分层 bundle 的社区发行版。