首页 / DeepSeek Harness 入门教程 / Profile 与 Bundle 组合模型

DeepSeek Harness 入门教程

Profile 与 Bundle 组合模型

本教程共 32 篇 · 第 7 篇 · 更新于 2026-08-15 · 约 6 分钟阅读

ProfileBundledsh-base组合模型配置

本节目标:搞清 Profile(装配方案)和 Bundle(组合包)的分工,理解 dsh 启动时按什么顺序把各层配置叠成最终插件树。

上一章说了,dsh 的一切都是插件。那么问题来了:几百个插件,谁来选、按什么顺序装?

答案是两个概念:ProfileBundle。把 dsh 想成点菜:Profile 是菜单,Bundle 是后厨的菜谱。菜单决定上哪些菜、按什么顺序;菜谱决定每道菜怎么做。你点菜时(dsh --profile web),后厨照着菜单执行。

两者都写在 package.json 里,靠 dsh 字段声明自己。但回答的问题完全不同。

两个概念,两种 manifest

Bundle 是 Cordis 配置项及其挂载代码的分发格式。它随 npm 包分发,manifest 声明 dsh.bundle。它回答「这个包贡献什么」:一个插入或覆盖插件行的 patch 文件。

Profile 是存放在 Harness home 中的具名组装。它列出要叠放的 Bundle,存放自己安装的树外插件,还保存用户自己的 cordis.patch.yml。manifest 声明 dsh.profile,回答「这套配置由哪些 Bundle 按什么顺序组成」。

一句话区分:Bundle 是作者编写并分发的东西;Profile 是用户用 dsh --profile <name> 启动的东西。 没有东西同时是两者。

Note

Profile 目录位于安装目录之外,路径模板是 $DSH_HOME/profiles/<name>$DSH_HOME 默认为 ~/.dsh)。webheadless 两个 Profile 在首次使用时从随附模板自动初始化;其他 Profile 要通过 dsh plugin --profile <name> <pnpm 参数> 创建。

dsh-base:每个 Profile 的第一层

官方随发行版交付三个组合包:

组合包作用
@deepseek-ai/dsh-base每个 Profile 的第一层:模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测
@deepseek-ai/dsh-web-app在 base 之上增加浏览器应用(Web UI)
@deepseek-ai/dsh-headless在 base 之上增加一次性运行器,完全不带服务器

web Profile 叠放 base + web-app;headless Profile 叠放 base + headless。不管哪种形态,base 都是地基。你日常看到的能力——LLM 适配器、工具流水线、会话日志、沙箱、审批——几乎全部来自这一层。

一个 Bundle 的 package.json 长这样:

{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "type": "module",
  "main": "index.js",
  "files": ["index.js", "cordis.patch.yml"],
  "dsh": {
    "bundle": {
      "patch": "./cordis.patch.yml"
    }
  }
}

关键字段是 dsh.bundle.patch:指向这个包贡献的 patch 文件。patch 文件里按包名引用插件(如 - name: 'dsh-hello-plugin'),安装后 pnpm 会把包链接进 node_modules,模块解析就能找到代码。没有 dsh.bundle 声明的包仍然可以安装,但只作为普通依赖,不会激活任何配置层。

新手最常问:普通 npm 包和 Bundle 有什么区别?判断标准就一条——有没有 dsh.bundle 声明。

组合顺序:四层叠加

运行中的 dsh 是一棵插件树,由启动时按序叠加的各层组合而成。以空条目列表为起点,顺序如下:

  1. 按 Profile 列出的顺序,应用每个 Bundle 的 patch
  2. 应用 Profile 自己的 cordis.patch.yml
  3. 应用 home 级 $DSH_HOME/cordis.patch.yml
  4. 应用任意 --patch 覆盖层(可多个)
空根 → bundle 序 → profile patch → home patch → --patch 覆盖层

一条 patch 按 id 定位某个条目,替换其整个 config,或插入新条目。靠后的层覆盖靠前的层,这就是「分层可替换」的来源:出厂默认配置在 Bundle 层,你的个人偏好写在 Profile 或 home 层,临时调试用 --patch,互不干扰。

人话版:像在桌上贴便利贴,越晚贴的越靠上,盖住下面同位置的文字。同 id 的条目,后盖的赢。

profile 的 manifest 同样写在 package.json 里:

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

dsh.profile.bundles 中列出的 Bundle 先从 dsh 安装目录解析,再从 Profile 自身的 node_modules 解析;树外插件由 dsh plugin 安装进 Profile 目录。

用命令验证组合结果

组合模型不需要靠猜。两个命令直接看结果:

# 查看 web Profile 组合后的完整配置树(不启动)
dsh --profile web --dump-config

# 查看排除用户层后的默认配置树
dsh --profile web --dump-default-config
# 正常启动
dsh web                          # --profile web 的别名
dsh --profile headless "任务描述"  # 一次性运行任务

--dump-config 打印出的任何条目,都可以由你自己的 patch 替换。想确认某个插件是否被加载、某个配置项生效没有,先 dump 再看,比翻文档快得多。

Tip

dsh webdsh --profile web 的别名。启动器只解析自己的 flag,--profile 之后、第一个无法识别的 token 之前,都属于应用参数。例如 dsh --profile web --port 8080--port 属于 web 应用,不是启动器参数。

三层视角:Bundle / Profile / Patch

把三者的关系放在一起看:

概念manifest 键回答的问题谁编写 / 谁使用
Bundledsh.bundle这个包贡献什么(一个 patch 文件)插件作者编写,随包分发
Profiledsh.profile这套配置由哪些 bundle 按什么顺序组成用户用 dsh --profile 启动
Patch无(YAML 文件)按 id 增删改插件条目任何人,在任意覆盖层使用
Warning

版本基线 @deepseek-ai/dsh 0.1.0-rc.6 处于 Developer Preview,profile/bundle 机制仍在快速迭代。命令以 dsh --version 实测为准;--dump-config 看到的树,永远比文档描述更接近真相。

小结

  • Profile 是菜单,Bundle 是菜谱:一个决定装什么,一个决定怎么装。
  • Bundle 随 npm 包分发,声明 dsh.bundle;Profile 存在 Harness home,声明 dsh.profile
  • 没有东西同时是两者;普通 npm 包没有 dsh.bundle 就不激活配置层。
  • 四层叠加:Bundle 序 → Profile patch → home patch → --patch,后层覆盖前层。
  • patch 按 id 定位条目、替换整个 config;验证用 dsh --profile web --dump-config